微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > IO端口和IO内存的区别及分别使用的函数接口

IO端口和IO内存的区别及分别使用的函数接口

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

可在用户空间使用,至少在PC机上可以。GNUC库在中定义它们。如果在用户空间使用这些函数,必须满足下列条件:

1)、程序必须使用-O选项编译来强制扩展内联函数

2)、必须使用ioperm和iopl系统调用(#include )来获得进行操作I/O端口的权限。ioperm为获取单个端口的操作许可,iopl为获取整个I/O空间许可。这2个函数都是x86特有的

3)、程序必须以root来调用ioperm或者iopl,或者其父进程(祖先)必须以root获得的端口操作权限

如果平台不支持ioperm和iopl系统调用,通过使用/dev/prot设备文件,用户空间仍然可以存取I/O端口。但是要注意的是,这个文件的定义也是依赖平台的。

1.4、字串操作

除了一次传递一个数据的I/O操作,某些处理器实现了一次传递一序列数据(单位可以是字节、字和双字)的特殊指令。这些所谓的字串指令,它们完成任务比一个C语言循环更快。下列宏定义实现字串操作,在某些体系上,它们通过使用单个机器指令实现;但如果目标处理器没有进行字串I/O指令,则通过执行一个紧凑的循环实现。

字串函数的原型是:

/* insb:从I/O端口port读取count个数据(单位字节)到以内存地址addr为开始的内存空间*/
voidinsb(unsignedport,void*addr,unsignedlongcount);
/* outsb:将内存地址addr开始的count个数据(单位字节)写到I/O端口port*/
voidoutsb(unsignedport,void*addr,unsignedlongcount);
/* insw:从I/O端口port读取count个数据(单位字)到以内存地址addr为开始的内存空间*/
voidinsw(unsignedport,void*addr,unsignedlongcount);
/* outsw:将内存地址addr开始的count个数据(单位字)写到I/O端口port*/
voidoutsw(unsignedport,void*addr,unsignedlongcount);
/* insl:从I/O端口port读取count个数据(单位双字)到以内存地址addr为开始的内存空间*/
voidinsl(unsignedport,void*addr,unsignedlongcount);
/* outsl:将内存地址addr开始的count个数据(单位双字)写到I/O端口port*/
voidoutsl(unsignedport,void*addr,unsignedlongcount);

注意:使用字串函数时,它们直接将字节流从端口中读取或写入。当端口和主机系统有不同的字节序时,会导致不可预期的结果。使用inw读取端口应在必要时自行转换字节序,以匹配主机字节序。

1.5、暂停式I/O操作函数

由于处理器的速率可能与外设(尤其是低速设备)的并不匹配,当处理器过快地传送数据到或自总线时,这时可能就会引起问题。解决方法是:如果在I/O指令后面紧跟着另一个相似的I/O指令,就必须插入一个小的延时。为此,Linux提供了暂停式I/O操作函数,这些函数的名子只是在非暂停式I/O操作函数(前面提到的那些I/O操作函数都是非暂停式的)名后加上_p,如inb_p、outb_p等。大部分体系都支持这些函数,尽管它们常常被扩展为与非暂停I/O同样的代码,因为如果体系使用一个合理的现代外设总线,没有必要额外暂停。

以下是ARM体系暂停式I/O宏的定义:

#defineoutb_p(val,port)outb((val),(port))
#defineoutw_p(val,port)outw((val),(port))
#defineoutl_p(val,port)outl((val),(port))
#defineinb_p(port)inb((port))
#defineinw_p(port)inw((port))
#defineinl_p(port)inl((port))
#defineoutsb_p(port,from,len)outsb(port,from,len)
#defineoutsw_p(port,from,len)outsw(port,from,len)
#defineoutsl_p(port,from,len)outsl(port,from,len)
#defineinsb_p(port,to,len)insb(port,to,len)
#defineinsw_p(port,to,len)insw(port,to,len)
#defineinsl_p(port,to,len)insl(port,to,len)

因为ARM使用内部总线,就没有必要额外暂停,所以暂停式的I/O函数被扩展为与非暂停式I/O同样的代码。

1.6、平台依赖性

由于自身的特性,I/O指令高度依赖于处理器,非常难以隐藏各体系间的不同。因此,大部分的关于端口I/O的源码是平台依赖的。以下是x86和ARM所使用函数的总结:

IA-32(x86)

x86_64

这个体系支持本章介绍的所有函数;port参数的类型为unsignedshort。

ARM

端口映射到内存,并且支持本章介绍的所有函数;port参数的类型为unsignedint;字串函数用C语言实现。

2、使用I/O内存

尽管I/O端口在x86世界中非常流行,但是用来和设备通讯的主要机制是通过内存映射的寄存器和设备内存,两者都称为I/O内存,因为寄存器和内存之间的区别对软件是透明的。

I/O内存仅仅是一个类似于RAM的区域,处理器通过总线访问该区域,以实现对设备的访问。同样,读写这个区域是有边际效应。

根据计算机体系和总线不同,I/O内存可分为可以或者不可以通过页表来存龋若通过页表存取,内核必须先重新编排物理地址

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

网站地图

Top