当前位置:必发365电子游戏 > 操作系统 > 任何设备都可以选择合适的总线连接到主机,在介绍注册函数
任何设备都可以选择合适的总线连接到主机,在介绍注册函数
2019-12-19

linux下bus,device,driver三者关系

                            

linux设备驱动模型 - device/bus/driver,linuxbus

在linux驱动模型中,为了便于管理各样设备,大家把差别道具分别挂在她们相应的总线上,设备对应的驱动程序也在总线上找,那样就提出了deivce-bus-driver的模型,硬件上有好些个配备总线,那么大家就在器材模型上抽象出bus概念,相应的device就象征设备,driver表示驱动,在代码中它们对应的布局体上边介绍,对于实际的配备及总线,那几个构造体就足以松手到实在总线上。

  1.bus:

  总线作为主机和外设的连年通道,某些总线是比较专门的学问的,变成了不胜枚举研商。如 PCI,USB,1394,IIC等。任何设施都能够挑选至极的总线连接到主机。当然主机也许有可能正是CPU本人。内存也是因此BUS连接到主机的,可内存使用的总线不是外设总线,因而和内存使用同意气风发类其他总线的道具,谈及BUS相比草率。

  一块网卡在嵌入式开采中,直接通过内部存款和储蓄器总线接入到CPU。大家在写网卡驱动时,要给该BUS定义就劳动了。

1. bus

问询bus,就要先介绍下bus的布局体,一条总线定义完后要登记到系统中,第2节介绍注册函数,最终再介绍下任何部分相关API

  2.driver:

  驱动程序是在CPU运维时,提供操作的软件接口。全体的设施必需有与之配套驱动程序本事健康办事。三个驱动程序能够使得多个近乎可能完全两样的配备。

1.1 struct bus_type

struct bus_type {
    const char      *name;--------------------------------------------总线名字
    const char      *dev_name;
    struct device       *dev_root;
    struct device_attribute *dev_attrs; /* use dev_groups instead */
    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);-------匹配函数(用于匹配device&driver)
    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
    int (*probe)(struct device *dev);----------------------------------用于初始化驱动
    int (*remove)(struct device *dev);
    void (*shutdown)(struct device *dev);

    int (*online)(struct device *dev);
    int (*offline)(struct device *dev);

    int (*suspend)(struct device *dev, pm_message_t state);-----------PM相关
    int (*resume)(struct device *dev);--------------------------------PM相关

    const struct dev_pm_ops *pm;--------------------------------------PM相关

    const struct iommu_ops *iommu_ops;

    struct subsys_private *p;
    struct lock_class_key lock_key;
};

  3.device:

  设备便是连接在总线上的物理实体。设备是有意义之分的。具备相像效果的设施被归到一个类(CLASS中卡塔尔(英语:State of Qatar)。如音频设备(和音响相关的都算卡塔尔(قطر‎,输入设备(鼠标,键盘,游戏杆等卡塔尔(قطر‎。。。。

  从微观考虑,任何设施一定要连接到主机技术宣布其坚守。三个鼠标离开了Computer主机就 不再是鼠标了。提到了连接就必然现身总线BUS。任何设施要正规运作必需有软件扶助,全部的装置必需有DENCOREIVE奥德赛。设备的指标正是水到渠成功用,依照效果与利益的 分类,该装置必然归于有个别CLASS。

  1.三者的概念在 include/linux/device.h里。

  2.总线中的这两条链表是怎么产生:

  那必要每一趟现身二个装置就要向总线陈诉,可能说注册,每回现身一个使得,也要向总 线陈诉,只怕说注册。例如系统开头化的时候,会扫描连接了哪些设备,并为每二个装置创立起三个struct device的变量,每贰遍有二个驱动程序,将要思虑三个struct device_driver布局的变量。把那一个变量统统加入相应的链表,device 插入devices 链表,driver插入drivers链表。那样经过总线就会找到每八个配备,每贰个驱动.但是,假诺Computer里独有设备却绝非对应的驱动,那么设备不能专业。反过来,即使唯有驱动却不曾配备,驱动也起绵绵任何意义。

  3.总线上的两条链表已经有了,链表里的device和driver又是怎样联系

  每一个要用的device在Computer运转以前就已经插好了,插放在它应当在的职位上,然后Computer运转,然后操作系统开头伊始化,总线以前扫描设备,每找到一个装置,就为其报名三个struct device构造,并且挂入总线中的devices链表中来;

  然后每五个驱动程序先河开头化,起头注册其struct device_driver构造,然后它去总线的devices链表中去追寻(遍历卡塔尔,去研究每二个尚未曾绑定driver的设备,即struct device中的struct device_driver指针仍然为空的配备,然后它会去考查这种设施的天性,看是还是不是是他所扶助的设备,假使是,那么调用三个叫作 device_bind_driver的函数。换句话说,把struct device中的struct device_driver driver指向那么些driver,而struct device_driver driver把struct device插足他的那张struct klist klist_devices链表中来。就那样,bus、device和driver,那三者之间大概说他们中的两两中间,就给关系上了

1.2 注册总线

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);
    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;
    priv->subsys.kobj.ktype = &bus_ktype;
    priv->drivers_autoprobe = 1;

    retval = kset_register(&priv->subsys);--------------------在/sys/bus目录下创建当前总线目录
    if (retval)
        goto out;

    retval = bus_create_file(bus, &bus_attr_uevent);----------在当前总线目录下创建文件uevent
    if (retval)
        goto bus_uevent_fail;

    priv->devices_kset = kset_create_and_add("devices", NULL,
                         &priv->subsys.kobj);-----------------在当前总线目录下创建devices目录
    if (!priv->devices_kset) {
        retval = -ENOMEM;
        goto bus_devices_fail;
    }

    priv->drivers_kset = kset_create_and_add("drivers", NULL,
                         &priv->subsys.kobj);----------------在当前总线目录下创建drivers目录
    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);-------------------------在当前总线目录下创建probe相关文件
    if (retval)
        goto bus_probe_files_fail;

    retval = bus_add_groups(bus, bus->bus_groups);
    if (retval)
        goto bus_groups_fail;

    pr_debug("bus: '%s': registeredn", bus->name);
    return 0;

。。。。。。
}

  4.热插拔:

  device可以在微管理机运维之后在插入也许拔出计算机了。由此,很难再说是先有 device还是先有driver了。因为都有望。device可以在任何时刻现身,而driver 也得以在任何时刻被加载,所以,现身的景况就是,每当三个struct device诞生,它就能够去bus的drivers链表中找找自个儿的另四分之二,反之,每当叁个叁个struct device_driver诞生,它就去bus的devices链表中检索它的那多个设备。假诺找到了适当的,那么ok,和事情发生以前这种景况一下,调用 device_bind_driver绑定好.

1.3 其他API

总线卸载函数

extern void bus_unregister(struct bus_type *bus);

2. device

先介绍devices布局体,在介绍注册函数

2.1 struct 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;---------------------所属的device类型

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

    struct bus_type *bus;       /* type of bus device is on */---所属的bus
    struct device_driver *driver;   /* which driver has allocated this
                       device */---------------------------------对应的驱动driver
    void        *platform_data; /* Platform specific data, device
                       core doesn't touch it */------------------私有platform数据
    void        *driver_data;   /* Driver data, set and get with
                       dev_set/get_drvdata */--------------------私有driver数据
    struct dev_pm_info  power;-----------------------------------PM相关
    struct dev_pm_domain    *pm_domain;--------------------------PM相关

#ifdef CONFIG_PINCTRL
    struct dev_pin_info *pins;
#endif

#ifdef CONFIG_NUMA
    int     numa_node;  /* NUMA node this device is close to */
#endif
    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. */
    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;-----------------------------------devres相关

    struct klist_node   knode_class;
    struct class        *class;----------------------------------------所属的class
    const struct attribute_group **groups;  /* optional groups */

    void    (*release)(struct device *dev);
    struct iommu_group  *iommu_group;

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

2.2 设备注册函数

device的注册函数device_register分两步,先最初化device_initialize,重假设早先化所属的kset为/sys/devices目录,及别的(如PM相关),然后再登记,函数为device_add

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

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

    if (!dev->p) {
        error = device_private_init(dev);
        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);------------------有初始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);---没有初始name就设置默认的

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

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

    parent = get_device(dev->parent);
    kobj = get_device_parent(dev, parent);
    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);---在/sys/devices目录下创建当前设备目录
    if (error)
        goto Error;

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

    error = device_create_file(dev, &dev_attr_uevent);--------在当前设备目录下创建文件uevent
    if (error)
        goto attrError;

    error = device_add_class_symlinks(dev);-------------------创建链接文件
    if (error)
        goto SymlinkError;
    error = device_add_attrs(dev);----------------------------创建其他文件,如在class目录下
    if (error)
        goto AttrsError;
    error = bus_add_device(dev);------------------------------device加入到bus-device的链表中
    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);--------__device_attach-------调用此函数来和driver进行匹配
    if (parent)-----------------------------------------加入到父设备链表中
        klist_add_tail(&dev->p->knode_parent,
                   &parent->p->klist_children);

    if (dev->class) {-----------------------------------和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);
    }
。。。。。。
}

切实device怎么样相称到对应的driver在函数__device_attach中举办,参与开首device未有driver,那么会在bus中找到呼应的driver,看下函数__任何设备都可以选择合适的总线连接到主机,在介绍注册函数。device_attach

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);---------如果已经有driver,那么就绑定到device并进行probe
        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);----如果没有driver,就遍历总线上的driver,直到找到并进行probe
        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 proben");
            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;
}

2.3 其他API

device卸载函数

extern void device_unregister(struct device *dev);

3. driver

先介绍driver的结构体,再介绍注册函数

3.1 struct device_driver

struct device_driver {
    const char      *name;-----------------------------driver名字
    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);---PM相关
    int (*resume) (struct device *dev);------------------------PM相关
    const struct attribute_group **groups;

    const struct dev_pm_ops *pm;-------------------------------PM相关

    struct driver_private *p;
};

3.2 注册函数

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

    BUG_ON(!drv->bus->p);

    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 methodsn", drv->name);

    other = driver_find(drv->name, drv->bus);
    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;
}

看下函数bus_add_driver

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 %sn", bus->name, drv->name);

    priv = kzalloc(sizeof(*priv), GFP_KERNEL);
    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;-------设置所属总线的drivers
    error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
                     "%s", drv->name);------------在所属总线的drivers目录下创建本驱动目录
    if (error)
        goto out_unregister;

    klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);---把本驱动加入到总线驱动链表中
    if (drv->bus->p->drivers_autoprobe) {
        if (driver_allows_async_probing(drv)) {
            pr_debug("bus: '%s': probing driver %s asynchronouslyn",
                drv->bus->name, drv->name);
            async_schedule(driver_attach_async, drv);
        } else {
            error = driver_attach(drv);
            if (error)
                goto out_unregister;
        }
    }------------------__driver_attach--------------调用此函数来进行探测初始化
    module_add_driver(drv->owner, drv);

    error = driver_create_file(drv, &driver_attr_uevent);
    if (error) {
        printk(KERN_ERR "%s: uevent attr (%s) failedn",
            __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) failedn",
            __func__, drv->name);
    }

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

    return 0;
。。。。。。。。
}

那就是说驱动是什么同盟到相应的device的,继续研讨函数__driver_attach

(drivers/base/dd.c)

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 deferraln");
        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)    /* Needed for USB */
        device_lock(dev->parent);
    device_lock(dev);
    if (!dev->driver)
        driver_probe_device(drv, dev);------没有driver就设置此driver为device的driver,然后调用驱动probe初始化
    device_unlock(dev);
    if (dev->parent)
        device_unlock(dev->parent);

    return 0;
}

3.3 其他API

卸载函数

extern void driver_unregister(struct device_driver *drv);

- device/bus/driver,linuxbus 在linux驱动模型中,为了便于管理各种设备,大家把差别道具分别挂在他们相应的总线上,设备对...