request_mem_region粗略讲解

linux request_mem_region 的粗略理解

文章来源 : http : //gliethttp.cublog.cn

  Linux 把基于I/O 映射方式的I/O 端口和基于内存映射方式的I/O 端口资源统称为“I/O 区域I/O Region )。I/O Region 仍然是一种I/O 资源,因此它仍然可以用resource 结构类型来描述。

  Linux 是以一种倒置的树形结构来管理每一类I/O 资源(如:I/O 端口、外设内存、DMAIRQ )的。每一类I/O 资源都对应有一颗倒置的资源树,树中的每一个节点都是一个resource 结构,而树的根结点root 则描述了该类资源的整个资源空间。


1 . 结构体
  1 . 1 > struct resource iomem_resource = { "PCI mem" , 0x00000000 , 0xffffffff , IORESOURCE_MEM };
  1 . 2 > struct resource {
                 const char * name ;
                 unsigned long start , end ;
                 unsigned long flags ;
                 struct resource * parent , * sibling , * child ;
              };
2 . 调用函数
  request_mem_region ( S1D_PHYSICAL_REG_ADDR , S1D_PHYSICAL_REG_SIZE , "EpsonFB_RG" )
# define request_mem_region ( start , n , name ) __request_region (& iomem_resource , ( start ), ( n ), ( name ))
__request_region 检查是否可以安全占用起始物理地址S1D_PHYSICAL_REG_ADDR 之后的连续S1D_PHYSICAL_REG_SIZE 字节大小空间

struct resource * __request_region ( struct resource * parent , unsigned long start , unsigned long n , const char * name )
{
     struct resource * res = kmalloc ( sizeof (* res ), GFP_KERNEL );

     if ( res ) {
         memset ( res , 0 , sizeof (* res ));
        res -> name = name ;
        res -> start = start ;
        res -> end = start + n - 1 ;
        res -> flags = IORESOURCE_BUSY ;

        write_lock (& resource_lock );

         for (;;) {
             struct resource * conflict ;

            conflict = __request_resource ( parent , res );      //sibling parent 下的所有单元, 检测申请部分是否存在交叠冲突
             if (! conflict )                                 //conflict=0; 申请成功, 正常安置了[start,end] 到相应位置
                 break ;
             if ( conflict != parent ) {
                parent = conflict ;
                 if (!( conflict -> flags & IORESOURCE_BUSY ))
                     continue ;
             }
             kfree ( res );                                     // 检测到了资源交叠冲突,kfree 归还kmalloc 申请的内存
            res = NULL ;
             break ;
         }
        write_unlock (& resource_lock );
     }
     return res ;
}

static struct resource * __request_resource ( struct resource * root , struct resource * new )
{
     unsigned long start = new -> start ;
     unsigned long end = new -> end ;
     struct resource * tmp , ** p ;

     if ( end < start )
         return root ;
     if ( start < root -> start )
         return root ;
     if ( end > root -> end )
         return root ;
    p = & root -> child ;                                       //root 下的第一个链表元素*p.[child 链表是以I/O 资源物理地址从低到高的顺序排列的]
     for (;;) {
        tmp = * p ;
         if (! tmp || tmp -> start > end ) {
             new -> sibling = tmp ;
             * p = new ;
// 可以从root->child=null 开始我们的分析考虑, 此时tmp=null, 那么第一个申请将以!tmp 条件满足而进入
// 这时root->child 的值为new 指针,new->sibling = tmp = null; 当第二次申请发生时: 如果tmp->start > end 成立,
// 那么,root->child 的值为new 指针,new->sibling = tmp; 这样就链接上了,空间分布图如:
//child=[start,end]-->[tmp->start,tmp->end](1); 如果条件tmp->start > end 不成立,那么只能是!tmp 条件进入
// 那么,root->child 的值不变,tmp->sibling = new;new->sibling = tmp = null 这样就链接上了,空间分布图如:
//child=[child->start,child->end]-->[start,end](2);
// 当第三次申请发生时: 如果start(2) 中的[child->end,end] 之间, 那么tmp->end < start 将成立, 继而continue,
// 此时tmp = (2) 中的[start,end], 因为tmp->start < end, 所以继续执行p = &tmp->slibing = null,
// 因为tmp->end > start, 所以资源冲突, 返回(2) 中的[start,end]
// 综上的两个边界值情况和一个中间值情况的分析, 可以知道代码实现了一个从地地址到高地址的顺序链表
// 模型图:childe=[a,b]-->[c,d]-->[e,f], 此时有一个[x,y] 需要插入进去,tmp 作为sibling 指针游动
//tmp 指向child=[a,b],
//tmp 指向[a,b],tmp->start>y, 插入后的链接图为:child=[x,y]-->[a,b]-->[c,d]-->[e,f]-->null;tmp->end>=x, 冲突返回tmp
//tmp 指向[c,d],tmp->start>y, 插入后的链接图为:child=[a,b]-->[x,y]-->[c,d]-->[e,f]-->null;tmp->end>=x, 冲突返回tmp
//tmp 指向[e,f],tmp->start>y, 插入后的链接图为:child=[a,b]-->[c,d]-->[x,y]-->[e,f]-->null;tmp->end>=x, 冲突返回tmp
//tmp 指向null                  , 插入后的链接图为:child=[a,b]-->[c,d]-->[e,f]-->[x,y]-->null;
// 顺利的达到了检测冲突, 顺序链接的目的
             new -> parent = root ;     
             return NULL ;
         }
        p = & tmp -> sibling ;
         if ( tmp -> end < start )
             continue ;
         return tmp ;
     }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值