• Linux 获取设备树源文件(DTS)里描述的资源【转】


    转自:http://www.linuxidc.com/Linux/2013-07/86839.htm

    转自:http://blog.sina.com.cn/s/blog_636a55070101mced.html

    在linux使用platform_driver_register() 注册  platform_driver 时, 需要在 platform_driver 的probe() 里面知道设备的中断号, 内存地址等资源。

    这些资源的描述信息存放在 resource 数据结构中, 相同的资源存放在一个树形树形数据结构中, 通过父节点, 兄弟节点, 子节点相连。 比如中断资源, IO端口资源, IO内存资源, DMA资源有不同资源树。

    Linux使用 struct resource 来描述一个resouce

    struct resource {
        resource_size_t start;      //资源范围的开始
        resource_size_t end;        //资源范围的结束
        const char *name;   //资源拥有者名
        unsigned long flags; //资源属性标识
        struct resource *parent, *sibling, *child;  //资源树的父节点, 兄弟节点, 字节点指针
    };

    resource_size_t 由系统决定 为uint32_t 或uint64_t 。
     

    在platform机制里, 使用platform_get_resource()来获取指定的资源类型。


    比如获取想获取中断号,


        irq = platform_get_irq(pdev, 0);
     
    int platform_get_irq(struct platform_device *dev, unsigned int num) 
    {
        struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);
     
        return r ? r->start : -ENXIO;
    }
    EXPORT_SYMBOL_GPL(platform_get_irq);    
                 

    platform_get_irq() 会返回一个start, 即可用的中断号。


    之后便可使用request_irq() 来注册中断服务函数。


    再比如想要获取IO内存资源:

    struct resource *res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);


    即可得到一个IO内存资源节点指针, 包括了地址的开始,结束地址等, 该IO内存的长度可用 resource_size() 来获取, 但这段资源只是一个描述, 想真正使用这段IO内存, 还要经过先申请, 再映射的过程。例如可使用devm_request_mem_region()申请出使用这段IO内存, 再使用ioremap() 将其映射出来, 供用户空间使用。

    devm_request_mem_region(&pdev->dev, res_mem->start, resource_size(res_mem),
                        res_mem->name))

    addr_start = ioremap(res_mem->start, resource_size(res_mem));


    ioremap() 的返回值即为该资源的虚拟地址。


    IO内存的资源是在设备树源(Device Tree Source)文件(以.dts结尾)里给出的,.dts文件就是用来描述目标板硬件信息的, 在uboot启动后, 使用uboot提供的特定API将其获取出来, 如fdt_getprop(), fdt_path_offset(), 这些API包含在uboot 的头文件<libfdt.h> 里面。
     
    uboot将.dts文件里的描述解析出来, 再对相应寄存器赋值, 在linux启动后, 使用  platform_get_resource() 即可获取到这些给定的资源, 在驱动里使用。


    例如一个在.dts文件中关于gpio资源的描述:

      gpio: gpio-controller@1070000000800 {
                #gpio-cells = <2>;
                compatible = "cavium,octeon-3860-gpio";
                reg = <0x10700 0x00000800 0x0 0x100>;

                gpio-controller;

    根据其描述, 可知道gpio控制器的IO内存起始地址为:0x107900000800, 长度为0x100.

    即从 0x107900000800 到 0x1079000008ff.

    在目标板里使用  cat /proc/iomem  可以看到:


    1070000000800-10700000008ff : /soc@0/gpio-controller@1070000000800


    关于i2c 的描述:

            twsi0: i2c@1180000001000 {
                #address-cells = <1>;
                #size-cells = <0>;
                compatible = "cavium,octeon-3860-twsi";
                reg = <0x11800 0x00001000 0x0 0x200>;

                interrupts = <0 45>;
                clock-rate = <100000>;

    IO内存起始地址为: 0x118000001000, 长度为0x200.

    从 0x118000001000 到 0x1180000011ff.

    在目标板里使用  cat /proc/iomem  可以看到:


    1180000001000-11800000011ff : /soc@0/i2c@1180000001000

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

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

    platform_get_resource函数源码如下:

    struct resource *platform_get_resource(struct platform_device *dev,

                                       unsigned int type, unsigned int num)

    {

           int i;

           for (i = 0; i < dev->num_resources; i++) {

                  struct resource *r = &dev->resource[i];

                  if (type == resource_type(r) && num-- == 0)

                         return r;

           }

           return NULL;

    }

    函数分析:

    struct resource *r = &dev->resource[i];

    这行代码使得不管你是想获取哪一份资源都从第一份资源开始搜索。

    if (type == resource_type(r) && num-- == 0)

    这行代码首先通过type == resource_type(r)判断当前这份资源的类型是否匹配,如果匹配则再通过num-- == 0判断是否是你要的,如果不匹配重新提取下一份资源而不会执行num-- == 0这一句代码。

    通过以上两步就能定位到你要找的资源了,接着把资源返回即可。如果都不匹配就返回NULL。

    实例分析:

    下面通过一个例子来看看它是如何拿到设备资源的。

    设备资源如下:

    static struct resource s3c_buttons_resource[] = {

           [0]={

                  .start = S3C24XX_PA_GPIO,

                  .end   = S3C24XX_PA_GPIO + S3C24XX_SZ_GPIO - 1,

                  .flags = IORESOURCE_MEM,

           },

           [1]={

                  .start = IRQ_EINT8,

                  .end   = IRQ_EINT8,

                  .flags = IORESOURCE_IRQ,

           },

           [2]={

                  .start = IRQ_EINT11,

                  .end   = IRQ_EINT11,

                  .flags = IORESOURCE_IRQ,

           },

           [3]={

                  .start = IRQ_EINT13,

                  .end   = IRQ_EINT13,

                  .flags = IORESOURCE_IRQ,

           },

           [4]={

                  .start = IRQ_EINT14,

                  .end   = IRQ_EINT14,

                  .flags = IORESOURCE_IRQ,

           },

           [5]={

                  .start = IRQ_EINT15,

                  .end   = IRQ_EINT15,

                  .flags = IORESOURCE_IRQ,

           },

           [6]={

                  .start = IRQ_EINT19,

                  .end   = IRQ_EINT19,

                  .flags = IORESOURCE_IRQ,

           }

    };

    驱动中通过下面代码拿到第一份资源:

    struct resource *res;

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

    函数进入for里面,i=0,num_resources=7,拿出resource[0]资源。resource_type(r)提取出该份资源 的资源类型并与函数传递下来的资源类型进行比较,匹配。Num=0(这里先判断是否等于0再自减1)符合要求,从而返回该资源。

    获取剩下资源的代码如下:

    for(i=0; i<6; i++){

                  buttons_irq = platform_get_resource(pdev,IORESOURCE_IRQ,i);

                 if(buttons_irq == NULL){

                      dev_err(dev,"no irq resource specified ");

                       ret = -ENOENT;

                       goto err_map;

                  }

                  button_irqs[i] = buttons_irq->start; 

    }

    分析如下:

    For第一次循环:

    buttons_irq = platform_get_resource(pdev,IORESOURCE_IRQ,0);

    在拿出第一份资源进行resource_type(r)判断资源类型时不符合(此时num-- == 0这句没有执行),进而拿出第二份资源,此时i=1,num_resources=7,num传递下来为0,资源类型判断时候匹配,num也等于0,从而确定资源并返回。

    For第二次循环:

    buttons_irq = platform_get_resource(pdev,IORESOURCE_IRQ,1);

    拿出第二份资源的时候resource_type(r)资源类型匹配,但是num传递下来时候为1,执行num-- == 0时不符合(但num开始自减1,这导致拿出第三份资源时num==0),只好拿出第三份资源。剩下的以此类推。

    总结:

    struct resource *platform_get_resource(struct platform_device *dev,

                                       unsigned int type, unsigned int num)

    unsigned int type决定资源的类型,unsigned int num决定type类型的第几份资源(从0开始)。即使同类型资源在资源数组中不是连续排放也可以定位得到该资源。

    比如第一份IORESOURCE_IRQ类型资源在resource[2],而第二份在resource[5],那

    platform_get_resource(pdev,IORESOURCE_IRQ,0);

    可以定位第一份IORESOURCE_IRQ资源;

    platform_get_resourc

  • 相关阅读:
    Entity SQL 初入
    ObjectQuery查询及方法
    Entity Framework 的事务 DbTransaction
    Construct Binary Tree from Preorder and Inorder Traversal
    Reverse Linked List
    Best Time to Buy and Sell Stock
    Remove Duplicates from Sorted Array II
    Reverse Integer
    Implement Stack using Queues
    C++中const限定符的应用
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/4800848.html
Copyright © 2020-2023  润新知