gdt-A20

导航

linux设备模型之platform

===============================
本文系本站原创,欢迎转载!
转载请注明出处: http://www.cnblogs.com/gdt-a20

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

      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;
   }
 

三、platform_driver的注册

      driver部分比较简单,其结构为:

            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 (*resume)(struct platform_device *);
                      struct device_driver driver;                                             //内嵌的标准driver结构           
                      const struct platform_device_id *id_table;                       //支持的设备id表
             };

  注册函数分析:

  int platform_driver_register(struct platform_driver *drv)
  {
                      drv->driver.bus = &platform_bus_type;                          //设置bus
                      if (drv->probe)                                                             //如果platform_driver下的probe为真,就把内嵌
                                drv->driver.probe = platform_drv_probe;               //的标准driver的probe设置成platform_drv_probe
                      if (drv->remove)                                                           //可见外层的probe比内层的优先级别高
                                drv->driver.remove = platform_drv_remove;
                      if (drv->shutdown)
                                 drv->driver.shutdown = platform_drv_shutdown;

                      return driver_register(&drv->driver);                               //注册标准driver
  }

四、总结

       分析了platform架构以及初始化以及注册流程,结合前面关于标注模型的理解,理解这部分,应当很简单!  ^_^

posted on 2011-05-18 14:18  gdt-A20  阅读(1660)  评论(0编辑  收藏  举报