虚拟总线,没有对应的硬件设备,主要用于管理系统的外设资源。内核假设所有的设备都挂载到platform总线上来进行统一的管理,提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性。
Platform_device 和 Platform_driver分别用以表示设备和驱动,使用platform机制开发底层驱动大致流程:调用函数platform_add_devices注册platform_device; 调用函数platform_driver_register注册platform_driver。
Platform的初始化:start_kernel---> rest_init ---> kernel_thread(kernel_init,NULL, CLONE_FS | CLONE_SIGHAND) ---> do_basic_setup ---> driver_init---> platform_bus_init
int __init platform_bus_init(void)
{
interror;
early_platform_cleanup();
error= device_register(&platform_bus);
if(error)
returnerror;
error= bus_register(&platform_bus_type);
if(error)
device_unregister(&platform_bus);
returnerror;
}
Platform_device注册过程:
struct platform_device {
constchar * name;
int id;
structdevice dev;
u32 num_resources;
struct resource *resource;
structplatform_device_id *id_entry;
};
成员resource存入了最为重要的设备资源信息,定义在include/linux/ioport.h
/*
*Resources are tree-like, allowing
*nesting etc..
*/
struct resource {
resource_size_tstart;
resource_size_tend;
constchar *name;
unsignedlong flags;
structresource *parent, *sibling, *child;
};
下面以tq2440平台的dm9000驱动为例简单分析一下:
static struct platform_device*tq2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&s3c_device_rtc,
#ifdef CONFIG_DM9000
&s3c_device_dm9000,
#endif
&s3c_device_usbgadget,
&s3c_device_uda134x,
};
struct platform_device s3c_device_dm9000 ={
.name = "dm9000",
.id = 0,
.num_resources = ARRAY_SIZE(s3c_dm9k_resource),
.resource =s3c_dm9k_resource,
.dev = {
.platform_data= &s3c_dm9k_platdata,
}
};
//DM9000网卡使用的资源列表,0x20000000,0x20000004
static struct resource s3c_dm9k_resource[]= {
[0]= {
.start =S3C2410_CS4, // S3C2410_CS4:0x20000000(BANK4基地址)
.end = S3C2410_CS4 + 3,
.flags = IORESOURCE_MEM,
},
[1]= {
.start =S3C2410_CS4 + 4,
.end = S3C2410_CS4 + 4 + 3,
.flags = IORESOURCE_MEM,
},
[2]= {
.start =IRQ_EINT7, //连接 EINT7引脚
.end = IRQ_EINT7,
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
}
};
定义好设备之后就可以调用platform_device_add添加platform_device 到设备模型中,具体过程如下:
MACHINE_START(S3C2440, "TQ2440")
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18)& 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.init_irq = s3c24xx_init_irq,
.map_io = tq2440_map_io,
.init_machine = tq2440_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END
------>
platform_add_devices(tq2440_devices,ARRAY_SIZE(tq2440_devices));
添加tq2440_devices[]中定义的platform设备,按照数组的定义依次调用platform_device_register;最终调用platform_device_add把platform设备添加到设备模型。
int platform_device_add(structplatform_device *pdev)
{
inti, ret = 0;
if(!pdev)
return-EINVAL;
if(!pdev->dev.parent)
pdev->dev.parent= &platform_bus;
pdev->dev.bus= &platform_bus_type;
if(pdev->id != -1)
dev_set_name(&pdev->dev,"%s.%d", pdev->name, pdev->id); // 有多个同类设备,用pdev->name, pdev->id标识该设备。
else
dev_set_name(&pdev->dev,pdev->name); //只用pdev->name标识该设备
for(i = 0; i < pdev->num_resources; i++) {
structresource *p, *r = &pdev->resource[i];
if(r->name == NULL)
r->name= dev_name(&pdev->dev);
p= r->parent;
if(!p) {
if(resource_type(r) == IORESOURCE_MEM)
p= &iomem_resource; //作为IOMEM资源分配
elseif (resource_type(r) == IORESOURCE_IO)
p= &ioport_resource; //作为IOPORT资源分配
}
if(p && insert_resource(p, r)) {
printk(KERN_ERR
"%s: failed to claim resource%d\n",
dev_name(&pdev->dev), i);
ret= -EBUSY;
gotofailed;
}
}
pr_debug("Registeringplatform device '%s'. Parent at %s\n",
dev_name(&pdev->dev),dev_name(pdev->dev.parent));
ret= device_add(&pdev->dev); //添加设备到设备树
if(ret == 0)
returnret;
failed:
while(--i >= 0) {
structresource *r = &pdev->resource[i];
unsignedlong type = resource_type(r);
if(type == IORESOURCE_MEM || type == IORESOURCE_IO)
release_resource(r);
}
returnret;
}