一、字符设备驱动流程
- 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据。字符设备是面向流的设备,常见的字符设备有鼠标、键盘、串口、控制台和LED设备等。
- 存放位置:在 /dev 目录下对应一个设备文件
分配cdev(二选一) | register_chrdev_region | dev_t from, unsigned count, const char * name | 分配名为name,count设备号为from+count的字符设备,有端口占用的风险 |
alloc_chrdev_region | dev_t *dev, unsigned baseminor, unsigned count, const char *name | 让内核分配名为name,count设备号存在dev+count中的字符设备 | |
初始化file_opera | struct file_operations file_opera ={ .... } | 将自定义的操作方法加入到file_opera | |
初始化cdev | cdev_init | struct cdev *cdev, const struct file_operations *fops | 将cdev加入cdev链表,cdev中的kobject加入其链表,绑定fops操作方法块 |
注册cdev | cdev_add | struct cdev *p, dev_t dev, unsigned count | 申请设备号dev+count个字符设备,并加入到总线中 |
cdev.owner = THIS_MODULE | 给字符设备中的owner赋值,常用THIS_MODULE
| ||
创建设备节点(可选) | class_create | owner, name | 创建一个设备名为name的基类 |
device_create | struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ... | 以class为数据基类,在其之上创建一个设备号为devt的名为fmt的设备节点,parent、drvdata常为NULL,devt要与相对应注册的字符设备号一致 |
初始化流程如上图所示,其相关函数作用可自行百度搜索,其主要注意事项如下:
|
其中在注册完字符设备 cdev_add 后,cdev结构体除了owner均已初始化,所以我们还要加上owner的初始化。
|
在cdev_add后,可选择执行 class_create(owner, name) → device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...) 自动生成设备文件。
|
执行class_create → device_create 后即在dev中生成设备文件(设备节点)。
其对应Linux操作为和流程思考如下:
Linux系统中 总线挂载着各个驱动和设备,驱动实质上就是跟设备通信的特定方法
make编译出来的.ko文件为驱动文件
insmod 后 挂载设备到 linux 系统,同时给它分配主设备号(用来区分驱动类型),
从此在 lsmod 及 proc/devices(设备驱动记录)可以查询驱动名称和它的主设备号
mknod /dev/XXX c 主设备号 次设备号
mknod 后在 dev 中生成设备驱动文件XXX----实质为系统操作主设备号对应的驱动文件接口,可以对这个文件open/write等操作
rmmod 是卸载掉了设备,在 lsmod 和proc/devices中查询不到
没有删除XXX文件前,设备文件依然存在,但是它对应的主设备号驱动已经被卸载了
rm /dev/XXX 删除了设备文件
驱动操作命令:
insmod / modprobe 加载驱动
rmmod 卸载驱动
lsmod 查看系统中所有已经被加载了的所有的模块以及模块间的依赖关系
modinfo 获得模块的信息