Linux系统对IO端口和IO内存的管理
以从/proc/ioports文件中获得。
2、内存映射方式
将IO端口映射为内存进行访问,在设备打开或驱动模块被加载时,申请IO端口区域并使用ioport_map()映射到内存,之后使用IO内存的函数进行端口访问,最后,在设备关闭或驱动模块被卸载时释放IO端口并释放映射。
映射函数的原型为:
void *ioport_map(unsigned long port, unsigned int count);
通过这个函数,可以把port开始的count个连续的I/O端口重映射为一段“内存空间”。然后就可以在其返回的地址上像访问I/O内存一样访问这些I/O端口。但请注意,在进行映射前,还必须通过request_region( )分配I/O端口。
当不再需要这种映射时,需要调用下面的函数来撤消:
void ioport_unmap(void *addr);
在设备的物理地址被映射到虚拟地址之后,尽管可以直接通过指针访问这些地址,但是宜使用Linux内核的如下一组函数来完成访问I/O内存:·读I/O内存
unsigned int ioread8(void *addr);
unsigned int ioread16(void *addr);
unsigned int ioread32(void *addr);
与上述函数对应的较早版本的函数为(这些函数在Linux 2.6中仍然被支持):
unsigned readb(address);
unsigned readw(address);
unsigned readl(address);
·写I/O内存
void iowrite8(u8 value, void *addr);
void iowrite16(u16 value, void *addr);
void iowrite32(u32 value, void *addr);
与上述函数对应的较早版本的函数为(这些函数在Linux 2.6中仍然被支持):
void writeb(unsigned value, address);
void writew(unsigned value, address);
void writel(unsigned value, address);
流程如下:
六、Linux下访问IO内存
IO内存的访问方法是:首先调用request_mem_region()申请资源,接着将寄存器地址通过ioremap()映射到内核空间的虚拟地址,之后就可以Linux设备访问编程接口访问这些寄存器了,访问完成后,使用ioremap()对申请的虚拟地址进行释放,并释放release_mem_region()申请的IO内存资源。
struct resource *requset_mem_region(unsigned long start, unsigned long len,char *name);
这个函数从内核申请len个内存地址(在3G~4G之间的虚地址),而这里的start为I/O物理地址,name为设备的名称。注意,。如果分配成功,则返回非NULL,否则,返回NULL。
另外,可以通过/proc/iomem查看系统给各种设备的内存范围。
要释放所申请的I/O内存,应当使用release_mem_region()函数:
void release_mem_region(unsigned long start, unsigned long len)
申请一组I/O内存后, 调用ioremap()函数:
void * ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags);
其中三个参数的含义为:
phys_addr:与requset_mem_region函数中参数start相同的I/O物理地址;
size:要映射的空间的大小;
flags:要映射的IO空间的和权限有关的标志;
功能:将一个I/O地址空间映射到内核的虚拟地址空间上(通过release_mem_region()申请到的)
流程如下:
六、ioremap和ioport_map
下面具体看一下ioport_map和ioport_umap的源码:
[plain]view plaincopyprint?
- void__iomem*ioport_map(unsignedlongport,unsignedintnr)
- {
- if(port>PIO_MASK)
- returnNULL;
- return(void__iomem*)(unsignedlong)(port+PIO_OFFSET);
- }
- voidioport_unmap(void__iomem*addr)
- {
- /*Nothingtodo*/
- }
ioport_map仅仅是将port加上PIO_OFFSET(64k),而ioport_unmap则什么都不做。这样portio的64k空间就被映射到虚拟地址的64k~128k之间,而ioremap返回的虚拟地址则肯定在3G之上。ioport_map函数的目的是试图提供与ioremap一致的虚拟地址空间。分析ioport_map()的源代码可发现,所谓的映射到内存空间行为实际上是给开发人员制造的一个“假象”,并没有映射到内核虚拟地址,仅仅是为了让工程师可使用统一的I/O内存访问接口ioread8/iowrite8(......)访问I/O端口。
最后来看一下ioread8的源码,其实现也就是对虚拟地址进行了判断,以区分IO端口和IO内存,然后分别使用inb/outb和readb/writeb来读写。
[plain]view plaincopyprint?
- unsignedintfastcallioread8(void__iomem*addr)
- {
- IO_COND(addr,returninb(port),returnreadb(addr));
- }
- #defineVERIFY_PIO(port)BUG_ON((port&~PIO_MASK)!=PIO_OFFSET)
- #defineIO_COND(addr,is_pio,is_mmio)do{\
- unsignedlongport=(unsignedlong__force)addr;\
- if(port
- VERIFY_PIO(port);\
- port&=PIO_MASK;\
- is_pio;\
- }else{\
- is_mmio;\
- }\
- }while(0)
- 展开:
- unsignedintfastcallioread8(void__iomem*addr)
- {
Linux系统IO端口IO内 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)