Linux裝置模型分析之bus(基於3.10.1核心)
阿新 • • 發佈:2019-01-06
作者:劉昊昱
核心版本:3.10.1
一、bus定義
Linux裝置驅動模型中的bus,即可以是物理匯流排(如PCI、I2C匯流排)的抽象,也可以是出於裝置驅動模型架構需要而定義的虛擬的“platform”匯流排。一個符合Linux裝置驅動模型的device或device_driver必須掛靠在一個bus上,無論這個bus是物理的還是虛擬的。
Linux核心使用bus_type結構體來描述bus,該結構體定義在include/linux/device.h檔案中,其內容如下:
56/** 57 * struct bus_type - The bus type of the device 58 * 59 * @name: The name of the bus. 60 * @dev_name: Used for subsystems to enumerate devices like ("foo%u", dev->id). 61 * @dev_root: Default device to use as the parent. 62 * @bus_attrs: Default attributes of the bus. 63 * @dev_attrs: Default attributes of the devices on the bus. 64 * @drv_attrs: Default attributes of the device drivers on the bus. 65 * @match: Called, perhaps multiple times, whenever a new device or driver 66 * is added for this bus. It should return a nonzero value if the 67 * given device can be handled by the given driver. 68 * @uevent: Called when a device is added, removed, or a few other things 69 * that generate uevents to add the environment variables. 70 * @probe: Called when a new device or driver add to this bus, and callback 71 * the specific driver's probe to initial the matched device. 72 * @remove: Called when a device removed from this bus. 73 * @shutdown: Called at shut-down time to quiesce the device. 74 * @suspend: Called when a device on this bus wants to go to sleep mode. 75 * @resume: Called to bring a device on this bus out of sleep mode. 76 * @pm: Power management operations of this bus, callback the specific 77 * device driver's pm-ops. 78 * @iommu_ops: IOMMU specific operations for this bus, used to attach IOMMU 79 * driver implementations to a bus and allow the driver to do 80 * bus-specific setup 81 * @p: The private data of the driver core, only the driver core can 82 * touch this. 83 * 84 * A bus is a channel between the processor and one or more devices. For the 85 * purposes of the device model, all devices are connected via a bus, even if 86 * it is an internal, virtual, "platform" bus. Buses can plug into each other. 87 * A USB controller is usually a PCI device, for example. The device model 88 * represents the actual connections between buses and the devices they control. 89 * A bus is represented by the bus_type structure. It contains the name, the 90 * default attributes, the bus' methods, PM operations, and the driver core's 91 * private data. 92 */ 93struct bus_type { 94 const char *name; 95 const char *dev_name; 96 struct device *dev_root; 97 struct bus_attribute *bus_attrs; 98 struct device_attribute *dev_attrs; 99 struct driver_attribute *drv_attrs; 100 101 int (*match)(struct device *dev, struct device_driver *drv); 102 int (*uevent)(struct device *dev, struct kobj_uevent_env *env); 103 int (*probe)(struct device *dev); 104 int (*remove)(struct device *dev); 105 void (*shutdown)(struct device *dev); 106 107 int (*suspend)(struct device *dev, pm_message_t state); 108 int (*resume)(struct device *dev); 109 110 const struct dev_pm_ops *pm; 111 112 struct iommu_ops *iommu_ops; 113 114 struct subsys_private *p; 115 struct lock_class_key lock_key; 116};
下面我們來看一下bus_type各個成員的作用:
name,代表bus的名字。
dev_name,用來遍歷bus上的device。
dev_root,bus上device的根節點。
bus_attrs,bus的屬性。
dev_attrs,bus上device的屬性。
drv_attrs,bus上device_driver的屬性。
match,當一個新的device或device driver被加入到該bus時,match函式會被呼叫進行匹配操作。更詳細的說,當一個device被加入時,會和bus上的所有device_driver進行匹配操作,如果有device_driver能支援這個device,則匹配成功,match返回非0值。當一個device_driver被加入到bus時,會和bus上的所有device進行匹配操作,如果有它能支援的device,則匹配成功,match返回非0值。
uevent,當某個device加入或被刪除,或者其它一些會發送uevnt訊息的事件發生時,該函式會被呼叫。
probe,當一個新的device或device_driver被加入bus時,該函式會被呼叫,它又會進而呼叫相應device_driver的probe函式對匹配的device進行初始化。
remove,當一個device被刪除時,這個函式會被呼叫。
shutdown,當系統關機時,該函式會被呼叫。
suspend,當bus的某個device要進入休眠狀態時,這個函式會被呼叫。
resume,當bus上的某個休眠device被喚醒時,這個函式會被呼叫。
pm,bus上的電源管理操作函式,會進而呼叫相應device_driver的pm函式。
iommu_ops,bus的iommu相關操作。
p,bus私有資料,只有bus driver本身能訪問這些資料,其型別是struct subsys_private,該結構體定義在drivers/base/base.h檔案中,其內容如下:
3/**
4 * struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure.
5 *
6 * @subsys - the struct kset that defines this subsystem
7 * @devices_kset - the subsystem's 'devices' directory
8 * @interfaces - list of subsystem interfaces associated
9 * @mutex - protect the devices, and interfaces lists.
10 *
11 * @drivers_kset - the list of drivers associated
12 * @klist_devices - the klist to iterate over the @devices_kset
13 * @klist_drivers - the klist to iterate over the @drivers_kset
14 * @bus_notifier - the bus notifier list for anything that cares about things
15 * on this bus.
16 * @bus - pointer back to the struct bus_type that this structure is associated
17 * with.
18 *
19 * @glue_dirs - "glue" directory to put in-between the parent device to
20 * avoid namespace conflicts
21 * @class - pointer back to the struct class that this structure is associated
22 * with.
23 *
24 * This structure is the one that is the actual kobject allowing struct
25 * bus_type/class to be statically allocated safely. Nothing outside of the
26 * driver core should ever touch these fields.
27 */
28struct subsys_private {
29 struct kset subsys;
30 struct kset *devices_kset;
31 struct list_head interfaces;
32 struct mutex mutex;
33
34 struct kset *drivers_kset;
35 struct klist klist_devices;
36 struct klist klist_drivers;
37 struct blocking_notifier_head bus_notifier;
38 unsigned int drivers_autoprobe:1;
39 struct bus_type *bus;
40
41 struct kset glue_dirs;
42 struct class *class;
43};
subsys,代表bus對應的kset,即bus對應子系統。bus對應一個kset,而device和device_driver都對應一個kobject,由此也可以看出它們的區別。在Linux裝置模型中,bus對應的kset是subsys,bus對應的kobject是subsys.kobj,bus對應的父kset是subsys.kobj.kset。所有通過bus_register註冊進系統的bus的父kset均為bus_kset,它對應/sys/bus目錄,所以,bus對應的目錄都在/sys/bus目錄下,如/sys/bus/usb。
devices_kset,該bus上所有device的集合。
interfaces,子系統interfaces連結串列。
drivers_kset,該bus上所有device_driver的集合。
klist_devices,該bus上所有device的連結串列。
klist_drivers,該bus上所有device_driver的連結串列。
bus_notifier,bus notifier列表。
drivers_autoprobe,表明當向bus加入一個device或device_driver時,是否自動進行匹配操作。
bus,指向相關聯的bus_type。
二、bus初始化
bus的初始化操作是在buses_init函式中完成的,該函式定義在drivers/base/bus.c檔案中,其內容如下:
1300int __init buses_init(void)
1301{
1302 bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
1303 if (!bus_kset)
1304 return -ENOMEM;
1305
1306 system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
1307 if (!system_kset)
1308 return -ENOMEM;
1309
1310 return 0;
1311}
1302行,呼叫kset_create_and_add建立bus_kset,它是所有bus的容器,對應/sys/bus目錄。這裡指定了當bus_kset中的成員狀態有變化時,用來通知使用者空間的uevent操作函式集為bus_uevent_ops,它定義在drivers/base/bus.c檔案中,其內容如下:
161static const struct kset_uevent_ops bus_uevent_ops = {
162 .filter = bus_uevent_filter,
163};
這個操作函式集中只定義了filter函式,用來決定狀態發生變化時是否通知使用者空間,其定義如下:
152static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
153{
154 struct kobj_type *ktype = get_ktype(kobj);
155
156 if (ktype == &bus_ktype)
157 return 1;
158 return 0;
159}
如果ktype不是“bus_ktype”,則不通知使用者空間。
回到buses_init函式,1306行,呼叫kset_create_and_add建立system_kset,對應/sys/devices/system目錄。
三、bus的註冊
註冊一個bus是通過呼叫bus_register函式完成的,該函式定義在drivers/base/bus.c檔案中,其內容如下:
900/**
901 * bus_register - register a driver-core subsystem
902 * @bus: bus to register
903 *
904 * Once we have that, we register the bus with the kobject
905 * infrastructure, then register the children subsystems it has:
906 * the devices and drivers that belong to the subsystem.
907 */
908int bus_register(struct bus_type *bus)
909{
910 int retval;
911 struct subsys_private *priv;
912 struct lock_class_key *key = &bus->lock_key;
913
914 priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
915 if (!priv)
916 return -ENOMEM;
917
918 priv->bus = bus;
919 bus->p = priv;
920
921 BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
922
923 retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
924 if (retval)
925 goto out;
926
927 priv->subsys.kobj.kset = bus_kset;
928 priv->subsys.kobj.ktype = &bus_ktype;
929 priv->drivers_autoprobe = 1;
930
931 retval = kset_register(&priv->subsys);
932 if (retval)
933 goto out;
934
935 retval = bus_create_file(bus, &bus_attr_uevent);
936 if (retval)
937 goto bus_uevent_fail;
938
939 priv->devices_kset = kset_create_and_add("devices", NULL,
940 &priv->subsys.kobj);
941 if (!priv->devices_kset) {
942 retval = -ENOMEM;
943 goto bus_devices_fail;
944 }
945
946 priv->drivers_kset = kset_create_and_add("drivers", NULL,
947 &priv->subsys.kobj);
948 if (!priv->drivers_kset) {
949 retval = -ENOMEM;
950 goto bus_drivers_fail;
951 }
952
953 INIT_LIST_HEAD(&priv->interfaces);
954 __mutex_init(&priv->mutex, "subsys mutex", key);
955 klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
956 klist_init(&priv->klist_drivers, NULL, NULL);
957
958 retval = add_probe_files(bus);
959 if (retval)
960 goto bus_probe_files_fail;
961
962 retval = bus_add_attrs(bus);
963 if (retval)
964 goto bus_attrs_fail;
965
966 pr_debug("bus: '%s': registered\n", bus->name);
967 return 0;
968
969bus_attrs_fail:
970 remove_probe_files(bus);
971bus_probe_files_fail:
972 kset_unregister(bus->p->drivers_kset);
973bus_drivers_fail:
974 kset_unregister(bus->p->devices_kset);
975bus_devices_fail:
976 bus_remove_file(bus, &bus_attr_uevent);
977bus_uevent_fail:
978 kset_unregister(&bus->p->subsys);
979out:
980 kfree(bus->p);
981 bus->p = NULL;
982 return retval;
983}
914行,為struct subsys_private指標priv分配記憶體空間。
923行,設定priv->subsys.kobj的名字為bus->name,對應sysfs檔案系統中該bus的目錄名。
927行,設定priv->subsys.kobj.kset為bus_kset,即所有通過bus_register函式註冊的bus本身是一個kset(即priv->subsys),該kset對應的kobject是priv->subsys.kobj,該kset的父kset是priv->subsys.kobj.kset,這裡設定為bus_kset。因為bus_kset在buses_init函式中初始化,對應/sys/bus目錄,所以後面我們註冊的bus的根目錄都在/sys/bus目錄下,如/sys/bus/usb。
928行,設定priv->subsys.kobj.ktype為bus_ktype。因為對kobject屬性檔案的讀寫操作將會呼叫kobject.ktype.sysfs_ops指定的show和store函式,所以,讀寫bus對應的屬性檔案,將會呼叫bus_ktype.sysfs_ops指定的show和store函式。bus_ktype定義在drivers/base/bus.c檔案中,其內容如下:
148static struct kobj_type bus_ktype = {
149 .sysfs_ops = &bus_sysfs_ops,
150};
bus_sysfs_ops定義在drivers/base/bus.c檔案中,其內容如下:
122static const struct sysfs_ops bus_sysfs_ops = {
123 .show = bus_attr_show,
124 .store = bus_attr_store,
125};
同樣是在drivers/base/bus.c檔案中,bus_attr_show和bus_attr_store函式定義如下:
95/*
96 * sysfs bindings for buses
97 */
98static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr,
99 char *buf)
100{
101 struct bus_attribute *bus_attr = to_bus_attr(attr);
102 struct subsys_private *subsys_priv = to_subsys_private(kobj);
103 ssize_t ret = 0;
104
105 if (bus_attr->show)
106 ret = bus_attr->show(subsys_priv->bus, buf);
107 return ret;
108}
109
110static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr,
111 const char *buf, size_t count)
112{
113 struct bus_attribute *bus_attr = to_bus_attr(attr);
114 struct subsys_private *subsys_priv = to_subsys_private(kobj);
115 ssize_t ret = 0;
116
117 if (bus_attr->store)
118 ret = bus_attr->store(subsys_priv->bus, buf, count);
119 return ret;
120}
to_bus_attr是一個巨集,定義在drivers/base/bus.c檔案中,如下:
26#define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
bus_attribute定義在include/linux/device.h檔案中,其內容如下:
43struct bus_attribute {
44 struct attribute attr;
45 ssize_t (*show)(struct bus_type *bus, char *buf);
46 ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
47};
to_subsys_private定義在drivers/base/base.h檔案中,如下:
44#define to_subsys_private(obj) container_of(obj, struct subsys_private, subsys.kobj)
至此,我們可以回顧一下整個呼叫流程:
呼叫bus_register註冊任意一個bus時(如usb、i2c等等),都指定了該bus對應的bus_type.p.subsys.kobj.ktype為bus_ktype,所以對任意一個bus對應的屬性檔案進行讀寫操作時,都會呼叫bus_ktype.sysfs_ops.bus_attr_show和bus_ktype.sysfs_ops.bus_attr_store函式。注意,讀寫usb匯流排屬性檔案時是呼叫這兩個函式,讀寫i2c匯流排屬性檔案時也是呼叫這兩個函式,所有的匯流排呼叫的是同一個函式。那麼怎麼區分不同匯流排的操作呢?關鍵點是在bus_attr_show和bus_attr_store函式內部,通過to_bus_attr將引數傳遞過來的struct attribute變數轉換為包含它的struct bus_attribute物件,進而呼叫bus_attribute.show和bus_attribute.store函式。而bus_attribute物件定義在bus_type結構體中,即bus_type.bus_attrs,每個bus有不同的bus_type定義,也就有不同的bus_type.bus_attrs,也就有不同的bus_type.bus_attrs.show和bus_type.bus_attrs.store實現。
回到bus_register函式中:
929行,設定priv->drivers_autoprobe為1,指示當向bus加入一個device或device_driver時,自動進行匹配操作。
931行,呼叫kset_register註冊priv->subsys,這時在/sys/bus下建立了相應bus目錄結構。
935行,呼叫bus_create_file建立bus_attr_uevent對應的屬性檔案。
bus_create_file函式定義在drivers/base/bus.c檔案中,其內容如下:
127int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
128{
129 int error;
130 if (bus_get(bus)) {
131 error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
132 bus_put(bus);
133 } else
134 error = -EINVAL;
135 return error;
136}
bus_attr_uevent定義在drivers/base/bus.c檔案中:
898static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
BUS_ATTR定義在include/linux/device.h檔案中:
49#define BUS_ATTR(_name, _mode, _show, _store) \
50struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)
__ATTR定義在include/linux/sysfs.h檔案中:
66/**
67 * Use these macros to make defining attributes easier. See include/linux/device.h
68 * for examples..
69 */
70
71#define __ATTR(_name,_mode,_show,_store) { \
72 .attr = {.name = __stringify(_name), .mode = _mode }, \
73 .show = _show, \
74 .store = _store, \
75}
由bus_attr_uevent的定義可以看出,它沒有定義show函式,而是隻定義了store函式bus_uevent_store,該函式定義在drivers/base/bus.c檔案中,其內容如下:
889static ssize_t bus_uevent_store(struct bus_type *bus,
890 const char *buf, size_t count)
891{
892 enum kobject_action action;
893
894 if (kobject_action_type(buf, count, &action) == 0)
895 kobject_uevent(&bus->p->subsys.kobj, action);
896 return count;
897}
回到bus_register函式:
939-944行,呼叫kset_create_and_add建立名為devices的kset,賦值給priv->devices_kset,並指定該kset的parent kobject為priv->subsys.kobj。所以該kset對應於使用者空間/sys/bus/bus_name/devices目錄。
946-951行,呼叫kset_create_and_add建立名為devices的kset,賦值給priv->drivers_kset,並指定該kset的parent kobject為priv->subsys.kobj。所以該kset對應於使用者空間/sys/bus/bus_name/drivers目錄。
953行,初始化priv->interfaces
955行,初始化priv->klist_devices,klist_devices_get和klist_devices_put函式定義在drivers/base/bus.c檔案中,其內容如下:
873static void klist_devices_get(struct klist_node *n)
874{
875 struct device_private *dev_prv = to_device_private_bus(n);
876 struct device *dev = dev_prv->device;
877
878 get_device(dev);
879}
880
881static void klist_devices_put(struct klist_node *n)
882{
883 struct device_private *dev_prv = to_device_private_bus(n);
884 struct device *dev = dev_prv->device;
885
886 put_device(dev);
887}
956行,初始化priv->klist_drivers。
958行,呼叫add_probe_files函式,該函式定義在drivers/base/bus.c檔案中,其內容如下:
641static int add_probe_files(struct bus_type *bus)
642{
643 int retval;
644
645 retval = bus_create_file(bus, &bus_attr_drivers_probe);
646 if (retval)
647 goto out;
648
649 retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
650 if (retval)
651 bus_remove_file(bus, &bus_attr_drivers_probe);
652out:
653 return retval;
654}
該函式建立了兩個屬性檔案:/sys/bus/bus_name/drivers_probe和/sys/bus/bus_name/drivers_autoprobe
屬性bus_attr_drivers_probe和bus_attr_drivers_autoprobe定義在drivers/base/bus.c檔案中,如下:
637static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);
638static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,
639 show_drivers_autoprobe, store_drivers_autoprobe);
可見bus_attr_drivers_probe只定義了store函式,bus_attr_drivers_autoprobe定義了show和store兩個函式,它們都定義在drivers/base/bus.c檔案中,如下:
226static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
227{
228 return sprintf(buf, "%d\n", bus->p->drivers_autoprobe);
229}
230
231static ssize_t store_drivers_autoprobe(struct bus_type *bus,
232 const char *buf, size_t count)
233{
234 if (buf[0] == '0')
235 bus->p->drivers_autoprobe = 0;
236 else
237 bus->p->drivers_autoprobe = 1;
238 return count;
239}
240
241static ssize_t store_drivers_probe(struct bus_type *bus,
242 const char *buf, size_t count)
243{
244 struct device *dev;
245
246 dev = bus_find_device_by_name(bus, NULL, buf);
247 if (!dev)
248 return -ENODEV;
249 if (bus_rescan_devices_helper(dev, NULL) != 0)
250 return -EINVAL;
251 return count;
252}
show_drivers_autoprobe函式只是顯示當前bus->p->drivers_autoprobe的值。
store_drivers_autoprobe函式根據使用者空間傳遞過來的引數設定bus->p->drivers_autoprobe的值。
store_drivers_probe函式在246行呼叫bus_find_device_by_name函式根據使用者空間傳遞進來的裝置名(儲存在buf中)查詢對應的device。249行,呼叫bus_rescan_devices_helper函式為該裝置查詢對應的device_driver。
回到bus_register函式:
962行,呼叫bus_add_attrs,該函式定義在drivers/base/bus.c檔案中,其內容如下:
838/**
839 * bus_add_attrs - Add default attributes for this bus.
840 * @bus: Bus that has just been registered.
841 */
842
843static int bus_add_attrs(struct bus_type *bus)
844{
845 int error = 0;
846 int i;
847
848 if (bus->bus_attrs) {
849 for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
850 error = bus_create_file(bus, &bus->bus_attrs[i]);
851 if (error)
852 goto err;
853 }
854 }
855done:
856 return error;
857err:
858 while (--i >= 0)
859 bus_remove_file(bus, &bus->bus_attrs[i]);
860 goto done;
861}
如果指定了bus的預設屬性,即bus->bus_attrs不為NULL,則建立對應的屬性檔案。
至此,bus_register函式我們就分析完了。