寄存器与内存
寄存器与内存的区别在哪里呢?寄存器和RAM
的主要不同在于寄存器操作有副作用(side effect
或边际效果):读取某个地址时可能导致该地址内容发生变化,比如很多设备的中断状态寄存器只要一读取,便自动清零。
内存与I/O
在X86
处理器中存在I/O
空间的概念,I/O
空间是相对内存空间而言的,它们是彼此独立的地址空间,在32
位的x86
系统中,I/O
空间大小为64K
,内存空间大小为4G
。
X86
:支持内存空间、IO
空间。ARM
:只支持内存空间。MIPS
:只支持内存空间。PowerPC
:只支持内存空间。
IO端口与IO内存
IO
端口:当一个寄存器或内存位于IO
空间时,称其为IO
端口。IO
内存:当一个寄存器或内存位于内存空间时,称其为IO
内存。
操作I/O端口
对I/O
端口的操作需按如下步骤完成:申请、访问和释放。
申请I/O端口
内核提供了一套函数来允许驱动申请它需要的I/O
端口,其中核心的函数是:
struct resource *request_region ( unsigned long first, unsigned long n, const char *name );
这个函数告诉内核,你要使用从first
开始的n
个端口,name
参数是设备的名字。如果申请成功,返回非NULL
;申请失败,返回NULL
。
系统中端口的分配情况记录在/proc/ioports
中。如果不能分配需要的端口,可以来这里查看谁在使用。
访问I/O端口
I/O
端口可分为8
位、16
位和32
位端口。Linux
内核头文件(体系依赖的头文件asm/io.h
)定义了下列内联函数来访问I/O
端口:
unsigned inb ( unsigned port ); /* 读字节端口(8位宽) */
void outb ( unsigned char byte, unsigned port ); /* 写字节端口(8位宽) */
unsigned inw ( unsigned port ); /* 读字节端口(16位宽) */
void outw ( unsigned short word, unsigned port ); /* 写字节端口(16位宽) */
unsigned inl ( unsigned port ); /* 读字节端口(32位宽) */
void outl ( unsigned longword, unsigned port ); /* 写字节端口(32位宽) */
释放I/O端口
当用完一组I/O
端口(通常在驱动卸载时),应使用如下函数把它们返还给系统:
void release_region ( unsigned long start, unsigned long n );
操作I/O内存
对I/O
内存的操作需按如下步骤完成:申请、映射、访问和释放。
申请I/O内存
内核提供了一套函数来允许驱动申请它需要的I/O
内存,其中核心的函数是:
struct resource *request_mem_region ( unsigned long start, unsigned long len, char *name );
这个函数申请一个从start
开始,长度为len
字节的内存区。如果成功,返回非NULL
;否则返回NULL
,所有已经在使用的I/O
内存在/proc/iomem
中列出。
映射I/O内存
在访问I/O
内存之前,必须进行物理地址到虚拟地址的映射,ioremap
函数具有此功能:
void *ioremap ( unsigned long phys_addr, unsigned long size );
访问I/O内存
访问I/O
内存的正确方法是通过一系列内核提供的函数:
1. 从I/O
内存读,使用下列之一:
unsigned ioread8 ( void *addr );
unsigned ioread16 ( void *addr );
unsigned ioread32 ( void *addr );
2. 写I/O
内存,使用下列之一:
void iowrite8 ( u8 value, void *addr );
void iowrite16 ( u16 value, void *addr );
void iowrite32 ( u32 value, void *addr );
3. 老版本的I/O
内存访问函数:从I/O
内存读,使用下列之一:
unsigned readb ( address );
unsigned readw ( address );
unsigned readl ( address );
写I/O
内存,使用下列之一:
unsigned writeb ( unsigned value, address );
unsigned writew ( unsigned value, address );
unsigned writel ( unsigned value, address );
释放I/O内存
I/O
内存不再需要使用时应当释放,步骤如下:
void iounmap ( void *addr );
void release_mem_region ( unsigned long start, unsigned long len );