版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Android驱动-LED驱动的编写1.编写Android驱动时,首先先要完成Linux驱动,因为android驱动其实是在linux驱动基础之上完成了HAL层(硬件抽象层),如果想要测试的话,自己也要编写Java程序来测试你的驱动。2.android的根文件系统是eclair_2.1版本。我会上传做好的根文件系统提供大家。这里要说的是,android底层内核还是linux的内核,只是进行了一些裁剪。做好的linux内核镜像,这个我也会上传给大家。android自己做了一套根文件系统,这才是android自己做的东西。android事实上只是做了一套根文件系统罢了。 假设linux驱动大家都已
2、经做好了。我板子上有四个灯,通过ioctl控制四个灯,给定不同的参数,点亮不同的灯。linux驱动代码因平台不同而有所不同,这就不黏代码了。这是我测试linux驱动编写的驱动,代码如下: cpp view plaincopy #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #i
3、nclude <sys/ioctl.h> #define LED_ON _IO ('k',1) #define LED_OFF _IO ('k',2) int main() int i = 0; int dev_fd; dev_fd = open("/dev/led",O_RDWR); if ( dev_fd = -1 ) printf("Cann't open file /dev/ledn"); exit(1); while(1) ioctl(dev_fd,LED_ON,1); sleep(1); i
4、octl(dev_fd,LED_OFF,1); sleep(1); ioctl(dev_fd,LED_ON,2); sleep(1); ioctl(dev_fd,LED_OFF,2); sleep(1); ioctl(dev_fd,LED_ON,3); sleep(1); ioctl(dev_fd,LED_OFF,3); sleep(1); ioctl(dev_fd,LED_ON,4); sleep(1); ioctl(dev_fd,LED_OFF,4); sleep(1); return 0; 下面开始把linux驱动封装成android驱动。首先介绍一下android驱动用到的三个重要的结
5、构体,struct hw_module_t;struct hw_device_t;struct hw_module_methods_t;android源码里面结构体的声明cpp view plaincopy typedef struct hw_module_t uint 32_t tag; uint16_t version_major; uint16_t version_minor; const char *id; const char *name; const char *author; const hw_module_methods_t *methods; void* dso; uint3
6、2_t reserved32-7; hw_module_t; cpp view plaincopy typedef struct hw_device_t uint32_t tag; uint32_t version; struct hw_module_t* module; uint32_t reserved12; int (*close) (struct hw_device_t *device); hw_device_t; cpp view plaincopy typedef struct hw_module_methods_t int (*open) (const struct hw_mod
7、ule_t *module, const char *id, struct hw_device_t *device); hw_module_methods_t; 我们经常会用到这三个结构体。 android驱动目录结构:led |- hal | |-jni | |- Android.mk | |-com_farsgiht_server_ledServer.cpp | |-stub | |- include | | |-led.h | |-module | |-Android.mk | |-led.c |- linux_drv首先我们要编写一个stub(代理),代理的意思是,针对你所特有的设备,
8、你找一个代理人就可以帮你完成,它是操作linux驱动的第一层。编写头文件,名字led.h代码如下;cpp view plaincopy #include <hardware/hardware.h> #include <fcntl.h> #include <errno.h> #include <cutils/log.h> #include <cutils/atomic.h> #define LED_HARDWARE_MODULE_ID "led" struct led_module_t struct hw_modul
9、e_t common; ; struct led_control_device_t struct hw_device_t common; int (*set_on) (struct led_control_device_t *dev, int arg); int (*set_off)(struct led_control_device_t *dev, int arg); ; struct led_control_context_t struct led_control_device_t device; ; struct hw_module_t sturct hw_device_t 这两个结构体
10、不能直接使用,所以进行了一下封装(继承)。led_module_t 继承 hw_module_tled_control_device_t 继承 hw_device_tled_control_context_t 继承 led_control_device_t在led_control_device_t 结构体有函数指针的声明,因为后面代码中会给这些函数指针赋值 编写led.c代码如下:cpp view plaincopy #define LOG_TAG "LedStub" #include <hardware/hardware.h> #include <fcn
11、tl.h> #include <errno.h> #include <cutils/log.h> #include <cutils/atomic.h> #include <sys/ioctl.h> #include "./include/led.h" #define LED_ON _IO ('k',1) #define LED_OFF _IO ('k',2) int fd; static int led_set_on(struct led_control_device_t *dev, in
12、t arg) LOGI("led_set_on"); ioctl(fd, LED_ON, arg); return 0; static int led_set_off(struct led_control_device_t *dev, int arg) LOGI("led_set_off"); ioctl(fd, LED_OFF, arg); return 0; static int led_device_close(struct hw_device_t *device) struct led_control_context_t *context = (
13、struct led_control_context_t *)device; if(context) free(context); close(fd); return 0; static int led_device_open(const struct hw_module_t *module, const char *name, struct hw_device_t *device) struct led_control_context_t *context; LOGD("led_device_open"); context = (struct led_control_co
14、ntext_t *)malloc(sizeof(*context); memset(context, 0, sizeof(*context); context->mon.tag = HARDWARE_DEVICE_TAG; context->mon.version = 0; context->mon.module= module; context->mon.close = led_device_close; context->device.set_on = led_set_on; context->device.set_off = led_set_off;
15、*device = (struct hw_device_t *)&(context->device); if(fd = open("/dev/led",O_RDWR) = -1) LOGI("ERROR: open"); else LOGI("open led device okn"); return 0; static struct hw_module_methods_t led_module_methods = open:led_device_open ; const struct led_module_t HAL_
16、MODULE_INFO_SYM = common: tag: HARDWARE_MODULE_TAG, version_major:1, version_minor:0, id:LED_HARDWARE_MODULE_ID, name:"d_stub", author:"K_Linux_Man", methods: &led_module_methods, , ; 首先先看 struct led_module_t HAL_MODULE_INFO_SYM。这个结构体的名字必须是这个名字,否则系统无法找到led_module_t这个结构体。然后对le
17、d_module_t 里的成员hw_module_t结构体赋值。最关键的为id和methods两个成员的赋值,id必须要赋值,因为后面有个函数要找到hw_module_t就是通过id号去找的。 methods被赋值之后,上层的jni才能去调用。接着看methods 结构体里的成员就一个,open函数指针,对这个函数指针进行了赋值,赋了led_device_open函数,这个函数实现的主要就是分配led_control_context_t结构体空间,并对成员进行赋值。注意hw_device_t 里的成员module、close必须赋值。函数指针赋值:context->device.set_
18、on = led_set_on;context->device.set_off = led_set_off;下面这句话的用意是,传进来的device指针赋予新的值,只要调用这个函数,传进来的二级指针所指向的一级指针就有值了(二级指针改变了一级指针的指向,你可以看我写的 int*p 和 int *p 博文)。*device = (struct hw_device_t *)&(context->device);接着就是打开设备文件,得到fdled_set_on();里面调用ioctl;led_set_off();里面调用ioctl; 接下来写jni了。com_farsight_
19、server_ledServer.cpp文件文件代码:cpp view plaincopy #define LOG_TAG "ledService" #include "utils/Log.h" #include <stdlib.h> #include <string.h> #include <unistd.h> #include <assert.h> #include <jni.h> #include "./stub/include/led.h" static led_co
20、ntrol_device_t *sLedDevice = NULL; static jint led_set_on(JNIEnv *env, jobject thiz, jint arg) if(sLedDevice) LOGI("led_set_on"); sLedDevice->set_on(sLedDevice, (int)arg); se LOGI("sLedDevice is NULL"); ; return 0; static jint led_set_off(JNIEnv *env, jobject thiz, jint arg) i
21、f(sLedDevice) LOGI("led_set_off"); sLedDevice->set_off(sLedDevice, (int)arg); else LOGI("sLedDevice is null"); return 0; static inline int led_control_open(const struct hw_module_t *module, struct led_control_device_t *device) LOGI("led_control_open"); return module-
22、>methods->open(module, LED_HARDWARE_MODULE_ID, (struct hw_device_t *)device); static jint led_init(JNIEnv *env, jclass clazz) led_module_t const *module; LOGI("led_init"); if(hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t *)&module) = 0) LOGI("get Module OK");
23、 if (led_control_open(&module->common, &sLedDevice) != 0) LOGI("led_init error"); return -1; LOGI("led_init success"); return 0; static const JNINativeMethod gMethods = "_init", "()Z", (void *)led_init, "_set_on", "(I)I", (void *
24、)led_set_on, "_set_off", "(I)I", (void *)led_set_off, ; static int registerMethods(JNIEnv *env) static const char * const kClassName = "com/farsight/server/ledService" jclass clazz; clazz = env->FindClass(kClassName); if(clazz = NULL) LOGE("Can't find class
25、%sn", kClassName); return -1; if(env->RegisterNatives(clazz, gMethods, sizeof(gMethods)/sizeof(gMethods0) != JNI_OK) LOGE("failed registering methods for %sn", kClassName); return -1; return 0; jint JNI_OnLoad(JavaVM *vm, void *reserved) JNIEnv *env = NULL; jint ult = -1; LOGI(&quo
26、t;JNI_onLoad"); if(vm->GetEnv(void *)&env, JNI_VERSION_1_4) != JNI_OK) LOGE("ERROR: jni_onload()n"); goto fail; assert(env != NULL); if(registerMethods(env) != 0) LOGE("ERROR: registerMethod()n"); goto fail; result = JNI_VERSION_1_4; fail: return result; 在jni里首先加载jni库
27、文件的时候先要调用JNI_OnLoad函数,通过系统函数GetEnv让env指针获得有效的值。然后接着调用registerMethods函数,这个函数是自己定义一个函数。static const char * const kClassName = "com/farsight/server/ledService" 类名与Eclipse下开发对应的包一致。不过点换成了下划线。然后找到对应的类,接着就是向系统注册Native函数(Native Interface即本地接口函数),函数列表gMethods里 _init是上层framework去加载库时候调用的,当上层调用_init
28、时,与之对应调用的函数就是led_init, ()Z的意思是函数led_init参数为空,返回为空。这里其实就是做了一个函数的映射,上层用的java函数,在这里与之对应成c 函数。同理,其余的_set_on _set_off就不必赘述。在调用led_init()函数时,系统是如何找到与之对应的stub的呢(也就是如何找到hw_module_t结构体的呢)?主要的函数就是hw_get_module这个函数是通过第一个参数ID号,找到系统里已经存在的与之对应id号的stub(即led_module_t HAL_MODULE_INFO_SYM 结构体变量),第二个参数就传进去的二级指针,让modul
29、e获取有效的值,接着调用 led_control_open,这个函数是内联函数,函数里面接着调用了HAL_MODULE_INFO_SYM 里的methods,methods里就一个成员open,其实呢就是调用了led.c(stub)的led_device_open函数,sLedDevice指针是一个全局变量,经过这个函数的调用,sLedDevice就获得了hw_deive_t的地址(sLedDevice指向了hw_device_t)。本来一个指针没有值,但是通过传进去二级指针,就能让原来为空的指针获得有效的值,你可以参考我写的博文 int*p和 int *p,对你们理解二级指针改变一级指针指向有帮助。既然在jni层能够获得stub里的hw_module_t 和 hw_device_t,那么去调用stub里的函数也就不是问题了。 接下来就是去实现framework层了,framew层里的service去调用jni的。framework层里的service是在eclipse下开发的。文件名:ledService.java代码:cpp view plaincopy package c
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026上半年四川成都市卫生健康委员会所属部分事业单位招聘166人备考题库必考附答案详解
- 2026海南海口市美兰区校园招聘教师45人备考题库(一)含答案详解【黄金题型】
- 2026广东韶关市始兴县青年就业见习基地招募见习人员备考题库含答案详解【基础题】
- 2026广东佛山市顺德区乐从第一实验学校(教务文员)招聘1人备考题库带答案详解(预热题)
- 2026湖北恩施州来凤县绿水镇中心幼儿园带班教师1名备考题库【满分必刷】附答案详解
- 2026广东高鲲能源数据投资有限公司招聘第四批人员6人备考题库附答案详解ab卷
- 2026云南省房物业管理有限公司招聘12人备考题库及完整答案详解【各地真题】
- 2026浙江宁波华侨温德姆至尊豪廷大酒店招聘2人备考题库带答案详解(a卷)
- 2026广东佛山市南海区大沥镇太平成远小学招聘备考题库【能力提升】附答案详解
- 2026江苏宿迁市泗洪县招聘合同制和公益性岗位人员15人备考题库及参考答案详解(突破训练)
- 2026年江苏信息职业技术学院单招职业倾向性测试必刷测试卷附答案
- 2026年皖北卫生职业学院单招职业适应性测试题库附答案
- 海事局国考面试题及答案
- 2026年江西电力职业技术学院单招职业技能考试题库及参考答案详解1套
- 妇科肿瘤及早期症状
- 谈话室装修合同范本
- 化肥产品生产许可证实施细则(一)(复肥产品部分)2025
- 骨关节疾病的pt康复教案
- 备战2026年中考语文5年中考2年模拟真题作文探究-【浙江省】(解析版)
- 2025年10月自考00908网络营销与策划试题及答案含评分参考
- 天然水体中的主要离子专题培训教案
评论
0/150
提交评论