寄存器和RAM的主要不同在于寄存器操作有副作用(LDD3上讲的side effect 或者 边际效果):当你读取某个地址时,可能导致该地址内容发生变化,比如很多设备的中断状态寄存器只要一读取,便自动清零。
在x86处理器中存在I/O空间的概念,I/O空间是相对内存空间而言的,他们是互相独立的地址空间,在32位的x86系统中,I/O空间大小为64k,内存空间大小为4G
ARM、MIPS、PowerPC只支持内存空间
只有x86有IO空间
IO端口:当一个寄存器或者内存位于IO空间时,称为IO端口
IO内存:当一个寄存器或者内存位于内存空间时,称为IO内存
步骤:
1)申请IO端口
核心函数:
struct resource *request_region(unsigned long first, unsigned long n, const char *name)
first |
第一个IO端口的地址 |
n |
要申请多少个IO口 |
name |
操作这个IO端口的设备名字 |
申请成功 |
返回非NULL |
申请失败 |
返回NULL |
系统中端口的分配情况记录在/proc/ioports中,如果不能分配需要的端口,可以来这里查看谁在使用!!
2)访问
IO端口可以分为8-位,16-位,32-位端口
在头文件<asm/io.h>
定义了内联函数来访问IO端口:
读字节端口(8位):unsigned inb(unsigned port)
写字节端口(8位):void outb(unsigned char byte, unsigned port)
读字节端口(16位):unsigned inw(unsigned port)
写字节端口(16位):void outw(unsigned short word, unsigned port)
读字节端口(32位):unsigned inl(unsigned port)
写字节端口(32位):void outl(unsigned long word, unsigned port)
3)释放
当用完一组IO端口(通常在驱动卸载时),应使用如下函数把它们返还给系统:
void release_region(unsigned long start, unsigned long n)
步骤:
1)申请IO端口
核心函数:
struct resource *request__mem_region(unsigned long start, unsigned long len, const char *name)
start |
IO内存的起始地址 |
len |
长度为len字节的内存区 |
name |
操作这个IO端口的设备名字 |
申请成功 |
返回非NULL |
申请失败 |
返回NULL |
系统中端口的分配情况记录在/proc/iomem中,如果不能分配需要的端口,可以来这里查看谁在使用!!
2)映射IO内存
在申请了IO内存之前,仅仅是申请了物理地址。
在访问IO内存之前,必须进行物理地址到虚拟地址的映射
使用函数(常用):
void *ioremap(unsigned long phys_addr, unsigned long size)
3)访问IO内存
2.6内核
从IO内存读,使用下列之一:
unsigned ioread8(void *addr)
unsigned ioread16(void *addr)\
unsigned ioread32(void *addr)
写到IO内存,使用下列之一:
void iowrite8(u8 value, void *addr)
void iowrite16(u16 value, void *addr)
void iowrite32(u32 value, void *addr)
2.4内核
从IO内存读,使用下列之一:
unsigned readb(address)
unsigned readw(address)
unsigned readl(address)
写到IO内存,使用下列之一:
unsigned writeb(unsigned value, address)
unsigned writew(unsigned value, address)
unsigned writel(unsigned value, address)
4)释放IO内存
步骤:
1)void iounmap(void *addr)
2)void release_mem_region(unsigned long start, unsigned long len)