Android驱动开发-- 1.内核driver层
2015-12-09 14:25
369 查看
Android系统要控制硬件设备,首先需要在驱动层写一个驱动,android的底层是Linux,写设备驱动和Linux下写设备驱动一样。
在Linux系统中,设备驱动是以文件的形式表现,可以使用和操作普通文件相同的操作命令对设备文件进行操作,例如打开、关闭、读、写等。
写字符设备驱动步骤:
1. 定义一个file_operations结构体,并在结构体里面定义设备的打开、关闭、读、写、控制等操作函数。
2. 在结构体外实现结构体里面定义的操作函数。
3. 向内核注册和卸载驱动模块。
为了方便测试,这里采取控制LED点灯的方式测试,测试的硬件是Cubieboard和扩展板DVK522(见下图)。
一、在lichee/linux-3.4/driver/char目录下新建myled文件夹,新建一个LEDdriver.c文件,代码如下:
Cubieboard DVK522扩展板上的LED0-LED2对应CPU的PE4-PE6引脚,CPU A20的GPIO寄存器地址如下图表。
二、编译代码,在Ubuntu操作系统完成。
linux驱动的加载方式,可以采用系统启动后动态加载驱动模块的方式,在这里将驱动直接编译进内核中,系统启动过程加载模块驱动。
1. 在myled文件夹新建Kconfig和Makefile两个文件,Kconfig是在编译前执行配置命令make menuconfig时用到的,而Makefile是执行编译命令make是用到的。
2. 在Kconfig中添加如下内容:
config MYLED
tristate "My LEDdriver Driver"
default y
help
This is the first android LEDdriver.
default y表示默认将该驱动编译进内核。
3. 在makefile中添加如下内容:
obj-$(CONFIG_MYLED) += myled.o
4. 修改drivers/kconfig文件,在endmenu前添加:
source "drivers/myled/Kconfig"
5. 修改drivers/Makefile文件,添加:
obj-$(CONFIG_MYLED) += myled/
6. 修改arch/arm/kconfig文件,添加:
source "drivers/myled/Kconfig"
7. 在linux-3.4目录下执行make ARCH=arm menuconfig,查看是否有My LEDdriver Driver,勾选上*号。
8. 在lichee目录下编译,编译成功后,在drivers/myled可以看到myled.ko。
9. 重新编译打包android系统,烧录到SD卡或开发板的NAND Flash。
三、测试。
上电开机启动android系统,连接开发板串口登录进系统,可以在/dev和/sys/class下看到myled节点,说明编译的myled驱动加载到设备驱动成功。
内核驱动完成后,需要写一个测试程序在用户空间测试一下驱动能否控制到LED灯,请见下一节:Android驱动开发-- 2.测试驱动程序。
在Linux系统中,设备驱动是以文件的形式表现,可以使用和操作普通文件相同的操作命令对设备文件进行操作,例如打开、关闭、读、写等。
写字符设备驱动步骤:
1. 定义一个file_operations结构体,并在结构体里面定义设备的打开、关闭、读、写、控制等操作函数。
2. 在结构体外实现结构体里面定义的操作函数。
3. 向内核注册和卸载驱动模块。
为了方便测试,这里采取控制LED点灯的方式测试,测试的硬件是Cubieboard和扩展板DVK522(见下图)。
一、在lichee/linux-3.4/driver/char目录下新建myled文件夹,新建一个LEDdriver.c文件,代码如下:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/device.h> #include <asm/uaccess.h> #include <linux/io.h> static struct class *firstdrv_class; static struct class_device *firstdrv_class_dev; volatile unsigned long *gpfcon = NULL; volatile unsigned long *gpfdat = NULL; //配置GPIO为输出口 static int cubieboard2_leds_open(struct inode *inode, struct file *file) { printk(KERN_ALERT "cubieboard2_leds_open\n"); /* 设置PE4, PE5, PE6 为输出*/ *gpfcon &= ~ ((0x7<<( 4*4)) | (0x7<<( 5*4)) | (0x7<<( 6*4)) ); *gpfcon |= ((0x1<<( 4*4)) | (0x1<<( 5*4)) | (0x1<<( 6*4)) ); return 0; } //GPIO输出高低电平以控制LED灯亮灭 static int cubieboard2_leds_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { int val_dev; //将用户空间的数据拷贝内核 copy_from_user(&val_dev, buf, count); //copy_to _user(); if (val_dev == 1) { //LED on printk(KERN_ALERT "write val==1, LED on\n"); *gpfdat&= ~(1<<4) | (1<<5) | (1<<6); } if (val_dev == 0) { //LED off printk(KERN_ALERT "write val==0, LED off\n"); *gpfdat|= (1<<4) | (1<<5) | (1<<6); } return 0; } static struct file_operations cubieboard2_leds_ops = { .owner = THIS_MODULE, .open = cubieboard2_leds_open, .write = cubieboard2_leds_write, }; int major; int cubieboard2_leds_init(void) { //注册file_operations结构体 //动态分配驱动号 major=register_chrdev(0,"myled",&cubieboard2_leds_ops); //注册设备类 firstdrv_class=class_create(THIS_MODULE, "myled"); if(IS_ERR(firstdrv_class)) return RTP_ERR(firstdrv_class); //创建设备节点 firstdrv_class_dev = device_create(firstdrv_class, NULL, MKDEV(major,0), NULL, "myled"); if (unlikely(IS_ERR(firstdrv_class_dev))) return RTP_ERR(firstdrv_class_dev); //映射寄存器,寄存器地址查阅A20规格书 gpfcon = (volatile unsigned long *)ioremap(0x01c20890,16); gpfdat = (volatile unsigned long *)ioremap(0x01c208a0,16); return 0; } void cubieboard2_leds_exit(void) { //卸载驱动号 unregister_chrdev(major,"myled"); //释放设备节点 device_unregister(firstdrv_class_dev); //销毁设备类 class_destroy(firstdrv_class); //释放GPIO寄存器映射 iounmap(gpfcon); iounmap(gpfdat); return 0; } module_init(cubieboard2_leds_init); module_exit(cubieboard2_leds_exit); MODULE_AUTHOR("Ken Qiu"); MODULE_DESCRIPTION("LED driver"); MODULE_LICENSE("GPL");
Cubieboard DVK522扩展板上的LED0-LED2对应CPU的PE4-PE6引脚,CPU A20的GPIO寄存器地址如下图表。
二、编译代码,在Ubuntu操作系统完成。
linux驱动的加载方式,可以采用系统启动后动态加载驱动模块的方式,在这里将驱动直接编译进内核中,系统启动过程加载模块驱动。
1. 在myled文件夹新建Kconfig和Makefile两个文件,Kconfig是在编译前执行配置命令make menuconfig时用到的,而Makefile是执行编译命令make是用到的。
2. 在Kconfig中添加如下内容:
config MYLED
tristate "My LEDdriver Driver"
default y
help
This is the first android LEDdriver.
default y表示默认将该驱动编译进内核。
3. 在makefile中添加如下内容:
obj-$(CONFIG_MYLED) += myled.o
4. 修改drivers/kconfig文件,在endmenu前添加:
source "drivers/myled/Kconfig"
5. 修改drivers/Makefile文件,添加:
obj-$(CONFIG_MYLED) += myled/
6. 修改arch/arm/kconfig文件,添加:
source "drivers/myled/Kconfig"
7. 在linux-3.4目录下执行make ARCH=arm menuconfig,查看是否有My LEDdriver Driver,勾选上*号。
8. 在lichee目录下编译,编译成功后,在drivers/myled可以看到myled.ko。
9. 重新编译打包android系统,烧录到SD卡或开发板的NAND Flash。
三、测试。
上电开机启动android系统,连接开发板串口登录进系统,可以在/dev和/sys/class下看到myled节点,说明编译的myled驱动加载到设备驱动成功。
内核驱动完成后,需要写一个测试程序在用户空间测试一下驱动能否控制到LED灯,请见下一节:Android驱动开发-- 2.测试驱动程序。
相关文章推荐
- Linux socket 初步
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件