一、新字符设备驱动原理
1、使用函数register_chrdev注册字符设备,会浪费很多的次设备号,而且主设备号还需要我们指定,不够智能。
2、可以使用函数alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)注册,该函数可以指定需要多少次设备号。并使用函数unregister_chrdev_region(dev_t from, unsigned count)卸载设备。
3、如果已经给定主设备号可以使用函数register_chrdev_region(dev_t from, unsigned count, const char *name)
注册设备,参数 from 是要申请的起始设备号(给定的设备号,参数 count 是要申请的数量,参数 name 是设备名字。
4、所以要考虑两种情况,有给定主设备号和没用给定主设备号的情况。一般是给定主设备号,然后使用MKDEV构建一个完整的dev_t,次设备号选择0。
5、字符设备注册:在linux中使用cdev结构体表示字符设备,先定义好cdev变量然后使用函数cdev_init对其进行初始化,然后再使用cdev_add函数进行添加字符设备,注销驱动的时候要使用cdev_del函数删除相应的字符设备。
6、自动创建设备节点:在嵌入式Linux中,使用mdev来实现设备节点文件的自动创建和删除,包括热插拔事件。
1)首先创建一个类,使用函数class *class_create (struct module *owner, const char *name),卸载驱动的时候要删除相关的类,使用函数class_destroy(struct class *cls)。
2)然后创建一个设备,使用函数device *device_create(struct class *class,struct device *parent,dev_t devt,void *drvdata,const char *fmt, ...),同样卸载设备的时候要删除相应的设备,使用函数device_destroy(struct class *class, dev_t devt)。
二、文件私有数据
三、新字符设备驱动编写
1、编写一个cdev结构体来表示我们的设备,包含信息如下:
/*cdev结构体*/
struct newchrled_dev {
struct cdev cdev; /*字符设备*/
dev_t devid; /*设备号*/
struct class *class; /*类*/
struct device *device; /*设备*/
int major; /*主设备号*/
int minor; /*次设备号*/
};
/*定义结构体变量*/
struct newchrled_dev newchrled;
2、在驱动入口函数内编写判断是否有给定主设备号的代码
if (newchrled.major)
{
newchrled.devid = MKDEV(newchrled.major, 0);
ret = register_chrdev_region(newchrled.devid, 1, NEWCHRLED_NAME);
} else {
ret = alloc_chrdev_region(&newchrled.devid, 0, 1, NEWCHRLED_NAME);
newchrled.major = MAJOR(newchrled.devid);
newchrled.minor = MINOR(newchrled.devid);
}
3、初始化cdev变量,并添加字符设备
cdev_init(&newchrled.cdev, &newchrled_fops);
ret = cdev_add(&newchrled.cdev, newchrled.devid, 1);
4、编写自动创建设备节点文件的代码
/*创建类*/
newchrled.class = class_create(THIS_MODULE, NEWCHRLED_NAME);
if (IS_ERR(newchrled.class)) {
return PTR_ERR(newchrled.class);
}
/*创建设备*/
newchrled.device = device_create(newchrled.class, NULL, newchrled.devid, NULL,
NEWCHRLED_NAME);
if (IS_ERR(newchrled.device)) {
return PTR_ERR(newchrled.device);
}
5、在驱动出口函数要编写卸载驱动的语句和删除类与设备的语句
/*1、删除字符设备*/
cdev_del(&newchrled.cdev);
/*2、注销设备号*/
unregister_chrdev_region(newchrled.devid, 1);
/*3、摧毁设备*/
device_destroy(newchrled.class, newchrled.devid);
/*4、摧毁类*/
class_destroy(newchrled.class);