歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux驅動設備模型之Platform

[概述]

一個現實的Linux設備和驅動通常都需要掛接在一種總線上,對於本身依附於PCI、USB、IIC、SPI等的設備而言,這自然不是問題,但是在嵌入式系統中,SoC系統中集成的獨立的外設控制器,掛接在SoC內存空間的外設(IIC,RTC,SPI,LCD,看門狗)等卻不依附於此類總線。基於這一背景,Linux發明了一種虛擬的總線,稱為platform總線,相應的設備稱為platformdevice,而驅動稱為platform driver。

注意,所謂的platform device並不是與字符設備,塊設備和網絡設備並列的概念,而是Linux系統提供的一種附加手段。

[Platform的兩大好處]

1、使得設備被掛接在一個總線上,因此,符合Linux2.6的設備模型。其結果是,配套的sysfs節點、設備電源管理都成為可能;

2、 隔離BSP和驅動。在BSP中定義platform設備和設備使用的資源、設備的具體配置信息,而在驅動中,只需要通過通用的API去獲取資源和數據,做到了板相關代碼和驅動代碼的分離,使得驅動具有更好的可擴展性和跨平台性。

[platform_device& platform_driver]

  1. struct platform_device {  
  2.          constchar        * name;  /* 設備名www.linuxidc.com */  
  3.          int              id;     /* 設備ID */  
  4.          structdevice    dev;           /* 內嵌的設備結構體www.linuxidc.com */  
  5.          u32            num_resources;       /* 設備使用各類資源數量 */  
  6.          structresource        * resource;       /* 資源 */  
  7.    
  8.          structplatform_device_id       *id_entry;  
  9.    
  10.          /*arch specific additions */  
  11.          structpdev_archdata      archdata;  
  12. };  

Platform_device通常在BSP的板文件中實現,在板文件中,將platform_device歸納為一個數組,最終調用platform_add_device()函數統一注冊。

  1. struct resource {  
  2.          resource_size_tstart;  
  3.          resource_size_tend;  
  4.          constchar *name;  
  5.          unsignedlong flags;  
  6.          structresource *parent, *sibling, *child;  
  7. };  

Platform_device的資源由resource來描述,通常只要關心start、end、flags,分別表示開始值,結束值和類型。Start和end的含義會隨著flags而變更,當flags為IORESOURCE_MEM時,start和end分別表示該platform_device占據內存的開始地址和結束地址;當flags為IORESOURCE_IRQ時,start和end分別表示該platform_device使用的中斷號的開始值和結束值。

對resource的定義通常也在BSP的板文件中進行,而我們在設備驅動中可以用platform_get_resource()來獲取resource。

  1. struct platform_driver {  
  2.          int(*probe)(struct platform_device *);  
  3.          int(*remove)(struct platform_device *);  
  4.          void(*shutdown)(struct platform_device *);  
  5.          int(*suspend)(struct platform_device *, pm_message_t state);  
  6.          int(*resume)(struct platform_device *);  
  7.          structdevice_driver driver;  
  8.          structplatform_device_id *id_table;  
  9. };  

Platform_driver中包含了probe(),remove(),shutdown(),suspend(),resume()函數,通常是由驅動來實現。如果bus中定義了probe,remove,shutdown函數,會優先調用。

[platform_bus_type& 驅動和設備匹配方式]

  1. struct bus_type platform_bus_type = {  
  2.          .name                = "platform",  
  3.          .dev_attrs        = platform_dev_attrs,  
  4.          .match               = platform_match,  
  5.          .uevent              = platform_uevent,  
  6.          .pm           = &platform_dev_pm_ops,  
  7. };  

Platform總線並沒有對bus_type進行封裝,總線維護了兩條鏈klist_devices和klist_drivers(這兩條鏈表在成員subsys_private下):

Klist_devices 用來連接所有的platformdevice,調用platform_device_register函數時,會把設備掛接到klist_devices鏈表上;

Klist_drivers 用來連接所有的platformdriver,調用platform_driver_register函數時,會把驅動掛接到klist_drivers鏈表上。

驅動和設備通過match函數來進行匹配

  1. static int platform_match(struct device*dev, struct device_driver *drv)  
  2. {  
  3.          structplatform_device *pdev = to_platform_device(dev);  
  4.          structplatform_driver *pdrv = to_platform_driver(drv);  
  5.    
  6.          /*Attempt an OF style match first */  
  7.          if(of_driver_match_device(dev, drv))  
  8.                    return1;  
  9.    
  10.          /*Then try to match against the id table */  
  11.          if(pdrv->id_table)  
  12.                    returnplatform_match_id(pdrv->id_table, pdev) != NULL;  
  13.    
  14.          /*fall-back to driver name match */  
  15.          return(strcmp(pdev->name, drv->name) == 0);  
  16. }  
Copyright © Linux教程網 All Rights Reserved