微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > Linux系统对IO端口和IO内存的管理

Linux系统对IO端口和IO内存的管理

时间:11-22 来源:互联网 点击:

以从/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?

  1. void__iomem*ioport_map(unsignedlongport,unsignedintnr)
  2. {
  3. if(port>PIO_MASK)
  4. returnNULL;
  5. return(void__iomem*)(unsignedlong)(port+PIO_OFFSET);
  6. }
  7. voidioport_unmap(void__iomem*addr)
  8. {
  9. /*Nothingtodo*/
  10. }

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?

  1. unsignedintfastcallioread8(void__iomem*addr)
  2. {
  3. IO_COND(addr,returninb(port),returnreadb(addr));
  4. }
  5. #defineVERIFY_PIO(port)BUG_ON((port&~PIO_MASK)!=PIO_OFFSET)
  6. #defineIO_COND(addr,is_pio,is_mmio)do{\
  7. unsignedlongport=(unsignedlong__force)addr;\
  8. if(port
  9. VERIFY_PIO(port);\
  10. port&=PIO_MASK;\
  11. is_pio;\
  12. }else{\
  13. is_mmio;\
  14. }\
  15. }while(0)
  16. 展开:
  17. unsignedintfastcallioread8(void__iomem*addr)
  18. {

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top