platform_get_resource函数实现细节

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\n");

                   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_resource(pdev,IORESOURCE_IRQ,1);

可以定位第二份IORESOURCE_IRQ资源。

       之所以能定位到资源,在于函数实现中的这一行代码:

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

该行代码,如果没有匹配资源类型,num-- == 0不会执行而重新提取下一份资源,只有资源匹配了才会寻找该类型的第几份资源,即使这些资源排放不连续。

其中platform_device的资源,资源本身由 resource结构体描述,其定义如下:

resouce结构体定义

struct resource {
     resource_size_t start;
     resource_size_t end;
     const char *name;
     unsigned long flags;
     struct resource *parent, *sibling, *child;
};

我们通常关心start、end和flags这3个字段,分别标明资源的开始值、结束值和类型,flags可以为IORESOURCE_IO、 IORESOURCE_MEM、IORESOURCE_IRQ、IORESOURCE_DMA等。
start、end的含义会随着flags而变更,如当flags为IORESOURCE_MEM时,start、end分别表示该platform_device占据的内存的开始地址和结束地址;
当flags为IORESOURCE_IRQ时,start、end分别表示该platform_device使用的中断号的开始值和结束值,如果只使用了1个中断号,开始和结束值相同。
对于同种类型的资源而言,可以有多份,譬如说某设备占据了2个内存区域,则可以定义2个IORESOURCE_MEM资源。
resource的定义也通常在BSP的板文件中进行,而在具体的设备驱动中透过platform_get_resource()这样的API来获取,此API的原型为:

struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);


在aml_i2c的驱动中则是通过如下办法拿到这2份资源:

aml-i2c.c文件中aml_i2c_probe()函数中
i2c->master_no = plat->master_no;   /*master a:0 master b:1*/

/*master a or master b*/
res = platform_get_resource(pdev, IORESOURCE_MEM, i2c->master_no);   //通过下面可知master_no 为1,即master b

等价于下面两句:

xxx_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);   //master a
yyy_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);   //master b


对于IRQ而言,platform_get_resource()还有一个进行了封装的变体platform_get_irq(),其原型为:
int platform_get_irq(struct platform_device *dev, unsigned int num);
它实际上调用了“platform_get_resource(dev, IORESOURCE_IRQ, num);”。

设备除了可以在BSP中定义资源以外,还可以附加一些数据信息,因为对设备的硬件描述除了中断、内存、DMA通道以外,可能还会有一些配置信息,
而这些配置信息也依赖于板,不适宜直接放置在设备驱动本身,因此,platform也提供了platform_data的支持。platform_data 的形式是自定义的,
如对于aml-i2c而言,platform_data为一个aml_i2c_plat结构体,我们就可以将使用master a还是master b,i2c speed等信息放入platform_data:

static struct aml_i2c_platform aml_i2c_plat = {
 .wait_count  = 1000000,     // i2c wait ack timeout
 .wait_ack_interval = 5,
 .wait_read_interval = 5,
 .wait_xfer_interval = 5,
 .master_no  = AML_I2C_MASTER_B,    //AML_I2C_MASTER_B值为1  即master b
 .use_pio   = 0,           //0: hardware i2c, 1: manual pio i2c
 .master_i2c_speed = AML_I2C_SPPED_400K,  //AML_I2C_SLAVE_ADDR=0x6c

 .master_b_pinmux = {
  .scl_reg = MESON_I2C_MASTER_B_GPIOB_0_REG,
  .scl_bit = MESON_I2C_MASTER_B_GPIOB_0_BIT,
  .sda_reg = MESON_I2C_MASTER_B_GPIOB_1_REG,
  .sda_bit = MESON_I2C_MASTER_B_GPIOB_1_BIT,
 }
};

static struct platform_device aml_i2c_device = {
 .name    = "aml-i2c",
 .id    = -1,
 .num_resources   = ARRAY_SIZE(aml_i2c_resource),
 .resource   = aml_i2c_resource,
 .dev = {
  .platform_data = &aml_i2c_plat,
 },
};

而在aml-i2c的驱动中,通过如下方式就拿到了platform_data:
struct aml_i2c_platform *plat = pdev->dev.platform_data;
其中,pdev为platform_device的指针。

另, 在platform_device中的 .resource 也可以不定义而放在 .platform_data中自定义 .resource

你可能感兴趣的:(内存资源分配)