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的主要内容,如果未能解决你的问题,请参考以下文章

bus_typedevicedevice_driver

(kobjectktypekset,bus_typedevicedevice_driver)