platform_device结构体描述设备的名称、资源信息等。该结构被定include/linux/platform_device.h中, 定义的结构体原型如下:
struct platform_device {
const char * name; //定义平台设备的名称
int id;
struct device dev;
u32 num_resources;
struct resource * resource; //定义平台设备的资源。
};
最重要的一个成员struct resource * resource。struct resource被定义在include/linux/ioport.h中,定义原型如下:
struct resource {
resource_size_t start; //定义资源的起始地址
resource_size_t end; //定义资源的结束地址
const char *name; //定义资源的名称
unsigned long flags; //定义资源的类型,比如MEM,IO,IRQ,DMA类型
struct resource *parent, *sibling, *child; //资源链表指针
};
以RTC驱动为例(为什么用RTC,RTC是一个标准的plartform device,机制是相同的,但是相对比较简单)
在arch/
ARM/mach-sep4020/devices.c中加入rtc的plartform_device结构体和resources结构体:
static struct resource sep4020_rtc_resource[] = {
[0] = { .start = RTC_BASE_V,
.end = RTC_BASE_V+ 0x2f,
.flags = IORESOURCE_MEM,
}
[1] = {
.start = INTSRC_RTC,
.end = INTSRC_RTC,
.flags = IORESOURCE_IRQ,
}
};
struct platform_device sep4020_device_rtc = {
.name = "sep4020_rtc",
.id = -1,
.num_resources = ARRAY_SIZE(sep4020_rtc_resource),
.resource = sep4020_rtc_resource,
};
然后再通过4020.c文件中的__initdata设备数组将这个plartform_device结构体注册进去了:
static struct platform_device *devices[] __initdata = {
&serial_device,
&sep4020_device_rtc,
&epson_ohci_device,
&sep4020_device_u***gadget
};
platform_add_devices(devices, ARRAY_SIZE(devices)); 通过调用platform_add_devices()向系统中添加该设备了,
该函数内部调用platform_device_register( )进行设备注册。要注意的是,这里的platform_device设备的注册过程必须在相应设备驱动加载之前被调用,即执行platform_driver_register()之前,原因是驱动注册时需要匹配内核中所有已注册的设备名。(后面会详细介绍device和driver之间是如何通过注册的名字进行连接的)
platform_driver简介
platform_driver结构体的原型定义,在include/linux/platform_device.h中,代码如下:
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*suspend_late)(struct platform_device *, pm_message_t state);
int (*resume_early)(struct platform_device *);
int (*resume)(struct platform_device *);
struct device_driver driver;
};
内核提供的platform_driver结构体的注册函数为platform_driver_register(),
其原型定义在driver/base/platform.c文件中,具体实现代码如下:
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);
}
总结,通常情况下只要和内核本身运行依赖性不大的外围设备,相对独立的,拥有各自独自的资源(地址总线和IRQs),都可以用platform_driver实现。如:LCD,网卡、USB、UART等,都可以用platfrom_driver写,而timer,irq等小系统之内的设备则最好不用platfrom_driver机制。