platform框架

1.platform_device结构体

struct platform_device {
const char * name;/* 设备名 */
u32 id;
struct device dev;
u32 num_resources;/* 设备所使用各类资源数量 */
struct resource * resource;/* 资源 */
};
设备的分配:
struct platform_device *platform_device_alloc(const char *name, int id); //name:设备名,id:设备
id,一般为-1 
设备的注册:
int platform_device_add(struct platform_device *pdev); 
对platform_device的定义通常在BSP的板文件中实现,在板文件中,将platform_device归纳
为一个数组:
static struct platform_device *smdk2410_devices[] __initdata = { 
&s3c_device_usb, 
&s3c_device_lcd, 
&s3c_device_wdt, 
&s3c_device_i2c0, 
&s3c_device_iis, 
}; 
最终通过 platform_add_devices()函数统一注册:
static void __init smdk2410_init(void) 
{ 
s3c_i2c0_set_platdata(NULL); 
platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices)); 
smdk_machine_init(); 
} 
platform_add_devices()函数可以将平台设备添加到系统中,这个函数的 原型为:
int platform_add_devices(struct platform_device **devs, int num);
该函数的第一个参数为平台设备数组的指针,第二个参数为平台设备的数量,它内部调用了
platform_device_register()函 数用于注册单个的平台设备。
2.platform_driver包含具体的操作函数,通常需要由驱动实现:
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 (*resume)(struct platform_device *);
struct device_driver driver;
};
看看驱动是怎么注册进去的:
int platform_driver_register(struct platform_driver *drv) 
{ 
。。。 
return driver_register(&drv->driver); 
} 
int driver_register(struct device_driver *drv) 
{ 
。。。。 
ret = bus_add_driver(drv); 
。。。 
} 
int bus_add_driver(struct device_driver *drv) 
{ 
。。。 
if (drv->bus->p->drivers_autoprobe) { 
error = driver_attach(drv); 
if (error) 
goto out_unregister; 
} 
。。。 
} 
int driver_attach(struct device_driver *drv) 
{ 
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); 
} 
来看__driver_attach这个函数,其中分别调用了driver_match_device,driver_probe_device函数。
static int __driver_attach(struct device *dev, void *data) 
{ 
struct device_driver *drv = data; 
if (!driver_match_device(drv, dev)) 
return 0; 
if (dev->parent) 
down(&dev->parent->sem); 
down(&dev->sem); 
if (!dev->driver) 
driver_probe_device(drv, dev)
up(&dev->sem); 
if (dev->parent) 
up(&dev->parent->sem); 

return 0; 
}
匹配的时候调用的bus的match函数。匹配成功后调用驱动的probe函数。
int driver_probe_device(struct device_driver *drv, struct device *dev) 
{ 
。。。 
ret = really_probe(dev, drv); 
。。。 
} 
static int really_probe(struct device *dev, struct device_driver *drv) 
{ 
。。。 
int driver_probe_device(struct device_driver *drv, struct device *dev) 
{ 
。。。 
ret = really_probe(dev, drv); 
。。。 
} 
static int really_probe(struct device *dev, struct device_driver *drv) 
{ 
。。。 
if (dev->bus->probe) { 
ret = dev->bus->probe(dev); 
if (ret) 
goto probe_failed; 
} else if (drv->probe) { 
ret = drv->probe(dev); 
if (ret) 
goto probe_failed; 
} 
。。。 
} 
由relly_probe函数可以看出,如果bus定义了probe函数,则调用bus的probe
函数;如果bus,没有定义而driver定义了probe函数,则调用driver的probe
函数。

3.bus_type类型的platform_bus_type
(1)基本结构
struct bus_type platform_bus_type = {
name = “platform”,
dev_attrs = platform_dev_attrs,
match = platform_match,
uevent = platform_uevent,
pm = PLATFORM_PM_OPS_PTR,
};
EXPORT_SYMBOL_GPL(platform_bus_type);
(2)match()表明了platform_device和platform_driver之间如何匹配
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev; 
pdev = container_of(dev, struct platform_device, dev); 
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0); 
}
匹配platform_device和platform_driver主要看二者的name字段是否相同
(3)总线初始化
platform_bus_type是在系统初始化的时候初始化的,不用我们做什么工作:
.int __init platform_bus_init(void) 
{ 
int error; 
early_platform_cleanup(); 
error = device_register(&platform_bus); 
if (error) 
return error; 
error = bus_register(&platform_bus_type); 
if (error) 
device_unregister(&platform_bus); 
return error; 
} 
4.设备中的资源
flags可以为IORESOURCE_IO、 IORESOURCE_MEM、IORESOURCE_IRQ、IORESOURCE_DMA等
static struct resource ldd6410_dm9000_resource[] = {
[0] = {
.start = 0×18000000,
.end = 0×18000000 + 3,
.flags = IORESOURCE_MEM
},
[1] = {
.start = IRQ_EINT(7),
.end = IRQ_EINT(7),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
}
};
获取资源:
db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5.plat_data
对设备的硬件描述除了中断、内存、DMA通道以外,可能还会有一些配置信 
息,而 这些配置信息也依赖于板,不适宜直接放置在设备驱动本身,因此,
platform也提供了platform_data的支持。例如:
static struct dm9000_plat_data ldd6410_dm9000_platdata = {
.flags = DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM,
.dev_addr = { 0×0, 0×16, 0xd4, 0×9f, 0xed, 0xa4 },
};
static struct platform_device ldd6410_dm9000 = {
.name = “dm9000″,
.id = 0,
.num_resources = ARRAY_SIZE(ldd6410_dm9000_resource),
.resource = ldd6410_dm9000_resource,
.dev = {
.platform_data = &ldd6410_dm9000_platdata,
}
};
获取plat_data:
struct dm9000_plat_data *pdata = pdev->dev.platform_data;
其中,pdev为platform_device的指针。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章