寄存器与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)
寄存器的操作有副作用(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);
else
ret = __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;
else
offset = (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;
else
offset = (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);
}
}