1. 程式人生 > >Kernel 裝置驅動模型

Kernel 裝置驅動模型

    Linux為統一管理系統中的裝置和驅動框架,提出了一套裝置驅動模型框架:匯流排(bus),裝置(device)和驅動(driver)。這套框架不僅維護了匯流排,裝置和驅動之間的關聯關係,也提供了一套完整的sysfs驅動模型檢視,同時還實現了裝置的熱插拔機制。裝置驅動模型基於的底層基礎設施kobject/kset/kobj_type(這個基礎設施構成了裝置模型最基本的實現機制)已經作過專門的分析,sysfs模型檢視和熱插拔機制也會專門分析。這篇主要針對匯流排,裝置和驅動的實現(匯流排,裝置和驅動的核心表示),關聯關係(匯流排,裝置和驅動如何註冊)作分析。

    1,基本概念:

        (1)匯流排(bus_type)。匯流排是系統中裝置和驅動的集合,可以是系統中實際硬體匯流排的抽象,也可以是一個虛擬的匯流排。匯流排管理著其下注冊的所有裝置和驅動,並負責裝置和驅動間的匹配關係。當設備註冊到匯流排時,匯流排需要檢查裝置是否已經註冊過,並負責輪尋該總線上的所有驅動,為其找到一個匹配的驅動。當驅動註冊到匯流排時,同樣匯流排需要檢查該驅動是否已經註冊過,並負責輪尋該總線上的所有裝置,為該驅動找到所有匹配的裝置。

        (2)裝置(device)

。裝置可以是系統中實際硬體裝置的抽象,也可以是一個虛擬的裝置。一個裝置通常用來負責維護著該裝置在系統中佔用的資源(如,io埠或io記憶體,中斷請求線,dma資源資訊等),但這個資源的管理通常交給更高層次的封裝(如字元裝置,塊裝置和網路裝置等)去處理,裝置模型僅僅維護其跟匯流排以及驅動之間的關係。

        (3)驅動(device_driver)。驅動是一系列操作的集合,這些操作負責裝置的資源探測和移除,電源管理,開啟和關閉,讀寫操作等。同樣,開啟和關閉,讀寫等業務相關的操作,也是交給更上層的封裝去處理,驅動模型僅僅提供裝置探測和移除,電源管理等基礎介面。當然,驅動還會維護其同匯流排和裝置間的關係。

    2,資料結構:

        (1)匯流排結構 bus_type

struct bus_type {
    const char        *name;    // 匯流排名字
    const char        *dev_name;
    struct device        *dev_root;
    const struct attribute_group **bus_groups;
    const struct attribute_group **dev_groups;
    const struct attribute_group **drv_groups;

    int (*match)(struct device *dev, struct device_driver *drv);    // 匹配操作,用來匹配下掛的裝置和驅動
    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
    int (*probe)(struct device *dev);    // 裝置探測函式,用來分配裝置資源,優先順序高於驅動的probe,但通常使用驅動的probe
    int (*remove)(struct device *dev);    // probe的逆操作,用來釋放probe中分配的裝置資源
    void (*shutdown)(struct device *dev);

    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);

    const struct dev_pm_ops *pm;

    const struct iommu_ops *iommu_ops;

    struct subsys_private *p;    // 匯流排被看做子系統,該欄位維護著匯流排下的裝置和驅動列表
    struct lock_class_key lock_key;

    bool need_parent_lock;
};

struct subsys_private {
    struct kset subsys;    // 子系統本身就是一個kset
    struct kset *devices_kset;    // 該匯流排下掛的裝置列表,由kset關聯
    struct list_head interfaces;
    struct mutex mutex;

    struct kset *drivers_kset;    // 該裝置下掛的驅動列表,由kset關聯
    struct klist klist_devices;
    struct klist klist_drivers;
    struct blocking_notifier_head bus_notifier;    // 匯流排的事件通知列表
    unsigned int drivers_autoprobe:1;
    struct bus_type *bus;    // 關聯的bus_type

    struct kset glue_dirs;
    struct class *class;    // 匯流排類別
};

    從上述資料結構定義可以看出,匯流排主要由兩個結構體表示:一個是 bus_type,用來定義匯流排自身的基本資訊和基本操作,另外一個是 subsys_private,用來定義維護匯流排下裝置和驅動關係的連結串列,由kset維護其sysfs檢視關係。

        (2)驅動結構 device_driver:

struct device_driver {
    const char        *name;    // 驅動名字
    struct bus_type        *bus;    // 該驅動所屬的匯流排

    struct module        *owner;
    const char        *mod_name;    /* used for built-in modules */

    bool suppress_bind_attrs;    /* disables bind/unbind via sysfs */
    enum probe_type probe_type;

    const struct of_device_id    *of_match_table;
    const struct acpi_device_id    *acpi_match_table;

    int (*probe) (struct device *dev);    // 驅動探測函式,用來給裝置分配各種資源
    int (*remove) (struct device *dev);// 驅動移除函式,用來釋放裝置分配的各種資源

    void (*shutdown) (struct device *dev);
    int (*suspend) (struct device *dev, pm_message_t state);
    int (*resume) (struct device *dev);    // 電源管理函式,休眠和喚醒回撥

    const struct attribute_group **groups;

    const struct dev_pm_ops *pm;
    void (*coredump) (struct device *dev);

    struct driver_private *p;    // 驅動私有結構,主要用來管理驅動和匯流排,裝置的關聯關係
};

struct driver_private {
    struct kobject kobj;    // 驅動本身是個kobject
    struct klist klist_devices;    // 該驅動下匹配的裝置連結串列
    struct klist_node knode_bus;    // 掛在bus連結串列的節點
    struct module_kobject *mkobj;
    struct device_driver *driver;    // 所屬的device_driver
};

    驅動的資料組織結構跟匯流排很類似,也是用兩個結構來表示。一個是device_driver,用來定義驅動自身的基本資訊和基本操作。另外一個是 driver_private,用來定義維護驅動和匯流排,裝置關係的連結串列,並有kobject維護其sysfs檢視關係。

    (3)裝置結構 device:

struct device {
    struct device        *parent;    // 該裝置的父裝置。一個裝置可能是樹狀的,一個裝置下面包含多個子裝置。

    struct device_private    *p;    // 裝置的私有資料結構,用來維護裝置和匯流排,驅動的關係

    struct kobject kobj;    // 裝置本身就是一個kobject
    const char        *init_name; /* initial name of the device */
    const struct device_type *type;

    struct mutex        mutex;    /* mutex to synchronize calls to
                     * its driver.
                     */

    struct bus_type    *bus;        /* type of bus device is on */    // 該裝置所屬的匯流排
    struct device_driver *driver;    /* which driver has allocated this
                       device */    // 該裝置關聯的匯流排

    void        *platform_data;    /* Platform specific data, device
                       core doesn't touch it */    // 平臺相關的資料

    void        *driver_data;    /* Driver data, set and get with
                       dev_set/get_drvdata */    // 驅動相關的資料

    struct dev_links_info    links;
    struct dev_pm_info    power;
    struct dev_pm_domain    *pm_domain;

#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
    struct irq_domain    *msi_domain;
#endif
#ifdef CONFIG_PINCTRL
    struct dev_pin_info    *pins;
#endif
#ifdef CONFIG_GENERIC_MSI_IRQ
    struct list_head    msi_list;
#endif

#ifdef CONFIG_NUMA
    int        numa_node;    /* NUMA node this device is close to */
#endif
    const struct dma_map_ops *dma_ops;    // dma操作
    u64        *dma_mask;    /* dma mask (if dma'able device) */
    u64        coherent_dma_mask;/* Like dma_mask, but for
                         alloc_coherent mappings as
                         not all hardware supports
                         64 bit addresses for consistent
                         allocations such descriptors. */
    u64        bus_dma_mask;    /* upstream dma_mask constraint */
    unsigned long    dma_pfn_offset;

    struct device_dma_parameters *dma_parms;

    struct list_head    dma_pools;    /* dma pools (if dma'ble) */

    struct dma_coherent_mem    *dma_mem; /* internal for coherent mem
                         override */
#ifdef CONFIG_DMA_CMA
    struct cma *cma_area;        /* contiguous memory area for dma
                       allocations */
#endif
    /* arch specific additions */
    struct dev_archdata    archdata;

    struct device_node    *of_node; /* associated device tree node */
    struct fwnode_handle    *fwnode; /* firmware device node */

    dev_t            devt;    /* dev_t, creates the sysfs "dev" */
    u32            id;    /* device instance */

    spinlock_t        devres_lock;
    struct list_head    devres_head;

    struct klist_node    knode_class;
    struct class        *class;
    const struct attribute_group **groups;    /* optional groups */

    void    (*release)(struct device *dev);    // 裝置自定義的release操作
    struct iommu_group    *iommu_group;
    struct iommu_fwspec    *iommu_fwspec;

    bool            offline_disabled:1;
    bool            offline:1;
    bool            of_node_reused:1;
};

struct device_private {
    struct klist klist_children;    // 子裝置連結串列
    struct klist_node knode_parent;    // 掛接在父裝置的連結串列節點
    struct klist_node knode_driver;    // 掛接在驅動的連結串列節點
    struct klist_node knode_bus;    // 掛接在匯流排的連結串列節點
    struct list_head deferred_probe;
    struct device *device;    // 所屬的device結構
};

    再次,裝置的資料組織結構跟匯流排和驅動很類似,也是用兩個結構來表示。一個是device,用來定義裝置自身的基本資訊和基本操作。另外一個是 device_private,用來定義維護裝置和匯流排,驅動關係的連結串列。其維護sysfs檢視關係的kobject定義在device結構中。

    3,匯流排註冊:

        系統啟動過程中,根據平臺的不同,會註冊很多匯流排,如I2C,I2S,PCI或者虛擬的platform匯流排等。這些匯流排的註冊都是通過介面 bus_register 註冊的。下面看看 bus_register 介面:

int bus_register(struct bus_type *bus)
{
    int retval;
    struct subsys_private *priv;
    struct lock_class_key *key = &bus->lock_key;

    priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);    // 首先分配 bus_type 結構
    if (!priv)
        return -ENOMEM;

    priv->bus = bus;
    bus->p = priv;    // 設定相互引用關係

    BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);

    retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);    // 設定匯流排名字
    if (retval)
        goto out;

    priv->subsys.kobj.kset = bus_kset;    // 設定 kset 關係,使其掛接在 /sys/bus/下
    priv->subsys.kobj.ktype = &bus_ktype;    // 設定匯流排的sysfs操作
    priv->drivers_autoprobe = 1;

    retval = kset_register(&priv->subsys);    // 註冊匯流排kset結構
    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,
                         &priv->subsys.kobj);    // 建立匯流排下裝置連結串列的kset,並註冊該kset

    if (!priv->devices_kset) {
        retval = -ENOMEM;
        goto bus_devices_fail;
    }

    priv->drivers_kset = kset_create_and_add("drivers", NULL,
                         &priv->subsys.kobj);    // 建立匯流排下驅動連結串列的kset,並註冊該kset

    if (!priv->drivers_kset) {
        retval = -ENOMEM;
        goto bus_drivers_fail;
    }

    INIT_LIST_HEAD(&priv->interfaces);
    __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);    // 匯流排sysfs檔案建立
    if (retval)
        goto bus_probe_files_fail;

    retval = bus_add_groups(bus, bus->bus_groups);    // 匯流排sysfs組建立
    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(bus->p->drivers_kset);
bus_drivers_fail:
    kset_unregister(bus->p->devices_kset);
bus_devices_fail:
    bus_remove_file(bus, &bus_attr_uevent);
bus_uevent_fail:
    kset_unregister(&bus->p->subsys);
out:
    kfree(bus->p);
    bus->p = NULL;
    return retval;
}
EXPORT_SYMBOL_GPL(bus_register);

    匯流排的註冊,就是建立一個 subsys_private 結構,初始化 bus_type結構,並將 subsys_private註冊進sysfs檔案系統。

    4,設備註冊:

        設備註冊到匯流排後,還要做些額外的工作。需要查詢並匹配匯流排下的驅動,並利用匹配的驅動程式來初始化裝置資源。匹配介面是bus下的match()介面,初始化裝置資源是driver的probe()介面。

int device_register(struct device *dev)
{
    device_initialize(dev);
    return device_add(dev);
}

void device_initialize(struct device *dev)
{
    dev->kobj.kset = devices_kset;
    kobject_init(&dev->kobj, &device_ktype);
    INIT_LIST_HEAD(&dev->dma_pools);
    mutex_init(&dev->mutex);
    lockdep_set_novalidate_class(&dev->mutex);
    spin_lock_init(&dev->devres_lock);
    INIT_LIST_HEAD(&dev->devres_head);
    device_pm_init(dev);
    set_dev_node(dev, -1);
#ifdef CONFIG_GENERIC_MSI_IRQ
    INIT_LIST_HEAD(&dev->msi_list);
#endif
    INIT_LIST_HEAD(&dev->links.consumers);
    INIT_LIST_HEAD(&dev->links.suppliers);
    dev->links.status = DL_DEV_NO_DRIVER;
}

int device_add(struct device *dev)
{
    struct device *parent;
    struct kobject *kobj;
    struct class_interface *class_intf;
    int error = -EINVAL;
    struct kobject *glue_dir = NULL;

    dev = get_device(dev);
    if (!dev)
        goto done;

    if (!dev->p) {
        error = device_private_init(dev);    // 分配device_private結構
        if (error)
            goto done;
    }

    /*
     * for statically allocated devices, which should all be converted
     * some day, we need to initialize the name. We prevent reading back
     * the name, and force the use of dev_name()
     */
    if (dev->init_name) {
        dev_set_name(dev, "%s", dev->init_name);
        dev->init_name = NULL;
    }

    /* subsystems can specify simple device enumeration */
    if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
        dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);

    if (!dev_name(dev)) {
        error = -EINVAL;
        goto name_error;
    }

    pr_debug("device: '%s': %s\n", dev_name(dev), __func__);

    parent = get_device(dev->parent);
    kobj = get_device_parent(dev, parent);
    if (IS_ERR(kobj)) {
        error = PTR_ERR(kobj);
        goto parent_error;
    }
    if (kobj)
        dev->kobj.parent = kobj;

    /* use parent numa_node */
    if (parent && (dev_to_node(dev) == NUMA_NO_NODE))
        set_dev_node(dev, dev_to_node(parent));

    /* first, register with generic layer. */
    /* we require the name to be set before, and pass NULL */
    error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);    // 將device加入bus的kset中
    if (error) {
        glue_dir = get_glue_dir(dev);
        goto Error;
    }

    /* notify platform of device entry */
    if (platform_notify)
        platform_notify(dev);

    error = device_create_file(dev, &dev_attr_uevent);
    if (error)
        goto attrError;

    error = device_add_class_symlinks(dev);
    if (error)
        goto SymlinkError;
    error = device_add_attrs(dev);
    if (error)
        goto AttrsError;
    error = bus_add_device(dev);    // 將device加入bus連結串列
    if (error)
        goto BusError;
    error = dpm_sysfs_add(dev);
    if (error)
        goto DPMError;
    device_pm_add(dev);

    if (MAJOR(dev->devt)) {
        error = device_create_file(dev, &dev_attr_dev);
        if (error)
            goto DevAttrError;

        error = device_create_sys_dev_entry(dev);
        if (error)
            goto SysEntryError;

        devtmpfs_create_node(dev);
    }

    /* Notify clients of device addition.  This call must come
     * after dpm_sysfs_add() and before kobject_uevent().
     */
    if (dev->bus)
        blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                         BUS_NOTIFY_ADD_DEVICE, dev);

    kobject_uevent(&dev->kobj, KOBJ_ADD);
    bus_probe_device(dev);    // 探測裝置驅動,加入裝置連結串列
    if (parent)
        klist_add_tail(&dev->p->knode_parent,
                   &parent->p->klist_children);

    if (dev->class) {
        mutex_lock(&dev->class->p->mutex);
        /* tie the class to the device */
        klist_add_tail(&dev->knode_class,
                   &dev->class->p->klist_devices);

        /* notify any interfaces that the device is here */
        list_for_each_entry(class_intf,
                    &dev->class->p->interfaces, node)
            if (class_intf->add_dev)
                class_intf->add_dev(dev, class_intf);
        mutex_unlock(&dev->class->p->mutex);
    }
done:
    put_device(dev);
    return error;
 SysEntryError:
    if (MAJOR(dev->devt))
        device_remove_file(dev, &dev_attr_dev);
 DevAttrError:
    device_pm_remove(dev);
    dpm_sysfs_remove(dev);
 DPMError:
    bus_remove_device(dev);
 BusError:
    device_remove_attrs(dev);
 AttrsError:
    device_remove_class_symlinks(dev);
 SymlinkError:
    device_remove_file(dev, &dev_attr_uevent);
 attrError:
    kobject_uevent(&dev->kobj, KOBJ_REMOVE);
    glue_dir = get_glue_dir(dev);
    kobject_del(&dev->kobj);
 Error:
    cleanup_glue_dir(dev, glue_dir);
parent_error:
    put_device(parent);
name_error:
    kfree(dev->p);
    dev->p = NULL;
    goto done;
}

int bus_add_device(struct device *dev)
{
    struct bus_type *bus = bus_get(dev->bus);
    int error = 0;

    if (bus) {
        pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));
        error = device_add_groups(dev, bus->dev_groups);
        if (error)
            goto out_put;
        error = sysfs_create_link(&bus->p->devices_kset->kobj,
                        &dev->kobj, dev_name(dev));
        if (error)
            goto out_groups;
        error = sysfs_create_link(&dev->kobj,
                &dev->bus->p->subsys.kobj, "subsystem");
        if (error)
            goto out_subsys;
        klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);    // 將device加入bus 的klist_devices連結串列
    }
    return 0;

out_subsys:
    sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
out_groups:
    device_remove_groups(dev, bus->dev_groups);
out_put:
    bus_put(dev->bus);
    return error;
}

void bus_probe_device(struct device *dev)
{
    struct bus_type *bus = dev->bus;
    struct subsys_interface *sif;

    if (!bus)
        return;

    if (bus->p->drivers_autoprobe)
        device_initial_probe(dev);   

    mutex_lock(&bus->p->mutex);
    list_for_each_entry(sif, &bus->p->interfaces, node)
        if (sif->add_dev)
            sif->add_dev(dev, sif);
    mutex_unlock(&bus->p->mutex);
}

void device_initial_probe(struct device *dev)
{
    __device_attach(dev, true);
}

// 執行真正的裝置探測

static int __device_attach(struct device *dev, bool allow_async)
{
    int ret = 0;

    device_lock(dev);
    if (dev->driver) {    // 如果驅動已經存在
        if (device_is_bound(dev)) {    // 裝置已經綁定了驅動,直接返回
            ret = 1;
            goto out_unlock;
        }
        ret = device_bind_driver(dev);    // 裝置繫結驅動
        if (ret == 0)
            ret = 1;
        else {
            dev->driver = NULL;
            ret = 0;
        }
    } else {    // 裝置還未關聯驅動
        struct device_attach_data data = {
            .dev = dev,
            .check_async = allow_async,
            .want_async = false,
        };

        if (dev->parent)
            pm_runtime_get_sync(dev->parent);

        ret = bus_for_each_drv(dev->bus, NULL, &data,
                    __device_attach_driver);    // 輪循總線上的驅動,依次執行__device_attach_driver進行匹配

        if (!ret && allow_async && data.have_async) {
            /*
             * If we could not find appropriate driver
             * synchronously and we are allowed to do
             * async probes and there are drivers that
             * want to probe asynchronously, we'll
             * try them.
             */
            dev_dbg(dev, "scheduling asynchronous probe\n");
            get_device(dev);
            async_schedule(__device_attach_async_helper, dev);
        } else {
            pm_request_idle(dev);
        }

        if (dev->parent)
            pm_runtime_put(dev->parent);
    }
out_unlock:
    device_unlock(dev);
    return ret;
}

static int __device_attach_driver(struct device_driver *drv, void *_data)
{
    struct device_attach_data *data = _data;
    struct device *dev = data->dev;
    bool async_allowed;
    int ret;

    /*
     * Check if device has already been claimed. This may
     * happen with driver loading, device discovery/registration,
     * and deferred probe processing happens all at once with
     * multiple threads.
     */
    if (dev->driver)
        return -EBUSY;

    ret = driver_match_device(drv, dev);    // 呼叫匯流排的match()方法,判斷device跟driver是否匹配
    if (ret == 0) {
        /* no match */
        return 0;
    } else if (ret == -EPROBE_DEFER) {
        dev_dbg(dev, "Device match requests probe deferral\n");
        driver_deferred_probe_add(dev);
    } else if (ret < 0) {
        dev_dbg(dev, "Bus failed to match device: %d", ret);
        return ret;
    } /* ret > 0 means positive match */

    async_allowed = driver_allows_async_probing(drv);

    if (async_allowed)
        data->have_async = true;

    if (data->check_async && async_allowed != data->want_async)
        return 0;

    return driver_probe_device(drv, dev);    // 執行驅動的probe()函式,分配裝置資源
}

static inline int driver_match_device(struct device_driver *drv,
                      struct device *dev)
{
    return drv->bus->match ? drv->bus->match(dev, drv) : 1;    // 呼叫bus的match()函式
}

int driver_probe_device(struct device_driver *drv, struct device *dev)
{
    int ret = 0;

    if (!device_is_registered(dev))
        return -ENODEV;

    pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
         drv->bus->name, __func__, dev_name(dev), drv->name);

    pm_runtime_get_suppliers(dev);
    if (dev->parent)
        pm_runtime_get_sync(dev->parent);

    pm_runtime_barrier(dev);
    if (initcall_debug)
        ret = really_probe_debug(dev, drv);
    else
        ret = really_probe(dev, drv);    // 執行driver的probe()函式
    pm_request_idle(dev);

    if (dev->parent)
        pm_runtime_put(dev->parent);

    pm_runtime_put_suppliers(dev);
    return ret;
}

static int really_probe(struct device *dev, struct device_driver *drv)
{
    int ret = -EPROBE_DEFER;
    int local_trigger_count = atomic_read(&deferred_trigger_count);
    bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) &&
               !drv->suppress_bind_attrs;

    if (defer_all_probes) {
        /*
         * Value of defer_all_probes can be set only by
         * device_defer_all_probes_enable() which, in turn, will call
         * wait_for_device_probe() right after that to avoid any races.
         */
        dev_dbg(dev, "Driver %s force probe deferral\n", drv->name);
        driver_deferred_probe_add(dev);
        return ret;
    }

    ret = device_links_check_suppliers(dev);
    if (ret == -EPROBE_DEFER)
        driver_deferred_probe_add_trigger(dev, local_trigger_count);
    if (ret)
        return ret;

    atomic_inc(&probe_count);
    pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
         drv->bus->name, __func__, drv->name, dev_name(dev));
    WARN_ON(!list_empty(&dev->devres_head));

re_probe:
    dev->driver = drv;

    /* If using pinctrl, bind pins now before probing */
    ret = pinctrl_bind_pins(dev);
    if (ret)
        goto pinctrl_bind_failed;

    ret = dma_configure(dev);
    if (ret)
        goto dma_failed;

    if (driver_sysfs_add(dev)) {
        printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
            __func__, dev_name(dev));
        goto probe_failed;
    }

    if (dev->pm_domain && dev->pm_domain->activate) {
        ret = dev->pm_domain->activate(dev);
        if (ret)
            goto probe_failed;
    }

    if (dev->bus->probe) {
        ret = dev->bus->probe(dev);    // 優先執行bus的probe()函式

        if (ret)
            goto probe_failed;
    } else if (drv->probe) {
        ret = drv->probe(dev);    // 其次執行 driver的probe()函式

        if (ret)
            goto probe_failed;
    }

    if (test_remove) {
        test_remove = false;

        if (dev->bus->remove)
            dev->bus->remove(dev);
        else if (drv->remove)
            drv->remove(dev);

        devres_release_all(dev);
        driver_sysfs_remove(dev);
        dev->driver = NULL;
        dev_set_drvdata(dev, NULL);
        if (dev->pm_domain && dev->pm_domain->dismiss)
            dev->pm_domain->dismiss(dev);
        pm_runtime_reinit(dev);

        goto re_probe;
    }

    pinctrl_init_done(dev);

    if (dev->pm_domain && dev->pm_domain->sync)
        dev->pm_domain->sync(dev);

    driver_bound(dev);
    ret = 1;
    pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
         drv->bus->name, __func__, dev_name(dev), drv->name);
    goto done;

probe_failed:
    dma_deconfigure(dev);
dma_failed:
    if (dev->bus)
        blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                         BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
pinctrl_bind_failed:
    device_links_no_driver(dev);
    devres_release_all(dev);
    driver_sysfs_remove(dev);
    dev->driver = NULL;
    dev_set_drvdata(dev, NULL);
    if (dev->pm_domain && dev->pm_domain->dismiss)
        dev->pm_domain->dismiss(dev);
    pm_runtime_reinit(dev);
    dev_pm_set_driver_flags(dev, 0);

    switch (ret) {
    case -EPROBE_DEFER:
        /* Driver requested deferred probing */
        dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name);
        driver_deferred_probe_add_trigger(dev, local_trigger_count);
        break;
    case -ENODEV:
    case -ENXIO:
        pr_debug("%s: probe of %s rejects match %d\n",
             drv->name, dev_name(dev), ret);
        break;
    default:
        /* driver matched but the probe failed */
        printk(KERN_WARNING
               "%s: probe of %s failed with error %d\n",
               drv->name, dev_name(dev), ret);
    }
    /*
     * Ignore errors returned by ->probe so that the next driver can try
     * its luck.
     */
    ret = 0;
done:
    atomic_dec(&probe_count);
    wake_up(&probe_waitqueue);
    return ret;
}

    5,驅動註冊

    驅動註冊到匯流排後,還要做些額外的工作。需要查詢並匹配匯流排下的裝置,並呼叫驅動程式來初始化裝置資源。匹配介面是bus下的match()介面,初始化裝置資源是bus或者driver的probe()介面。

int driver_register(struct device_driver *drv)
{
    int ret;
    struct device_driver *other;

    if (!drv->bus->p) {
        pr_err("Driver '%s' was unable to register with bus_type '%s' because the bus was not initialized.\n",
               drv->name, drv->bus->name);
        return -EINVAL;
    }

    if ((drv->bus->probe && drv->probe) ||
        (drv->bus->remove && drv->remove) ||
        (drv->bus->shutdown && drv->shutdown))
        printk(KERN_WARNING "Driver '%s' needs updating - please use "
            "bus_type methods\n", drv->name);

    other = driver_find(drv->name, drv->bus);    // 查詢驅動是否已經註冊了,如果註冊過了,返回-EBUSY
    if (other) {
        printk(KERN_ERR "Error: Driver '%s' is already registered, "
            "aborting...\n", drv->name);
        return -EBUSY;
    }

    ret = bus_add_driver(drv);    // 將驅動加入匯流排
    if (ret)
        return ret;
    ret = driver_add_groups(drv, drv->groups);
    if (ret) {
        bus_remove_driver(drv);
        return ret;
    }
    kobject_uevent(&drv->p->kobj, KOBJ_ADD);

    return ret;
}

int bus_add_driver(struct device_driver *drv)
{
    struct bus_type *bus;
    struct driver_private *priv;
    int error = 0;

    bus = bus_get(drv->bus);
    if (!bus)
        return -EINVAL;

    pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

    priv = kzalloc(sizeof(*priv), GFP_KERNEL);    // 分配device_driver的driver_private結構
    if (!priv) {
        error = -ENOMEM;
        goto out_put_bus;
    }
    klist_init(&priv->klist_devices, NULL, NULL);
    priv->driver = drv;
    drv->p = priv;
    priv->kobj.kset = bus->p->drivers_kset;    // 初始化

    error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
                     "%s", drv->name);

    if (error)
        goto out_unregister;

    klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);    // 將driver加入bus的驅動連結串列中
    if (drv->bus->p->drivers_autoprobe) {
        if (driver_allows_async_probing(drv)) {
            pr_debug("bus: '%s': probing driver %s asynchronously\n",
                drv->bus->name, drv->name);
            async_schedule(driver_attach_async, drv);
        } else {
            error = driver_attach(drv);    // 輪循bus下的所有裝置,依次執行match()和probe()
            if (error)
                goto out_unregister;
        }
    }
    module_add_driver(drv->owner, drv);

    error = driver_create_file(drv, &driver_attr_uevent);
    if (error) {
        printk(KERN_ERR "%s: uevent attr (%s) failed\n",
            __func__, drv->name);
    }
    error = driver_add_groups(drv, bus->drv_groups);
    if (error) {
        /* How the hell do we get out of this pickle? Give up */
        printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
            __func__, drv->name);
    }

    if (!drv->suppress_bind_attrs) {
        error = add_bind_files(drv);
        if (error) {
            /* Ditto */
            printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
                __func__, drv->name);
        }
    }

    return 0;

out_unregister:
    kobject_put(&priv->kobj);
    /* drv->p is freed in driver_release()  */
    drv->p = NULL;
out_put_bus:
    bus_put(bus);
    return error;
}

int driver_attach(struct device_driver *drv)
{
    return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);    // 執行 __driver_attach()
}

static int __driver_attach(struct device *dev, void *data)
{
    struct device_driver *drv = data;
    int ret;

    /*
     * Lock device and try to bind to it. We drop the error
     * here and always return 0, because we need to keep trying
     * to bind to devices and some drivers will return an error
     * simply if it didn't support the device.
     *
     * driver_probe_device() will spit a warning if there
     * is an error.
     */

    ret = driver_match_device(drv, dev);    // 先進行match()方法,匹配裝置
    if (ret == 0) {
        /* no match */
        return 0;
    } else if (ret == -EPROBE_DEFER) {
        dev_dbg(dev, "Device match requests probe deferral\n");
        driver_deferred_probe_add(dev);
    } else if (ret < 0) {
        dev_dbg(dev, "Bus failed to match device: %d", ret);
        return ret;
    } /* ret > 0 means positive match */

    if (dev->parent && dev->bus->need_parent_lock)
        device_lock(dev->parent);
    device_lock(dev);
    if (!dev->driver)
        driver_probe_device(drv, dev);    // 再呼叫bus/driver的probe()方法進行資源分配
    device_unlock(dev);
    if (dev->parent && dev->bus->need_parent_lock)
        device_unlock(dev->parent);

    return 0;
}

    後續driver_match_device() 和 driver_probe_device() 的過程和device_register中一樣