Android中linux内核模块--开发设备驱动程序 && 上层接口实施

一、内核模块开发

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
C/C++ code?
#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:
C/C++ code?
#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层的硬件服务










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值