I/O端口与I/O内存

来源:互联网 发布:电脑老板键软件 编辑:程序博客网 时间:2024/04/24 01:27
寄存器与ram的区别:
    寄存器的操作有副作用(side effect),如有些状态寄存器,读取后便会自动清零。

X86:支持I/O空间,支持内存空间
ARM,MIPS,POWERPC:只支持内存空间

I/O端口:一个寄存器或内存位于I/O空间
I/O内存:一个寄存器或内存位于内存空间

I/O端口的操作:
    (1)申请
        request_region(start,n,name)
    (2)访问
        8位:inb(), outb()
        16位:inw(), outw()
        32位:inl(), outl()
    (3)释放
        release_region(start,n)

I/O内存的操作:
    (1)申请
        request_mem_region(start,n,name)
    (2)映射
        void __iomem *ioremap(unsigned long offset, unsigned long size);
    (3)访问
        8位:ioread8(), iowrite8()
        16位:ioread16(), iowrite16()
        32位:ioread32(), iowrite32()
        老版本:
            readb, readw, readl
            writeb, writew, writel
    (4)释放
        void iounmap(volatile void __iomem *virtual)

        release_mem_region(start,n)


对于arm,powerpc来说,只有I/O内存操作,可以映射到一个虚拟地址,然后用访问指针的方式来读写,而不用ioread等。


相关函数:

#define request_region(start,n,name)__request_region(&ioport_resource, (start), (n), (name))#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name))#define release_region(start,n)__release_region(&ioport_resource, (start), (n))#define release_mem_region(start,n)__release_region(&iomem_resource, (start), (n))

/* * This is compatibility stuff for IO resources. * * Note how this, unlike the above, knows about * the IO flag meanings (busy etc). * * request_region creates a new busy region. * * check_region returns non-zero if the area is already busy. * * release_region releases a matching busy region. *//** * __request_region - create a new busy resource region * @parent: parent resource descriptor * @start: resource start address * @n: resource region size * @name: reserving caller's ID string */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);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;}EXPORT_SYMBOL(__request_region);/** * __check_region - check if a resource region is busy or free * @parent: parent resource descriptor * @start: resource start address * @n: resource region size * * Returns 0 if the region is free at the moment it is checked, * returns %-EBUSY if the region is busy. * * NOTE: * This function is deprecated because its use is racy. * Even if it returns 0, a subsequent call to request_region() * may fail because another driver etc. just allocated the region. * Do NOT use it.  It will be removed from the kernel. */int __check_region(struct resource *parent, resource_size_t start,resource_size_t n){struct resource * res;res = __request_region(parent, start, n, "check-region");if (!res)return -EBUSY;release_resource(res);kfree(res);return 0;}EXPORT_SYMBOL(__check_region);/** * __release_region - release a previously reserved resource region * @parent: parent resource descriptor * @start: resource start address * @n: resource region size * * The described resource region must match a currently busy region. */void __release_region(struct resource *parent, resource_size_t start,resource_size_t n){struct resource **p;resource_size_t end;p = &parent->child;end = start + n - 1;write_lock(&resource_lock);for (;;) {struct resource *res = *p;if (!res)break;if (res->start <= start && res->end >= end) {if (!(res->flags & IORESOURCE_BUSY)) {p = &res->child;continue;}if (res->start != start || res->end != end)break;*p = res->sibling;write_unlock(&resource_lock);kfree(res);return;}p = &res->sibling;}write_unlock(&resource_lock);printk(KERN_WARNING "Trying to free nonexistent resource ""<%016llx-%016llx>\n", (unsigned long long)start,(unsigned long long)end);}EXPORT_SYMBOL(__release_region);

/* * We're addressing an 8 or 16-bit peripheral which tranfers * odd addresses on the low ISA byte lane. */u8 __inb8(unsigned int port){u32 ret;/* * The SuperIO registers use sane addressing techniques... */if (SUPERIO_PORT(port))ret = __raw_readb((void __iomem *)ISAIO_BASE + (port << 2));else {void __iomem *a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1);/* * Shame nothing else does */if (port & 1)ret = __raw_readl(a);elseret = __raw_readb(a);}return ret;}/* * We're addressing a 16-bit peripheral which transfers odd * addresses on the high ISA byte lane. */u8 __inb16(unsigned int port){unsigned int offset;/* * The SuperIO registers use sane addressing techniques... */if (SUPERIO_PORT(port))offset = port << 2;elseoffset = (port & ~1) << 1 | (port & 1);return __raw_readb((void __iomem *)ISAIO_BASE + offset);}u16 __inw(unsigned int port){unsigned int offset;/* * The SuperIO registers use sane addressing techniques... */if (SUPERIO_PORT(port))offset = port << 2;else {offset = port << 1;BUG_ON(port & 1);}return __raw_readw((void __iomem *)ISAIO_BASE + offset);}/* * Fake a 32-bit read with two 16-bit reads.  Needed for 3c589. */u32 __inl(unsigned int port){void __iomem *a;if (SUPERIO_PORT(port) || port & 3)BUG();a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1);return __raw_readw(a) | __raw_readw(a + 4) << 16;}EXPORT_SYMBOL(__inb8);EXPORT_SYMBOL(__inb16);EXPORT_SYMBOL(__inw);EXPORT_SYMBOL(__inl);void __outb8(u8 val, unsigned int port){/* * The SuperIO registers use sane addressing techniques... */if (SUPERIO_PORT(port))__raw_writeb(val, (void __iomem *)ISAIO_BASE + (port << 2));else {void __iomem *a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1);/* * Shame nothing else does */if (port & 1)__raw_writel(val, a);else__raw_writeb(val, a);}}void __outb16(u8 val, unsigned int port){unsigned int offset;/* * The SuperIO registers use sane addressing techniques... */if (SUPERIO_PORT(port))offset = port << 2;elseoffset = (port & ~1) << 1 | (port & 1);__raw_writeb(val, (void __iomem *)ISAIO_BASE + offset);}void __outw(u16 val, unsigned int port){unsigned int offset;/* * The SuperIO registers use sane addressing techniques... */if (SUPERIO_PORT(port))offset = port << 2;else {offset = port << 1;BUG_ON(port & 1);}__raw_writew(val, (void __iomem *)ISAIO_BASE + offset);}void __outl(u32 val, unsigned int port){BUG();}EXPORT_SYMBOL(__outb8);EXPORT_SYMBOL(__outb16);EXPORT_SYMBOL(__outw);EXPORT_SYMBOL(__outl);

/* * These are typically used in PCI drivers * which are trying to be cross-platform. * * Bus type is always zero on IIep. */void __iomem *ioremap(unsigned long offset, unsigned long size){char name[14];sprintf(name, "phys_%08x", (u32)offset);return _sparc_alloc_io(0, offset, size, name);}/* * Comlimentary to ioremap(). */void iounmap(volatile void __iomem *virtual){unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;struct resource *res;if ((res = _sparc_find_resource(&sparc_iomap, vaddr)) == NULL) {printk("free_io/iounmap: cannot free %lx\n", vaddr);return;}_sparc_free_io(res);if ((char *)res >= (char*)xresv && (char *)res < (char *)&xresv[XNRES]) {xres_free((struct xresource *)res);} else {kfree(res);}}


原创粉丝点击