platform機制將設備本身的資源註冊進內核,由內核統一管理,在驅動程序中使用這些資源時通過platform device提供的標準接口進行申請並使用。這樣提高了驅動和資源管理的獨立性,這樣擁有更好的可移植性。platform機制的本身使用並不複雜,由兩部分組成:platform_device和platfrom_driver。Platform driver通過platform bus獲取platform_device。
通常情況下只要和內核本身運行依賴性不大的外圍設備,相對獨立的,擁有各自獨立的資源(地址總線和IRQs),都可以用 platform_driver來管理,而timer,irq等小系統之內的設備則最好不用platfrom_driver機制。
platform_device最大的特定是CPU直接尋址設備的寄存器空間,即使對於其他總線設備,設備本身的寄存器無法通過CPU總線訪問,但總線的controller仍然需要通過platform bus來管理。
總之,platfrom_driver的根本目的是爲了統一管理系統的外設資源,爲驅動程序提供統一的接口來訪問系統資源,將驅動和資源分離,提高程序的可移植性。
2、 基於platform總線的驅動開發流程
基於Platform總線的驅動開發流程如下:
• 定義初始化platform bus
• 定義各種platform devices
• 註冊各種platform devices
• 定義相關platform driver
• 註冊相關platform driver
• 操作相關設備
Linux系統中許多部分對設備是如何鏈接的並不感興趣,但是他們需要知道哪些類型的設備是可以使用的。設備模型提供了一種機制來對設備進行分類,在更高的功能層面上描述這些設備,並使得這些設備對用戶空間可見。因此從2.6內核開始引入了設備模型。
總線是處理器和一個或多個設備之間的通道,在設備模型中, 所有的設備都通過總線相連。總線可以相互插入。設備模型展示了總線和它們所控制的設備之間的實際連接。
Platform總線是2.6 kernel中最近引入的一種虛擬總線,主要用來管理CPU的片上資源,具有更好的移植性,因此在2.6 kernel中,很多驅動都用platform改寫了。
platform_bus_type的定義如下:
- http://lxr.linux.no/#linux+v2.6.25/drivers/base/platform.c#L609
- 609struct bus_type platform_bus_type = {
- 610 .name = "platform",
- 611 .dev_attrs = platform_dev_attrs,
- 612 .match = platform_match,
- 613 .uevent = platform_uevent,
- 614 .suspend = platform_suspend,
- 615 .suspend_late = platform_suspend_late,
- 616 .resume_early = platform_resume_early,
- 617 .resume = platform_resume,
- 618};
- 619EXPORT_SYMBOL_GPL(platform_bus_type);
- http://lxr.linux.no/#linux+v2.6.25/include/linux/device.h#L55
- 55struct bus_type {
- 56 const char *name;
- 57 struct bus_attribute *bus_attrs;
- 58 struct device_attribute *dev_attrs;
- 59 struct driver_attribute *drv_attrs;
- 60
- 61 int (*match)(struct device *dev, struct device_driver *drv);
- 62 int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
- 63 int (*probe)(struct device *dev);
- 64 int (*remove)(struct device *dev);
- 65 void (*shutdown)(struct device *dev);
- 66
- 67 int (*suspend)(struct device *dev, pm_message_t state);
- 68 int (*suspend_late)(struct device *dev, pm_message_t state);
- 69 int (*resume_early)(struct device *dev);
- 70 int (*resume)(struct device *dev);
- 71
- 72 struct bus_type_private *p;
- 73};
總線bus是聯繫driver和device的中間樞紐。Device通過所屬的bus找到driver,由match操作方法進行匹配。
在數據結構設計上,總線、設備及驅動三者相互關聯。
platform device包含device,根據device可以獲得相應的bus及driver。
設備添加到總線上後形成一個雙向循環鏈表,根據總線可以獲得其上掛接的所有device,進而獲得了 platform device。根據device也可以獲得驅動該總線上所有設備的相關driver。
platform driver包含driver,根據driver可以獲得相應的bus,進而獲得bus上所有的device,進一步獲得platform device,根據name對driver與platform device進行匹配,匹配成功後將device與相應的driver關聯起來,即實現了platform device和platform driver的關聯。
匹配成功後調用driver的probe進而調用platform driver的probe,在probe裏實現驅動特定的功能。
Plarform device會有一個名字用於driver binding(在註冊driver的時候會查找driver的目標設備的bus位置,這個過程稱爲driver binding),另外IRQ以及地址空間等資源也要給出 。
platform_device結構體用來描述設備的名稱、資源信息等。該結構被定義在http://lxr.linux.no/#linux+v2.6.25/include/linux/platform_device.h#L16中,定義原型如下:
- struct platform_device
{
- const char
* name; //定義平臺設備的名稱,此處設備的命名應和相應驅動程序命名一致
- int id;
- struct device dev;
- u32 num_resources;
- struct resource * resource;
//定義平臺設備的資源
- };
下面來看一下platform_device結構體中最重要的一個成員struct resource * resource。struct resource被定義在http://lxr.linux.no/#linux+v2.6.25/include/linux/ioport.h#L18中,定義原型如下:
- 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;
- };
- int device_register(struct device
*dev)
- {
- device_initialize(dev);
- return device_add(dev);
- }
- //初始化一個設備,然後加入到系統中
- int platform_device_register(struct platform_device
*pdev)
- {
- device_initialize(&pdev->dev);
- return platform_device_add(pdev);
- }
- EXPORT_SYMBOL_GPL(platform_device_register);
另外一種機制就是動態申請platform_device_alloc一個platform_device設備,然後通過platform_device_add_resources及platform_device_add_data等添加相關資源和屬性。
無論哪一種platform_device,最終都將通過platform_device_add這冊到platform總線上。
device_register()和platform_device_register()都會首先初始化設備
區別在於第二步:其實platform_device_add()包括device_add(),不過要先註冊resources,然後將設備掛接到特定的platform總線。
Platform device是一種device自己是不會做事情的,要有人爲它做事情,那就是platform driver。platform driver遵循linux系統的driver model。對於device的discovery/enumerate都不是driver自己完成的而是由由系統的driver註冊機制完成。driver編寫人員只要將註冊必須的數據結構初始化並調用註冊driver的kernel API就可以了。
接下來來看platform_driver結構體的原型定義,在http://lxr.linux.no/#linux+v2.6.25/include/linux/platform_device.h#L48中,代碼如下:
- 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;
- };
可見,它包含了設備操作的幾個功能函數,同時包含了一個device_driver結構,說明device_driver是platform_driver的基類。驅動程序中需要初始化這個變量。下面看一下這個變量的定義,位於http://lxr.linux.no/#linux+v2.6.25/include/linux/device.h#L121中:
- struct device_driver
{
- const char
*name;
- struct bus_type *bus;
- struct module *owner;
- const char
*mod_name;
/* used for built-in modules
*/
- int
(*probe)
(struct device *dev);
- int (*remove)
(struct device *dev);
- void (*shutdown)
(struct device *dev);
- int (*suspend)
(struct device *dev, pm_message_t state);
- int (*resume)
(struct device *dev);
- struct attribute_group **groups;
- struct driver_private *p;
- };
需要注意這兩個變量:name和owner。其作用主要是爲了和相關的platform_device關聯起來,owner的作用是說明模塊的所有者,驅動程序中一般初始化爲THIS_MODULE。
device_driver結構中也有一個name變量。platform_driver從字面上來看就知道是設備驅動。設備驅動是爲誰服務的呢?當然是設備了。內核正是通過這個一致性來爲驅動程序找到資源,即 platform_device中的resource。
內核提供的platform_driver結構體的註冊函數爲platform_driver_register(),其原型定義在http://lxr.linux.no/#linux+v2.6.25/drivers/base/platform.c#L458文件中,具體實現代碼如下:
- int platform_driver_register(struct platform_driver
*drv)
- {
- drv->driver.bus
= &platform_bus_type;
- /*設置成platform_bus_type這個很重要,因爲driver和device是通過bus聯繫在一起的,具體在本例中是通過 platform_bus_type中註冊的回調例程和屬性來是實現的, driver與device的匹配就是通過 platform_bus_type註冊的回調例程platform_match
()來完成的。*/
- if (drv->probe)
- drv->driver.probe
= platform_drv_probe;
- //在really_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);
- }
- EXPORT_SYMBOL_GPL(platform_driver_register);
device_driver提供了一些操作接口,但其並沒有實現,相當於一些虛函數,由派生類platform_driver進行重載,無論何種類型的driver都是基於device_driver派生而來的,device_driver中具體的各種操作都是基於統一的基類接口的,這樣就實現了面向對象的設計。
更詳細的請看:http://blog.csdn.net/sailor_8318/article/details/5267698