一、bus定义
Linux设备驱动模型中的bus,即可以是物理总线(如PCI、I2C总线)的抽象,也可以是出于设备驱动模型架构需要而定义的虚拟的“platform”总线。一个符合Linux设备驱动模型的device或device_driver必须挂靠在一个bus上,无论这个bus是物理的还是虚拟的。
Linux内核使用bus_type结构体来描述bus,该结构体定义在include/linux/device.h文件中,其内容如下:
[cpp] view plain copy
  1. 56/**
  2. 57 * struct bus_type - The bus type of the device
  3. 58 *
  4. 59 * @name:   The name of the bus.
  5. 60 * @dev_name:   Used for subsystems to enumerate devices like ("foo%u", dev->id).
  6. 61 * @dev_root:   Default device to use as the parent.
  7. 62 * @bus_attrs:  Default attributes of the bus.
  8. 63 * @dev_attrs:  Default attributes of the devices on the bus.
  9. 64 * @drv_attrs:  Default attributes of the device drivers on the bus.
  10. 65 * @match:  Called, perhaps multiple times, whenever a new device or driver
  11. 66 *      is added for this bus. It should return a nonzero value if the
  12. 67 *      given device can be handled by the given driver.
  13. 68 * @uevent: Called when a device is added, removed, or a few other things
  14. 69 *      that generate uevents to add the environment variables.
  15. 70 * @probe:  Called when a new device or driver add to this bus, and callback
  16. 71 *      the specific driver's probe to initial the matched device.
  17. 72 * @remove: Called when a device removed from this bus.
  18. 73 * @shutdown:   Called at shut-down time to quiesce the device.
  19. 74 * @suspend:    Called when a device on this bus wants to go to sleep mode.
  20. 75 * @resume: Called to bring a device on this bus out of sleep mode.
  21. 76 * @pm:     Power management operations of this bus, callback the specific
  22. 77 *      device driver's pm-ops.
  23. 78 * @iommu_ops:  IOMMU specific operations for this bus, used to attach IOMMU
  24. 79 *              driver implementations to a bus and allow the driver to do
  25. 80 *              bus-specific setup
  26. 81 * @p:      The private data of the driver core, only the driver core can
  27. 82 *      touch this.
  28. 83 *
  29. 84 * A bus is a channel between the processor and one or more devices. For the
  30. 85 * purposes of the device model, all devices are connected via a bus, even if
  31. 86 * it is an internal, virtual, "platform" bus. Buses can plug into each other.
  32. 87 * A USB controller is usually a PCI device, for example. The device model
  33. 88 * represents the actual connections between buses and the devices they control.
  34. 89 * A bus is represented by the bus_type structure. It contains the name, the
  35. 90 * default attributes, the bus' methods, PM operations, and the driver core's
  36. 91 * private data.
  37. 92 */
  38. 93struct bus_type {
  39. 94    const char      *name;
  40. 95    const char      *dev_name;
  41. 96    struct device       *dev_root;
  42. 97    struct bus_attribute    *bus_attrs;
  43. 98    struct device_attribute *dev_attrs;
  44. 99    struct driver_attribute *drv_attrs;
  45. 100
  46. 101    int (*match)(struct device *dev, struct device_driver *drv);
  47. 102    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
  48. 103    int (*probe)(struct device *dev);
  49. 104    int (*remove)(struct device *dev);
  50. 105    void (*shutdown)(struct device *dev);
  51. 106
  52. 107    int (*suspend)(struct device *dev, pm_message_t state);
  53. 108    int (*resume)(struct device *dev);
  54. 109
  55. 110    const struct dev_pm_ops *pm;
  56. 111
  57. 112    struct iommu_ops *iommu_ops;
  58. 113
  59. 114    struct subsys_private *p;
  60. 115    struct lock_class_key lock_key;
  61. 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文件中,其内容如下:
[cpp] view plain copy
  1. 3/**
  2. 4 * struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure.
  3. 5 *
  4. 6 * @subsys - the struct kset that defines this subsystem
  5. 7 * @devices_kset - the subsystem's 'devices' directory
  6. 8 * @interfaces - list of subsystem interfaces associated
  7. 9 * @mutex - protect the devices, and interfaces lists.
  8. 10 *
  9. 11 * @drivers_kset - the list of drivers associated
  10. 12 * @klist_devices - the klist to iterate over the @devices_kset
  11. 13 * @klist_drivers - the klist to iterate over the @drivers_kset
  12. 14 * @bus_notifier - the bus notifier list for anything that cares about things
  13. 15 *                 on this bus.
  14. 16 * @bus - pointer back to the struct bus_type that this structure is associated
  15. 17 *        with.
  16. 18 *
  17. 19 * @glue_dirs - "glue" directory to put in-between the parent device to
  18. 20 *              avoid namespace conflicts
  19. 21 * @class - pointer back to the struct class that this structure is associated
  20. 22 *          with.
  21. 23 *
  22. 24 * This structure is the one that is the actual kobject allowing struct
  23. 25 * bus_type/class to be statically allocated safely.  Nothing outside of the
  24. 26 * driver core should ever touch these fields.
  25. 27 */
  26. 28struct subsys_private {
  27. 29    struct kset subsys;
  28. 30    struct kset *devices_kset;
  29. 31    struct list_head interfaces;
  30. 32    struct mutex mutex;
  31. 33
  32. 34    struct kset *drivers_kset;
  33. 35    struct klist klist_devices;
  34. 36    struct klist klist_drivers;
  35. 37    struct blocking_notifier_head bus_notifier;
  36. 38    unsigned int drivers_autoprobe:1;
  37. 39    struct bus_type *bus;
  38. 40
  39. 41    struct kset glue_dirs;
  40. 42    struct class *class;
  41. 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文件中,其内容如下:
[cpp] view plain copy
  1. 1300int __init buses_init(void)
  2. 1301{
  3. 1302    bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
  4. 1303    if (!bus_kset)
  5. 1304        return -ENOMEM;
  6. 1305
  7. 1306    system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
  8. 1307    if (!system_kset)
  9. 1308        return -ENOMEM;
  10. 1309
  11. 1310    return 0;
  12. 1311}
1302行,调用kset_create_and_add创建bus_kset,它是所有bus的容器,对应/sys/bus目录。这里指定了当bus_kset中的成员状态有变化时,用来通知用户空间的uevent操作函数集为bus_uevent_ops,它定义在drivers/base/bus.c文件中,其内容如下:
[cpp] view plain copy
  1. 161static const struct kset_uevent_ops bus_uevent_ops = {
  2. 162    .filter = bus_uevent_filter,
  3. 163};
这个操作函数集中只定义了filter函数,用来决定状态发生变化时是否通知用户空间,其定义如下:
[cpp] view plain copy
  1. 152static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
  2. 153{
  3. 154    struct kobj_type *ktype = get_ktype(kobj);
  4. 155
  5. 156    if (ktype == &bus_ktype)
  6. 157        return 1;
  7. 158    return 0;
  8. 159}
如果ktype不是“bus_ktype”,则不通知用户空间。
回到buses_init函数,1306行,调用kset_create_and_add创建system_kset,对应/sys/devices/system目录。
 
三、bus的注册
注册一个bus是通过调用bus_register函数完成的,该函数定义在drivers/base/bus.c文件中,其内容如下:
[cpp] view plain copy
  1. 900/**
  2. 901 * bus_register - register a driver-core subsystem
  3. 902 * @bus: bus to register
  4. 903 *
  5. 904 * Once we have that, we register the bus with the kobject
  6. 905 * infrastructure, then register the children subsystems it has:
  7. 906 * the devices and drivers that belong to the subsystem.
  8. 907 */
  9. 908int bus_register(struct bus_type *bus)
  10. 909{
  11. 910    int retval;
  12. 911    struct subsys_private *priv;
  13. 912    struct lock_class_key *key = &bus->lock_key;
  14. 913
  15. 914    priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
  16. 915    if (!priv)
  17. 916        return -ENOMEM;
  18. 917
  19. 918    priv->bus = bus;
  20. 919    bus->p = priv;
  21. 920
  22. 921    BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
  23. 922
  24. 923    retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
  25. 924    if (retval)
  26. 925        goto out;
  27. 926
  28. 927    priv->subsys.kobj.kset = bus_kset;
  29. 928    priv->subsys.kobj.ktype = &bus_ktype;
  30. 929    priv->drivers_autoprobe = 1;
  31. 930
  32. 931    retval = kset_register(&priv->subsys);
  33. 932    if (retval)
  34. 933        goto out;
  35. 934
  36. 935    retval = bus_create_file(bus, &bus_attr_uevent);
  37. 936    if (retval)
  38. 937        goto bus_uevent_fail;
  39. 938
  40. 939    priv->devices_kset = kset_create_and_add("devices", NULL,
  41. 940                         &priv->subsys.kobj);
  42. 941    if (!priv->devices_kset) {
  43. 942        retval = -ENOMEM;
  44. 943        goto bus_devices_fail;
  45. 944    }
  46. 945
  47. 946    priv->drivers_kset = kset_create_and_add("drivers", NULL,
  48. 947                         &priv->subsys.kobj);
  49. 948    if (!priv->drivers_kset) {
  50. 949        retval = -ENOMEM;
  51. 950        goto bus_drivers_fail;
  52. 951    }
  53. 952
  54. 953    INIT_LIST_HEAD(&priv->interfaces);
  55. 954    __mutex_init(&priv->mutex, "subsys mutex", key);
  56. 955    klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
  57. 956    klist_init(&priv->klist_drivers, NULL, NULL);
  58. 957
  59. 958    retval = add_probe_files(bus);
  60. 959    if (retval)
  61. 960        goto bus_probe_files_fail;
  62. 961
  63. 962    retval = bus_add_attrs(bus);
  64. 963    if (retval)
  65. 964        goto bus_attrs_fail;
  66. 965
  67. 966    pr_debug("bus: '%s': registered\n", bus->name);
  68. 967    return 0;
  69. 968
  70. 969bus_attrs_fail:
  71. 970    remove_probe_files(bus);
  72. 971bus_probe_files_fail:
  73. 972    kset_unregister(bus->p->drivers_kset);
  74. 973bus_drivers_fail:
  75. 974    kset_unregister(bus->p->devices_kset);
  76. 975bus_devices_fail:
  77. 976    bus_remove_file(bus, &bus_attr_uevent);
  78. 977bus_uevent_fail:
  79. 978    kset_unregister(&bus->p->subsys);
  80. 979out:
  81. 980    kfree(bus->p);
  82. 981    bus->p = NULL;
  83. 982    return retval;
  84. 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文件中,其内容如下:
[cpp] view plain copy
  1. 148static struct kobj_type bus_ktype = {
  2. 149    .sysfs_ops  = &bus_sysfs_ops,
  3. 150};
bus_sysfs_ops定义在drivers/base/bus.c文件中,其内容如下:
[cpp] view plain copy
  1. 122static const struct sysfs_ops bus_sysfs_ops = {
  2. 123    .show   = bus_attr_show,
  3. 124    .store  = bus_attr_store,
  4. 125};
同样是在drivers/base/bus.c文件中,bus_attr_show和bus_attr_store函数定义如下:
[cpp] view plain copy
  1. 95/*
  2. 96 * sysfs bindings for buses
  3. 97 */
  4. 98static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr,
  5. 99                 char *buf)
  6. 100{
  7. 101    struct bus_attribute *bus_attr = to_bus_attr(attr);
  8. 102    struct subsys_private *subsys_priv = to_subsys_private(kobj);
  9. 103    ssize_t ret = 0;
  10. 104
  11. 105    if (bus_attr->show)
  12. 106        ret = bus_attr->show(subsys_priv->bus, buf);
  13. 107    return ret;
  14. 108}
  15. 109
  16. 110static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr,
  17. 111                  const char *buf, size_t count)
  18. 112{
  19. 113    struct bus_attribute *bus_attr = to_bus_attr(attr);
  20. 114    struct subsys_private *subsys_priv = to_subsys_private(kobj);
  21. 115    ssize_t ret = 0;
  22. 116
  23. 117    if (bus_attr->store)
  24. 118        ret = bus_attr->store(subsys_priv->bus, buf, count);
  25. 119    return ret;
  26. 120}
to_bus_attr是一个宏,定义在drivers/base/bus.c文件中,如下:
[cpp] view plain copy
  1. 26#define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
bus_attribute定义在include/linux/device.h文件中,其内容如下:
[cpp] view plain copy
  1. 43struct bus_attribute {
  2. 44    struct attribute    attr;
  3. 45    ssize_t (*show)(struct bus_type *bus, char *buf);
  4. 46    ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
  5. 47};
to_subsys_private定义在drivers/base/base.h文件中,如下:
[cpp] view plain copy
  1. 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文件中,其内容如下:
[cpp] view plain copy
  1. 127int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
  2. 128{
  3. 129    int error;
  4. 130    if (bus_get(bus)) {
  5. 131        error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
  6. 132        bus_put(bus);
  7. 133    } else
  8. 134        error = -EINVAL;
  9. 135    return error;
  10. 136}
bus_attr_uevent定义在drivers/base/bus.c文件中:
[cpp] view plain copy
  1. 898static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
BUS_ATTR定义在include/linux/device.h文件中:
[cpp] view plain copy
  1. 49#define BUS_ATTR(_name, _mode, _show, _store)   \
  2. 50struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)
__ATTR定义在include/linux/sysfs.h文件中:
[cpp] view plain copy
  1. 66/**
  2. 67 * Use these macros to make defining attributes easier. See include/linux/device.h
  3. 68 * for examples..
  4. 69 */
  5. 70
  6. 71#define __ATTR(_name,_mode,_show,_store) { \
  7. 72    .attr = {.name = __stringify(_name), .mode = _mode },   \
  8. 73    .show   = _show,                    \
  9. 74    .store  = _store,                   \
  10. 75}
由bus_attr_uevent的定义可以看出,它没有定义show函数,而是只定义了store函数bus_uevent_store,该函数定义在drivers/base/bus.c文件中,其内容如下:
[cpp] view plain copy
  1. 889static ssize_t bus_uevent_store(struct bus_type *bus,
  2. 890                const char *buf, size_t count)
  3. 891{
  4. 892    enum kobject_action action;
  5. 893
  6. 894    if (kobject_action_type(buf, count, &action) == 0)
  7. 895        kobject_uevent(&bus->p->subsys.kobj, action);
  8. 896    return count;
  9. 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文件中,其内容如下:
[cpp] view plain copy
  1. 873static void klist_devices_get(struct klist_node *n)
  2. 874{
  3. 875    struct device_private *dev_prv = to_device_private_bus(n);
  4. 876    struct device *dev = dev_prv->device;
  5. 877
  6. 878    get_device(dev);
  7. 879}
  8. 880
  9. 881static void klist_devices_put(struct klist_node *n)
  10. 882{
  11. 883    struct device_private *dev_prv = to_device_private_bus(n);
  12. 884    struct device *dev = dev_prv->device;
  13. 885
  14. 886    put_device(dev);
  15. 887}
956行,初始化priv->klist_drivers。
958行,调用add_probe_files函数,该函数定义在drivers/base/bus.c文件中,其内容如下:
[cpp] view plain copy
  1. 641static int add_probe_files(struct bus_type *bus)
  2. 642{
  3. 643    int retval;
  4. 644
  5. 645    retval = bus_create_file(bus, &bus_attr_drivers_probe);
  6. 646    if (retval)
  7. 647        goto out;
  8. 648
  9. 649    retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
  10. 650    if (retval)
  11. 651        bus_remove_file(bus, &bus_attr_drivers_probe);
  12. 652out:
  13. 653    return retval;
  14. 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文件中,如下:
[cpp] view plain copy
  1. 637static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);
  2. 638static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,
  3. 639        show_drivers_autoprobe, store_drivers_autoprobe);
可见bus_attr_drivers_probe只定义了store函数,bus_attr_drivers_autoprobe定义了show和store两个函数,它们都定义在drivers/base/bus.c文件中,如下:
[cpp] view plain copy
  1. 226static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
  2. 227{
  3. 228    return sprintf(buf, "%d\n", bus->p->drivers_autoprobe);
  4. 229}
  5. 230
  6. 231static ssize_t store_drivers_autoprobe(struct bus_type *bus,
  7. 232                       const char *buf, size_t count)
  8. 233{
  9. 234    if (buf[0] == '0')
  10. 235        bus->p->drivers_autoprobe = 0;
  11. 236    else
  12. 237        bus->p->drivers_autoprobe = 1;
  13. 238    return count;
  14. 239}
  15. 240
  16. 241static ssize_t store_drivers_probe(struct bus_type *bus,
  17. 242                   const char *buf, size_t count)
  18. 243{
  19. 244    struct device *dev;
  20. 245
  21. 246    dev = bus_find_device_by_name(bus, NULL, buf);
  22. 247    if (!dev)
  23. 248        return -ENODEV;
  24. 249    if (bus_rescan_devices_helper(dev, NULL) != 0)
  25. 250        return -EINVAL;
  26. 251    return count;
  27. 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文件中,其内容如下:
[cpp] view plain copy
  1. 838/**
  2. 839 * bus_add_attrs - Add default attributes for this bus.
  3. 840 * @bus: Bus that has just been registered.
  4. 841 */
  5. 842
  6. 843static int bus_add_attrs(struct bus_type *bus)
  7. 844{
  8. 845    int error = 0;
  9. 846    int i;
  10. 847
  11. 848    if (bus->bus_attrs) {
  12. 849        for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
  13. 850            error = bus_create_file(bus, &bus->bus_attrs[i]);
  14. 851            if (error)
  15. 852                goto err;
  16. 853        }
  17. 854    }
  18. 855done:
  19. 856    return error;
  20. 857err:
  21. 858    while (--i >= 0)
  22. 859        bus_remove_file(bus, &bus->bus_attrs[i]);
  23. 860    goto done;
  24. 861}
如果指定了bus的默认属性,即bus->bus_attrs不为NULL,则创建对应的属性文件。
至此,bus_register函数我们就分析完了。

Linux设备模型分析之bus(基于3.10.1内核)相关推荐

  1. Linux设备模型分析之kobject(基于3.10.1内核)

    一.kobject结构定义 kobject是Linux设备模型的最底层数据结构,它代表一个内核对象. kobject结构体定义在include/linux/kobject.h文件中: [cpp] vi ...

  2. Linux设备模型分析之kobject

    一.kobject应用举例 Linux设备模型最基本的组成元素是kobject,我们先来看一个kobject的应用例子,该程序在Ubuntu 10.10, 2.6.32-38-generic-pae内 ...

  3. Linux设备模型分析之kset

    上一篇博客我们分析了Linux设备模型中kobject的注册和使用,在这一篇文章中,我们来看一下kset的用法. 首先我们看一个使用kset的例子,代码如下: [cpp] view plaincopy ...

  4. linux kset subsystem 3.10内核,Linux设备模型分析之kset(基于3.10.1内核)

    作者:刘昊昱 内核版本:3.10.1 一.kset结构定义 kset结构体定义在include/linux/kobject.h文件中,其内容如下: 142/** 143 * struct kset - ...

  5. Linux设备模型分析之kset(基于3.10.1内核)

    一.kset结构定义 kset结构体定义在include/linux/kobject.h文件中,其内容如下: [cpp] view plaincopy 142/** 143 * struct kset ...

  6. Linux设备驱动程序架构分析之I2C架构(基于3.10.1内核)

    作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz 内核版本:3.10.1 I2C体系架构的硬件实体包括两部分: 硬件I2C Adapter:硬件I2C Adapter ...

  7. Linux通常把设备对象抽象为,linux 设备模型(1)

    设备模型(一) 一.概述 从2.6内核引入了sysfs文件系统,与proc, devfs, devpty同类别,属于虚拟的文件系统.目的是展示设备驱动模型中各组件的层次关系,第一层目录:block, ...

  8. linux的层次结构模型,linux 设备模型(1)

    设备模型(一) 一.概述 从2.6内核引入了sysfs文件系统,与proc, devfs, devpty同类别,属于虚拟的文件系统.目的是展示设备驱动模型中各组件的层次关系,第一层目录:block, ...

  9. Linux设备模型_导航篇

    Linux设备模型_导航篇 1. Linux设备模型系列文章说明 2. Linux设备模型系列文章目录 2.0 [Linux内核的整体架构](https://zhuanlan.zhihu.com/p/ ...

  10. linux设备模型:bus概念及pci_bus分析

    上一篇<<linux设备模型:kset及设备驱动抽象类(class)分析>>中分析了kset容器.class设备驱动抽象框架.class_kset用于类(class)的热插拔事 ...

最新文章

  1. git revert和git reset的区别
  2. 数据库事务的悲观锁和乐观锁
  3. java 网站转app_java – 将现有Web应用程序转换为桌面应用程序
  4. [羊城杯 2020]RRRRRRRSA
  5. SharePoint Explorer View
  6. 2019年中国教育信息化行业研究报告
  7. hpcc_使用Java将数据流式传输到HPCC
  8. dev控件swiftplot图滚动方法_无限轮播图使用Scroller就这么简单
  9. 同一表单内设置两个或两个以上的提交按钮 Two submit buttons in one form
  10. C# ComboBox自动完成功能的例子
  11. matlab gul介绍及串口通信实现,Matlab - GUl介绍及串口通信实现(转)
  12. 如何在blog中添加背景音乐
  13. python打印输出如下图形_python题目要求:输出如下图片中的图形
  14. ImageView显示灰色图片
  15. excel函数公式html文档,excel公式embed怎么用
  16. echart自定义动画_echarts动画效果
  17. 零基础搭建Win系统Anaconda+Pytorch+OpenCV深度学习环境(Win10、Win11、RTX 3090显卡也适用)
  18. 【龙印】步进电机使用七段式抛物线型S曲线加减速和路径规划的理论分析和实现
  19. HTML5中制作彩色圆环的代码,HTML5 五彩圆环Loading加载动画实现教程
  20. Chrome浏览器中使用 iframe 嵌入网页导致视频不能全屏的问题解决方法

热门文章

  1. Excel2010 count,countif,countifs使用
  2. 微信小程序九宫格抽奖大转盘
  3. python制作字符画(非gif转字符图)
  4. USB转串口电路之CH340G
  5. Silverlight MMORPG WebGame游戏设计(五)-----Client的嫁妆
  6. 固态+机械双硬盘的双系统安装
  7. php设计模式番外篇--超人的诞生
  8. 侯捷C++八部曲笔记(一、面向对象)
  9. TeamViewer和远程桌面冲突的问题
  10. python小练习(杂七杂八)