不知道我的理解哪有问题
对于上述问题,有以下解释:
对于48000000--5b00001c的那些特殊寄存器,在访问前应先按照cpu说明书上的地址在linux中申请同样的地址空间,成为io内存,再去访问----------因为
寄存器的地址对cpu而言是不变、既定的,但linux并不知道这些,比如他不知道WTCON寄存器的地址是0x53000000,所以要访问硬件WTCON的时候驱动程序必须先向linux申请从0x53000000开始的一段地址,用的便是request_mem_region(res->start, size, pdev->name),然后再将申请到的地址控件用ioremap转化成虚拟地址再去访问........当然如果你访问WTCON的时候却向内核申请了比如0x54000000(在0x54000000还未被申请的情况下,应该可以申请成功),这样访问到的寄存器便不是WTCON了
是的,后来看了一下request_mem_region源码,里面有个死循环在保护已被申请过的资源不被其他代码再request_mem_region成功。
在__request_region里面会再次分配一个struct resource *res,内核使用write_lock使这个res被独占的写,但是内核并没有保护那个驱动中可以接触的比如上面的static struct resource s3c_wdt_resource,所以
如果第二个驱动不去request_mem_region还是可以访问第一个驱动中request_mem_region过的资源的,但这样就可能两者都访问到不正确的结果。所以在每个驱动模块在使用io内存之前最好都要先使request_mem_region申请一下,这样就利用到了内核提供的锁保护机制,不用在自己的驱动中再写代码去防止已经申请到的资源被其他驱动有意无意的伤害到。目前的理解。
#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0)
struct resource * __request_region(struct resource *parent,
resource_size_t start, resource_size_t n,
const char *name, int flags)
{
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;
}
/* Uhhuh, that didn't work out.. */
kfree(res);
res = NULL;
break;
}
write_unlock(&resource_lock);
return res;
}
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;
}
}
最终结论:在对统一编址的arm平台的寄存器进行访问时,其实在cpu上已经固定把该块内存分配给了这些寄存器,只不过linux不知道,应该使用request_mem_region对该内存区域进行内存保护,也就是linux对其进行内存保护,但是如果直接使用该段内存也是可以的,但是可能会出现错误,所以任何内核代码在使用寄存器时都应该使用request_mem_region,以避免由于争夺该资源而导致错误的发生。
对于独立编址的平台,必须使用该函数了,呵呵,想一下也应该是这个样子,需要把一些寄存器映射到内存空间,再进行操作,不申请也不行啊~~~~
http://bbs.csdn.net/topics/370071947