Linux平台总线

发布时间 2023-12-24 14:48:54作者: yang_dh

linux drv和 dev都会注册进总线的链表,如果设备和驱动匹配,调用驱动程序的probe函数

image-20230817100007702

总线类型:bus_type

代码分析:

  1. 注册drv

    image-20230817100147811

举例说明:

分析注册一个平台drv

driver_register(&drv->driver)
	bus_add_driver(struct device_driver *drv)
		klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers)		/* 把这个drv添加进bus的链表中(bus->p->klist_drivers) */
		driver_attach(struct device_driver *drv)
			bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)  /* 对于bus中的每一个dev执行 __driver_attach 函数 */
			/* bus_for_each_dev 会拿到bus链表中的每一个dev结构体 */
			__driver_attach(struct device *dev, void *data)
				driver_match_device(drv, dev)	/* dev和drv的匹配函数,返回0表示匹配失败 */
					driver_probe_device(struct device_driver *drv, struct device *dev)
						really_probe(struct device *dev, struct device_driver *drv)	/* 真正的枚举,说明已经匹配到了 */
						dev->driver = drv;		/* 说明已经有drv适配这个dev了,后续dev分析的时候,会来判断这个设备是否已经有驱动支持了 */
							drv->probe(dev)

从bus->p->klist_devices这个链表中取dev,那么谁给这个链表添加dev的?

在注册设备的时候添加klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices)

  1. 注册dev

同样的例子:

platform_device_register(struct platform_device *pdev)
	platform_device_add(struct platform_device *pdev)
	pdev->dev.bus = &platform_bus_type;		/* 表示这个dev的总线是平台总线类型 */
	switch (pdev->id)  /* 根据 pdev->id 来判断在/sys/class/dev/下面的名字 */
		device_add(&pdev->dev)
			bus_add_device(dev)
			klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices)		/* 把这个dev添加进bus->p->klist_devices链表,上面有提过 */
				bus_probe_device(struct device *dev)
					device_initial_probe(struct device *dev)
						__device_attach(struct device *dev, bool allow_async)
						bus_for_each_drv(dev->bus, NULL, &data,__device_attach_driver)	/* 对于bus中的每一个drv执行 __device_attach_driver 函数 bus_for_each_drv会从链表中拿到每一个drv结构体 */
						__device_attach_driver(struct device_driver *drv, void *_data)
							if (dev->driver)		/* 如果这个设备已经有驱动了,就返回,不用在去匹配过程了 */
								return -EBUSY;		/* 在之前really_probe函数下,已经标记了这个设备支持的驱动了,由此可见,一个dev最多只能适配一个drv,但是会从drv链表中取出每个drv来匹配,所以无论是先注册dev还是drv都没有关系,因为总是每个都取出来匹配的,只是这个dev匹配到了支持的drv,就不会匹配其他的了 */
								driver_probe_device(drv, dev);
									really_probe(dev, drv);

这里又是取出bus链表中每一个drv的结构体,谁给这个链表添加drv的?

在注册drv的时候添加klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers)