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

2019-04-15 18:39发布

在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 ", 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 ", 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 "); 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 ", drv->name); other = driver_find(drv->name, drv->bus); if (other) { printk(KERN_ERR "Error: Driver '%s' is already registered, " "aborting... ", 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 ", 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 ", 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 ", __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 ", __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 ", __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 "); 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);