一、内核模块开发
1.module开发
(0)引言
如果你正在开发的设备驱动程序中需要与用户层的接口,一般可选的方法有:
1).注册虚拟的字符设备文件(包含misc字符设备节点),以这个虚拟设备上的 read/write/ioctl 等接口与用户交互;但 read/write 一般只能做一件事情, ioctl 可以根据 cmd 参数做多个功能,但其缺点是很明显的: ioctl 接口无法直接在 Shell 脚本中使用,为了使用 ioctl 的功能,还必须编写配套的 C语言的虚拟设备操作程序, ioctl 的二进制数据接口也是造成大小端问题 (big endian与little endian)、32位/64位不可移植问题的根源;
2).注册 proc 接口属性文件,接受用户的 read/write/ioctl 操作;同样的,一个 proc 项通常使用其 read/write/ioctl 接口,它所存在的问题与上面的虚拟字符设备的的问题相似;
3).sysfs虚拟文件系统:sysfs 接口---注册 Linux Sysfs属性文件. 总上述,最重要的是,添加虚拟字符设备支持和注册 proc 接口支持这两者所需要增加的代码量都并不少,最好的方法还是使用 Linux Sysfs属性支持,一切在用户层是可见的透明,且增加的代码量是最少的,可维护性也最好;
(1)从kernel启动开始,介入
......................
......................
module_init( )
......................
late_initcall
.....................
(2)具体开发实例(可以参见:mt-gpio驱动 http://blog.csdn.net/loongembedded/article/details/41179749)
//(本例子)mt-gpio驱动:sysfs字符设备属性文件 //(其他例子)smartcover 驱动:sysfs驱动属性文件
0). gpio 驱动简介---refer: http://blog.csdn.net/loongembedded/article/details/41179749
A. GPIO驱动架构图
B. GPIO驱动功能,用来配置GPIO引脚,主要的功能如下:
(a) 在系统启动阶段配置GPIO引脚的默认值。
(b) 在系统跑起来后,提供接口让其他模块来改变GPIO引脚功能。
C. GPIO驱动提供两种接口:
(a).向内核空间开放的接口(EXPORT_SYMBOL()导出内核符号):其他驱动可调用GPIO驱动提供的功能。比如mt_set_gpio_dir、mt_set_gpio_mode等。
(b).向用户空间开放的接口():用户空间可通过发送IOCTL(open、ioctl、write、read和close等函数)给/dev/mtgpio或/sys/class/misc/mtgpio/pin(misc字符设备节点mtgpio&&及该设备节点的sysfs属性文件pin),来操作GPIO口。
1).源码解析如下:
module 模块之1-----向内核提供的接口
module 模块之2-----module模块自身功能
2).最终生成的misc字符设备节点和sysfs属性文件如下:
3).上层调用该接口
首先修改权限:
(1) gpio.c
staticDEVICE_ATTR(pin, 0777,mt_gpio_show_pin, mt_gpio_store_pin);
(2) init.rc
chmod 0777 /dev/mtgpio
chmod 0777/dev/ttyMT3--------这是串口驱动对应的节点名称
chmod 0777/sys/class/misc/mtgpio/pin
然后写应用程序:
misc字符设备节点/dev/mtgpio的使用:默认的权限是所有者可读写。
oned_gpio_fd =open("/dev/mtgpio", O_RDWR);
if(oned_gpio_fd == -1)
{
LOGD("1DPower up Fail.........");
return -1;
}
//0x15为设置pin引脚为高电平命令,85表示pin引脚
ioctl(oned_gpio_fd, 0x15,85);
ioctl(oned_gpio_fd, 0x15,154);
ioctl(oned_gpio_fd, 0x15,150);
ioctl(oned_gpio_fd, 0x15,69);
ioctl(oned_gpio_fd, 0x15,72);
//0x14为设置pin引脚为低电平的命令
ioctl(oned_gpio_fd, 0x14,78);
usleep(1000);
misc的sysfs设备属性文件/sys/class/misc/mtgpio/pin使用:默认
oned_gpio_fd =open("/sys/class/misc/mtgpio/pin", O_RDWR);
write()/ read()文件
2.module之间的通信情况(可参见:http://blog.csdn.net/ramon1892/article/details/8448315)
可以使用EXPORT_SYMBOL_GPL( )符号导出;
想要实现的效果是:
先加载驱动1和驱动2,当驱动1的中断被触发后,进入中断处理函数,然后发送类似信号功能的某机制;
接着,驱动2收到后,停止阻塞,进行相应的处理...
请问:该用什么实现呢?
-----------------------------------------------------------------------------------------
我推荐使用内核完成量,该网友说总是编译有问题,然后我自己写了两个驱动测试了下:
drv_test/├── Makefile
├── module1
│ ├── Makefile
│ ├── module1.c
├── module2
│ ├── Makefile
│ ├── module2.c
最外层的Makefile:
obj-y := module1/ module2/
module1里面的Makeifle:
obj-m = module1.o
module2里面的Makeifle:
obj-m = module2.o
module1.c
#include<linux/module.h>
#include<linux/init.h>
#include<linux/completion.h>
DECLARE_COMPLETION(your_comp);
EXPORT_SYMBOL_GPL(your_comp);
void interrupt(int irq, void *data)
{
complete(&your_comp);
}
static int module1_init(void)
{
pr_info("this is a test module\n");
//request_irq(IRQ_NUM, NULL, interrupt,NULL)
return 1;
}
static void module1_exit(void)
{
pr_info("exit!\n");
}
module_init(module1_init);
module_exit(module1_exit);
MODULE_AUTHOR("ramon1892");
MODULE_LICENSE("GPL");
module2.c:
#include<linux/module.h>
#include<linux/init.h>
#include<linux/completion.h>
extern struct completion your_comp;
static int module2_init(void)
{
if(wait_for_completion_interruptible_timeout(&your_comp, 10*1000))
return 0;
pr_info("this is a test module\n");
return 1;
}
static void module2_exit(void)
{
pr_info("exit!\n");
}
module_init(module2_init);
module_exit(module2_exit);
MODULE_AUTHOR("ramon1892");
MODULE_LICENSE("GPL");
然后直接在drv_test目录下执行:
make -C 【/kernel/source/】 M=$PWD CFLAGS+=-DEXPORT_SYMTAB
就好了,最后insmod module1.ko; insmode module2.ko 工作正常。
二、整合到android系统中
详见:http://wenku.baidu.com/view/81a54c34b90d6c85ec3ac6bc.html?re=view
1.在Ubuntu上为Android系统编写Linux内核驱动程序 :
驱动程序的功能主要是向上层提供访问设备的寄存器的值,包括读和写。
这里,提供了三种访问设备寄存器的方法,一是通过proc文件系统来访问,二是通过传统的设备文件的方法来访问,三是通过devfs文件系统来访问。
完成这个内核驱动程序后,便可以在Android系统中得到三个文件,分别是/dev/hello、/sys/class/hello/hello/val和/proc/hello
(测试程序:在Android系统中增加C可执行程序来访问硬件驱动程序。)
2.在Ubuntu上为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序
3.为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口
4.在Ubuntu上为Android系统的Application Frameworks层增加硬件访问服务
5.为Android系统内置Java应用程序测试Application Frameworks层的硬件服务