This post tries to answer two questions:
- Who calls device driver’s probe() routine, and when?
- Where is probe() parameter from?
- Who calls device driver’s probe() routine, and when?
The story started from where the driver was registed.
TCC UART device driver (drivers/serial/tcc_serial.c), For example, its entry point defined like below:
static int __init tcc_seril_modinit(void)
{
...
platform_driver_register(drv);
...
}
module_init(tcc_serial_moinit);
The function call stack thereafter is:
1. XXX_driver_register(drv)
2. driver_register(&drv->driver);
3. bus_add_driver(drv);
4. driver_attach(drv);
5. bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
6. __driver_attach(struct device *dev, void *data);
7. driver_probe_device(drv, dev);
8. really_probe(dev, drv)
{
…
ret = drv->probe(dev);
…
}
Now it’s clear that the driver’s register function eventually called
driver’s probe() routine.
And, the “__init” symbol denotes this happened on kernel start up.
- Where is probe() parameter from?
The XXX_driver_register() passes a single parameter, drv. In case of TCC serial driver, its type is struct platform_driver.However, the driver’s probe() routine get a parameter dev, which type is struct platform_device.
Go through above functions call stack, we have noticed that from step 1 to step 4, the parameter is struct platform_driver; from step 6 to step 8, there is at least one struct platform_device parameter.
The step 5, however, references member struct bus_type of the driver.
The bus found(match) the driver’s partnership, the device, and passes struct device to __driver_attach.
NOTE:
Registing device MUST be prior to the driver’s registration.
The camera module init routine, for example:
int __init camera_core_init(void)
{
platform_device_register(&camera_core_device);
platform_driver_register(&camera_core_driver);
return 0;
}
In the case of TCC serial device driver, the dev parameter of probe() is exact the data passed to platform_device_register().
In arch/arm/mach-tcc8900/devices.c
platform_device_register(&tcc8900_uart0_device);
static struct resource uart0_resources[] = {
/* PA -> VA */
[0] = {
.start = 0xF0532000,
.end = 0xF05320FF,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = INT_UART0,
.end = INT_UART0,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device tcc8900_uart0_device = {
.name = "tcc8900-uart",
.id = 0,
.resource = uart0_resources,
.num_resources = ARRAY_SIZE(uart0_resources),
};