chardrivefram

字符设备驱动框架

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)设备节点被创建在内存上,系统重启,节点会被删除