字符设备驱动框架
1、设备号:驱动通过不同设备号区分不同的设备
申请注册设备号的方法:
1 2
| 方案1、用户自定义,向内核去注册 方案2、系统分配,然后再去注册
|
2、驱动需要实现对设备的控制(实现应用层对设备操作的函数接口)
3、设备节点(文件),给应用程序,应用程序视设备为文件
4、设备号
1
| 设备号(32bit) =主设备号(高12bit)=次设备号(低20bit)
|
申请注册:
1)静态注册(用户自定义设备号,向内核注册)
1 2 3 4 5 6 7 8 9 10 11
| #define major 500 #define minor 0 Dev_t devno=MKDEV(major,minor);//求出主设备号的函数宏 函数原型 :int register_chrdev_region(dev_t from,unsigned count,char *name) 功能:注册设备号 参数:form 设备号(用户自定义) count 表示的是注册设备号的数量 name 名字(描述设备号) 返回值:成功 0 失败 负数
|
2)动态注册(系统自动分配,向内核注册)
1 2 3 4 5 6 7 8
| 函数原型:int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count,const char *name) 功能:系统分配设备号,并注册 参数: dev 系统自动分配设备号 baseminor 次设备号 const 注册设备号的数量 name 名字 描述设备号 返回值:成功 0 失败 负数
|
3)注销
1 2 3 4
| void unregister_chrdev_region(dev_t from,unsigned count) 功能:注销设备号 参数: from 设备号 count 设备号的数量
|
5、如何实现设备控制
对于字符设备,内核提供结构体来描述一个设备的struct cdev,
1 2 3 4 5 6
| struct cdev { struct module *owner; const struct file_operations *ops; 对设备操作的集合 dev_t dev; 设备号 unsigned int count; };
|
1)初始化结构体
1 2 3 4 5
| 函数原型:void cdev_init(struct cdev *cdev,const struct file_operations *fops) 功能:初始化cdev结构体 参数:cdev cdev结构体 fops 对设备操作的集合 返回值:没有返回值
|
2) 将cdev结构体添加到内核链表
1 2 3 4 5 6 7
| 函数原型:int cdev_add(struct cdev *p,dev_t dev,unsigned count) 功能:将cdev结构体添加到内核链表 参数: p cdev结构体 dev 设备号 count cdev结构体数量 返回值:成功 0 失败 负数
|
3)将cdev移除
1 2
| 函数原型:void cdev_del(struct cdev *p) 参数:p cdev结构体
|
6、设备节点
1)手动创建
1
| mknod /dev/XXX.c 主设备号 次设备号
|
2)主、次设备号和驱动中的注册的设备号一致,将设备节点和设备关联
3)设备节点被创建在内存上,系统重启,节点会被删除