bus_typedevicedevice_driver
Posted Li-Yongjun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bus_typedevicedevice_driver相关的知识,希望对你有一定的参考价值。
活动地址:CSDN21天学习挑战赛
文章目录
总线
在《系统总线》这篇文章中,我们介绍了什么是总线,这里讲的总线是物理层面的,是指 CPU 与多个外设,或者外设与外设之间的物理通道。
在 Linux 驱动中,也存在总线的概念,这里讲的总线是软件层面的,主要用来管理设备和驱动,其中最重要的工作就是匹配设备和驱动。
当然,一个驱动也可以对应多个设备。
bus_type
在 Linux 驱动中,总线用 bus_type 结构体来表示,定义在 <linux/device.h>
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);
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;
;
name/dev_name: 总线自己和下属设备的名字
bus/dev/drv_groups: 相关 sysfs 的文件
match/probe…: 匹配设备,操作设备的接口
其中有个重要的成员结构 subsys_private,我们来看下它的内容
struct subsys_private
struct kset subsys;
struct kset *devices_kset;
struct list_head interfaces;
struct mutex mutex;
struct kset *drivers_kset;
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;
;
其中 klist_devices 和 klist_drivers 这两个成员很重要,它们分别串连了总线上所有的设备和所有的驱动。
当 bus 中的 devices 注册进去的时候,它会扫 drivers 的链表,当 drivers 注册进去的时候,它会扫 devices 的链表。进行一个 name 匹配,这就是 bus 管理 devices 和 drivers 的核心。
device
struct 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 ev_set/get_drvdata */
struct dev_pm_info power;
struct dev_pm_domain *pm_domain;
#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;
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 结构体来描述的。其中 dts 中定义的很多节点,最终都会转换为 struct device 结构体,用于描述一个设备的信息,管理设备用到的资源等。
device 结构体下一个重要的结构是 device_private,该结构体成员 knode_bus 就是用于挂载到上面提到的 bus 下的 subsys_private 结构体中的 klist_devices。
device_driver
struct device_driver
const char *name;
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 */
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; // 重要
;
同 device,
device_driver 结构体下一个重要的结构是 driver_private,该结构体成员 knode_bus 就是用于挂载到上面提到的 bus 下的 subsys_private 结构体中的 klist_drivers。
三者关系
匹配流程
以 mmc 总线为例,我们分析下总线匹配 driver 和 device 的大概流程
module_init(mmc_blk_init); // drivers/mmc/card/block.c
mmc_blk_init()
register_blkdev(MMC_BLOCK_MAJOR, "mmc"); // #define MMC_BLOCK_MAJOR 179
mmc_register_driver(&mmc_driver)
driver_register() // drivers/base/driver.c
driver_find()
bus_add_driver()
driver_attach()
bus_for_each_dev(, __driver_attach) // drivers/base/bus.c
klist_iter_init_node()
fn() = _driver_attach()
driver_match_device()
drv->bus->match(dev, drv)
mmc_bus_match()
return 1;
driver_probe_device()
really_probe()
dev->bus->probe(dev);
drv->probe(dev);
driver_bound()
以上为 mmcblk 驱动注册流程,包括:
注册设备:register_blkdev
注册驱动:mmc_register_driver (将 mmcblk 驱动注册到 mmc 总线)
上面讲过,将驱动注册到总线时,会触发遍历设备链表,查找有无与当前驱动匹配的设备,若存在,则调用 driver_probe_device()
int driver_probe_device(struct device_driver *drv, struct device *dev)
int ret = 0;
if (!device_is_registered(dev))
return -ENODEV;
pr_debug("bus: '%s': %s: matched device %s with driver %s\\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
printk("bus: '%s': %s: matched device %s with driver %s\\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
pm_runtime_barrier(dev);
ret = really_probe(dev, drv);
pm_request_idle(dev);
return ret;
dev kobj name = mmc0:0001
bus: 'mmc': driver_probe_device: matched device mmc0:0001 with driver mmcblk
其中 really_probe() 先调用 bus 的 probe(),再调用 driver 的 probe()。便开始真正干驱动的活了。
再接着,调用 driver_bound(),将驱动和设备绑定
driver: 'mmcblk': driver_bound: bound to device 'mmc0:0001'
bus: 'mmc': really_probe: bound device mmc0:0001 to driver mmcblk
在 sysfs 下也能找到对应的匹配信息
# ls /sys/bus/mmc
devices drivers drivers_autoprobe drivers_probe uevent
# ls /sys/bus/mmc/drivers
mmcblk
# ls /sys/bus/mmc/devices/
mmc0:0001 mmc1:0001
以上是关于bus_typedevicedevice_driver的主要内容,如果未能解决你的问题,请参考以下文章