字符设备驱动程序设计
概念
字符设备文件:
- 应用程序通过字符设备文件而调用字符设备驱动的文件操作
- 映射关系是一个文件描述符
字符设备文件创建方法可以使用以下命令形式:
cat /proc/devices // 查看主设备号
mknod /dev/xxx c 100 3 //(指明是字符设备) 主设备号 次设备号
或者直接用使用函数注册,自动生成。
设备号
数据类型:dev_t
高十二位为主设备号
低二十位为次设备号
主设备号:
标识设备对应的驱动程序
每个在内核中活动的字符设备驱动程序,包括编译进内核的和后来动态加载的,都有唯一的主设备号。
内核利用主设备号将设备与相应的驱动程序对应起来
- 次设备号
只由驱动程序使用,内核的其他部分不使用它,仅将它传递给驱动程序
设备号操作
a) 设备号合成分解
dev_t dev = MKDEV(主设备号,次设备号);/*主次设备号自己给,已知*/
主设备号= MAJOR(dev_t dev) /*设备号分解*/
次设备号= MINOR(dev_t dev)
b) 设备号处理(驱动加载时都需要申请相关设备号)
register_chrdev_region() // 静态申请
alloc_chrdev_region()//动态申请
unregister_chrdev_region()//设备号注销
设备的抽象封装
字符设备结构体:
struct cdev
{
struct kobject kobj; /*内核使用,驱动可以不用处理*/
struct module *owner; /*模块拥有者*/
const struct file_operations *ops; /*模块的文件操作*/
struct list_head list; /*内核链表,驱动可以不处理*/
dev_t dev; /*设备号*/
unsigned int count; /*设备数量*/
};
字符设备操作函数
i. 结构分配:
1. 静态分配:struct cdev xxx_dev;
2. 动态分配:struct cdev* pdev = cdev_alloc();
ii. 结构初始化:
void cdev_init(struct cdev *, const struct file_operations *);
iii. 字符设备注册:
int cdev_add(struct cdev *, dev_t dev_num, unsigned count);
iv. 字符设备删除
void cdev_del(struct cdev *p)
4.字符设备文件操作封装:
a) 上层应用程序使用文件操作函数都是通过该结构体映射到驱动中的文件操作中
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *,