linux设备驱动模型

来源:互联网 发布:不出于户 以知天下 编辑:程序博客网 时间:2024/05/01 18:48

在linux驱动模型中,为了便于管理各种设备,我们把不同设备分别挂在他们对应的总线上,设备对应的驱动程序也在总线上找,这样就提出了deivce-bus-driver的模型,硬件上有许多设备总线,那么我们就在设备模型上抽象出bus概念,相应的device就代表设备,driver表示驱动,在代码中它们对应的结构体下面介绍,对于实际的设备及总线,这些结构体就可以嵌入到实际总线上。

1. bus

了解bus,就要先介绍下bus的结构体,一条总线定义完后要注册到系统中,第二节介绍注册函数,最后再介绍下其他一些相关API

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

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': registered\n", bus->name);    return 0;。。。。。。}

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': %s\n", 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 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;}

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 methods\n", 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 %s\n", 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 asynchronously\n",                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) 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;。。。。。。。。}

那么驱动是如何匹配到对应的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 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)    /* 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);
0 0
原创粉丝点击