寄存器和RAM的主要不同在于寄存器操作有副作用(LDD3上讲的sideeffect或者边际效果):当你读取某个地址时,可能导致该地址内容发生变化,比如很多设备的中断状态寄存器只要一读取,便自动清零。
在x86处理器中存在I/O空间的概念,I/O空间是相对内存空间而言的,他们是互相独立的地址空间,在32位的x86系统中,I/O空间大小为64k,内存空间大小为4G
ARM、MIPS、PowerPC只支持内存空间
只有x86有IO空间
IO端口:当一个寄存器或者内存位于IO空间时,称为IO端口
IO内存:当一个寄存器或者内存位于内存空间时,称为IO内存
步骤:
1)申请IO端口
核心函数:
structresource*request_region(unsignedlongfirst,unsignedlongn,constchar*name)
first |
第一个IO端口的地址 |
n |
要申请多少个IO口 |
name |
操作这个IO端口的设备名字 |
申请成功 |
返回非NULL |
申请失败 |
返回NULL |
系统中端口的分配情况记录在/proc/ioports中,如果不能分配需要的端口,可以来这里查看谁在使用!!
2)访问
IO端口可以分为8-位,16-位,32-位端口
在头文件<asm/io.h>
定义了内联函数来访问IO端口:
读字节端口(8位):unsignedinb(unsignedport)
写字节端口(8位):voidoutb(unsignedcharbyte,unsignedport)
读字节端口(16位):unsignedinw(unsignedport)
写字节端口(16位):voidoutw(unsignedshortword,unsignedport)
读字节端口(32位):unsignedinl(unsignedport)
写字节端口(32位):voidoutl(unsignedlongword,unsignedport)
3)释放
当用完一组IO端口(通常在驱动卸载时),应使用如下函数把它们返还给系统:
voidrelease_region(unsignedlongstart,unsignedlongn)
步骤:
1)申请IO端口
核心函数:
structresource*request__mem_region(unsignedlongstart,unsignedlonglen,constchar*name)
start |
IO内存的起始地址 |
len |
长度为len字节的内存区 |
name |
操作这个IO端口的设备名字 |
申请成功 |
返回非NULL |
申请失败 |
返回NULL |
系统中端口的分配情况记录在/proc/iomem中,如果不能分配需要的端口,可以来这里查看谁在使用!!
2)映射IO内存
在申请了IO内存之前,仅仅是申请了物理地址。
在访问IO内存之前,必须进行物理地址到虚拟地址的映射
使用函数(常用):
void*ioremap(unsignedlongphys_addr,unsignedlongsize)
3)访问IO内存
2.6内核
从IO内存读,使用下列之一:
unsignedioread8(void*addr)
unsignedioread16(void*addr)\
unsignedioread32(void*addr)
写到IO内存,使用下列之一:
voidiowrite8(u8value,void*addr)
voidiowrite16(u16value,void*addr)
voidiowrite32(u32value,void*addr)
2.4内核
从IO内存读,使用下列之一:
unsignedreadb(address)
unsignedreadw(address)
unsignedreadl(address)
写到IO内存,使用下列之一:
unsignedwriteb(unsignedvalue,address)
unsignedwritew(unsignedvalue,address)
unsignedwritel(unsignedvalue,address)
4)释放IO内存
步骤:
1)voidiounmap(void*addr)
2)void release_mem_region(unsignedlongstart,unsignedlonglen)