说明:第一版架构为:APP+JNI(NDK)+Driver(linux),优点是开发简单,周期短,也作为自己的毕业设计

   现在更新第二版,FM服务完全植入Android系统中,成为系统服务,架构为:APP+Frameworks+JNI+HAL+Driver

整个系统设计,大致分为三篇文章介绍完毕,包括:

一、驱动设计篇

二、系统API接口篇

三、APP功能实现篇

---------------------------------------------------(二)系统接口篇-----------------------------------------------------------------

说明:关于系统接口,在FM系统中完全用不到这么复杂的流程,我这里是想把整个系统调用流程捋顺,所以使用了Frameworks(AIDL)->JNI->HAL

1.Frameworks

  1.1.首先我们需设计好暴露给APP端的API接口,这里我们采用aidl的机制实现

    进入到frameworks/base/core/java/android/os目录下,新建IFMService.aidl文件

  1. package android.os;
  2.  
  3. interface IFMService {
  4. int getADC();
  5. int getFreq();
  6. void setFreq(int freq);
  7. void searchNextorPreFreq(int enable);
  8. void setNextorPreFreq(int enable);
  9. void enableMute(int enable);
  10. int getIsMute();
  11. void startAutoSearch();
  12. }

  1.2.回到frameworks/base目录,编写编译规则,生成Stub接口文件

    打开Android.mk文件,在LOCAL_SRC_FILES属性中添加

  1. LOCAL_SRC_FILES += \
  2. ...
  3. core/java/android/os/IFMService.aidl \
  4. ...

  1.3.在frameworks/base目录下,使用mm命令编译IFMService.aidl生成IHelloService.Stub,在使用mm目录之前需要lunch系统的编译环境

    Stub实质上就是binder通信,client<-->proxy<-->stub<-->service

  1.4.进入到frameworks/base/services/java/com/android/server,新建FMService.java文件,继承IHelloService.Stub并实现接口函数

  1. package com.android.server;
  2.  
  3. import android.content.Context;
  4. import android.os.IFMService;
  5. import android.util.Slog;
  6.  
  7. public class FMService extends IFMService.Stub {
  8.  
  9. private static final String TAG = "FMService";
  10.  
  11. FMService() {
  12. Slog.d(TAG,"FM init...");
  13. init_native();
  14. }
  15.  
  16. public int getADC(){
  17.  
  18. return getADC_native();
  19. }
  20.  
  21. public int getFreq(){
  22. return getFreq_native();
  23. }
  24.  
  25. public void setFreq(int freq){
  26.  
  27. setFreq_native(freq);
  28. return ;
  29. }
  30.  
  31. public void searchNextorPreFreq(int enable){
  32.  
  33. searchNextorPreFreq_native(enable);
  34. return ;
  35. }
  36.  
  37. public void setNextorPreFreq(int enable){
  38.  
  39. setNextorPreFreq_native(enable);
  40. return ;
  41. }
  42.  
  43. public void enableMute(int enable){
  44.  
  45. enableMute_native(enable);
  46. return ;
  47. }
  48.  
  49. public int getIsMute(){
  50. return getIsMute_native();
  51. }
  52.  
  53. public void startAutoSearch(){
  54.  
  55. startAutoSearch_native();
  56. return ;
  57. }
  58.  
  59. private static native boolean init_native();
  60. private static native int getADC_native();
  61. private static native int getFreq_native();
  62. private static native void setFreq_native(int freq);
  63. private static native void searchNextorPreFreq_native(int enable);
  64. private static native void setNextorPreFreq_native(int enable);
  65. private static native void enableMute_native(int enable);
  66. private static native int getIsMute_native();
  67. private static native void startAutoSearch_native();
  68.  
  69. };

    在这个文件中,我们把函数调用传递到了JNI

  1.5.最后在Frameworks中我们需要启动我们的FMservice

    进入frameworks/base/services/java/com/android/server目录,在SystemServer.java文件中添加

  1. class ServerThread extends Thread {
  2. @Override
  3. public void run() {
  4. if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
  5. try {
  6. Slog.i(TAG, "DiskStats Service");
  7. ServiceManager.addService("diskstats", new DiskStatsService(context));
  8. } catch (Throwable e) {
  9. reportWtf("starting DiskStats Service", e);
  10. }
  11. try {
  12. Slog.i(TAG, "FM Service");
  13. ServiceManager.addService("fm5767", new FMService());
  14. } catch (Throwable e) {
  15. Slog.e(TAG, "Failure starting FM Service", e);
  16. }
  17. }
  18. }
  19. }

  1.6.编译service(若修改了service的实现方法可模块编译service模块)

    进入frameworks/base/services/java,使用命令mm进行编译,在out目录下的system/frameworks下生成services.jar,使用adb直接cp到板子上重启即可生效

2.JNI

  2.1.实现JNi函数,函数传递到HAL层

    进入frameworks/base/services/jni目录,新建com_android_server_FMService.cpp文件

  1. #define LOG_TAG "FMService_jni"
  2. #include "jni.h"
  3. #include "JNIHelp.h"
  4. #include "android_runtime/AndroidRuntime.h"
  5. #include <utils/misc.h>
  6. #include <utils/Log.h>
  7. #include <hardware/hardware.h>
  8. #include <hardware/hw_tea5767.h>
  9. #include <stdio.h>
  10.  
  11. namespace android
  12. {
  13. /*在硬件抽象层中定义的硬件访问结构体,参考<hardware/tea5767.h>*/
  14. struct tea5767_device_t* tea5767_device = NULL;
  15.  
  16. //访问硬件的接口
  17. static jint tea5767_getADC(JNIEnv* env, jobject clazz){
  18. int adc = ;
  19. if(!tea5767_device){
  20. LOGE("FM jni is not open..");
  21. return adc;
  22. }
  23. adc = tea5767_device->getADC(tea5767_device);
  24. LOGI("get fm adc = %d",adc);
  25.  
  26. return adc;
  27. }
  28.  
  29. static jint tea5767_getFreq(JNIEnv* env, jobject clazz){
  30. int freq = ;
  31. if(!tea5767_device){
  32. LOGE("FM jni is not open..");
  33. return freq;
  34. }
  35. freq = tea5767_device->getFreq(tea5767_device);
  36. LOGI("get fm freq = %d",freq);
  37.  
  38. return freq;
  39. }
  40.  
  41. static void tea5767_setFreq(JNIEnv* env, jobject clazz, jint freq){
  42.  
  43. if(!tea5767_device){
  44. LOGE("FM jni is not open..");
  45. return ;
  46. }
  47. tea5767_device->setFreq(tea5767_device,freq);
  48. LOGI("set fm freq = %d",freq);
  49.  
  50. return ;
  51. }
  52.  
  53. static void tea5767_searchNextorPreFreq(JNIEnv* env, jobject clazz, jint enable){
  54.  
  55. if(!tea5767_device){
  56. LOGE("FM jni is not open..");
  57. return ;
  58. }
  59. tea5767_device->searchNextorPreFreq(tea5767_device,enable);
  60. LOGI("searchNextorPreFreq state = %d",enable);
  61.  
  62. return ;
  63. }
  64.  
  65. static void tea5767_setNextorPreFreq(JNIEnv* env, jobject clazz, jint enable){
  66.  
  67. if(!tea5767_device){
  68. LOGE("FM jni is not open..");
  69. return ;
  70. }
  71. tea5767_device->setNextorPreFreq(tea5767_device,enable);
  72. LOGI("setNextorPreFreq state = %d",enable);
  73.  
  74. return ;
  75. }
  76.  
  77. static void tea5767_enableMute(JNIEnv* env, jobject clazz, jint enable){
  78.  
  79. if(!tea5767_device){
  80. LOGE("FM jni is not open..");
  81. return ;
  82. }
  83. tea5767_device->enableMute(tea5767_device,enable);
  84. LOGI("enableMute state = %d",enable);
  85.  
  86. return ;
  87. }
  88.  
  89. static jint tea5767_getIsMute(JNIEnv* env, jobject clazz){
  90. int enable = ;
  91. if(!tea5767_device){
  92. LOGE("FM jni is not open..");
  93. return enable;
  94. }
  95. enable = tea5767_device->getIsMute(tea5767_device);
  96. LOGI("getIsMute state = %d",enable);
  97.  
  98. return enable;
  99. }
  100.  
  101. static void tea5767_autoSearch(JNIEnv* env, jobject clazz){
  102.  
  103. if(!tea5767_device){
  104. LOGE("FM jni is not open..");
  105. return ;
  106. }
  107. tea5767_device->autoSearch(tea5767_device);
  108. LOGI("fm start autoSearch");
  109.  
  110. return ;
  111. }
  112.  
  113. /*通过硬件抽象层定义的硬件模块打开接口打开硬件设备*/
  114. static inline int tea5767_device_open(const hw_module_t* module, struct tea5767_device_t** device) {
  115.  
  116. return module->methods->open(module, tea5767_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
  117. }
  118.  
  119. /*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/
  120. static jboolean tea5767_init(JNIEnv* env, jclass clazz) {
  121. tea5767_module_t* module;
  122.  
  123. LOGI("tea5767 JNI: initializing......");
  124. if(hw_get_module(tea5767_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == ) {
  125. LOGI("tea5767 JNI: tea5767 Stub found.");
  126. if(tea5767_device_open(&(module->common), &tea5767_device) == ) {
  127. LOGI("tea5767 JNI: tea5767 device is open.");
  128. return ;
  129. }
  130. LOGE("tea5767 JNI: failed to open tea5767 device.");
  131. return -;
  132. }
  133. LOGE("tea5767 JNI: failed to get tea5767 stub module.");
  134. return -;
  135. }
  136. /*JNI方法表*/
  137. static const JNINativeMethod method_table[] = {
  138. {"init_native", "()Z", (void*)tea5767_init},
  139. {"getADC_native", "()I", (void*)tea5767_getADC},
  140. {"getFreq_native", "()I", (void*)tea5767_getFreq},
  141. {"setFreq_native", "(I)V", (void*)tea5767_setFreq},
  142. {"searchNextorPreFreq_native", "(I)V", (void*)tea5767_searchNextorPreFreq},
  143. {"setNextorPreFreq_native", "(I)V", (void*)tea5767_setNextorPreFreq},
  144. {"enableMute_native", "(I)V", (void*)tea5767_enableMute},
  145. {"getIsMute_native", "()I", (void*)tea5767_getIsMute},
  146. {"startAutoSearch_native", "()V", (void*)tea5767_autoSearch},
  147. };
  148. /*注册JNI方法*/
  149. int register_android_server_FMService(JNIEnv *env) {
  150. return jniRegisterNativeMethods(env, "com/android/server/FMService", method_table, NELEM(method_table));
  151. }
  152. };

    注意:1.在tea5767_init函数中,通过HAL层提供的hw_get_module方法来加载模块ID,即tea5767_HARDWARE_MODULE_ID的硬件抽象层模块,而这个ID是在<hardware/hw_tea5767.h>中定义的。HAL层会根据该ID的值在Android系统的/system/lib/hw目录中找到相应的模块,然后加载起来,并且返回hw_module_t接口给调用者使用。

      2.在jniRegisterNativeMethods函数中,第二个参数的值必须对应FMService所在的包的路径,即com.android.server.FMService。

  2.2.自动加载FM模块的jni方法

    进入frameworks/base/services/jni目录中,编辑onload.cpp文件,添加属性

  1. namespace android {
  2. ...
  3. int register_android_server_FMService(JNIEnv *env);
  4. };
  5.  
  6. extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
  7. {
  8. ...
  9. register_android_server_FMService(env);
  10.  
  11. return JNI_VERSION_1_4;
  12. }

  2.3 添加编译选项,编译Fm的JNI模块

    进入frameworks/base/services/jni目录中,编辑Android.mk文件

  1. LOCAL_SRC_FILES:= \
  2. ...
  3. com_android_server_FMService.cpp \
  4. onload.cpp

  2.4.编译

    进入frameworks/base/services/jni目录,执行命令mm,编译,最后会在system/lib下生成libandroid_servers.so文件

3.HAL层

  3.1.定义HAL层的接口

    进入hardware/libhardware/include/hardware目录下,新建hw_tea5767.h文件

  1. #ifndef ANDROID_TEA5767_INTERFACE_H
  2. #define ANDROID_TEA5767_INTERFACE_H
  3. #include <hardware/hardware.h>
  4.  
  5. __BEGIN_DECLS
  6.  
  7. /*定义模块ID*/
  8. #define tea5767_HARDWARE_MODULE_ID "tea5767"
  9.  
  10. /*硬件模块结构体*/
  11. struct tea5767_module_t {
  12. struct hw_module_t common;
  13. };
  14.  
  15. /*硬件接口结构体*/
  16. struct tea5767_device_t {
  17. struct hw_device_t common;
  18. int fd;
  19. int (*getADC)(struct tea5767_device_t* dev);
  20. int (*getFreq)(struct tea5767_device_t* dev);
  21. void (*setFreq)(struct tea5767_device_t* dev, int freq);
  22. void (*searchNextorPreFreq)(struct tea5767_device_t* dev, int enable);
  23. void (*setNextorPreFreq)(struct tea5767_device_t* dev, int enable);
  24. void (*enableMute)(struct tea5767_device_t* dev, int enable);
  25. int (*getIsMute)(struct tea5767_device_t* dev);
  26. void (*autoSearch)(struct tea5767_device_t* dev);
  27. };
  28.  
  29. __END_DECLS
  30.  
  31. #endif

  3.2.实现HAL层的方法

    进入hardware/libhardware/modules目录下,新建hwfm/hwtea5767.c文件

  1. #define LOG_TAG "FM5767_Stub"
  2.  
  3. #include <hardware/hardware.h>
  4. #include <hardware/hw_tea5767.h>
  5. #include <fcntl.h>
  6. #include <errno.h>
  7. #include <cutils/log.h>
  8. #include <cutils/atomic.h>
  9.  
  10. #define DEVICE_NAME "/dev/tea5767"
  11. #define MODULE_NAME "tea5767"
  12. #define MODULE_AUTHOR "pngcui"
  13.  
  14. #define Search 3
  15. #define AutoSearch 4
  16. #define SETFREQ 5
  17. #define OPENMUTE 8
  18. #define CLOSEMUTE 9
  19. #define SHUTDOWN 10
  20. #define ADC 100
  21. #define FREQ 101
  22.  
  23. /*设备打开和关闭接口*/
  24. static int tea5767_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);
  25. static int tea5767_device_close(struct hw_device_t* device);
  26.  
  27. /*设备访问接口*/
  28. static int fm_getADC(struct tea5767_device_t* dev);
  29. static int fm_getFreq(struct tea5767_device_t* dev);
  30. static void fm_setFreq(struct tea5767_device_t* dev, int freq);
  31. static void fm_searchNextorPreFreq(struct tea5767_device_t* dev, int enable);
  32. static void fm_setNextorPreFreq(struct tea5767_device_t* dev, int enable);
  33. static void fm_enableMute(struct tea5767_device_t* dev, int enable);
  34. static int fm_getIsMute(struct tea5767_device_t* dev);
  35. static void fm_autoSearch(struct tea5767_device_t* dev);
  36.  
  37. /*模块方法表*/
  38. static struct hw_module_methods_t tea5767_module_methods = {
  39. open: tea5767_device_open
  40. };
  41.  
  42. /*
  43. *
  44. *实例变量名必须为HAL_MODULE_INFO_SYM,tag也必须为HARDWARE_MODULE_TAG,这是Android硬件抽象层规范规定的。
  45. */
  46.  
  47. /*模块实例变量*/
  48. struct tea5767_module_t HAL_MODULE_INFO_SYM = {
  49. common: {
  50. tag: HARDWARE_MODULE_TAG,
  51. version_major: ,
  52. version_minor: ,
  53. id: tea5767_HARDWARE_MODULE_ID,
  54. name: MODULE_NAME,
  55. author: MODULE_AUTHOR,
  56. methods: &tea5767_module_methods,
  57. }
  58. };
  59.  
  60. static int tea5767_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) {
  61. struct tea5767_device_t* dev;
  62. dev = (struct tea5767_device_t*)malloc(sizeof(struct tea5767_device_t));
  63.  
  64. if(!dev){
  65. LOGE("tea5767 Stub: failed to malloc space");
  66. return -EFAULT;
  67. }
  68.  
  69. memset(dev, , sizeof(struct tea5767_device_t));
  70. dev->common.tag = HARDWARE_DEVICE_TAG;
  71. dev->common.version = ;
  72. dev->common.module = (hw_module_t*)module;
  73. dev->common.close = tea5767_device_close;
  74.  
  75. dev->getADC = fm_getADC;
  76. dev->getFreq = fm_getFreq;
  77. dev->setFreq = fm_setFreq;
  78. dev->searchNextorPreFreq = fm_searchNextorPreFreq;
  79. dev->setNextorPreFreq = fm_setNextorPreFreq;
  80. dev->enableMute = fm_enableMute;
  81. dev->autoSearch = fm_autoSearch;
  82. dev->getIsMute = fm_getIsMute;
  83.  
  84. if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -) {
  85. LOGE("tea5767 Stub: failed to open /dev/tea5767 -- %s.", strerror(errno));
  86. free(dev);
  87. return -EFAULT;
  88. }
  89.  
  90. *device = &(dev->common);
  91. LOGI("tea5767 Stub: open /dev/tea5767 successfully.");
  92.  
  93. return ;
  94. }
  95.  
  96. static int tea5767_device_close(struct hw_device_t* device) {
  97. struct tea5767_device_t* tea5767_device = (struct tea5767_device_t*)device;
  98.  
  99. if(tea5767_device) {
  100. close(tea5767_device->fd);
  101. free(tea5767_device);
  102. }
  103.  
  104. return ;
  105. }
  106.  
  107. static int fm_getADC(struct tea5767_device_t* dev){
  108. LOGI("fm get ADC....");
  109.  
  110. int ret = ioctl(dev->fd,ADC, );
  111. LOGI("ret = %d",ret);
  112.  
  113. return ret;
  114. }
  115.  
  116. static int fm_getFreq(struct tea5767_device_t* dev){
  117. LOGI("fm get fm_getFreq....");
  118.  
  119. int ret = ioctl(dev->fd,, );
  120. LOGI("ret = %d",ret);
  121.  
  122. return ret;
  123. }
  124.  
  125. static void fm_setFreq(struct tea5767_device_t* dev, int freq){
  126. LOGI("fm get fm_setFreq....");
  127.  
  128. int ret = ioctl(dev->fd,FREQ, );
  129. LOGI("ret = %d",ret);
  130.  
  131. return ret;
  132. }
  133. static void fm_searchNextorPreFreq(struct tea5767_device_t* dev, int enable){
  134. LOGI("fm get fm_searchNextorPreFreq....");
  135.  
  136. int ret = ioctl(dev->fd,Search, enable);
  137.  
  138. LOGI("ret = %d",ret);
  139.  
  140. return ret;
  141. }
  142.  
  143. static void fm_setNextorPreFreq(struct tea5767_device_t* dev, int enable){
  144. LOGI("fm get fm_setNextorPreFreq....");
  145.  
  146. int ret = ioctl(dev->fd,Search, enable);
  147. LOGI("ret = %d",ret);
  148.  
  149. return ret;
  150. }
  151.  
  152. static void fm_enableMute(struct tea5767_device_t* dev, int enable){
  153. LOGI("fm get fm_enableMute....");
  154.  
  155. int ret;
  156. if(enable){
  157. ret = ioctl(dev->fd,OPENMUTE, );
  158. }else{
  159. ret = ioctl(dev->fd,CLOSEMUTE, );
  160. }
  161. LOGI("ret = %d",ret);
  162.  
  163. return ret;
  164. }
  165.  
  166. static int fm_getIsMute(struct tea5767_device_t* dev){
  167. LOGI("fm get fm_getIsMute....");
  168.  
  169. int ret = ioctl(dev->fd,CLOSEMUTE, );
  170. LOGI("ret = %d",ret);
  171.  
  172. return ret;
  173. }
  174.  
  175. static void fm_autoSearch(struct tea5767_device_t* dev){
  176. LOGI("fm get fm_autoSearch....");
  177.  
  178. int ret = ioctl(dev->fd,AutoSearch, );
  179. LOGI("ret = %d",ret);
  180.  
  181. return ret;
  182. }

    通过这个函数,实际上是操作了FM的文件设备,即/dev/tea5767,使用ioctl调用驱动程序中的函数,最终驱动起芯片工作。

  3.3.添加编译选项

    3.3.1.进入hardware/libhardware/modules/hwfm下,新建Android.mk文件

  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
  4. LOCAL_SHARED_LIBRARIES := liblog
  5. LOCAL_SRC_FILES := hwtea5767.c
  6. LOCAL_MODULE := tea5767.smdk4x12
  7. LOCAL_MODULE_TAGS := optional
  8. include $(BUILD_SHARED_LIBRARY)

  这里的LOCAL_MODULE的定义规则,我们可以根据hardware/libhardware/hardware.c文件中得出

  1. #define HAL_LIBRARY_PATH1 "/system/lib/hw"
  2. #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
  3.  
  4. static const char *variant_keys[] = {
  5. "ro.hardware", /* This goes first so that it can pick up a different
  6. file on the emulator. */
  7. "ro.product.board",
  8. "ro.board.platform",
  9. "ro.arch"
  10. };
  11.  
  12. int hw_get_module_by_class(const char *class_id, const char *inst,
  13. const struct hw_module_t **module)
  14. {
  15. int status;
  16. int i;
  17. const struct hw_module_t *hmi = NULL;
  18. char prop[PATH_MAX];
  19. char path[PATH_MAX];
  20. char name[PATH_MAX];
  21.  
  22. if (inst)
  23. snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
  24. else
  25. strlcpy(name, class_id, PATH_MAX);
  26.  
  27. /*
  28. * Here we rely on the fact that calling dlopen multiple times on
  29. * the same .so will simply increment a refcount (and not load
  30. * a new copy of the library).
  31. * We also assume that dlopen() is thread-safe.
  32. */
  33.  
  34. /* Loop through the configuration variants looking for a module */
  35. for (i= ; i<HAL_VARIANT_KEYS_COUNT+ ; i++) {
  36. if (i < HAL_VARIANT_KEYS_COUNT) {
  37. if (property_get(variant_keys[i], prop, NULL) == ) {
  38. continue;
  39. }
  40. snprintf(path, sizeof(path), "%s/%s.%s.so",
  41. HAL_LIBRARY_PATH2, name, prop);
  42. if (access(path, R_OK) == ) break;
  43.  
  44. snprintf(path, sizeof(path), "%s/%s.%s.so",
  45. HAL_LIBRARY_PATH1, name, prop);
  46. if (access(path, R_OK) == ) break;
  47. } else {
  48. snprintf(path, sizeof(path), "%s/%s.default.so",
  49. HAL_LIBRARY_PATH1, name);
  50. if (access(path, R_OK) == ) break;
  51. }
  52. }
  53.  
  54. status = -ENOENT;
  55. if (i < HAL_VARIANT_KEYS_COUNT+) {
  56. /* load the module, if this fails, we're doomed, and we should not try
  57. * to load a different variant. */
  58. status = load(class_id, path, module);
  59. }
  60.  
  61. return status;
  62. }
  63.  
  64. int hw_get_module(const char *id, const struct hw_module_t **module)
  65. {
  66. return hw_get_module_by_class(id, NULL, module);
  67. }

    所以LOCAL_MODULE的命名应该为name.prop,而prop的值为getprop ro.product.board的属性,itop4412平台上是smdk4x12,故LOCAL_MODULE为tea5767.smdk4x12

    3.3.2.把hwfm文件夹添加到编译系统中

      进入到hardware/libhardware/modules目录下,编辑Android.mk文件

  1. hardware_modules := gralloc hwcomposer audio nfc hwfm

  2. ifeq ($(BOARD_HAVE_MTK_MT6620),true)
  3. hardware_modules += gps
  4. endif
  5.  
  6. include $(call all-named-subdir-makefiles,$(hardware_modules))

  3.4.编译

    进入hardware/libhardware/modules/hwfm下,执行命令mm,最后在/system/lib/hw下生成tea5767.smdk4x12.so文件

4.更改/dev/tea5767设备文件权限

  由于设备文件是在内核驱动里面通过device_create创建的,而device_create创建的设备文件默认只有root用户可读写,而我们的APP一般不具有root权限,这时候就导致打开设备文件失败而报错:failed to open /dev/tea5767 -- Permission denied.

  进入device/samsung/smdk4x12/conf目录,编辑init.smdk4x12.rc文件,添加

  1. chmod 0777 /dev/tea5767

  最后可以完整的编译一次Android测试

至此,从Frameworks暴露给APP的接口到驱动的调用完成,后续会进行优化,欢迎大家指出错误与不足指出,非常感谢~~

完整工程代码下载:

https://github.com/pngcui/FM-radio

基于iTop4412的FM收音机系统设计(二)的更多相关文章

  1. 基于iTop4412的FM收音机系统设计(一)

    说明:第一版架构为:APP+JNI(NDK)+Driver(linux),优点是开发简单,周期短,也作为自己的毕业设计 现在更新第二版,FM服务完全植入Android系统中,成为系统服务,架构为:AP ...

  2. 基于iTop4412的FM收音机系统设计(三)

    说明:第一版架构为:APP+JNI(NDK)+Driver(linux),优点是开发简单,周期短,也作为自己的毕业设计 现在更新第二版,FM服务完全植入Android系统中,成为系统服务,架构为:AP ...

  3. FM收音机 RDS的强大功能

    FM收音机 RDS的强大功能 分类: MTK2011-04-26 16:06 14889人阅读 评论(6) 收藏 举报 交通公告体育音乐娱乐教育 前言 随着发展,会有越来越多的电台具有RDS广播功能, ...

  4. 文献综述三:基于JSP的商品信息管理系统设计与开发

    一.基本信息 标题:基于JSP的商品信息管理系统设计与开发 时间:2015 出版源:Computer Knowledge and Technology 文件分类:jsp技术的系统开发 二.研究背景 通 ...

  5. TEA5676 + AT24C08 FM收音机 搜台 存台 mmap 实现读写

    硬件说明TEA5767 + AT24c08 要使用耳机收听,不加功放芯片,声音非常小. 这2个芯片都支持 3.3 或 5.0 电源支持连线比较简单,sda scl 接到 2440 对应的 排针上,找出 ...

  6. 基于web的图书管理系统设计与实现

    原文链接:基于web的图书管理系统设计与实现 系统演示链接:点击这里查看演示 01 系统简述     图书管理系统就是利用计算机,结合互联网对图书进行结构化.自动化管理的一种软件,来提高对图书的管理效 ...

  7. 基于web的图书管理系统设计与实现(附演示地址)

    欢迎访问博主个人网站,记得收藏哦,点击查看 - - - >>>> 公众号推荐:计算机类毕业设计系统源码,IT技术文章分享,游戏源码,网页模板 小程序推荐:网站资源快速收录--百 ...

  8. Android RecyclerView单击、长按事件:基于OnItemTouchListener +GestureDetector标准实现(二),封装抽取成通用工具类

     Android RecyclerView单击.长按事件:基于OnItemTouchListener +GestureDetector标准实现(二),封装抽取成通用工具类 我写的附录文章2,介绍了 ...

  9. 与众不同 windows phone (20) - Device(设备)之位置服务(GPS 定位), FM 收音机, 麦克风, 震动器

    原文:与众不同 windows phone (20) - Device(设备)之位置服务(GPS 定位), FM 收音机, 麦克风, 震动器 [索引页][源码下载] 与众不同 windows phon ...

随机推荐

  1. 如何规范移动应用交互设计?UI/UX设计师须知的11个小技巧

    以下内容由Mockplus团队翻译整理,仅供学习交流,Mockplus是更快更简单的原型设计工具. 十年前,手机的使用只是为了沟通. 而近几年,情况发生了很大变化,我们很难找到不使用手机的人.手机在极 ...

  2. Java设计模式(4)——单例模式

    转载:http://wiki.jikexueyuan.com/project/java-design-pattern/singleton-pattern.html 单例模式根据实例化对象时机的不同分为 ...

  3. chorme 浏览器记住密码后input黄色背景处理方法(两种)

    使用chrome浏览器选择记住密码的账号,输入框会自动加上黄色的背景,有些设计输入框是透明背景的,需要去除掉这个黄色的背景: 方法1:阴影覆盖 input:-webkit-autofill {   - ...

  4. 关于int转char类型引发的一些思考

    signed char unsigned char

  5. Linux gcc支持的语法 __attribute__ 属性设置

    __attribute__实际上是gcc专有的一种语法,是用来设置函数属性.变量属性.类属性的 语法:之前在C中的结构体对齐中提到过,当时是用来告诉编译器这个结构体的对齐方式 ,其实他还有很多种用法, ...

  6. WPF 绑定备忘单

     Part I – Common Examples Basic Binding   {Binding}  Bind to current DataContext. {Binding Name}  Bi ...

  7. SpringMvc与Struts2的对比

    目前企业中使用SpringMvc的比例已经远远超过Struts2,那么两者到底有什么区别,是很多初学者比较关注的问题,下面我们就来对SpringMvc和Struts2进行各方面的比较: 1.核心控制器 ...

  8. Low-level Thinking in High-level Shading Languages

    因为要反汇编shader代码,所以google了数学函数_sat的知识,发现了一些高级着色语言的优化相关的问题.Low-level Thinking in High-level Shading Lan ...

  9. Javascript Object.defineProperty()

    转载声明: 本文标题:Javascript Object.defineProperty() 本文链接:http://www.zuojj.com/archives/994.html,转载请注明转自Ben ...

  10. Solr相似度算法一:DefaultSimilarity(基于TF-IDF的默认相似度算法)

    默认的similarity是基于TF/IDF 模块. 该 similarity有以下配置选项: discount_overlaps –确定是否重叠的标识(标记位置增量为0)都将被忽略在正常计算的时候. ...