• bus_type、device、device_driver


    活动地址:CSDN21天学习挑战赛

    总线

    在《系统总线》这篇文章中,我们介绍了什么是总线,这里讲的总线是物理层面的,是指 CPU 与多个外设,或者外设与外设之间的物理通道。
    在 Linux 驱动中,也存在总线的概念,这里讲的总线是软件层面的,主要用来管理设备和驱动,其中最重要的工作就是匹配设备和驱动。
    在这里插入图片描述
    当然,一个驱动也可以对应多个设备。

    bus_type

    在 Linux 驱动中,总线用 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);
    	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;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    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;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    其中 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;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    系统下挂载的形形色色的设备都是通过 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;	// 重要
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    同 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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    以上为 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    dev kobj name = mmc0:0001
    bus: 'mmc': driver_probe_device: matched device mmc0:0001 with driver mmcblk
    
    • 1
    • 2

    其中 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
    
    • 1
    • 2

    在 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    嵌入式操作系统的特点
    double类型数相减有小数误差问题
    OOP第二阶段题集总结
    【C语言】链表详解(无头单向非循环)
    SpringCloud:自定义skywalking链路追踪
    CDN策略好坏的重要性
    Git最新教程4——使用码云Gitee使用教程,创建项目仓库并上传代码
    go Jenkins流水线极速打包镜像上传
    Redis(一)入门:NoSQL OR SQL,看完这篇你就懂了
    智慧能源一体化管控平台
  • 原文地址:https://blog.csdn.net/lyndon_li/article/details/126423052