I/O端口和I/O内存--学习备忘

===============================   博客点滴积累,部分话语和知识点来源于网络,感谢网络资源的提供者======

设备通常会提供一组寄存器来用于控制设备,读写设备和获取设备状态,即控制寄存器,数据寄存器,和状态寄存器,这些寄存器可能位于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->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);   //检测是否冲突,不冲突就插入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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值