=============================== 博客点滴积累,部分话语和知识点来源于网络,感谢网络资源的提供者======
设备通常会提供一组寄存器来用于控制设备,读写设备和获取设备状态,即控制寄存器,数据寄存器,和状态寄存器,这些寄存器可能位于I/O空间,也可能位于内存空间,当位于I/O空间时,通常称为I/O端口,位于内存空间时,对应的内存空间成为I/O内存
对ARM架构来说,外设和内存统一编址,即外设和主存单元一样看待,所以对于ARM架构来说,称为I/O内存
对X86架构来说,外设和主存单元是分开编址,X86架构专门为寄存器开辟了一个独立的空间,称为I/O地址空间,即I/O端口
对于I/O 端口有两种操作方法
1) 直接使用I/O端口操作函数,在设备打开或驱动加载时申请I/O端口区域,之后直接使用inb() outb()等进行操作,在设备关闭或驱动卸载时释放
2)另一种方法是I/O端口映射为内存进行访问,它和I/O访问对比如下
我们再看函数 request_mem_region(start,n,name) 主要是声明一段地址的所有权,当有其他地方申请的就会失败
#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name))
struct resource * __request_region(struct resource *parent, resource_size_t start, resource_size_t n, const char *name)
{
struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
if (res) {
res->start = start;res->name = name;
res->end = start + n - 1;
res->flags = IORESOURCE_BUSY;
write_lock(&resource_lock);
for (;;) {
struct resource *conflict;
conflict = __request_resource(parent, res); //检测是否冲突,不冲突就插入struct resource *root 链表里
if (!conflict) //为NULL 则成功
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;
}
关键检测冲突函数的可以这样理解:插入排序,一次插入两个数,这两个数start end已经排好了,这样就好理解了,
child链表是以I/O资源物理地址从低到高的顺序排列的,从头开始判断是否冲突,不冲突就插入
/* Return the conflict entry if you can't request it */
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) { //当tmp =NULL ,一种是root->child 为空,一种遍历到结尾了,即新的元素就是最后一个元素,tmp->start > end 即插入到tmp前面,new->sibling = tmp
new->sibling = tmp;
*p = new;
new->parent = root;
return NULL;
}
p = &tmp->sibling;
if (tmp->end < start) // 当 tmp->start <= end tmp->end < start 发生冲突了,没有发生冲突,继续遍历下一个元素,
continue;
return tmp;
}
}
ioremap 这个函数主要实现物理内存到虚拟内存的映射,与vmalloc()函数类似需要建立新的页表,但是它并不进行vmalloc()中所执行的内存的分配行为,函数原型如下:
void __iomem * ioremap (unsigned long phys_addr, unsigned long size)