大家好,我是王鸽,在设备树的出现后,发现有些从事驱动工作久的人,只知道设备树修改,编译,出固件,变成“固件工程师”,导致对底层代码阅读能力下降,这个时候面试的时候会一脸尴尬起来,回归正题!首先,probe何时被调用?即在总线上驱动和设备的名字匹配,就会调用驱动的probe函数。 Device注册过程---device_register()kernel/drivers/base/core.c
intdevice_register(struct device *dev){ device_initialize(dev);return device_add(dev); |--error = bus_add_device(dev); |--bus_probe_device(dev); |--if (bus->p->drivers_autoprobe) { ret = device_attach(dev); WARN_ON(ret < 0);} } 其中device_attach函数中if (dev->driver) { ret = device_bind_driver(dev); }else { ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); pm_request_idle(dev);}__device_attach函数中(dd.c)if (!driver_match_device(drv, dev))(base.h) |--return drv->bus->match ? drv->bus->match(dev, drv) : 1;return driver_probe_device(drv, dev);(dd.c) |--ret = really_probe(dev, drv); |---dev->driver = drv; |--if (dev->bus->probe) { ret = dev->bus->probe(dev); if (ret){ goto probe_failed; } else if (drv->probe) { ret = drv->probe(dev);
Driver注册过程---driver_register()int driver_register(struct device_driver *drv) |--other = driver_find(drv->name, drv->bus); |--ret = bus_add_driver(drv); |--if (drv->bus->p->drivers_autoprobe) {|--error = driver_attach(drv); |--return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); 其中__driver_attach函数(dd.c)
if (!driver_match_device(drv, dev))return 0;if (dev->parent) /* Needed for USB */ device_lock(dev->parent); device_lock(dev);if (!dev->driver) driver_probe_device(drv, dev); |----ret = really_probe(dev, drv); |---dev->driver = drv; |--if (dev->bus->probe) { ret = dev->bus->probe(dev); if (ret){ goto probe_failed; } else if (drv->probe) { ret = drv->probe(dev);
从代码的追踪发现:
bus_for_each_drv()是对BUS上所有的Driver都进行__device_attach()操作;同样的,bus_for_each_dev()是对BUS上所有的Device都进行__driver_attach()操作。
BUS上实现的.match()函数,定义了Device和Driver绑定时的规则。比如Platform实现的就是先比较id_table,然后比较name的规则。如果BUS的match()函数没实现,认为BUS上的所有的Device和Driver都是match的,具体后续过程要看probe()的实现了。
Probe的规则是:如果BUS上实现了probe就用BUS的probe;否则才会用driver的probe。
Device一般是先于Driver注册,但也不全是这样的顺序。Linux的Device和Driver的注册过程分别枚举挂在该BUS上所有的Driver和Device实现了这种时序无关性。所有驱动的 probe 函数最终都会走到内核通用的 really_probe() 函数中被调用,而不同总线(如 I2C、SPI、PCI)的 probe 只是在这之前有各自的适配层,最终都会收敛到这个核心函数。# 触发源(二选一)触发源1:驱动注册 → driver_attach() → __driver_attach()触发源2:设备注册 → device_attach() → __device_attach() → driver_match_device() // 总线匹配(如I2C的i2c_device_match) → driver_probe_device() // 通用probe入口 → really_probe() // 内核probe核心函数 → ① 执行总线级probe(如有,如I2C的i2c_device_probe) → ② 最终调用驱动开发者实现的probe函数
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); pm_runtime_barrier(dev); ret = really_probe(dev, drv); pm_request_idle(dev);return ret;}
核心终点:really_probe()
这是所有驱动 probe 调用的最终核心入口,定义在 drivers/base/dd.c 中,核心逻辑伪代码如下:
staticintreally_probe(struct device *dev, struct device_driver *drv){ int ret = 0; // 1. 绑定驱动到设备 dev->driver = drv; // 2. 优先执行总线定义的probe(如I2C总线的i2c_device_probe) if (dev->bus->probe) { ret = dev->bus->probe(dev); // I2C总线会走到i2c_device_probe } // 3. 总线无probe时,直接执行驱动自带的probe else if (drv->probe) { ret = drv->probe(dev); // 部分总线直接调用驱动probe } // 4. probe成功/失败的后续处理(如添加设备到sysfs) if (ret == 0) { dev->probe_done = 1; } else { dev->driver = NULL; } return ret;}
总线适配层:以 I2C 为例的 i2c_device_probe()
I2C 总线在 dev->bus->probe 中注册了 i2c_device_probe,它是 “内核通用层” 到 “驱动实现层” 的适配,核心逻辑:
staticinti2c_device_probe(struct device *dev){struct i2c_client *client = i2c_verify_client(dev);// 转换为I2C设备对象struct i2c_driver *driver;int status;if (!client)return 0; driver = to_i2c_driver(dev->driver);// 转换为I2C驱动对象if (!driver->probe || !driver->id_table)// 最终调用你写的I2C驱动probe(如xxx_i2c_probe)return -ENODEV; client->driver = driver;if (!device_can_wakeup(&client->dev))device_init_wakeup(&client->dev, client->flags & I2C_CLIENT_WAKE);dev_dbg(dev, "probe\n"); status = driver->probe(client, i2c_match_id(driver->id_table, client));if (status) { client->driver = NULL;i2c_set_clientdata(client, NULL); }return status;}
最终执行:开发者实现的 probe
// 你写的I2C驱动probestaticintxxx_i2c_probe(struct i2c_client *client, conststruct i2c_device_id *id){ // 设备初始化、申请资源、注册字符设备等逻辑 return 0;}// 驱动结构体中关联static struct i2c_driver xxx_i2c_driver = { .probe = xxx_i2c_probe, // 最终被i2c_device_probe调用 .driver = { .name = "xxx_i2c", },};
不同总线的差异(核心不变,仅适配层不同)
| | | |
|---|
| | int (*probe)(struct i2c_client *, const i2c_device_id *) | really_probe → i2c_device_probe → 自定义 probe |
| | int (*probe)(struct spi_device *) | really_probe → spi_device_probe → 自定义 probe |
| | int (*probe)(struct pci_dev *, const pci_device_id *) | really_probe → 直接调用自定义 probe |
| | int (*probe)(struct platform_device *) | really_probe → platform_drv_probe → 自定义 probe |
总结
调用流程分为三层:① 触发匹配(设备 / 驱动注册)→ ② 总线适配(如 i2c_device_probe)→ ③ 执行开发者自定义的 probe;