Linux对I/O端口资源的管理(5)

  l 首先,调用__request_resource()函数进行资源分配。如果返回NULL,说明分配成功,因此就执行break语句推出for循环,返回所分配的resource结构的指针,函数成功地结束。

  l 如果__request_resource()函数分配不成功,则进一步判断所返回的冲突资源节点是否就是父资源节点parent。如果不是,则将分配行 为下降一个层次,即试图在当前冲突的资源节点中进行分配(只有在冲突的资源节点没有设置IORESOURCE_BUSY的情况下才可以),于是让 parent指针等于conflict,并在conflict->flags&IORESOURCE_BUSY为0的情况下执行 continue语句继续for循环。

  l 否则如果相冲突的资源节点就是父节点parent,或者相冲突资源节点设置了IORESOURCE_BUSY标志位,则宣告分配失败。于是调用kfree ()函数释放所分配的resource结构,并将res指针置为NULL,最后用break语句推出for循环。

  ④最后,返回所分配的resource结构的指针。

  3.3.2 I/O Region的释放

  函数__release_region()实现在一个父资源节点parent中释放给定范围的I/O Region。实际上该函数的实现思想与__release_resource()相类似。其源代码如下:

void __release_region(struct resource *parent,     unsigned long start, unsigned long n){ struct resource **p; unsigned long end; p = &parent->child; end = start + n - 1; for (;;) {  struct resource *res = *p;  if (!res)   break;  if (res->start <= start && res->end >= end) {   if (!(res->flags & IORESOURCE_BUSY)) {    p = &res->child;    continue;   }   if (res->start != start'  'res->end != end)    break;   *p = res->sibling;   kfree(res);   return;  }  p = &res->sibling; } printk("Trying to free nonexistent resource <%08lx-%08lx>", start, end);}

  类似地,该函数也是通过一个for循环来遍历父资源parent的child链表。为此,它让指针res指向当前正被扫描的子资源节点,指针p 指向前一个子资源节点的sibling成员变量,p的初始值为指向parent->child。For循环体的步骤如下:

  ①让res指针指向当前被扫描的子资源节点(res=*p)。

  ②如果res指针为NULL,说明已经扫描完整个child链表,所以退出for循环。

  ③如果res指针不为NULL,则继续看看所指定的I/O区域范围是否完全包含在当前资源节点中,也即看看[start,start+n-1] 是否包含在res->[start,end]中。如果不属于,则让p指向当前资源节点的sibling成员,然后继续for循环。如果属于,则执行 下列步骤:

  l 先看看当前资源节点是否设置了IORESOURCE_BUSY标志位。如果没有设置该标志位,则说明该资源节点下面可能还会有子节点,因此将扫描过程下降 一个层次,于是修改p指针,使它指向res->child,然后执行continue语句继续for循环。

  l 如果设置了IORESOURCE_BUSY标志位。则一定要确保当前资源节点就是所指定的I/O区域,然后将当前资源节点从其父资源的child链表中去 除。这可以通过让前一个兄弟资源节点的sibling指针指向当前资源节点的下一个兄弟资源节点来实现(即让*p=res->sibling),最 后调用kfree()函数释放当前资源节点的resource结构。然后函数就可以成功返回了。

  3.3.3 检查指定的I/O Region是否已被占用

  函数__check_region()检查指定的I/O Region是否已被占用。其源代码如下:

int __check_region(struct resource *parent, unsigned long start, unsigned long n){ struct resource * res; res = __request_region(parent, start, n, "check-region"); if (!res)  return -EBUSY; release_resource(res); kfree(res); return 0;}

  该函数的实现与__check_resource()的实现思想类似。首先,它通过调用__request_region()函数试图在父资源 parent中分配指定的I/O Region。如果分配不成功,将返回NULL,因此此时函数返回错误值-EBUSY表示所指定的I/O Region已被占用。如果res指针不为空则说明所指定的I/O Region没有被占用。于是调用__release_resource()函数将刚刚分配的资源释放掉(实际上是将res结构从parent的 child链表去除),然后调用kfree()函数释放res结构所占用的内存。最后,返回0值表示指定的I/O Region没有被占用。

3.4 管理I/O端口资源

  我们都知道,采用I/O映射方式的X86处理器为外设实现了一个单独的地址空间,也即“I/O空间”(I/O Space)或称为“I/O端口空间”,其大小是64KB(0x0000-0xffff)。Linux在其所支持的所有平台上都实现了“I/O端口空间” 这一概念。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/25128.html