Linux存储IO栈(3)-- 设备驱动模型
来源:互联网 发布:上海网络教研 编辑:程序博客网 时间:2024/06/05 11:10
概述
Linux的设备驱动模型能够带来以下的优点:
* 使用统一机制来表达设备与驱动之间的关系,规范设备驱动的编写,核心代码复用。
* 将系统中的设备以树结构组织,并且通过sysfs将其呈现在用户空间——包括所有的总线和内部连接。
* 支持设备的热拔插机制。
* 支持通用的电源管理机制,通过由叶子节点到根节点的方向遍历设备树,确保子设备在父设备之前断电。
内核基于内核对象和sysfs,通过抽象以下五种概念,实现了设备驱动模型的框架,使得编写子系统成为“八股文”。
1. bus_type: 总线类型,每个子系统有且只有一个总线类型,由bus_type和subsys_private两个结构共同描述。
2. device: 设备,描述挂在总线类型中的设备,由device和device_private两个结构共同描述。
3. driver: 驱动, 描述挂在总线类型中的驱动模块,由device_driver和driver_private两个结构共同描述。
4. class: 类,每个总线类型有且只有一个类,由class和subsys_private两个结构共同描述。
5. class_interface: 接口,每个类有多个接口,由class_interface结构描述。
在Linux内核中,子系统是由bus_type, device, driver, class和class_interface之间的关系所描述,而设备驱动模型正是这些关系的核心实现,使得在编写子系统程序时,只要遵循设备模型的套路,便不需要关注于这些复杂的关系,只需实现自身的业务逻辑。
每个子系统都有一个总线类型,总线类型拥有一个设备链表和一个驱动链表,用于连接由该总线类型已发现的设备和已加载的驱动,设备发现和驱动加载的顺序是任意的。每个设备最多绑定到一个驱动,被绑定了驱动的设备可以正常工作。除此之外,每个设备可以唯一属于某个类,类中包含多个接口,接口的方法作用于设备,不管是先添加接口,还是先发现设备。
总线类型
总线类型的数据结构
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); //检测设备与驱动是否可以绑定 int (*uevent)(struct device *dev, struct kobj_uevent_env *env); //发送事件前,设置bus特有的环境变量 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); //当设备进入节能状态时,回调 int (*resume)(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;};struct subsys_private { struct kset subsys; //总线kset,scsi子系统对应/sys/bus/scsi struct kset *devices_kset; //设备kset, scsi子系统对应/sys/bus/scsi/devices struct list_head interfaces; //总线的接口链表 struct mutex mutex; struct kset *drivers_kset; //驱动kset, scsi子系统对应/sys/bus/scsi/drivers struct klist klist_devices; //总线的设备链表 struct klist klist_drivers; //总线的驱动链表 struct blocking_notifier_head bus_notifier; //子系统变化时,需要通知的链表 unsigned int drivers_autoprobe:1; //是否允许设备或驱动加载时,自动探测 struct bus_type *bus; //指向总线类型 struct kset glue_dirs; struct class *class; //指向总线类型的类};
从上面的两个结构可以看到,bus_type包含的主要是实现子系统应该具体关注的比如name,一组回调函数。而subsys_private结构主要是设备驱动模型中的关系的表达,如字段subsys的类型是kset,描述该子系统在sysfs中的表达;klist_devices和klist_drivers分别是设备链表和驱动链表,用于管理总线类型的所有设备和驱动。之后仍然会遇到xxx_private的结构,以这种方式命名的结构,都是给设备驱动模型核心使用的,业务子系统无需也不能使用。
总线类型注册/反注册
实现子系统的第一步就是创建bus_type,并将其注册到系统,此时需要调用bus_register:
/** * bus_register - register a driver-core subsystem * @bus: bus to register * * Once we have that, we register the bus with the kobject * infrastructure, then register the children subsystems it has: * the devices and drivers that belong to the subsystem. */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_type和subsys_private bus->p = priv; BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier); //设置总线类型名称到kobject中,在sysfs中显示 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); //将总线类型添加到设备模型中 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, //创建devices目录 &priv->subsys.kobj); if (!priv->devices_kset) { retval = -ENOMEM; goto bus_devices_fail; } priv->drivers_kset = kset_create_and_add("drivers", NULL, //创建drivers目录 &priv->subsys.kobj); 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中添加探测文件drivers_autoprobe和drivers_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; //失败回滚操作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);
注册总线类型后,便可以在系统看到:
root@ubuntu16:~# ls /sys/bus/scsi -ltotal 0drwxr-xr-x 2 root root 0 Sep 5 16:01 devicesdrwxr-xr-x 4 root root 0 Sep 2 09:44 drivers-rw-r--r-- 1 root root 4096 Sep 5 11:29 drivers_autoprobe--w------- 1 root root 4096 Sep 5 11:29 drivers_probe--w------- 1 root root 4096 Sep 2 09:44 ueventroot@ubuntu16:~#
当从系统中注销子系统时,需要调用bus_unregister,完成总线类型的反注册:
/** * bus_unregister - remove a bus from the system * @bus: bus. * * Unregister the child subsystems and the bus itself. * Finally, we call bus_put() to release the refcount */void bus_unregister(struct bus_type *bus){ pr_debug("bus: '%s': unregistering\n", bus->name); if (bus->dev_root) device_unregister(bus->dev_root); //删除根设备 bus_remove_groups(bus, bus->bus_groups); //删除总线的属性文件 remove_probe_files(bus); //删除探测文件drivers_autoprobe和drivers_probe kset_unregister(bus->p->drivers_kset); //删除drivers目录 kset_unregister(bus->p->devices_kset); //删除devices目录 bus_remove_file(bus, &bus_attr_uevent); //删除uevent文件 kset_unregister(&bus->p->subsys); //删除总线目录}EXPORT_SYMBOL_GPL(bus_unregister);
设备
设备的数据结构
struct device { struct device *parent; //指向父设备,eg.HBA 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; devive归属的bus */ 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_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 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; //设备资源链表头 struct klist_node knode_class; //链入类的设备链表 struct 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;};struct device_private { struct klist klist_children; //子设备链表 struct klist_node knode_parent; //链入父设备的children链表 struct klist_node knode_driver; //链入驱动的设备链表中 struct klist_node knode_bus; //链入总线的设备链表 struct list_head deferred_probe; //链入延迟探测链表 struct device *device; //指向关联的device};struct device_type { const char *name; //设备类型的名称 const struct attribute_group **groups; //设备的公有属性组 int (*uevent)(struct device *dev, struct kobj_uevent_env *env); //发送事件前调用,用于设置事件环境变量 char *(*devnode)(struct device *dev, umode_t *mode, //在创建设备时,提供名字线索 kuid_t *uid, kgid_t *gid); void (*release)(struct device *dev); //设备释放时回调 const struct dev_pm_ops *pm;};
在设备驱动模型中,device结构有bus域,指向device所属的总线类型;class域指向device所属的唯一的类;driver域指向设备所绑定的驱动。与内核对象一样,设备也被组织层层次结构,通过parent指向父设备。
device_private结构由设备驱动模型处理,维护和其他结构之间的内部关系。device_type结构定义设备公有的属性和方法。
设备的注册与反注册
当设备被发现后,需要将设备注册到系统,需要调用device_register函数:
/** * device_register - register a device with the system. * @dev: pointer to the device structure * * This happens in two clean steps - initialize the device * and add it to the system. The two steps can be called * separately, but this is the easiest and most common. * I.e. you should only call the two helpers separately if * have a clearly defined need to use and refcount the device * before it is added to the hierarchy. * * For more information, see the kerneldoc for device_initialize() * and device_add(). * * NOTE: _Never_ directly free @dev after calling this function, even * if it returned an error! Always use put_device() to give up the * reference initialized in this function instead. */int device_register(struct device *dev){ device_initialize(dev); //初始化device结构 return device_add(dev); //将设备添加到系统}EXPORT_SYMBOL_GPL(device_register);void device_initialize(struct device *dev){ dev->kobj.kset = devices_kset; // /sys/devices/ kobject_init(&dev->kobj, &device_ktype); // device的类型为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}EXPORT_SYMBOL_GPL(device_initialize);
device_register函数调用device_initialize对device结构进行初始化,调用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) { //如果device没有设置devcie_private,在这里分配并初始化 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); //设置device的kobject名字 dev->init_name = NULL; } /* subsystems can specify simple device enumeration */ if (!dev_name(dev) && dev->bus && dev->bus->dev_name) //如果device没有设置init_name, 则使用bus的dev_name和设备id生成 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 (kobj) dev->kobj.parent = kobj; //设置device的kobject的parent字段 /* 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添加到parent的目录中 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); //为设备的默认属性添加对应的文件 if (error) goto AttrsError; error = bus_add_device(dev); //将device添加到bus_type 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); //在设备目录下创建dev属性对应文件,用于保存设备号 if (error) goto DevAttrError; error = device_create_sys_dev_entry(dev); //在/sys/block和/sys/char创建一个到设备所在目录的符号链接 if (error) goto SysEntryError; devtmpfs_create_node(dev); //在/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); //发送设备ADD事件 bus_probe_device(dev); //尝试将device绑定到device_driver if (parent) //如果指定了parent,将设备添加到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, //调用device所属的class中所有class_interface的add_dev &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); kobject_del(&dev->kobj); Error: cleanup_device_parent(dev); put_device(parent);name_error: kfree(dev->p); dev->p = NULL; goto done;}EXPORT_SYMBOL_GPL(device_add);
设备添加到系统主要流程都在device_add函数实现,上面代码的注释基本把主要函数的作用进行了描述。值得关注的一个函数便是bus_probe_device,该函数完成将设备绑定到驱动的动作。
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) //如果bus允许自动探测 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) { //指定了device所要绑定的driver if (klist_node_attached(&dev->p->knode_driver)) { //检查knode_driver是否绑定到链表 ret = 1; goto out_unlock; } ret = device_bind_driver(dev); //绑定,修改相应链表 if (ret == 0) ret = 1; else { dev->driver = NULL; ret = 0; } } else { //没有指定device要绑定的driver struct device_attach_data data = { .dev = dev, .check_async = allow_async, .want_async = false, }; if (dev->parent) pm_runtime_get_sync(dev->parent); //遍历bus中所有驱动,尝试attach ret = bus_for_each_drv(dev->bus, NULL, &data, __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;}
通过上面3个函数的追踪,__device_attach函数遍历bus所有的驱动,尝试执行attach,具体调用__device_attach_driver函数。
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; /* * 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; if (!driver_match_device(drv, dev)) //调用bus的match函数,测试是否匹配 return 0; //进一步probe设备,需要设备已经注册 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);}int driver_probe_device(struct device_driver *drv, struct device *dev){ int ret = 0; if (!device_is_registered(dev)) //检查device是否register return -ENODEV; pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); if (dev->parent) pm_runtime_get_sync(dev->parent); pm_runtime_barrier(dev); ret = really_probe(dev, drv); //真正执行探测 pm_request_idle(dev); if (dev->parent) pm_runtime_put(dev->parent); return ret;}
从上面两个函数来看,真正执行probe的函数是really_probe。
//返回1表示成功,返回0表示中间步骤出现异常,已回滚所有操作。static int really_probe(struct device *dev, struct device_driver *drv){ int ret = 0; int local_trigger_count = atomic_read(&deferred_trigger_count); 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)); dev->driver = drv; //将设备的driver指向当前驱动 /* If using pinctrl, bind pins now before probing */ ret = pinctrl_bind_pins(dev); if (ret) goto probe_failed; if (driver_sysfs_add(dev)) { //在sysfs驱动目录中创建指向设备的符号链接,同时在设备目录中创建指向驱动的符号链接 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; } /* * Ensure devices are listed in devices_kset in correct order * It's important to move Dev to the end of devices_kset before * calling .probe, because it could be recursive and parent Dev * should always go first */ devices_kset_move_last(dev); if (dev->bus->probe) { ret = dev->bus->probe(dev); //优先调用bus_type中的probe方法 if (ret) goto probe_failed; } else if (drv->probe) { ret = drv->probe(dev); //其次,调用driver中的probe方法 if (ret) goto probe_failed; } 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: //探测失败, 回滚操作 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); switch (ret) { case -EPROBE_DEFER: /* Driver requested deferred probing */ dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name); driver_deferred_probe_add(dev); /* Did a trigger occur while probing? Need to re-trigger if yes */ if (local_trigger_count != atomic_read(&deferred_trigger_count)) driver_deferred_probe_trigger(); 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;}
到此,设备添加到系统的主要流程便基本清楚,不再往下跟踪。
驱动
驱动数据结构
struct device_driver { const char *name; //driver名称 struct bus_type *bus; //driver所属的bus_type 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); //在device绑定到driver之前,对device进行初始化 int (*remove) (struct device *dev); //在device解绑到driver时,回调 void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); int (*resume) (struct device *dev); const struct attribute_group **groups; //driver的属性 const struct dev_pm_ops *pm; //电源相关 struct driver_private *p; //driver私有结构};struct driver_private { struct kobject kobj; struct klist klist_devices; //driver所支持的device链表 struct klist_node knode_bus; //链入bus_type的驱动链表中 struct module_kobject *mkobj; struct device_driver *driver; //指向driver};
device_driver结构中,bus域指向驱动所属的总线类型,knode_bus域用于链入总线类型的驱动链表。driver_private结构中的klist_devices域用于链接所有绑定到本驱动的设备。
驱动注册与反注册
驱动在加载时,需要将其注册到总线类型,调用driver_register实现:
int driver_register(struct device_driver *drv){ int ret; struct device_driver *other; BUG_ON(!drv->bus->p); //确保bus已经注册到驱动模型中 //如果bus_type和driver都实现了同一个回调,优先使用bus_type的回调函数,打印告警信息 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); //将driver添加到bus if (ret) return ret; ret = driver_add_groups(drv, drv->groups); //创建driver属性文件 if (ret) { bus_remove_driver(drv); return ret; } kobject_uevent(&drv->p->kobj, KOBJ_ADD); //发送ADD事件到用户空间 return ret;}EXPORT_SYMBOL_GPL(driver_register);
添加driver到bus_type,由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); //分配driver_private结构空间 if (!priv) { error = -ENOMEM; goto out_put_bus; } klist_init(&priv->klist_devices, NULL, NULL); //初始化driver设备链表 priv->driver = drv; //关联device_driver和driver_private drv->p = priv; priv->kobj.kset = bus->p->drivers_kset; //driver_private中的kobj的kset域指向subsys中的drivers_kset error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, //添加driver到sysfs "%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)) { //允许异步执行probe pr_debug("bus: '%s': probing driver %s asynchronously\n", drv->bus->name, drv->name); async_schedule(driver_attach_async, drv); //异步probe } else { error = driver_attach(drv); //同步probe if (error) goto out_unregister; } } module_add_driver(drv->owner, drv); //驱动实现的模块 error = driver_create_file(drv, &driver_attr_uevent); //在driver中添加uevent属性文件 if (error) { printk(KERN_ERR "%s: uevent attr (%s) failed\n", __func__, drv->name); } error = driver_add_groups(drv, bus->drv_groups); //添加driver的属性文件 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); //在driver目录添加的bind和unbind两个属性文件 if (error) { /* Ditto */ printk(KERN_ERR "%s: add_bind_files(%s) failed\n", __func__, drv->name); } } return 0;out_unregister: kobject_put(&priv->kobj); kfree(drv->p); drv->p = NULL;out_put_bus: bus_put(bus); return error;}
bus_add_driver函数完成驱动添加到总线类型,当驱动添加完成后,如果总线类型设置了允许自动探测标志drivers_autoprobe,便可以根据是否允许异步探测调用driver_attach_async或driver_attach,driver_attach_async也是调用driver_attach:
int driver_attach(struct device_driver *drv){ return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);}EXPORT_SYMBOL_GPL(driver_attach);static int __driver_attach(struct device *dev, void *data){ struct device_driver *drv = data; /* * 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. */ if (!driver_match_device(drv, dev)) //调用bus_type.match return 0; if (dev->parent) /* Needed for USB */ device_lock(dev->parent); device_lock(dev); if (!dev->driver) driver_probe_device(drv, dev); //完成probe的主要函数 device_unlock(dev); if (dev->parent) device_unlock(dev->parent); return 0;}int driver_probe_device(struct device_driver *drv, struct device *dev){ int ret = 0; if (!device_is_registered(dev)) //检查device是否register return -ENODEV; pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); if (dev->parent) pm_runtime_get_sync(dev->parent); pm_runtime_barrier(dev); ret = really_probe(dev, drv); //真正执行探测 pm_request_idle(dev); if (dev->parent) pm_runtime_put(dev->parent); return ret;}
根据上面3个函数,最终仍然是调用前面描述过的really_probe函数完成最后的探测。
到这里驱动注册完成,结合之前的设备注册流程,无论是驱动注册或是设备注册,只要总线类型设置了自动探测标志位,这两个流程都会执行探测。所以设备发现与驱动的加载顺序已经不再重要,也是通过这种双向探测方式,Linux内核支持设备的热拔插机制。
驱动卸载时,需要调用driver_unregister函数,使driver脱离总线类型:
void driver_unregister(struct device_driver *drv){ if (!drv || !drv->p) { WARN(1, "Unexpected driver unregister!\n"); return; } driver_remove_groups(drv, drv->groups); //删除驱动的属性文件 bus_remove_driver(drv); //从总线类型中移除驱动}EXPORT_SYMBOL_GPL(driver_unregister);void bus_remove_driver(struct device_driver *drv){ if (!drv->bus) return; if (!drv->suppress_bind_attrs) remove_bind_files(drv); //删除驱动目录下bind和unbind文件 driver_remove_groups(drv, drv->bus->drv_groups); //删除总线类型的驱动属性文件 driver_remove_file(drv, &driver_attr_uevent); //删除驱动目录下uevent文件 klist_remove(&drv->p->knode_bus); //从总线类型的驱动链表中移除驱动 pr_debug("bus: '%s': remove driver %s\n", drv->bus->name, drv->name); driver_detach(drv); //驱动与所有绑定的设备进行解绑 module_remove_driver(drv); //驱动实现的模块 kobject_put(&drv->p->kobj); //减少引用计数 bus_put(drv->bus);}
类
类数据结构
struct class { const char *name; //类名称 struct module *owner; //指向实现这个类的模块的指针 struct class_attribute *class_attrs; //类公共属性 const struct attribute_group **dev_groups; //归属与该类的设备的默认属性 struct kobject *dev_kobj; //类链入sysfs的kobject int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); //发送事件前,设置类的特定环境变量 char *(*devnode)(struct device *dev, umode_t *mode); //创建设备时,返回设备名称 void (*class_release)(struct class *class); //类释放时回调 void (*dev_release)(struct device *dev); //设备释放时回调 int (*suspend)(struct device *dev, pm_message_t state); //设备进入睡眠状态时,回调 int (*resume)(struct device *dev); //设备被唤醒时,回调 const struct kobj_ns_type_operations *ns_type; //sysfs支持命名空间 const void *(*namespace)(struct device *dev); //返回设备所在的命名空间 const struct dev_pm_ops *pm; //电源相关 struct subsys_private *p; //类所属的子系统私有数据结构};
类的私有数据类型与总线类型的私有数据类型都是subsys_private,这里将不再重复描述。
类注册与反注册
子系统需要使用类时,需要调用class_register函数向总线类型注册类:
#define class_register(class) \({ \ static struct lock_class_key __key; \ __class_register(class, &__key); \})int __class_register(struct class *cls, struct lock_class_key *key){ struct subsys_private *cp; int error; pr_debug("device class '%s': registering\n", cls->name); cp = kzalloc(sizeof(*cp), GFP_KERNEL); //分配私有数据空间 if (!cp) return -ENOMEM; klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put); //初始化该class的device链表 INIT_LIST_HEAD(&cp->interfaces); //初始化接口链表 kset_init(&cp->glue_dirs); __mutex_init(&cp->mutex, "subsys mutex", key); error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name); //将在/sys/class/目录下显示该名称 if (error) { kfree(cp); return error; } /* set the default /sys/dev directory for devices of this class */ if (!cls->dev_kobj) cls->dev_kobj = sysfs_dev_char_kobj;#if defined(CONFIG_BLOCK) /* let the block class directory show up in the root of sysfs */ if (!sysfs_deprecated || cls != &block_class) cp->subsys.kobj.kset = class_kset;#else cp->subsys.kobj.kset = class_kset; // 全局变量class_kset指的是 /sys/class/#endif cp->subsys.kobj.ktype = &class_ktype; cp->class = cls; //class与subsys_private关联 cls->p = cp; error = kset_register(&cp->subsys); //在/sys/class/目录下创建该类对应的目录 if (error) { kfree(cp); return error; } error = add_class_attrs(class_get(cls)); //在/sys/class/xxx/目录下创建类属性文件 class_put(cls); return error;}EXPORT_SYMBOL_GPL(__class_register);
类的注册比较简单,注释已经比较详细。当子系统需要卸载类时,需要调用class_register函数:
void class_unregister(struct class *cls){ pr_debug("device class '%s': unregistering\n", cls->name); remove_class_attrs(cls); //删除/sys/class/xxx/目录下的类属性文件 kset_unregister(&cls->p->subsys); //删除/sys/class/目录}
接口
接口数据结构
struct class_interface { struct list_head node; //链入class中 struct class *class; //指向所属的class //在接口被添加或者设备被添加到接口所在的类时,从接口中添加或删除设备 int (*add_dev) (struct device *, struct class_interface *); void (*remove_dev) (struct device *, struct class_interface *);};
接口注册与反注册
向类中注册接口,需要调用class_interface_register函数完成:
int class_interface_register(struct class_interface *class_intf){ struct class *parent; struct class_dev_iter iter; struct device *dev; if (!class_intf || !class_intf->class) //确保class和class_interface都存在 return -ENODEV; parent = class_get(class_intf->class); //增加引用计数,并返回接口所属的class if (!parent) return -EINVAL; mutex_lock(&parent->p->mutex); list_add_tail(&class_intf->node, &parent->p->interfaces); //将class_interface添加到class的接口链表 if (class_intf->add_dev) { //如果接口设置了add_dev方法,对该class的所有device调用 class_dev_iter_init(&iter, parent, NULL, NULL); while ((dev = class_dev_iter_next(&iter))) class_intf->add_dev(dev, class_intf); //接口方法作用于设备 class_dev_iter_exit(&iter); } mutex_unlock(&parent->p->mutex); return 0;}
从类中删除接口,需要调用class_interface_unregister函数完成:
void class_interface_unregister(struct class_interface *class_intf){ struct class *parent = class_intf->class; struct class_dev_iter iter; struct device *dev; if (!parent) return; mutex_lock(&parent->p->mutex); list_del_init(&class_intf->node); //将class_interface从class的接口链表中删除 if (class_intf->remove_dev) { //如果接口设置了remove_dev方法,对该class的所有device调用 class_dev_iter_init(&iter, parent, NULL, NULL); while ((dev = class_dev_iter_next(&iter))) class_intf->remove_dev(dev, class_intf); //接口方法作用于设备 class_dev_iter_exit(&iter); } mutex_unlock(&parent->p->mutex); class_put(parent);}
基于设备驱动模型实现子系统
Linux设备驱动模型已经将每种对象的关系,sysfs的呈现方式已经实现了。实现子系统只需要定义业务自身的总线类型, 设备, 驱动, 类, 接口分别”继承”bus_type, device, driver, class, class_interface。并根据具体业务实现各个结构规定的回调函数。最后调用上述的注册函数添加到系统,便完成子系统的开发。
- Linux存储IO栈(3)-- 设备驱动模型
- Linux设备驱动模型摘抄(3)
- Linux设备驱动模型
- Linux设备驱动模型
- Linux设备驱动模型
- linux设备驱动模型
- Linux设备驱动模型
- Linux设备驱动模型
- linux设备驱动模型
- linux设备驱动模型
- Linux设备驱动模型
- Linux 设备驱动模型
- Linux设备驱动模型 .
- Linux设备驱动模型
- linux驱动模型 - 设备
- Linux设备驱动模型
- Linux设备驱动模型
- Linux设备驱动模型
- S1JAVA第十一章作业六
- 从Eclipse转战Android Studio坑之——百度地图
- 设计模式之代理模式
- 第十一章 类和对象复习
- DLL的创建与使用
- Linux存储IO栈(3)-- 设备驱动模型
- HTML5 新增的结构元素——能用不代表用对了
- Mybatis特殊值Enum类型转换器-ValuedEnumTypeHandler
- iOS PNChart 使用详解
- 计算机程序
- java练习---季节
- 静态版通讯录的实现
- 对应用程序角度的MySQL查询优化的一点个人小结
- 蓝鸥Unity开发教程之课时6 脚本生命周期