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

Linux設備模型之platform

 platform可以說是內核抽象出來的一條虛擬總線平台,內核開發者原意是想把硬件層次上的結構關系用軟件抽象模擬出來,但是對一些硬件,這樣做往往不太合適,例如對於片上soc,外圍設備的控制器都集成在處理器上,如果過度的剝離抽象,會使得原本物理上緊密的結構而在軟件上變成的偏於獨立,因此有了platform,對於聯系緊密的soc這往往再合適不過,另外對於從soc上直接引出的引腳,難於獨立出來,都可以利用platform來表述。

      有了前面關於bus,driver,device的理解,platform平台的理解就比較簡單,都是以前面為原型進行的再次封裝,好了下面就讓我們以具體代碼為例進行分析。

一、platform的初始化

     platform的初始化代碼位於driver/base目錄下的platform.c

 

  int __init platform_bus_init(void)
{
    int error;

    early_platform_cleanup();                               //
清除platform設備鏈表

    error = device_register(&platform_bus);           //將平台bus作為一個設備注冊,出現在device目錄
    if (error)
        return error;
    error =  bus_register(&platform_bus_type);     
//注冊平台類型的bus,將出現在bus目錄下
    if (error)
        device_unregister(&platform_bus);
    return error;
}

來看一下 early_platform_cleanup() 這個函數:

void __init early_platform_cleanup(void)
{
         struct platform_device *pd, *pd2;

        /* clean up the devres list used to chain devices */

        /*       遍歷early_platform_device_list,把連接到此的所有節點清0,

            平台設備都會掛到該節點,現在是平台設備的初始化階段,自然不

            能有連接到此的設備                                                                */
       
l ist_for_each_entry_safe(pd, pd2, &early_platform_device_list, 
                 dev.devres_head) {                                                       
        list_del(&pd->dev.devres_head);                                      
        memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
       }

}

再來看一下另外兩個結構體:

struct device platform_bus = {
    .init_name    = "platform",
};

以及

struct bus_type platform_bus_type = {
    .name        = "platform",
    .dev_attrs    = platform_dev_attrs,
    .match        = platform_match,
    .uevent        = platform_uevent,
    .pm        = &platform_dev_pm_ops,
};

 

二、platform_device的注冊

     platform_device無疑是device的封裝,先給出該結構具體代碼:

 

    struct platform_device {
               const char    * name;                              //名稱
               int        id;                                             //id號
               struct device    dev;                                //內嵌的標准模型device
               u32        num_resources;                       //持有資源數
               struct resource    * resource;                 //指向具體資源

               const struct platform_device_id    *id_entry;           

               /* arch specific additions */
               struct pdev_archdata    archdata;
   }; 
  

    其中的資源結構體代碼為:

    struct resource {
           resource_size_t start;                                         //資源起始地址,可以是寄存器起始地址等等
           resource_size_t end;                                          //結束地址
           const char *name;                                              //名稱
           unsigned long flags;                                            //標志
           struct resource *parent, *sibling, *child;                //層次級聯結構指針
    };
     

   具體的注冊函數為:

 

       int platform_device_register(struct platform_device *pdev)
      {
                    device_initialize(&pdev->dev);                          //和標准設備注冊時候初始化是一樣,就不多說了,

                    return platform_device_add(pdev);                    // 不明白的可以看 前面一篇文章 具,體看一下這個
      }

===================================================

     int platform_device_add(struct platform_device *pdev)
    {
                   int i, ret = 0;
                   if (!pdev)
                               return -EINVAL;
                   if (!pdev->dev.parent)
                               pdev->dev.parent = &platform_bus;                  //掛接到platform_bus下面
                   pdev->dev.bus = &platform_bus_type;                          //指定bus類型為platform_bus_type
                   if (pdev->id != -1)
                               dev_set_name(&pdev->dev, "%s.%d",

                                                   pdev->name,  pdev->id);              //設置名字,將platform下的名字傳到內部device,最終會
                   else                                                                          //傳到kobj
                               dev_set_name(&pdev->dev, "%s", pdev->name);
                    for (i = 0; i < pdev->num_resources; i++) {                   //設置資源層次結構
                                struct resource *p, *r = &pdev->resource[i];
                                if (r->name == NULL)                                     //資源名稱為NULL則把設備名稱設置給它
                                                   r->name = dev_name(&pdev->dev);
                                p = r->parent;                                                //取得資源的父節點,資源在內核中也是層次安排的,
                                if (!p) {                                                           //具有父節點,兄弟節點,子節點
                                                   if (resource_type(r) == IORESOURCE_MEM)       //如果父節點為NULL,並且資源類型為
                                                                p = &iomem_resource;                          //IORESOURCE_MEM,則把父節點設置

                                                                                                                           //為iomem_resource,否則如果類型為
                                                   else if (resource_type(r) == IORESOURCE_IO)     //IORESOURCE_IO,則把父節點設置為

                                                                p = &ioport_resource;                            //IORESOURCE_IO,由此我們可以看出
                                }                                                                                          //內核數據之間的條理性之強
                               if (p && insert_resource(p, r)) {                       //將資源插入父節點,也就是出現在父節點目錄層次下
                                                  printk(KERN_ERR"%s: failed to claim resource %d/n",
                                                            dev_name(&pdev->dev), i);

                                                 ret = -EBUSY;
                                                 goto failed;
                               }
                      }
                      pr_debug("Registering platform device '%s'. Parent at %s/n",
                      dev_name(&pdev->dev), dev_name(pdev->dev.parent));
                      ret = device_add(&pdev->dev);                                //標准設備注冊
                      if (ret == 0)
                               return ret;
    failed:
               while (--i >= 0) {
                       struct resource *r = &pdev->resource[i];
                       unsigned long type = resource_type(r);
                       if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
                                release_resource(r);
               }
                return ret;
   }  

Copyright © Linux教程網 All Rights Reserved