字符设备驱动框架
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux中设备分类:
按照对设备的访问方式可分为以下三类:
1.字符设备(char device)
(1)例如:键盘、鼠标、串口、帧缓存等;
(2)通过/dev/下的设备节点访问;以字节为单位访问;
(3)一般只支持顺序访问;(特例:帧缓存framebuffer)
(4)无缓冲。
2.块设备(block device)
(1)例如:磁盘、光驱、flash等;
(2)以固定大小为单位访问:磁盘以扇区(512B)为单位;flash以页为单位。
(3)支持随机访问;
(4)有缓冲(减少磁盘IO,提高效率)。
3.网络设备(network device)
(1)无设备文件(节点);
(2)应用层通过socket接口访问网络设备(报文发送和接收的媒介)。
设备驱动在内核中的结构:
1.VFS虚拟文件系统作用:向应用层提供一致的文件访问接口,正是由于VFS
的存在,才可以将设备以文件的方式访问。
2.虚拟文件系统,存在于内存中,不在磁盘上,掉电丢失。例如:/proc、/sys、
/tmp。
设备号:
1.作用:唯一地标识一个设备;
2.类型:dev_t devno;即32位无符号整型;
3.组成:
(1)主设备号:用于区分不同类型(按功能划分)的设备;
(2)此设备号:用于区分相同类型的不同设备。
注意:相同类型的设备(主设备号相同)可以使用同一个驱动。
4.构建设备号:
int major = 250; int minor = 0;
(1)dev_t devno = (major << 20) | minor;不建议使用;
(2)利用宏来构建:dev_t devno = MKDEV (major, minor);
注意:我们可以通过文件$(srctree)/documentation/device.txt来查看内核对设备号的分配情况。
(1)该文本中的有对应设备文件的设备号是已经被申请过的,我们不可以重
复使用(申请);
(2)从中可以看出,我们在编写驱动程序时可以使用的主设备号范围为
240~254,为了方便记忆,通常使用250作为主设备号。
字符设备驱动框架:
驱动:作用,为应用层提供访问设备的接口(对设备发的各种操作)。
一、申请设备号
1.构建设备号:dev_t devno = MKDEV (major, minor);
2.申请设备号:
(1)动态申请:alloc_chrdev_region;
(2)静态申请: register_chrdev_region。
(3)静态申请设备号的优缺点:
优点:可以提前创建设备文件;
缺点:有可能会发成冲突,导致申请失败。
(4)register_chrdev_region函数详解:
注意:
①最后一个参数是设备名称。且在/proc/devices下会有关于当前
系统已经注册成功的设备信息;
②申请设备号应在加载函数中实现;同时,在卸载函数中我们也要
调用unregister_chrdev_region来释放设备号。
二、实现操作集合struct file_operations {……}
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 *);
unsigned int (*poll) (struct fiel *, poll_table *);
int (*fasync) (int, struct file *, int);
long (*unlock_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*release) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*lock) (struct file *, int, struct file_lock *);
……
};除owner成员外,其他成员均是对文件进行相关操作的函数指针。
1.对设备的大多数操作函数都有参数struct file *filp;
2.在起始阶段我们可以先定义一个空的操作集合:
struct file_operations { .owner = THIS_MODULE };
注意:
(1)可以看出宏THIS_MODULE代表结构体struct module的起始地址;
(2)我们可以通过“.
体指定成员赋值。
三、注册字符设备:
1.通过结构体struct cdev将设备号devno和操作集合file_operations
关联起来;
2.并将cdev结构体加入到内核维护的cdev链表中。(计算机系统支持很多
字符设备,内核会维护一个cdev链表,这样我们就可以通过设备号找到
对应的操作集合了)
3.cdev结构体的定义如下:
4.我们通过调用内核函数cdev_init和cdev_add来完成字符设备的注册。