• 基于iTop4412的FM收音机系统设计(二)


    说明:第一版架构为: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 
    13                   Slog.i(TAG, "FM Service");
    14 
    15                   ServiceManager.addService("fm5767", new FMService());
    16 
    17             } catch (Throwable e) {
    18 
    19                   Slog.e(TAG, "Failure starting FM Service", e);
    20 
    21             }  
    22         }
    23     }
    24 }

       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 = 0;
     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 = 0;
     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     
     78     static void tea5767_enableMute(JNIEnv* env, jobject clazz, jint enable){
     79 
     80         if(!tea5767_device){
     81             LOGE("FM jni is not open..");
     82             return ;
     83         }
     84         tea5767_device->enableMute(tea5767_device,enable);
     85         LOGI("enableMute state = %d",enable);
     86 
     87         return ;
     88     }
     89 
     90     static jint tea5767_getIsMute(JNIEnv* env, jobject clazz){
     91         int enable = 0;
     92         if(!tea5767_device){
     93             LOGE("FM jni is not open..");
     94             return enable;
     95         }
     96         enable = tea5767_device->getIsMute(tea5767_device);
     97         LOGI("getIsMute state = %d",enable);
     98 
     99         return enable;
    100     }
    101 
    102     static void tea5767_autoSearch(JNIEnv* env, jobject clazz){
    103 
    104         if(!tea5767_device){
    105             LOGE("FM jni is not open..");
    106             return ;
    107         }
    108         tea5767_device->autoSearch(tea5767_device);
    109         LOGI("fm start autoSearch");
    110 
    111         return ;
    112     }
    113 
    114    /*通过硬件抽象层定义的硬件模块打开接口打开硬件设备*/  
    115     static inline int tea5767_device_open(const hw_module_t* module, struct tea5767_device_t** device) { 
    116  
    117         return module->methods->open(module, tea5767_HARDWARE_MODULE_ID, (struct hw_device_t**)device);  
    118     }  
    119     
    120     /*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/  
    121     static jboolean tea5767_init(JNIEnv* env, jclass clazz) {  
    122         tea5767_module_t* module;  
    123           
    124         LOGI("tea5767 JNI: initializing......");  
    125         if(hw_get_module(tea5767_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {  
    126             LOGI("tea5767 JNI: tea5767 Stub found.");  
    127             if(tea5767_device_open(&(module->common), &tea5767_device) == 0) {  
    128                 LOGI("tea5767 JNI: tea5767 device is open.");  
    129                 return 0;  
    130             }  
    131             LOGE("tea5767 JNI: failed to open tea5767 device.");  
    132             return -1;  
    133         }  
    134         LOGE("tea5767 JNI: failed to get tea5767 stub module.");  
    135         return -1;        
    136     }  
    137         /*JNI方法表*/  
    138     static const JNINativeMethod method_table[] = {  
    139         {"init_native", "()Z", (void*)tea5767_init},
    140         {"getADC_native", "()I", (void*)tea5767_getADC},
    141         {"getFreq_native", "()I", (void*)tea5767_getFreq},
    142         {"setFreq_native", "(I)V", (void*)tea5767_setFreq},
    143         {"searchNextorPreFreq_native", "(I)V", (void*)tea5767_searchNextorPreFreq},
    144         {"setNextorPreFreq_native", "(I)V", (void*)tea5767_setNextorPreFreq},
    145         {"enableMute_native", "(I)V", (void*)tea5767_enableMute},
    146         {"getIsMute_native", "()I", (void*)tea5767_getIsMute},
    147         {"startAutoSearch_native", "()V", (void*)tea5767_autoSearch},
    148     };  
    149         /*注册JNI方法*/  
    150     int register_android_server_FMService(JNIEnv *env) {  
    151         return jniRegisterNativeMethods(env, "com/android/server/FMService", method_table, NELEM(method_table));  
    152     }  
    153 }; 

        注意: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: 1,  
     52         version_minor: 0,  
     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, 0, sizeof(struct tea5767_device_t));  
     70     dev->common.tag = HARDWARE_DEVICE_TAG;  
     71     dev->common.version = 0;  
     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)) == -1) {  
     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 0;  
     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 0;  
    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, 0);
    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,100, 0);
    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, 0);
    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, 0);
    158     }else{
    159         ret = ioctl(dev->fd,CLOSEMUTE, 0);
    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, 0);
    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, 87500);
    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=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
    36         if (i < HAL_VARIANT_KEYS_COUNT) {
    37             if (property_get(variant_keys[i], prop, NULL) == 0) {
    38                 continue;
    39             }
    40             snprintf(path, sizeof(path), "%s/%s.%s.so",
    41                      HAL_LIBRARY_PATH2, name, prop);
    42             if (access(path, R_OK) == 0) break;
    43 
    44             snprintf(path, sizeof(path), "%s/%s.%s.so",
    45                      HAL_LIBRARY_PATH1, name, prop);
    46             if (access(path, R_OK) == 0) break;
    47         } else {
    48             snprintf(path, sizeof(path), "%s/%s.default.so",
    49                      HAL_LIBRARY_PATH1, name);
    50             if (access(path, R_OK) == 0) break;
    51         }
    52     }
    53 
    54     status = -ENOENT;
    55     if (i < HAL_VARIANT_KEYS_COUNT+1) {
    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 
    3 ifeq ($(BOARD_HAVE_MTK_MT6620),true)
    4 hardware_modules += gps
    5 endif
    6 
    7 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文件,添加

        chmod 0777 /dev/tea5767

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

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

    完整工程代码下载:

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

  • 相关阅读:
    ArcGIS添加鹰眼
    C#设计模式--工厂方法
    C#设计模式--简单工厂
    C# 单例模式(转)
    事务的 原子性、一致性、隔离性、持久性
    asp.net 常用的3中身份验证
    angular localStorage使用方法
    angular.js升序降序过滤器
    ionic中$ionicPopover和$ionicModal
    ionic的弹出框$ionicPopover
  • 原文地址:https://www.cnblogs.com/pngcui/p/7284479.html
Copyright © 2020-2023  润新知