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

http://www.wowotech.net/device_model/bus.html

posted @ 2020-05-16 17:59  Action_er  阅读(1747)  评论(0编辑  收藏  举报