平台总线设备驱动程序采用了分层分离的机制,我们先简述一下其大体上的原理,然后在从具体代码出发进行分析。
大体原理:在内核中存在平台设备总线,我们要把设备挂载到总线设备列表中,同时也要把驱动挂在到总线驱动列表中,但是相匹配的设备和驱动的名字要保持一致,因为总线会根据设备和驱动的名字是否一致,来决定他们是否匹配,一旦设备和驱动匹配起来,就会调用驱动程序里的probe函数进行处理。
代码分析,以/dirvers/mtd/nand/s3c2410.c为例来分析:
platform_driver_register(&s3c2410_nand_driver);
//驱动名为s3c2410-nand
drv->driver.bus = &platform_bus_type;
//platform_bus_type里存在match函数,待会会分析
driver_register(&drv->driver);
bus_add_driver(drv);
//将驱动添加到平台总线驱动列表中
我们搜索名“s3c2410-nand”的设备,最终在/arch/arm/plat-s3c24xx/devs.c中发现了线索:
struct platform_device s3c_device_nand = {
.name = "s3c2410-nand",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_nand_resource),
.resource = s3c_nand_resource,
};
那么这个设备是如何添加到总线上的呢?
.init_machine = osiris_init,
platform_add_devices(osiris_devices, ARRAY_SIZE(osiris_devices));//
关于osiris_devices的定义见注释1
platform_device_register(devs[i]);
platform_device_add(pdev);
device_add(&pdev->dev);
//将设备添加到总线
这样设备和驱动都注册到了总线上面,那么总线要做什么呢?
我们还记得注册驱动的时候有这么一句吧:
drv->driver.bus = &platform_bus_type;
我们来看看
platform_bus_type的定义:
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.suspend = platform_suspend,
.suspend_late = platform_suspend_late,
.resume_early = platform_resume_early,
.resume = platform_resume,
};
这里面有match函数,总线就是根据这个函数来判断设备和驱动是否匹配的,我们来看一下代码:
static int platform_match(struct device * dev, struct device_driver * drv)
{
struct platform_device *pdev = container_of(dev, struct platform_device, dev);
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
}
我们看到了,确实是根据驱动和设备的名字是否一致,来判断是否匹配的。
一旦匹配就会调用probe函数。
注释1:
static struct platform_device *osiris_devices[] __initdata = {
&s3c_device_i2c,
&s3c_device_wdt,
&s3c_device_nand,
&osiris_pcmcia,
};
疑问?
我水比较差,只能分析到这个地步了,下面是我的几点疑问,希望大家帮我一下好吗:
(1)我搜遍了代码也没有发现有谁调用了match函数,那么这个函数怎么被执行呢?
(2)为什么match成功后会调用probe函数呢?它也没有在哪个函数里面被调用啊!
(3)
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
if (drv->suspend)
drv->driver.suspend = platform_drv_suspend;
if (drv->resume)
drv->driver.resume = platform_drv_resume;
return driver_register(&drv->driver);
}
为什么一旦设置了 drv->probe就要自动设置 drv->driver.probe = platform_drv_probe;?drv.probe和drv->driver.probe两个probe有什么区别啊?
(4)
MACHINE_START(OSIRIS, "Simtec-OSIRIS")
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = osiris_map_io,
.init_machine = osiris_init,
.init_irq = s3c24xx_init_irq,
.init_machine = osiris_init,
.timer = &s3c24xx_timer,
MACHINE_END
这之间的代码何时被执行?