文章目录
- 1. 前言
- 2. 概念
- 2.1. 数据结构
- 2.2. probe函数
- 3. bus、设顺序device、备驱driver加载顺序
- 3.1. 加载方式
- 3.2. 加载顺序
- 4. device、加载driver匹配流程
- 4.1. 加载driver
- 4.2. 加载device
- 5. Reference
1. 前言
最近回看了下Linux设备驱动相关知识,匹配做了个总结。流程有些话需要说在前面:
- 文中有些内容为个人理解(上标H所标识内容),设顺序未必准确,备驱有误请评论指正。加载
- 4.2节的匹配内容主要目的是为了搞清楚driver和device在加载的过程中是如何通过bus相互匹配。
本文源码源自4.10.17版本linux内核。流程
2. 概念
Linux设备驱动有三个基本概念:总线、设顺序驱动以及设备。备驱 三者之间关 系 H 三者之间关系^H 三者之间关系H简单描述如下:
- 总线为外设或片内模组与核心处理器之间的加载通信总线,例如SPI、匹配I2C、流程SDIO、USB等。
- 每个驱动、设备都需要挂载到一种总线上;
- 挂载到相同总线的驱动和设备可以通过该总线进行匹配,实现设备与对应的驱动之间的绑定。
2.1. 数据结构
以下为总线、驱动及设备在linux内核中对应的核心数据结构
// 总线数据结构 -- include/linux/device.hstruct 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); 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;};// drivers/base/base.hstruct subsys_private { struct kset subsys; // the struct kset that defines this subsystem struct kset *devices_kset; // the subsystem's 'devices' directory struct list_head interfaces; struct mutex mutex; struct kset *drivers_kset; // the list of drivers associated 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;};
// 驱动数据结构 -- include/linux/device.hstruct device_driver { const char *name; struct bus_type *bus; // 指向本驱动挂载的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; struct driver_private *p; // 如下};// drivers/base/base.hstruct driver_private { struct kobject kobj; struct klist klist_devices; struct klist_node knode_bus; struct module_kobject *mkobj; struct device_driver *driver;};
// 设备数据结构 -- include/linux/device.hstruct device { struct device *parent; struct device_private *p; struct kobject kobj; 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 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; struct iommu_fwspec *iommu_fwspec; bool offline_disabled:1; bool offline:1;};
2.2. probe函数
bus_type和device_driver中都包含probe()
函数,两者关系可追踪到函数really_probe()
中(该函数在后续的调用加载流程中会描述具体执行的位置,可先跳过,后续查看加载流程时返回此处查看),如下:
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; ... 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; 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; } /* * 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); /***** 以下为重点