LINUX字符设备驱动模块分析(二)混杂设备驱动模型分析

      在结束了对字符设备驱动模型的分析之后,我们分析linux设备驱动中使用字符设备驱动模型的框架,本篇我们介绍混杂设备驱动模型。

       linux系统中设计了一个混杂字符设备驱动模型,系统中任何类型的设备均可以使用该驱动模型的接口,实现字符设备的创建。混杂字符设备驱动模型简化了字符设备驱动的创建接口,只需要调用misc_register接口即可完成字符设备驱动的创建。本章我们介绍下该设备驱动模型。

 

 

混杂设备驱动模型相关的结构体变量

混杂设备驱动模型的结构体为miscdevice,仅这一个结构体变量,从其结构体定义也可以看出

该驱动模型的实现比较简洁明了。

struct miscdevice 

该结构体的定义如下,主要涉及如下几个方面:

  1. 通过fops指针,指向该字符设备文件的文件操作接口(open、read、write、ioctl、close等),通过该指针会实现与文件描述符中的f_op指针的关联,当调用系统调用接口open、read、write等对该文件进行操作时,即可实现对该文件的操作;
  2. 通过list成员,将系统中所有已注册的混杂字符设备链接在一起,该链表主要是混杂设备驱动模型内部的变量,通过该变量可实现对系统中已注册的混杂设备的查找,以及在混杂设备注册时的查重;
  3. 通过parent变量,实现将该混杂设备对应的device及其父device关联,从而可将该字符设备对应的device变量链入LINUX系统中的device树中;
  4. 通过this_device,并借助device_create、device_destroy接口,可借助LINUX设备-总线-驱动模型中的uevent机制,通过netlink向应用层发送设备添加或移除的事件消息,而应用层的udev/mdev在接收到该事件消息后,根据该device变量的devt成员,通过调用mknod系统调用接口,实现字符设备文件节点的创建或移除。
  5. 而nodename、mode则可通过uevent事件传递给应用层。
struct miscdevice  {
	/*次设备号*/
	int minor;
	const char *name;
	/*该混杂设备的文件处理接口指针(包括open、read、write等)*/
	const struct file_operations *fops;
	/*该链表用于将所有已注册的混杂设备链接在一起,方便查找与查重*/
	struct list_head list;
	/*该混杂设备的父设备,主要是与系统的设备驱动模型关联,通过该变量,可实现系统中
	所有的device通过一种树形结构关联起来*/
	struct device *parent;
	/*该混杂设备对应的device变量,通过该变量,并借助设备驱动模型的device_create接口
	通过向应用层发送设备添加的uevent,从而由udev/mdev实现字符设备文件节点的创建*/
	struct device *this_device;
	/*该变量主要用于在进行device添加或移除时,发送的uevent中会根据该
	变量传递“DEVNAME=”,而mode会以“DEVMODE=”信息传递给应用层*/
	const char *nodename;
	umode_t mode;
};

混杂设备驱动模型的设备号区间申请以及cdev的添加

   在上一节中,我们介绍了如何申请设备号区间以及进行cdev的添加,此处再次重复一遍,步骤如下:

  1. 调用alloc_chrdev_region/register_chrdev_region实现设备号的创建;
  2. 调用cdev_init/cdev_alloc、cdev_add,实现cdev的创建以及注册至cdev_map;
  3. 调用class_create创建一个类别;
  4. 调用device_create/device_add实现device类型变量的注册,该步主要目的是向应用层发送uevent,借助udev/mdev,从而实现字符设备文件的创建。

    

     而针对混杂字符设备驱动模型,在该驱动模型的初始化接口中,即完成上述4步的操作。在接口misc_init中,通过调用register_chrdev申请了主设备号为10,次设备号区间0-255的设备号区间,并通过调用cdev_alloc、cdev_add接口完成了cdev变量的创建以及注册至cdev_map中。同时该接口也创建了一个名为“misc”的类,混杂字符设备对应的device类型变量均会链接至该类(针对linux设备-总线-驱动模型以及class与device关联,请参考之前写的文档,为了不喧宾夺主,此处不再细说这部分内容)。

扫描二维码关注公众号,回复: 9646567 查看本文章

      下图为申请完字符设备区间后,chrdevs变量的示意图(其中蓝色虚线框为混杂设备驱动模型申请的设备号区间)

 

 

      下图为执行cdev_alloc、cdev_add后,cdev_map中增加针对混杂字符设备相关的关联,其中蓝色虚线框为混杂设备驱动相关的内容(该混杂设备对应的cdev变量的销毁借助设备驱动模型中kref变量,以及函数cdev_dynamic_release,在引用计数为时,实现该cdev变量内存空间的释放),该cdev的ops指向misc_fops,而misc_fops中定义了misc_open接口。

 

 

      执行完以上操作后,即完成了混杂字符设备驱动模型的设备号区间申请,cdev的注册等功能。至此混杂字符设备驱动模型中与字符设备驱动模块的相关的工作基本上已完成,下面主要是提供次设备创建的接口罢了。

 

混杂字符设备注册与注销接口

    在上一节中,针对次设备号的创建,我们也进行了说明。主要就如下两种方式:

  1. 在应用层直接调用mknod命令实现字符设备文件inode的创建;
  2. 借助linux设备-总线-驱动模型中的uevent,通过调用device_add接口,创建一个device类型的设备变量,并设置该设备变量对应的设备号,然后即会向应用程序发送设备添加的uevent(通过netlink传递该uevent信息),而应用层程序通过udev进行接收uevent事件(或者通过mdev接收udeve事件),当确认该设备存在设备号以及设备添加event后,即自动调用mknod系统调用,实现字符设备文件的创建。

 

     而针对混杂字符设备驱动模型而言,为了让其字符设备的创建自动化,因此其选择上述b中描述的方式,下面我们分析下其注册函数misc_register的实现,其实现流程如下图所示,主要的功能如下:

  1. 调用device_create创建device类型的变量,从而借助设备模型的uevent事件信息,实现字符设备文件节点的创建;
  2. 将混杂设备链接至misc_list上,以便实现查找与查重。

针对misc_list以及各混杂设备之间的关联,其关联图如下所示:

 

针对注销接口misc_deregister,其实现的功能与注册刚好相反,也就是将该混杂设备从misc_list移除,调用device_destroy从devices_kset上移除该混杂设备对应device变量,且解除与“misc”类的链接(若次设备号在范围0-63内,则位动态申请的次设备后,则需要clear变量misc_minors对应位,以便继续使用)。

 

 

 

如何执行到具体混杂设备驱动的文件操作接口

        在上一节中,我们说过针对申请了多个次设备号的cdev而言,可在其注册的open接口中,根据各自模块维护的次设备变量,实现具体次设备的操作。如spi通用字符设备中的open接口中通过device_list链表,并根据设备号查找到对应spidev_data类型的变量,从而完成针对具体spi device的通信;而在i2c通用字符设备驱动中的open接口中,通过i2c_dev_list链表并借助次设备号,查找到i2c_dev类型的变量,从而借助对应的i2c_adapter,实现数据通信。

 

        而针对混杂设备驱动模型而言,其也是使用类似的操作,在其open接口misc_open中,借助链表misc_list以及传递的次设备号,查找对应的混杂设备,从而调用其fops指针中的文件操作接口,实现具体设备对应的操作接口(具体实现如下流程图所示,该接口实现较简洁明确,不再细说)。

 

 

驱动中如何实现混杂设备的注册

主要通过如下两个操作,即可实现混杂设备的注册:

  1. 创建一个miscdevice类型的变量,并完成初始化;
  2. 调用misc_register,即可完成混杂设备的注册。

我们以看门狗为例,只需执行如下操作即可完成混杂设备的注册:

	static struct miscdevice wdt_miscdev = {
		.minor = WATCHDOG_MINOR,
		.name = "watchdog",
		.fops = &wdt_fops,
	};
   misc_register(&wdt_miscdev)

结语

       至此,我们即完成了混杂字符设备驱动模型的分析,该模型相对来说也比较好理解,其实i2c通用字符设备以及spi通用字符设备的驱动模型也是针对字符设备创建的模型,它们的实现也比较相似。我们再回头去比较这三个模型的时候,也可以加深我们对字符驱动模型的印象,同时也可以提升我们的设计思路(如在i2c通用字符设备驱动、spi通用字符设备驱动中,其文件操作接口是统一的,通过传递的参数完成与具体设备的通信,而混杂设备由于扩展性,因此由各混杂设备自己来实现文件操作接口)。

发布了140 篇原创文章 · 获赞 30 · 访问量 45万+

猜你喜欢

转载自blog.csdn.net/lickylin/article/details/103841875
今日推荐