字符设备节点读写实验
简介
在“编写模块_helloworld”中,创建了一个最小的module,但是里面没有实现任何功能,只是一个能安装能卸载的模块而已。而在篇文章中,增加module功能,创建一个可以交互的module,也就是将module做成一个设备节点,通过读写设备节点,与module进行交互,可以使用write向设备写数据,也可以通过read从设备读取数据。这个设备就像一个文件一样
感谢
Photo by Karolina Wv: https://www.pexels.com/photo/a-bison-on-a-grassy-field-6929327/
代码
https://github.com/liodegwin/kernel/tree/main/module/io
原理
基本流程分为两块,第一是创建一个设备节点,这样就可以在安装模块的时候,在/dev目录下出现一个代表设备的文件,从而让我们可以read和write,来与内核模块交互;第二是实现open,read,write等对设备的操作函数,比如,我write这个设备的时候,就把写的字符串保存下来,等到read的时候,再把存的那些字符给用户空间,这就是一个简单的交互了
对于创建设备节点,首先要注册驱动程序register_chrdev,然后是创建设备类class_create,最后是创建一个设备节点device_create
而对于open,read,write等对于设备的操作函数,就是实现file_operations结构体中的函数,基本是利用copy_to_user和copyb_from_user来在用户空间和内核空间传递数据
相关函数
注册字符设备驱动
所谓的注册字符设备驱动,就是让内核知道有这样的一个驱动,内核好管理,将驱动和它能被应用的设备联系起来,就是使用下面的这个函数register_chrdev
1 | static inline int register_chrdev(unsigned int major,constchar* name, |
https://elixir.bootlin.com/linux/v5.15.82/source/include/linux/fs.h#L2743
https://www.cnblogs.com/zhaobinyouth/p/6227644.html
入口参数
major:主设备号,一般写0,内核来分配,免得冲突
name:设备名称
fops:file_operations结构体,封装了对设备的操作
创建设备节点
创建设备类
创建设备节点,必须要先创建设备属于的类,在/sys/class中有所有的设备类,也可以自己增加,我们自己增加设备类,需要使用class_create宏,非常简单,只有两个参数
https://elixir.bootlin.com/linux/v5.15.82/source/include/linux/device/class.h#L273
1 | /** |
入口参数
owner:一个module的指针,这个module拥有这个class,一般填THIS_MODULE
name:这个class的名字,自己起一个名字
返回值
成功的话,返回一个struct class的指针,失败的话返回一个错误指针,通过查错误码来看看是哪种错误发生了
典型代码
1 | //create dev class |
创建设备节点
使用device_create宏来创建设备节点,详细如下
https://elixir.bootlin.com/linux/v5.15.82/source/include/linux/device.h#L898
1 | /* |
入口参数
cls:设备类指针
parent:父设备指针
devt:设备号(主次都有)
drvdata:私有数据
fmt:名字
返回值
struct device 的指针,拿到了一个设备的指针
典型代码
1 | #include <linux/device.h> |
实验观察
安装模块
首先是执行make,然后有
1 | [liode@liodePC:95:tmp]$ ls |
观察到,出现了几个变化,首先是模块中多了一个drv_io,然后是sys/class中多了一个drv_io_class,最后是设备节点创建出来了,我们可以使用了,就是/dev/io_1
1 | [liode@liodePC:96:tmp]$ sudo insmod drv_io.ko |
设备节点的读写
1 | [liode@liodePC:102:tmp]$ ./test -w hello |
观察到我们把hello字符串存到了内核中,然后也能正确的取出来,完全成功了
总结
对于设备节点的创建,主要是要了解三个函数:regiser_chrdrv,class_create,device_create,对于读写,就是自己实现open,read,write等对于文件操作的系统调用