原链接:http://blog.csdn.net/k_linux_man/article/details/7023824
转载注明出处,作者:K_Linux_Man
开发平台:farsight s5pc100-a
内核:linux2.6.29
环境搭配:有博文介绍
开发环境:Ubuntu 、Eclipse
首先强调一下要点:
1.编写android驱动时,首先先要完成linux驱动,因为android驱动其实是在linux驱动基础之上完成了HAL层(硬件抽象层),如果想要测试的话,自己也要编写java程序来测试你的驱动。
2.android的根文件系统是eclair_2.1版本。我会上传做好的根文件系统提供大家。这里要说的是,android底层内核还是linux的内核,只是进行了一些裁剪。做好的linux内核镜像,这个我也会上传给大家。android自己做了一套根文件系统,这才是android自己做的东西。android事实上只是做了一套根文件系统罢了。
假设linux驱动大家都已经做好了。我板子上有四个灯,通过ioctl控制四个灯,给定不同的参数,点亮不同的灯。
linux驱动代码因平台不同而有所不同,这就不黏代码了。
这是我测试linux驱动编写的驱动,代码如下:
-
#include<stdio.h>
-
#include<stdlib.h>
-
#include<unistd.h>
-
#include<fcntl.h>
-
#include<string.h>
-
#include<sys/types.h>
-
#include<sys/stat.h>
-
#include<sys/ioctl.h>
-
#defineLED_ON_IO('k',1)
-
#defineLED_OFF_IO('k',2)
-
intmain()
-
{
-
inti=0;
-
intdev_fd;
-
dev_fd=open("/dev/led",O_RDWR);
-
if(dev_fd==-1){
-
printf("Cann'topenfile/dev/led\n");
-
exit(1);
-
}
-
while(1)
-
{
-
ioctl(dev_fd,LED_ON,1);
-
sleep(1);
-
ioctl(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);
-
-
}
-
return0;
-
}
下面开始把linux驱动封装成android驱动。
首先介绍一下android驱动用到的三个重要的结构体,
struct hw_module_t;
struct hw_device_t;
struct hw_module_methods_t;
android源码里面结构体的声明
-
typedefstructhw_module_t{
-
-
uint32_ttag;
-
-
uint16_tversion_major;
-
-
uint16_tversion_minor;
-
-
constchar*id;
-
-
constchar*name;
-
-
constchar*author;
-
-
consthw_module_methods_t*methods;
-
-
void*dso;
-
-
uint32_treserved[32-7];
-
-
}hw_module_t;
-
typedefstructhw_device_t{
-
-
uint32_ttag;
-
-
uint32_tversion;
-
-
structhw_module_t*module;
-
-
uint32_treserved[12];
-
-
int(*close)(structhw_device_t*device);
-
-
}hw_device_t;
-
typedefstructhw_module_methods_t{
-
-
int(*open)(conststructhw_module_t*module,constchar*id,
-
-
structhw_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(代理),代理的意思是,针对你所特有的设备,你找一个代理人就可以帮你完成,它是操作linux驱动的第一层。
编写头文件,名字led.h
代码如下;
-
#include<hardware/hardware.h>
-
#include<fcntl.h>
-
#include<errno.h>
-
#include<cutils/log.h>
-
#include<cutils/atomic.h>
-
-
-
#defineLED_HARDWARE_MODULE_ID"led"
-
-
-
structled_module_t{
-
structhw_module_tcommon;
-
};
-
-
structled_control_device_t{
-
structhw_device_tcommon;
-
-
int(*set_on)(structled_control_device_t*dev,intarg);
-
int(*set_off)(structled_control_device_t*dev,intarg);
-
};
-
-
-
structled_control_context_t{
-
structled_control_device_tdevice;
-
};
struct hw_module_t sturct hw_device_t 这两个结构体不能直接使用,所以进行了一下封装(继承)。
led_module_t 继承 hw_module_t
led_control_device_t 继承 hw_device_t
led_control_context_t 继承 led_control_device_t
在led_control_device_t 结构体有函数指针的声明,因为后面代码中会给这些函数指针赋值
编写led.c
代码如下:
-
#defineLOG_TAG"LedStub"
-
#include<hardware/hardware.h>
-
#include<fcntl.h>
-
#include<errno.h>
-
#include<cutils/log.h>
-
#include<cutils/atomic.h>
-
#include<sys/ioctl.h>
-
#include"../include/led.h"
-
-
-
#defineLED_ON_IO('k',1)
-
#defineLED_OFF_IO('k',2)
-
-
intfd;
-
-
staticintled_set_on(structled_control_device_t*dev,intarg)
-
{
-
LOGI("led_set_on");
-
ioctl(fd,LED_ON,arg);
-
return0;
-
}
-
-
staticintled_set_off(structled_control_device_t*dev,intarg)
-
{
-
LOGI("led_set_off");
-
ioctl(fd,LED_OFF,arg);
-
return0;
-
}
-
-
staticintled_device_close(structhw_device_t*device)
-
{
-
structled_control_context_t*context=(structled_control_context_t*)device;
-
if(context)free(context);
-
close(fd);
-
return0;
-
}
-
-
-
staticintled_device_open(conststructhw_module_t*module,constchar*name,
-
structhw_device_t**device)
-
{
-
structled_control_context_t*context;
-
LOGD("led_device_open");
-
context=(structled_control_context_t*)malloc(sizeof(*context));
-
memset(context,0,sizeof(*context));
-
-
context->device.common.tag=HARDWARE_DEVICE_TAG;
-
context->device.common.version=0;
-
context->device.common.module=module;
-
context->device.common.close=led_device_close;
-
-
context->device.set_on=led_set_on;
-
context->device.set_off=led_set_off;
-
-
*device=(structhw_device_t*)&(context->device);
-
-
if((fd=open("/dev/led",O_RDWR))==-1)
-
{
-
LOGI("ERROR:open");
-
}else{
-
LOGI("openleddeviceok\n");
-
}
-
-
return0;
-
}
-
-
staticstructhw_module_methods_tled_module_methods={
-
open:led_device_open
-
};
-
-
-
conststructled_module_tHAL_MODULE_INFO_SYM={
-
common:{
-
tag:HARDWARE_MODULE_TAG,
-
version_major:1,
-
version_minor:0,
-
id:LED_HARDWARE_MODULE_ID,
-
name:"led_stub",
-
author:"K_Linux_Man",
-
methods:&led_module_methods,
-
},
-
};
首先先看 struct led_module_t HAL_MODULE_INFO_SYM。这个结构体的名字必须是这个名字,否则系统无法找到led_module_t这个结构体。
然后对led_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_on = led_set_on;
context->device.set_off = led_set_off;
下面这句话的用意是,传进来的device指针赋予新的值,只要调用这个函数,传进来的二级指针所指向的一级指针就有值了(二级指针改变了一级指针的指向,你可以看我写的 int*p 和 int **p 博文)。
*device = (struct hw_device_t *)&(context->device);
接着就是打开设备文件,得到fd
led_set_on();里面调用ioctl;
led_set_off();里面调用ioctl;
接下来写jni了。。com_farsight_server_ledServer.cpp文件
文件代码:
-
#defineLOG_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"
-
-
-
staticled_control_device_t*sLedDevice=NULL;
-
-
-
staticjintled_set_on(JNIEnv*env,jobjectthiz,jintarg)
-
{
-
if(sLedDevice){
-
LOGI("led_set_on");
-
sLedDevice->set_on(sLedDevice,(int)arg);
-
}else{
-
LOGI("sLedDeviceisNULL");
-
};
-
return0;
-
}
-
-
staticjintled_set_off(JNIEnv*env,jobjectthiz,jintarg)
-
{
-
if(sLedDevice){
-
LOGI("led_set_off");
-
sLedDevice->set_off(sLedDevice,(int)arg);
-
}else{
-
LOGI("sLedDeviceisnull");
-
}
-
return0;
-
}
-
-
-
-
staticinlineintled_control_open(conststructhw_module_t*module,
-
structled_control_device_t**device)
-
{
-
LOGI("led_control_open");
-
returnmodule->methods->open(module,LED_HARDWARE_MODULE_ID,
-
(structhw_device_t**)device);
-
}
-
-
-
staticjintled_init(JNIEnv*env,jclassclazz)
-
{
-
led_module_tconst*module;
-
LOGI("led_init");
-
-
if(hw_get_module(LED_HARDWARE_MODULE_ID,(consthw_module_t**)&module)==0){
-
LOGI("getModuleOK");
-
if(led_control_open(&module->common,&sLedDevice)!=0){
-
LOGI("led_initerror");
-
return-1;
-
}
-
}
-
LOGI("led_initsuccess");
-
return0;
-
-
}
-
-
-
staticconstJNINativeMethodgMethods[]={
-
{"_init","()Z",(void*)led_init},
-
{"_set_on","(I)I",(void*)led_set_on},
-
{"_set_off","(I)I",(void*)led_set_off},
-
};
-
-
staticintregisterMethods(JNIEnv*env){
-
staticconstchar*constkClassName=
-
"com/farsight/server/ledService";
-
jclassclazz;
-
clazz=env->FindClass(kClassName);
-
if(clazz==NULL){
-
LOGE("Can'tfindclass%s\n",kClassName);
-
return-1;
-
}
-
-
if(env->RegisterNatives(clazz,gMethods,
-
sizeof(gMethods)/sizeof(gMethods[0]))!=JNI_OK)
-
{
-
LOGE("failedregisteringmethodsfor%s\n",kClassName);
-
return-1;
-
}
-
-
return0;
-
}
-
-
-
jintJNI_OnLoad(JavaVM*vm,void*reserved){
-
JNIEnv*env=NULL;
-
jintresult=-1;
-
LOGI("JNI_onLoad");
-
-
if(vm->GetEnv((void**)&env,JNI_VERSION_1_4)!=JNI_OK){
-
LOGE("ERROR:jni_onload()\n");
-
gotofail;
-
}
-
-
assert(env!=NULL);
-
if(registerMethods(env)!=0){
-
LOGE("ERROR:registerMethod()\n");
-
gotofail;
-
}
-
-
result=JNI_VERSION_1_4;
-
-
fail:
-
returnresult;
-
}
在jni里首先加载jni库文件的时候先要调用JNI_OnLoad函数,通过系统函数GetEnv让env指针获得有效的值。然后接着调用registerMethods函数,这个函数是自己定义一个函数。
static const char * const kClassName = "com/farsight/server/ledService"; 类名与Eclipse下开发对应的包一致。不过点换成了下划线。
然后找到对应的类,接着就是向系统注册Native函数(Native Interface即本地接口函数),函数列表gMethods里 _init是上层framework去加载库时候调用的,当上层调用_init时,与之对应调用的函数就是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 结构体变量),第二个参数就传进去的二级指针,让module获取有效的值,
接着调用 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

代码:
-
packagecom.farsight.server;
-
-
importandroid.util.Log;
-
-
publicclassledService{
-
static{
-
Log.i("ledService","LoadNativeserviceLIB");
-
System.loadLibrary("led_runtime");
-
}
-
publicledService(){
-
Log.i("JavaService","doinitNativeCall");
-
_init();
-
}
-
publicbooleanset_on(intarg){
-
if(0==_set_on(arg)){
-
returntrue;
-
}else{
-
returnfalse;
-
}
-
}
-
-
publicbooleanset_off(intarg){
-
if(0==_set_off(arg)){
-
returntrue;
-
}else{
-
returnfalse;
-
}
-
}
-
-
privatestaticnativeboolean_init();
-
privatestaticnativeint_set_on(intarg);
-
privatestaticnativeint_set_off(intarg);
-
}
private static native boolean _init();
private static native int _set_on(int arg);
private static native int _set_off(int arg);
这里的三个函数,就是在jni里声明的native interface接口函数。
当声明一个ledService的对象时,static里的函数库会加载,默认的路径就是去加载/system/lib下与之对应的库,强调一点就是,led_runtime省去了前面的lib和后缀.so。
这样,我们去调用jni的时候就能成功,否则会失败。
其余的就是在应用程序里声明一个ledService对象,然后调用对象里的set_on 和 set_off 就可以了。可以自己写一个应用程序去测试一下。
下面是我的一个项目的截图:
因为设计到M0开发板,所以会有温湿度以及RFID卡的截图。









源码下载地址:http://download.csdn.net/detail/k_linux_man/3865567
Android根文件系统、内核zIamge下载;http://download.csdn.net/detail/k_linux_man/3865826
分享到:
相关推荐
自己动手写最简单的Android驱动---LED驱动的编写 技术博客地址: http://blog.csdn.net/k_linux_man/article/details/7023824 Andoird驱动编写。编写Android驱动入门资料
对于初学者,可以从简单的设备驱动开始学习,如LED驱动或GPIO驱动。这些驱动通常涉及对硬件寄存器的操作,通过读写特定的寄存器来控制硬件状态。随着经验的积累,可以逐步挑战更复杂的驱动,如GPU驱动、Wi-Fi驱动或...
第一部分课程从最基础的Android应用开发环境搭建开始,简单讲解了Android界面及事件处理之后,深入剖析Android Handler多线程机制,重点讲解Android NDK应用层与驱动的通信; 第二部分内容,先简单讲解Android系统...
下面将以一个简单的LED驱动为例,详细介绍从驱动编写到用户空间应用调用的完整过程。 1. **创建驱动目录**: - 在Linux 3.0内核源码的`drivers`目录下创建一个新的子目录`hello_me`,用于存放LED驱动的相关文件。 ...
通过以上步骤,我们完成了从Kernel层到HAL层的一个简单LED驱动程序的编写过程。接下来,我们可以通过JNI层进一步将这些功能暴露给上层应用程序,实现更高级别的功能调用。 总的来说,Android驱动程序的设计和实现...
通常会从简单的例子开始,例如实现一个简单的LED控制HAL。 ### HAL Development #### 3.1 HAL Stub Analysis and Design (OOAD) 在设计HAL Stub时,需要采用面向对象的设计方法,定义清晰的类结构和接口。例如,...
5. **开发Linux Kernel层的驱动**: 最底层的驱动编写,通常也是用C语言实现,直接与硬件交互。 #### 三、Android代码调用过程 为了更深入地理解这一过程,我们可以进一步分析具体代码的调用过程。 1. **应用层**:...
第51节:用Android NDK测试LED驱动.zip 第52节:Android的蜂鸣器驱动.zip 第53节:Android下查询方式的按键驱动.zip 第54节:Android下ADC驱动.zip 第55节:Android下RTC驱动.zip 第56节:Linux内核中断原理.zip 第...
通过以上内容的详细介绍,我们可以看出,《Android应用程序开发宝典-基于TE&OK6410》不仅仅是一本简单的技术指南,它还涵盖了从开发环境搭建到应用程序调试的全过程,旨在帮助开发者全面掌握Android应用程序开发的...
首先,需要在内核中为LED灯提供一个简单的驱动,处理基本的开/关操作。然后,在HAL层创建一个LED服务,定义开启、关闭等接口。最后,在应用层编写JNI代码,通过这些接口控制LED灯的亮灭。 总的来说,Android系统非...
在了解APK通过硬件访问服务(HAL)实现驱动LED的过程之前,首先需要了解相关的技术背景和概念。HAL(硬件抽象层)是Android系统中用于隔离硬件和软件的部分,它为Android系统提供了一组标准的接口,使得Android可以不...
第一部分课程从最基础的Android应用开发环境搭建开始,简单讲解了Android界面及事件处理之后,深入剖析Android Handler多线程机制,重点讲解Android NDK应用层与驱动的通信; 第二部分内容,先简单讲解Android系统...
在Arduino开发中,控制LED是最基础的实践,通过编写简单的数字输出代码,可以让Arduino的引脚输出高低电平,进而驱动LED亮灭。 “mobile app”标签表明我们需要开发一个移动应用,这通常涉及到iOS和Android两个主要...
驱动程序是硬件与操作系统之间的桥梁,这部分实验可能要求学生编写简单的驱动程序,例如LED驱动,以理解设备驱动的工作原理和开发流程。 "Linux实验三:嵌入式Linux Led驱动程序设计实验说明"进一步深化了驱动开发...
这里可能包含了一些简单的测试程序,比如一个Android应用,它可以打开、关闭LED或改变亮度。测试代码可以帮助你在开发过程中快速检查和调试硬件驱动的实现。 总结来说,要实现Mini6410 LED功能的重写,你需要: 1....
对于Android Things来说,"Hello World"程序通常包括初始化系统、显示一条简单的消息以及可能的设备交互。在这个特定的示例中,可能会在连接到Android Things设备的显示屏上显示"Hello World"文本,或者通过某种形式...
Android HAL(硬件抽象层)是Android系统中的一个重要组成部分,它的引入主要是为了满足不同硬件制造商的需求,即能够在一定程度上保护各自的硬件驱动程序源代码不被公开。HAL的主要目标是提供一个标准化的接口,...
**Android HAL层详解** 在Android系统中,硬件抽象层...这对于开发Android驱动程序或进行设备定制有着重要的指导意义。同时,这个示例也展示了Android系统的开放性和可扩展性,使得开发者可以灵活地适配各种硬件平台。
- **LED闪烁(tl_led_flash)**:此案例展示了如何控制开发板上的LED灯,通过编写C语言程序来实现LED的点亮与熄灭。这一过程涉及到对GPIO(通用输入输出)接口的编程,是了解硬件接口和基本编程技能的良好起点。 -...
Android系统开发教程是一本关于Android软件开发的指导书,它涵盖了搭建Android开发环境以及开发Android应用实例等多个方面。本书为读者提供了一个全面的学习路径,以帮助开发者们掌握如何在不同的操作系统平台上搭建...