platform_device與platform_driver


 通常編寫linux字符設備常接觸到的file_operations以及miscdevice,然后申請設備號,注冊字符設備,沒有涉及到設備驅動模型,而驅動模型里,device_driver根本沒有涉及到設備操作的函數、file_operations等,只有一些電源管理,熱插拔相關的函數。platform_device里也主要是resource的管理,所以感覺兩者根本就沒關系,也很奇怪為什么要弄兩套東西來實現,而且兩者也對應不起來。通過查閱業內長輩原文博客針對platform_device和platform_driver做了些摘錄批注。

platform_device與platform_driver一直分不清關系。在網上搜了下,做個總結。兩者的工作順序是先定義platform_device -> 注冊 platform_device->,再定義 platform_driver-> 注冊 platform_driver。

1)定義platform_device

2)注冊platform_device

3)定義platform_driver

4)注冊platform_driver

 (

函數編寫分步:

1)resource 

2)platform_device

3)static struct platform_device *smdk6410_devices[] __initdata = {...... &s3c_device_usbgadget, &s3c_device_usb, //jeff add.......}

  platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));

4)platform_driver

 

 

1◐ resource

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,  
     }  
}; 
 //編號有無上限,那么上限是多少?
 
 
2◐定義platform_device
 以上是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  
             }  
};  

 

 3◐注冊platform_device

有了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實現是:

 4◐定義platform_driver

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", 信息③
        },  
};  

 

  5◐注冊platform_driver

      在驅動初始化(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://www.cnblogs.com/Ph-one/p/4671593.html 

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

參考原文:http://blog.csdn.net/zhandoushi1982/article/details/5130207

博文出自:http://www.cnblogs.com/Ph-one/p/4762710.html

 

 

 

                                                      修改:

                                                      瘋耔 

                                                      2015/08/27

                                        


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM