1. 总论
2. 系统初始化 platform device
3. 驱动程序使用 platform device
1. 总论
Linux-2.6.11引入了设备模型的概念,将大部分设备驱动挂载到虚拟总线上。
其目的在于:
1) 提供友好的用户接口,用户可以在sys/bus/platform/下找到相应的驱动和设备。
2) 更有利于电源管理。
2. 系统初始化 platform device
在驱动程序的初始化函数 xxx_probe(struct platform_device *pdev)中,其结构体参数platform_device,是在系统初始化过程中发现了该设备存在的前提条件下,通过platform_device_register(dev) 完成注册的,并且struct platform_device的结构变量被赋值。
以Xscal初始化sd卡控制器为例,
/* linux/arch/arm/mach-pxa/starwood_p1.c */
MACHINE_START(SAAR, "PXA935 handheld Platform (Starwood P1)")
... ...
.init_machine = saar_init,
MACHINE_END
static void __init saar_init(void)
{
... ...
saar_init_mmc();
... ...
}
static void __init saar_init_mmc(void)
{
... ...
pxa_set_mci_info(&saar_mci_platform_data); //saar_mci_platform_data完成该设备特有数据的赋值
... ...
}
static struct pxamci_platform_data saar_mci_platform_data = {
.detect_delay = 50,
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.init = saar_mci_init, //回调函数,设置sd卡控制器的探测中断pin脚 gpio_cd
.exit = saar_mci_exit,
};
void __init pxa_set_mci_info(struct pxamci_platform_data *info)
{
pxa_register_device(&pxa_device_mci, info);
}
struct platform_device pxa_device_mci = { //完成结构体platform_device的赋值
.name = "pxa2xx-mci", //芯片的设备名称,驱动通过匹配该名字找到设备
.id = 0,
.dev = {
.dma_mask = &pxamci_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(pxamci_resources),
.resource = pxamci_resources, //设置芯片的物理地址
};
void __init pxa_register_device(struct platform_device *dev, void *data)
{
... ...
dev->dev.platform_data = data; //将该设备特有的数据挂到 dev->dev.platform_data下
platform_device_register(dev);
... ...
}
3. 驱动程序使用 platform device
驱动程序通过platform_driver_register()找到与该驱动对应的设备,完成驱动和设备的绑定,并且挂载到虚拟总线上。
具体过程如下,
platform_driver_register(struct platform_driver *drv);
|
driver_register(&drv->driver);
|
bus_add_driver(drv);
|
driver_attach(drv);
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); //__driver_attach最后调用driver_bound(dev);
}
int bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
... ...
while ((dev = next_device(&i)) && !error)
fn(dev, data); //fn即__driver_attach,完成设备与驱动的绑定
... ...
}
static void driver_bound(struct device *dev)
{
... ...
klist_add_tail(&dev->knode_driver, &dev->driver->p->klist_devices);
}
驱动程序找到了自己所对应的设备之后,就可以对该设备初始化了,即probe()操作,在probe()中,便可以使用platform_device结构体里的数据了。
仍然以sd卡控制器为例,
/* linux/drivers/mmc/host/pxamci.c */
static int __init pxamci_init(void)
{
... ...
return platform_driver_register(&pxamci_driver);
}
static struct platform_driver pxamci_driver = {
.probe = pxamci_probe,
... ...
};
static int pxamci_probe(struct platform_device *pdev)
{
struct resource *r;
/*
* 得到sd卡控制器芯片的物理地址
*/
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
host->res = r;
/*
* 得到sd卡控制器芯片的内部中断源并申请中断
*/
irq = platform_get_irq(pdev, 0);
host->irq = irq;
request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
... ...
}