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

  ⑥如果上述两条件不能同时满足,则说明还没有找到,因此要继续扫描链表。在继续扫描之前,我们还是要判断一下this指针是否为空。如果为空, 说明已经扫描完整个child链表,因此就可以推出for循环了。否则就将new->start的值修改为this->end+1,并让 this指向下一个兄弟资源节点,从而继续扫描链表中的下一个子资源节点。

  3.2.5 分配接口allocate_resource()

  在find_resource()函数的基础上,函数allocate_resource()实现:在一颗资源树中分配一条指定大小的、且包含在指定区域[min,max]中的、未使用资源区域。其源代码如下:

/* * Allocate empty slot in the resource tree given range and alignment. */int allocate_resource(struct resource *root, struct resource *new,        unsigned long size,        unsigned long min, unsigned long max,        unsigned long align,        void (*alignf)(void *, struct resource *, unsigned long),        void *alignf_data){    int err;    write_lock(&resource_lock);    err = find_resource(root, new, size, min, max, align, alignf, alignf_data);    if (err >= 0 && __request_resource(root, new)) err = -EBUSY;    write_unlock(&resource_lock);    return err;}

  3.2.6 获取资源的名称列表

  函数get_resource_list()用于获取根节点root的子资源名字列表。该函数主要用来支持/proc/文件系统(比如实现proc/ioports文件和/proc/iomem文件)。其源代码如下:

int get_resource_list(struct resource *root, char *buf, int size){ char *fmt; int retval; fmt = "        %08lx-%08lx : %s"; if (root->end < 0x10000)  fmt = "        %04lx-%04lx : %s"; read_lock(&resource_lock); retval = do_resource_list(root->child, fmt, 8, buf, buf + size) - buf; read_unlock(&resource_lock); return retval;}

  可以看出,该函数主要通过调用内部静态函数do_resource_list()来实现其功能,其源代码如下:

/* * This generates reports for /proc/ioports and /proc/iomem */static char * do_resource_list(struct resource *entry, const char *fmt,   int offset, char *buf, char *end){ if (offset < 0)  offset = 0; while (entry) {  const char *name = entry->name;  unsigned long from, to;  if ((int) (end-buf) < 80)   return buf;  from = entry->start;  to = entry->end;  if (!name)   >";  buf += sprintf(buf, fmt + offset, from, to, name);  if (entry->child)     buf = do_resource_list(entry->child, fmt, offset-2, buf, end);  entry = entry->sibling; } return buf;}

  函数do_resource_list()主要通过一个while{}循环以及递归嵌套调用来实现,较为简单,这里就不在详细解释了。

3.3 管理I/O Region资源

  Linux将基于I/O映射方式的I/O端口和基于内存映射方式的I/O端口资源统称为“I/O区域”(I/O Region)。I/O Region仍然是一种I/O资源,因此它仍然可以用resource结构类型来描述。下面我们就来看看Linux是如何管理I/O Region的。

  3.3.1 I/O Region的分配

  在函数__request_resource()的基础上,Linux实现了用于分配I/O区域的函数__request_region(),如下:

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);   if (!conflict)    break;   if (conflict != parent) {    parent = conflict;    if (!(conflict->flags & IORESOURCE_BUSY))     continue;   }   /* Uhhuh, that didn't work out.. */   kfree(res);   res = NULL;   break;  }  write_unlock(&resource_lock); } return res;}

NOTE:

  ①首先,调用kmalloc()函数在SLAB分配器缓存中分配一个resource结构。

  ②然后,相应的根据参数值初始化所分配的resource结构。注意!flags成员被初始化为IORESOURCE_BUSY。

  ③接下来,用一个for循环开始进行资源分配,循环体的步骤如下:

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

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