Linux設備模型分析之bus(基於3.10.1內核)

作者:劉昊昱 

博客:http://blog.csdn.net/liuhaoyutz

內核版本: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函數我們就分析完了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章