platform_device與platform_driver

來源:互聯網
上載者:User

標籤:class   blog   code   http   tar   ext   

      做Linux方面也有三個多月了,對代碼中的有些結構一直不是非常明確,比方platform_device與platform_driver一直分不清關係。在網上搜了下,做個總結。兩者的工作順序是先定義platform_device -> 注冊 platform_device->,再定義 platform_driver-> 注冊 platform_driver。

 (1)platform_device裝置的注冊過程必須在對應裝置驅動載入之前被調用,由於驅動注冊時須要匹配核心中所以已注冊的裝置名稱。platform_device 是在系統啟動時在init.c 裡的s3c_arch_init() 函數裡進行注冊的。這個函數申明為arch_initcall(s3c_arch_init); 會在系統初始化階段被調用。arch_initcall 的優先順序高於module_init,所以會在Platform 驅動注冊之前調用。如今核心中不是採用arch_initcall(s3c_arch_init) 注冊platform_device 結構體而是通過.init_machine成員將其儲存在arch_initcall(customize_machine)等待調用(在mach-smdk6410.c中定義的MACHINE_START到MACHINE_END);事實上質是一樣的均放在.initcall3.init等待調用。之後再定義結構體struct platform_driver,在驅動初始化函數中調用函數platform_driver_register() 注冊 platform_driver。具體過程描寫敘述例如以下:

      Linux從2.6版本號碼開始引入了platform這個概念,在開發底層驅動程式時,首先要確認的就是裝置的資源資訊,在2.6核心中將每一個裝置的資源用結構platform_device來描寫敘述,該結構體定義在kernel/include/linux/platform_device.h中,

struct platform_device{      const char * name;      u32  id;      struct device dev;      u32  num_resources;      struct resource * resource;};


該結構一個重要的元素是resource,該元素存入了最為重要的裝置資源資訊,定義在kernel/include/linux/ioport.h中,
比方:

struct resource {       const char *name;       unsigned long start, end;       unsigned long flags;       struct resource *parent, *sibling, *child;};

實比如:

static struct resource s3c_usb_resource[] = { [0] = {       .start = S3C_PA_USBHOST,       .end   = S3C_PA_USBHOST + S3C_SZ_USBHOST - 1,       .flags = IORESOURCE_MEM,     }, [1] = {       .start = IRQ_UHOST,       .end   = IRQ_UHOST,       .flags = IORESOURCE_IRQ,     }};


以上是6410的USB  HOST分配的資源資訊。第1組描寫敘述了這個usb host裝置所佔用的匯流排位址範圍,起始地址和大小由硬體決定,IORESOURCE_MEM表示第1組描寫敘述的是記憶體類型的資源資訊;第2組描寫敘述了這個usb host裝置的中斷號,也由硬體設定,IORESOURCE_IRQ表示第2組描寫敘述的是中斷資源資訊。裝置驅動會依據flags來擷取對應的資源資訊。

      有了resource資訊,就能夠定義platform_device了:

struct platform_device s3c_device_usb = {         .name    = "s3c2410-ohci",  //s3c6410-usb         .id    = -1,         .num_resources   = ARRAY_SIZE(s3c_usb_resource),         .resource   = s3c_usb_resource,         .dev              = {                 .dma_mask = &s3c_device_usb_dmamask,                 .coherent_dma_mask = 0xffffffffUL             }};


有了platform_device就能夠調用函數platform_add_devices向系統中加入該裝置了。系統中的裝置資源都能夠採用這樣的方式列舉在一起,然後成一個指標數組,如:

static struct platform_device *smdk6410_devices[] __initdata = {

......

 &s3c_device_usbgadget,
 &s3c_device_usb,  //jeff add.

......

}

然後在6410的初始化函數smdk6410_machine_init()中運行:

platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));將全部的device加入進系統。platform_add_devices的優點在於它是一次性的運行多個platform_device_register。

(2) 至於驅動程式須要實現結構體struct platform_driver,也定義在kernel/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 pm_ext_ops *pm;      struct device_driver driver;};


則該處的USB HOST實現是:

static struct platform_driver ohci_hcd_s3c2410_driver = {     .probe  = ohci_hcd_s3c2410_drv_probe,     .remove  = ohci_hcd_s3c2410_drv_remove,     .shutdown = usb_hcd_platform_shutdown,     /*.suspend = ohci_hcd_s3c2410_drv_suspend, */     /*.resume = ohci_hcd_s3c2410_drv_resume, */     .driver  = {          .owner = THIS_MODULE,          .name = "s3c2410-ohci",        },};


      在驅動初始化(ohci-hcd.c的1124行)函數中調用函數platform_driver_register()注冊該platform_driver,須要注意的是s3c_device_usb結構中name元素和ohci_hcd_s3c2410_driver 結構中driver.name必須是同樣的,這樣在platform_driver_register()注冊時會對全部已注冊的platform_device中元素的name和當前注冊的platform_driver的driver.name進行比較,僅僅有找到具備同樣名稱的platform_device存在後,platform_driver才幹注冊成功。當注冊成功時會調用platform_driver結構元素probe函數指標,這裡就是ohci_hcd_s3c2410_drv_probe開始探測載入。platform driver中的函數都是以platform device作為參數進入。

(3)為什麼兩個name的名字必須匹配才幹實現device和driver的綁定?(1)在核心初始化時kernel_init()->do_basic_setup()->driver_init()->platform_bus_init()初始化platform_bus(虛擬匯流排);(2)裝置注冊的時候platform_device_register()->platform_device_add()->(pdev->dev.bus = &platform_bus_type)把裝置掛在虛擬platform bus下;(3)驅動注冊的時候platform_driver_register()->driver_register()->bus_add_driver()->driver_attach()->bus_for_each_dev(),對每一個掛在虛擬platform bus的裝置作__driver_attach()->driver_probe_device(),推斷drv->bus->match()是否存在而且是否運行成功,此時通過指標運行platform_match,比較strncmp(pdev->name, drv->name, BUS_ID_SIZE),假設相符就調用really_probe(實際就是啟動並執行對應裝置的platform_driver->probe(platform_device),注意platform_drv_probe的_dev參數是由bus_for_each_dev的next_device獲得)開始真正的探測載入,假設probe成功則綁定該裝置到該驅動。

      當進入probe函數後,須要擷取裝置的資源資訊,依據參數type所指定類型,比如IORESOURCE_MEM,來分別擷取指定的資源。
struct resource * platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);當然,也能夠固定資源類型,如擷取資源中的中斷號:struct int platform_get_irq(struct platform_device *dev, unsigned int num);

      probe函數一般完畢硬體裝置使能,struct resource的擷取以及虛擬位址的動態映射和詳細類型裝置的注冊(由於平台裝置僅僅是一種虛擬裝置類型);remove函數完畢硬體裝置的關閉,struct resource以及虛擬位址的動態映射的釋放和詳細類型裝置的登出。僅僅要和核心本身執行依賴性不大的外圍裝置 ( 換句話說僅僅要不在核心執行所需的一個最小系統之內的裝置 ), 相對獨立的擁有各自獨自的資源 (addresses and IRQs) ,都能夠用platform_driver 實現。如:lcd,usb,uart 等,都能夠用platfrom_driver 寫,而timer,irq等最小系統之內的裝置則最好不用platfrom_driver 機制,實際上核心實現也是這種。


 參考原文:http://blog.chinaunix.net/u1/49507/showart_494193.html

參考原文:http://blog.csdn.net/yd4330152763132/archive/2010/02/01/5275776.aspx

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.