字符设备驱动开发重点是使用register_chrdev函数注册字符设备,当不用设备时使用unregister_chrdev函数注销字符设备,驱动模块加载成功后还需要手动mknod创建设备节点。
register_chrdev和unregister_chrdev这两个函数是老版本内核驱动使用的函数,现在新的字符设备驱动已经不再使用这两个函数,而是使用linux内核推荐的新字符设备驱动API函数。
新字符设备驱动原理
分配和释放设备号
如果没有指定设备号,向内核申请设备号
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
如果给定了设备的主设备号和次设备号,用如下函数注册设备号
int register_chrdev_region(dev_t from, unsigned count, const char *name)
// from是要申请的起始设备号, count是要申请的数量,name 是设备名字
不管是通过alloc_chrdev_region还是register_chrdev_region申请的设备号,释放设备号统一使用如下函数
void unregister_chrdev_region(dev_t from, unsigned count)
新字符设备驱动,设备号分配示例代码如下:
int major; /* 主设备号 */
int minor; /* 次设备号 */
dev_t devid; /* 设备号 */
if (major) { /* 定义了主设备号 */
devid = MKDEV(major, 0); /* 大部分驱动次设备号都选择0 */
register_chrdev_region(devid, 1, "test");
} else { /* 没有定义设备号 */
alloc_chrdev_region(&devid, 0, 1, "test"); /* 申请设备号 */
major = MAJOR(devid); /* 获取分配号的主设备号 */
minor = MINOR(devid); /* 获取分配号的次设备号 */
}
unregister_chrdev_region(devid, 1); /* 注销设备号 */
新的字符设备注册方法
在 Linux中使用 中使用 cdev结构体表示一个字符设备, cdev结构体在 结构体在 include/linux/cdev.h文件中的定义如下:
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops; // 设备操作函数集合
struct list_head list;
dev_t dev; // 字符设备名称
unsigned int count;
};
编写字符设备驱动前,需要定义一个cdev的结构体变量:
struct cdev test_cdev;
cdev_init函数
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
// 初始化test_cdev结构体变量
struct cdev test_cdev;
/* 设备操作函数 */
static struct file_operations test_fops = {
.owner = THIS_MODULE,
/* 其他具体的初始项 */
};
testcdev.owner = THIS_MODULE;
cdev_init(&test_cdev, &test_fops); /* 初始化cdev结构体变量 */
cdev_add函数
先使用cdev_init函数对cdev结构体变量进行初始化,然后使用cdev_add函数向Linux系统添加这个字符设备。
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
// p 为执行cdev结构体的指针,dev为设备号,count是要添加的设备数量
struct cdev testcdev;
/* 设备操作函数 */
static struct file_operations test_fops = {
.owner = THIS_MODULE,
/* 其他具体的初始项 */
};
testcdev.owner = THIS_MODULE;
cdev_init(&testcdev, &test_fops); /* 初始化cdev结构体变量 */
cdev_add(&testcdev, devid, 1); /* 添加字符设备 */
以上就是新的注册字符设备代码段,Linux内核中大量的字符设备驱动都是采用这种方法向Linux内核添加字符设备的。
cdev_del函数
卸载驱动的时候一定要使用cdev_del函数从Linux内核中删除相应的字符设备。
void cdev_del(struct cdev *p)
// p 就是要删除的字符设备结构体指针
cdev_del(&testcdev); /* 删除cdev */
cdev_del和 unregister_chrdev_region这两个函数合起来的功能相当于unregister_chrdev函数
自动创建设备节点
modprobe加载驱动程序后,还需要使用命令mknod手动创建设备节点。现在可以在驱动中自动创建节点,使用modprobe加载驱动成功后会自动在/dev目录下创建对应的设备文件。