5 生成设备节点
5.1 杂项设备
一部分驱动要和上层
通信,都需要生成设备节点,上层应用通过一套标准的接口函数调用设备节点就可以控制底层以及和底层通信。
主设备号只有256 个,设备又非常多,所以引入了子设备号。其中杂项设备的主设备号是10,在任何Linux 系统中它都是固定的。
在虚拟机的Ubuntu 系统上,使用命令“cat /proc/misc”,可以查看到PC机Ubuntu 系统的杂项设备。启动
开发板,在超级终端中输入命令“cat /proc/misc”也可以查看对应的杂项设备。
一般将Linux 驱动分为字符设备、块设备、网络设备,但是这个分类不能包含所有的设备,所以将无法归类的设备统称为杂项设备,杂项设备可能用到字符设备、快设备、网络设备中的一项或者多项设备。
5.2 杂项设备结构体
杂项设备的头文件在“include/linux/miscdevice.h”有两个需要掌握的函数和一个结构体
extern int misc_register(struct miscdevice * misc);杂项设备注册函数;一般在probe 中调用,参数是miscdevice
extern int misc_deregister(struct miscdevice *misc);杂项设备卸载函数;一般是在hello_remove 中用于卸载驱动。
int .minor;设备号,赋值为MISC_DYNAMIC_MINOR,这个宏定义可以查到为10
const char *name;设备名称
const struct file_opera
tions *fops;file_operations 结构体的成员函数属于驱动设计的主体内容,里面的函数和Linux 系统给应用程序提供系统接口一一对应,file_operations 结构体在头文件“include/linux/fs.h”中。
如上图所示,可以看到结构体中包含的参数非常多。
struct module *owner;一般是THIS_MODULE。
int (*open) (struct inode *, struct file *);对应上层的open 函数,打开文件。
int (*release) (struct inode *, struct file *);对应上层的close 函数,打开文件操作之后一般需要关闭。
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);读函数,上层应用从底层读取函数。
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);写函数,上层应用向底层传输数据。
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);这个函数功能和写函数稍微有点重合,但是这个函数占用的内存非常小,主要针对IO 口的控制。
5.3 生成杂项设备节点的源代码
1)如下图所示,将头文件“linux/platform_device.h”、“linux/miscdevice.h”以及“linux/fs.h”添加到文件中。然后定义一个DEVICE_NAME,将其赋值为"hello_ctl123",帮助大家理解这个设备节点名称和前面介绍的注册设备名称是不同的。
2)如下图所示,向添加hello_probe 中添加注册杂项设备的函数misc_register,如下图所示,将miscdevice 参数定义为hello_dev。
[size=12.0000pt]3)如下图所示,定义了miscdevice hello_dev。参数minor 为MISC_DYNAMIC_MINOR,也就是10参数name 为DEVICE_NAME,也就是hello_ctl123参数fops 为“hello_ops”
[size=11.0000pt]4) 如下图所示,定义了file_operations hello_ops,其中有四个参数。
参数owner 为THIS_MODULE,参数open 为hello_open,参数release 为hello_release,参数unlocked_ioctl 为hello_ioctl,
[size=12.0000pt]5) 如下图所示,对hello_ops 结构体中的函数挨个定义。
设备节点和驱动名以及设备名没有一关系,不过最好设备节点的命名便于识别。
更多精彩内容请关注微信公众号:小拇指的脑瓜子