利用动态内存生气编写驱动,使得驱动的具有较强的移植性,内核中封装了一些函数以供驱动开发者使用,屏蔽了具体的细节。
1. 动态获取内存的函数 request_mem_region()
#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0)
(1) iomem_resource :
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
start:申请地址起始地址
end:申请地址结束地址
name:申请内存名字
flags:内存的标识,IO或者中断等。
struct resource iomem_resource = {
.name = "PCI mem",
.start = 0,
.end = -1,
.flags = IORESOURCE_MEM,
};
#define IORESOURCE_MEM 0x00000200
flag 表示资源的类型,Linux中将IO、中断等统称为资源。
对iomem_resource 的理解:这是一个root节点,挂载着接下来申请的存储空间。这应该是内核管理动态内存申请释放的一种方法,所有动态申请的内存都挂接在一个父亲(parent)下面,多个动态内存间又是兄弟关系(sibling)。正如结构体 resource中最后一行定义的那样,这可是一个庞大的亲戚关系网络,只要找到其中一个child或者sibling,就能揪出整个家族 ~-~
2. 动态内存王国的缔造者 —— __request_region() 函数
struct resource * __request_region(struct resource *parent,
resource_size_t start, resource_size_t n,
const char *name, int flags)
{
DECLARE_WAITQUEUE(wait, current);
struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
if (!res)
return NULL;
res->name = name;
res->start = start;
res->end = start + n - 1;
res->flags = IORESOURCE_BUSY;
res->flags |= flags;
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;
}
if (conflict->flags & flags & IORESOURCE_MUXED) {
add_wait_queue(&muxed_resource_wait, &wait);
write_unlock(&resource_lock);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
remove_wait_queue(&muxed_resource_wait, &wait);
write_lock(&resource_lock);
continue;
}
/* Uhhuh, that didn't work out.. */
kfree(res);
res = NULL;
break;
}
write_unlock(&resource_lock);
return res;
}
该函数中重点是 __request_resource(parent, res) 函数,当返回值为空,则跳出整个for循环,且返回 res。那么 __request_resource(parent, res) 究竟做了什么,在什么条件下才能放回 NULL,进入 __request_resource(parent, res) ,一探究竟。通过__request_resource()函数,同时也鉴定了将要申请的内存是不是数据这个大家庭的,是就收留并返回NULL。第30行的if是对 IORESOURCE_MUXED(software muxed)的处理。
(1) __request_resource
static struct resource * __request_resource(struct resource *root, struct resource *new)
{
resource_size_t start = new->start;
resource_size_t 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;
for (;;) {
tmp = *p;
if (!tmp || tmp->start > end) {
new->sibling = tmp;
*p = new;
new->parent = root;
return NULL;
}
p = &tmp->sibling;
if (tmp->end < start)
continue;
return tmp;
}
}
前面三个if都是在判断将要申请资源的合法性,若非法,则返回root即为__request_region() 中的parent。for循环中对新加入的资源做了”亲子鉴定“,鉴定的原则是 兄弟间内存区域不能重叠!