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的指針。

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