linux设备驱动(4)bus详解
1. 概述
总线(bus)是linux发展过程中抽象出来的一种设备模型,为了统一管理所有的设备,内核中每个设备都会被挂载在总线上,这个bus可以是对应硬件的bus(i2c bus、spi bus)、可以是虚拟bus(platform bus)。
bus将所有挂在上面的具体设备抽象成两部分,device_driver和device。
driver实现了同类型设备的驱动程序实现,而device则向系统注册具体的设备需要的资源,每当添加一个新的driver(device)到bus中时,都将调用bus的match函数,试图寻找匹配的device(driver)。如果匹配成功,就调用probe函数,在probe函数中实现设备的初始化、各种配置以及生成用户空间的文件接口。probe函数是总线在匹配成功时调用的函数,bus->probe和drv->probe中只会有一个起效,同时存在时使用bus->probe。
内核通过struct bus_type结构,抽象bus,它是在include/linux/device.h中定义的,在第一节中讲述。
2. 结构体subsys_private
位于:drivers\base\Base.h
驱动核心的私有数据,只有驱动核心才可以访问。使用struct subsys_private可以将struct bus_type中的部分细节屏蔽掉,利于外界使用bus_type。struct driver_private和struct device_private都有类似的功能。
1 /** 2 * struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure. 3 * 4 * @subsys - the struct kset that defines this subsystem 5 * @devices_kset - the subsystem's 'devices' directory 6 * @interfaces - list of subsystem interfaces associated 7 * @mutex - protect the devices, and interfaces lists. 8 * 9 * @drivers_kset - the list of drivers associated 10 * @klist_devices - the klist to iterate over the @devices_kset 11 * @klist_drivers - the klist to iterate over the @drivers_kset 12 * @bus_notifier - the bus notifier list for anything that cares about things 13 * on this bus. 14 * @bus - pointer back to the struct bus_type that this structure is associated 15 * with. 16 * 17 * @glue_dirs - "glue" directory to put in-between the parent device to 18 * avoid namespace conflicts 19 * @class - pointer back to the struct class that this structure is associated 20 * with. 21 * 22 * This structure is the one that is the actual kobject allowing struct 23 * bus_type/class to be statically allocated safely. Nothing outside of the 24 * driver core should ever touch these fields. 25 */ 26 struct subsys_private { 27 struct kset subsys;//代表bus在sysfs中的类型 28 struct kset *devices_kset;//代表bus目录下的drivers子目录 29 struct list_head interfaces; 30 struct mutex mutex; 31 32 struct kset *drivers_kset;//代表bus目录下地devices子目录 33 struct klist klist_devices;//bus的设备链表 34 struct klist klist_drivers;//bus的驱动链表 35 struct blocking_notifier_head bus_notifier;//用于在总线上内容发送变化时调用特定的函数 36 unsigned int drivers_autoprobe:1;//标志定义是否允许device和driver自动匹配,如果允许会在device或者driver注册时就进行匹配工作,默认是1 37 struct bus_type *bus;//指针指向struct bus_type类型。 38 39 struct kset glue_dirs; 40 struct class *class; 41 }
该结构和device_driver中的struct driver_private类似,device_driver中有提到它,但没有详细说明。看到结构内部的字段,就清晰多了,没事不要乱起名字嘛!什么subsys啊,看的晕晕的!不过还是试着先理解一下为什么起名为subsys吧:按理说,这个结构就是集合了一些bus模块需要使用的私有数据,例如kset啦、klist啦等等,命名为bus_private会好点(就像device、driver模块一样)【事实上早期版本确实是命名为bus_type_private】。不过为什么内核最终抛弃了呢呢?看看include/linux/device.h中的struct class结构(我们会在下一篇文章中介绍class)就知道了,因为class结构中也包含了一个一模一样的struct subsys_private指针,看来class和bus很相似啊,所以在内核的subsys_private在现在最新版本就是这样。
1 linux2.6.35.7 最开始bus和class的private是分开的,已经很相似了 2 struct class_private { 3 struct kset class_subsys; 4 struct klist class_devices; 5 struct list_head class_interfaces; 6 struct kset class_dirs; 7 struct mutex class_mutex; 8 struct class *class; 9 }; 10 struct bus_type_private { 11 struct kset subsys; 12 struct kset *drivers_kset; 13 struct kset *devices_kset; 14 struct klist klist_devices; 15 struct klist klist_drivers; 16 struct blocking_notifier_head bus_notifier; 17 unsigned int drivers_autoprobe:1; 18 struct bus_type *bus; 19 }; 20 linux 3.xxx bus有需求升级为subsys_private ,同时为后面去掉class_private 做基础 21 struct subsys_private { 22 struct kset subsys; 23 struct kset *devices_kset; 24 struct list_head interfaces; 25 struct mutex mutex; 26 struct kset *drivers_kset; 27 struct klist klist_devices; 28 struct klist klist_drivers; 29 struct blocking_notifier_head bus_notifier; 30 unsigned int drivers_autoprobe:1; 31 struct bus_type *bus; 32 struct kset glue_dirs; 33 struct class *class; 34 }; 35 struct class_private { 36 struct kset class_subsys; 37 struct klist class_devices; 38 struct list_head class_interfaces; 39 struct kset class_dirs; 40 struct mutex class_mutex; 41 struct class *class; 42 }; 43 linux3.x后期,两者完全统一用这个,class_private 在这个版本已经完全看不到了 44 struct subsys_private { 45 struct kset subsys; 46 struct kset *devices_kset; 47 struct list_head interfaces; 48 struct mutex mutex; 49 struct kset *drivers_kset; 50 struct klist klist_devices; 51 struct klist klist_drivers; 52 struct blocking_notifier_head bus_notifier; 53 unsigned int drivers_autoprobe:1; 54 struct bus_type *bus; // 55 struct kset glue_dirs; 56 struct class *class; // 57 };
想到这里,就好理解了,无论是bus,还是class,还是我们会在后面看到的一些虚拟的子系统,它都构成了一个“子系统(sub-system)”,该子系统会包含形形色色的device或device_driver,就像一个独立的王国一样,存在于内核中。而这些子系统的表现形式,就是/sys/bus(或/sys/class,或其它)目录下面的子目录,每一个子目录,都是一个子系统(如/sys/bus/spi/)。
3相关API介绍
位于:drivers\base\bus.c
3.1bus_register
1 /** 2 * bus_register - register a driver-core subsystem 3 * @bus: bus to register 4 * 5 * Once we have that, we register the bus with the kobject 6 * infrastructure, then register the children subsystems it has: 7 * the devices and drivers that belong to the subsystem. 8 */ 9 int bus_register(struct bus_type *bus) 10 { 11 int retval; 12 struct subsys_private *priv; 13 struct lock_class_key *key = &bus->lock_key; 14 15 priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);//开子系统结构体 16 if (!priv) 17 return -ENOMEM; 18 19 priv->bus = bus; 20 bus->p = priv; 21 22 BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier); 23 24 retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);//设置目录的名字 25 if (retval) 26 goto out; 27 28 priv->subsys.kobj.kset = bus_kset; 29 priv->subsys.kobj.ktype = &bus_ktype; 30 priv->drivers_autoprobe = 1;//本总线上device/driver注册时是否自动匹配 31 32 retval = kset_register(&priv->subsys);//注册kset,即在bus目录下就出现了对应目录 33 if (retval) 34 goto out; 35 36 retval = bus_create_file(bus, &bus_attr_uevent);//创建属性文件 37 if (retval) 38 goto bus_uevent_fail; 39 /*bus目录下创建devices和drivers目录,将来绑定该总线的设备和驱动就会存放于此*/ 40 priv->devices_kset = kset_create_and_add("devices", NULL, 41 &priv->subsys.kobj); 42 if (!priv->devices_kset) { 43 retval = -ENOMEM; 44 goto bus_devices_fail; 45 } 46 47 priv->drivers_kset = kset_create_and_add("drivers", NULL, 48 &priv->subsys.kobj); 49 if (!priv->drivers_kset) { 50 retval = -ENOMEM; 51 goto bus_drivers_fail; 52 } 53 //初始化priv中设备的驱动的链表 54 INIT_LIST_HEAD(&priv->interfaces); 55 __mutex_init(&priv->mutex, "subsys mutex", key); 56 klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);//初始化设备链表,用于连接bus上的device 57 klist_init(&priv->klist_drivers, NULL, NULL);//初始化驱动链表,用于连接bus上的device_driver 58 59 retval = add_probe_files(bus);//在bus目录下添加drivers_probe和drivers_autoprobe文件 60 if (retval) 61 goto bus_probe_files_fail; 62 63 retval = bus_add_attrs(bus); 64 if (retval) 65 goto bus_attrs_fail; 66 67 pr_debug("bus: '%s': registered\n", bus->name); 68 return 0; 69 70 bus_attrs_fail: 71 remove_probe_files(bus); 72 bus_probe_files_fail: 73 kset_unregister(bus->p->drivers_kset); 74 bus_drivers_fail: 75 kset_unregister(bus->p->devices_kset); 76 bus_devices_fail: 77 bus_remove_file(bus, &bus_attr_uevent); 78 bus_uevent_fail: 79 kset_unregister(&bus->p->subsys); 80 out: 81 kfree(bus->p); 82 bus->p = NULL; 83 return retval; 84 }
总结该API的主要功能如下:
- 为bus_type中struct subsys_private类型的指针分配空间,并更新priv->bus和bus->p两个指针为正确的值
- 初始化priv->subsys.kobj的name、kset、ktype等字段,启动name就是该bus的name(它会体现在sysfs中),kset和ktype由bus模块实现,分别为bus_kset和bus_ktype
- 调用kset_register将priv->subsys注册到内核中,该接口同时会向sysfs中添加对应的目录(如/sys/bus/spi)
- 调用bus_create_file向bus目录下添加一个uevent attribute(如/sys/bus/spi/uevent)
- 调用kset_create_and_add分别向内核添加devices和device_drivers kset,同时会体现在sysfs中
- 初始化priv指针中的mutex、klist_devices和klist_drivers等变量
- 调用add_probe_files接口,在bus下添加drivers_probe和drivers_autoprobe两个attribute(如/sys/bus/spi/drivers_probe和/sys/bus/spi/drivers_autoprobe),其中drivers_probe允许用户空间程序主动出发指定bus下的device_driver的probe动作,而drivers_autoprobe控制是否在device或device_driver添加到内核时,自动执行probe
- 调用bus_add_attrs,添加由bus_attrs指针定义的bus的默认attribute,这些attributes最终会体现在/sys/bus/xxx目录下
3.2bus_add_device和bus_add_driver详解见 linux设备驱动(2)device详解 和 linux设备驱动(3)device_driver详解
参考博文:
https://blog.csdn.net/qq_16777851/java/article/details/81488020