上一篇介绍了本实验所使用的主要IC及其通信方式,这里开始记录正式的开发过程。所选用的平台为MTK的MT6572,做过MTK智能平台研发的亲们都知道,MTK将自己的东西都添加在自加的包mediatek下面,kernel部分也不例外。然而为了体现普遍性,本实验我严格按照google提供的Android框架结构来进行相应添加的,即驱动程序添加在kernel/drivers/目录下。由于Android系统是基于Linux内核搭建起来的,所以Android驱动基本上就是Linux驱动。这里先简要介绍下编写Linux驱动程序的步骤:
第1步:建立Linux驱动框架(驱动的装载和卸载)
Linux内核在使用驱动时首先要装载驱动,装载过程中进行一些初始化工作:创建设备文件,分配内存等;在Linux系统退出时则需要卸载驱动,卸载过程中进行删除设备文件,释放内存等。所以Linux驱动需要提供了两个函数来分别处理驱动初始化和退出的工作,而Linux内核提供了两个宏来指定这两个函数:module_init和module_exit宏。Linux驱动程序一般都需要指定这俩函数,因此包含这俩函数和指定函数的这俩宏的C程序文件可看作是Linux的驱动框架。如本实验中breath_leds.c为呼吸灯驱动文件,其中有如下两句:
module_init(breath_leds_init);
module_exit(breath_leds_exit);
即表示呼吸灯驱动被装载时将执行breath_leds_init函数,Linux系统退出时将执行breath_leds_exit函数。
第2步:注册和注销设备文件
任何一个Linux驱动都需要一个设备文件,用来与应用程序完成交互。建立设备文件一般都在上一步指定的breath_leds_init函数中完成,相对应的,删除设备文件在上一步指定的breath_leds_exit函数中完成。由于该设备文件与应用程序是通过字节传输进行通信的,可作为字符设备进行创建,需要使用cdev_init, register_chrdev_region, cdev_add, class_create, device_create等函数。创建设备文件步骤如下:
1)使用cdev_init函数初始化cdev
描述字符设备文件需要一个cdev结构体,该结构体在<Linux内核源码>/include/linux/cdev.h中定义:
struct cdev {
struct kobject kobj; //封装设备文件的对象
struct module *owner; //指向所用内核模块指针
const struct file_operations *ops; //指向回调的指针
struct list_head list; //指向上一个和下一个cdev机构体指针
dev_t dev; //dev_t是int型数据类型,表示设备号。前12bit表示主设备号,后20bit表示次设备号
unsigned int count; //请求连接的设备编号范围(最大值),建立多设备时使用
};
调用cdev_init初始化大部分cdev成员变量,cdev_init函数代码:
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
memset(cdev, 0, sizeofsizeof *cdev);
INIT_LIST_HEAD(&cdev->list); //初始化首尾指针
kobject_init(&cdev->kobj, &ktype_cdev_default); //初始化设备文件对象
cdev->ops = fops; //关联file_operations
}
可以看出,cdev.owner变量并没有在该函数中初始化,所以cdev.owner需要自己另外初始化。本实验中对应代码为:
static struct cdev leds_cdev;
cdev_init(&leds_cdev, &dev_fops);
leds_cdev.owner = dev_fops.owner;
其中dev_fops为struct file_operations类型,稍候介绍。
2)使用register_chrdev_region或alloc_chrdev_region函数指定设备号
Linux设备文件的设备号分为主设备号和次设备号,用1个int类型(dev_t)表示,其中前12位表示主设备号,后20位表示从设备号。指定设备号有两种方法:
> 直接在代码中指定(register_chrdev_region)
> 动态分配(alloc_chrdev_region)
直接指定设备号虽然比较直观,但是如果主设备号和次设备号已经存在,建立设备文件就会失败。而使用alloc_chrdev_region函数会自动分配一个未使用的主设备号。alloc_chrdev_region函数原型如下:
int alloc