1 概念
总线是设备模型当中的基础组件,简化了驱动的编写和维护,总线可以是物理总线(如PCI,USB)或虚拟总线.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| struct bus_type { const char *name; const char *dev_name; const struct attribute_group **bus_groups; const struct attribute_group **dev_groups; const struct attribute_group **drv_groups;
int (*match)(struct device *dev, const struct device_driver *drv); int (*uevent)(const struct device *dev, struct kobj_uevent_env *env); int (*probe)(struct device *dev); void (*sync_state)(struct device *dev); void (*remove)(struct device *dev); void (*shutdown)(struct device *dev); const struct cpumask *(*irq_get_affinity)(struct device *dev, unsigned int irq_vec);
int (*online)(struct device *dev); int (*offline)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev);
int (*num_vf)(struct device *dev);
int (*dma_configure)(struct device *dev); void (*dma_cleanup)(struct device *dev);
const struct dev_pm_ops *pm;
bool need_parent_lock; };
struct subsys_private { struct kset subsys; struct kset *devices_kset; struct list_head interfaces; struct mutex mutex;
struct kset *drivers_kset; struct klist klist_devices; struct klist klist_drivers; struct blocking_notifier_head bus_notifier; unsigned int drivers_autoprobe:1; const struct bus_type *bus; struct device *dev_root;
struct kset glue_dirs; const struct class *class;
struct lock_class_key lock_key; };
|
我们可以看看每个 /sys/bus 的结构.
1 2
| $ ls /sys/bus/gpio/ devices drivers drivers_autoprobe drivers_probe uevent
|
2 bus 的注册
我们看看 bus 注册的过程, bus_register.
1 2 3 4 5 6 7 8 9
| bus_register |-kzalloc => subsys_private 空间 |-kobject_set_name => 设置 bus 名到 kobj |-kset_register => 在 /sys/bus/ 下创建 kobj 目录及其 attribute 文件 |-bus_create_file => 创建 uevent 文件 |-kset_create_and_add => 创建 /sys/bus/xxx/devices 文件 |-kset_create_and_add => 创建 /sys/bus/xxx/drivers 文件 |-add_probe_files => 创建 drivers_probe 和 drivers_autoprobe 文件 |-sysfs_create_groups => 创建 bus->bus_group 属性文件
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| int bus_register(const struct bus_type *bus) { int retval; struct subsys_private *priv; struct kobject *bus_kobj; struct lock_class_key *key;
priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL); if (!priv) return -ENOMEM;
priv->bus = bus;
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
bus_kobj = &priv->subsys.kobj; retval = kobject_set_name(bus_kobj, "%s", bus->name); if (retval) goto out;
bus_kobj->kset = bus_kset; bus_kobj->ktype = &bus_ktype; priv->drivers_autoprobe = 1;
retval = kset_register(&priv->subsys); if (retval) goto out;
retval = bus_create_file(bus, &bus_attr_uevent); if (retval) goto bus_uevent_fail;
priv->devices_kset = kset_create_and_add("devices", NULL, bus_kobj); if (!priv->devices_kset) { retval = -ENOMEM; goto bus_devices_fail; }
priv->drivers_kset = kset_create_and_add("drivers", NULL, bus_kobj); if (!priv->drivers_kset) { retval = -ENOMEM; goto bus_drivers_fail; }
INIT_LIST_HEAD(&priv->interfaces); key = &priv->lock_key; lockdep_register_key(key); __mutex_init(&priv->mutex, "subsys mutex", key); klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); klist_init(&priv->klist_drivers, NULL, NULL);
retval = add_probe_files(bus); if (retval) goto bus_probe_files_fail;
retval = sysfs_create_groups(bus_kobj, bus->bus_groups); if (retval) goto bus_groups_fail;
pr_debug("bus: '%s': registered\n", bus->name); return 0;
bus_groups_fail: remove_probe_files(bus); bus_probe_files_fail: kset_unregister(priv->drivers_kset); bus_drivers_fail: kset_unregister(priv->devices_kset); bus_devices_fail: bus_remove_file(bus, &bus_attr_uevent); bus_uevent_fail: kset_unregister(&priv->subsys); priv = NULL; out: kfree(priv); return retval; }
|
之后观察如何在 /sys/bus/xxx 下创建一个文件, 创建路径为:
1
| /sys/bus/<bus_name>/<attr->attr.name>
|