端口的概念:设备通过系统总线上的接口与CPU相连,接口电路中含有多种寄存器,CPU向设备读写数据实际上是向接口上的寄存器读写数据,这些寄存器称为I/O端口。一个接口通常包含控制端口,数据端口,状态端口。

地址的概念:

物理地址:地址总线上的地址,物理地址种很大一部分时留给内存的,也常被映射到其他存储器或总线上。

总线地址:总线的地址线或在地址周期产生的信号。CPU使用物理地址,外设使用总线地址。物理地址与总线地址的关系由系统设计决定。

      对于x86平台,物理地址就是总线地址。

虚拟地址:现代操作系统普遍使用虚拟内存管理VMM机制。这需要CPU中MMU的支持。这样CPU发出的内存地址将被MMU截获,这个地址被称为虚拟地址。MMU将地址映射成物理地址发送的地址总线上。

linux中,进程中的4GB虚拟内存分为用户空间和内核空间,用户空间0-3GB,剩下的1GB为内核空间。程序员只能使用虚拟地址,系统中的每个进程都有自己的私有用户空间(0-3GB),这个空间对其他进程时不可见的。

端口编址方式:

对外设的读写都是通过读写接口上的寄存器来完成的。端口的编址方式有两种:统一编址和独立编址

统一编址:外设端口地址占用内存空间,也被称为内存映射方式。

独立编址:外设端口地址不占用内存空间,有自己的I/O地址空间。CPU通过专门的指令来访问I/O地址空间。I/O地址空间分配见/proc/ioports

linux将内存映射方式和I/O映射方式的I/O端口通称为I/O区域,无论采用那种编址方式都需要先申请I/O区域

PC架构一共有65536个8bit的I/O端口,组成64KI/O地址空间,编号从0~0xFFFF。连续两个8bit的端口可以组成一个16bit的端口,连续4个组成一个32bit的端口。I/O地址空间和CPU的物理地址空间是两个不同的概念,例如I/O地址空间为64K,一个32bit的CPU物理地址空间是4G。

I/O端口的操作:

申请I/O端口:

/*

request_region告诉内核:要使用first开始的n个端口。参数name为设备名。

如果分配成功返回值是非NULL;否则无法使用需要的端口

(/proc/ioports包含了系统当前所有端口的分配信息,

若request_region分配失败时,可以查看该文件,看谁先用了你要的端口)

*/

struct resource *request_region(unsigned long first, unsigned long n, const char *name);

访问I/O端口:

Linux 内核头文件(体系依赖的头文件<asm/io.h>) 定义了下列内联函数来存取I/O端口

/* inb/outb:读/写字节端口(8位宽)。有些体系将port参数定义为unsigned long;而有些平台则将它定义为unsigned short。inb的返回类型也是依赖体系的 */

unsigned inb(unsigned port);

void outb(unsigned char byte, unsigned port)

/* inw/outw:读/写字端口(16位宽) */

unsigned inw(unsigned port);

void outw(unsigned short word, unsigned port);

/* inl/outl:读/写32位端口。longword也是依赖体系的,有的体系为unsigned long;而有的为unsigned int */

unsigned inl(unsigned port);

void outl(unsigned longword, unsigned port);

释放I/O端口:

/* 用完I/O端口后(可能在模块卸载时),应当调用release_region将I/O端口返还给系统。参数start和n应与之前传递给request_region一致 */

void release_region(unsigned long start, unsigned long n);

I/O内存的操作:

根据计算机体系和总线不同,I/O 内存可分为可以或者不可以通过页表来存取。

若通过页表存取,内核必须先重新编排物理地址,使其对驱动程序可见,这就意味着在进行任何I/O操作之前,你必 须调用ioremap;

如果不需要页表,I/O内存区域就类似于I/O端口,你可以直接使用适当的I/O函数读写它们。

申请I/O内存:

I/O 内存区在使用前必须先分配。分配内存区的函数接口在<linux/ioport.h>中定

/*request_mem_region 分配一个始于start ,len字节的I/O内存

分配成功,返回一个非NULL指针,失败则放回NULL

系统当前所有I/O内存分配信息都在/proc/iomem文件中列出,你分配失败时,可以看看该文件,看谁先占用了该内存区 */

struct resource *request_mem_region(unsigned long start, unsigned long len, char *name);

映射:

在访问I/O内存之前,分配I/O内存并不是唯一要求的步骤,你还必须保证内核可存取该I/O内存。

访问I/O内存并不只是简单解引用指针,在许多体系中,I/O 内存无法以这种方式直接存取。

因此,还必须通过ioremap 函数设置一个映射。

/* ioremap用于将I/O内存区映射到虚拟地址。参数phys_addr为要映射的I/O内存起始地址,参数size为要映射的I/O内存的大小,返回值为被映射到的虚拟地址 */

void *ioremap(unsigned long phys_addr, unsigned long size);

I/O内存访问:

经过 ioremap之后,设备驱动就可以存取任何I/O内存地址。

ioremap返回的地址不可以直接解引用,应当使用内核提供的访问函数。

访问I/O内存的正确方式是通过一系列专门用于实现此目的的函数:

#include <asm/io.h>

/* I/O内存读函数。参数addr应当是从ioremap获得的地址(可能包含一个整型偏移); 返回值是从给定I/O内存读取到的值 */

unsigned int ioread8(void *addr);

unsigned int ioread16(void *addr);

unsigned int ioread32(void *addr)

/* I/O内存写函数。参数addr同I/O内存读函数,参数value为要写的值 */

void iowrite8(u8 value, void *addr);

void iowrite16(u16 value, void *addr);

void iowrite32(u32 value, void *addr);

/* 以下这些函数读和写一系列值到一个给定的 I/O 内存地址,从给定的buf读或写count个值到给定的addr。参数count表示要读写的数据个数,而不是字节大小 */

void ioread8_rep(void *addr, void *buf, unsigned long count);

void ioread16_rep(void *addr, void *buf, unsigned long count);

void ioread32_rep(void *addr, void *buf, unsigned long count);

void iowrite8_rep(void *addr, const void *buf, unsigned long count);

void iowrite16_rep(void *addr, const void *buf, unsigned long count);

void iowrite32_rep(void *addr,,onst void *buf,,nsigned long count);

/* 需要操作一块I/O 地址时,使用下列函数(这些函数的行为类似于它们的C库类似函数): */

void memset_io(void *addr, u8 value, unsigned int count);

void memcpy_fromio(void *dest, void *source, unsigned int count);

void memcpy_toio(void *dest, void *source, unsigned int count);

/* 旧的I/O内存读写函数,不推荐使用 */

unsigned readb(address);

unsigned readw(address);

unsigned readl(address);

void writeb(unsigned value, address);

void writew(unsigned value, address);

void writel(unsigned value, address);

I/O内存释放:

void iounmap(void * addr); /* iounmap用于释放不再需要的映射 */

void release_mem_region(unsigned long start, unsigned long len); /* iounmap用于释放不再需要的映射 */

像I/O内存一样使用I/O端口

/* ioport_map重新映射count个I/O端口,使它们看起来I/O内存。

此后,驱动程序可以在ioport_map返回的地址上使用ioread8和同类函数

这样,就可以在编程时,消除了I/O 端口和I/O 内存的区别 */

void *ioport_map(unsigned long port, unsigned int count)

void ioport_unmap(void *addr);/* ioport_unmap用于释放不再需要的映射 */


来源:http://blog.163.com/cl2006ky@126/blog/static/87195173201332410243241/

还可以看:http://blog.sina.com.cn/s/blog_450e7a870100msqb.html

I/O端口与I/O内存的更多相关文章

  1. 【转】Linux设备驱动之I/O端口与I/O内存

    原文网址:http://www.cnblogs.com/geneil/archive/2011/12/08/2281367.html 一.统一编址与独立编址 该部分来自于:http://blog.ch ...

  2. linux中的 IO端口映射和IO内存映射

    参考自:http://blog.csdn.net/zyhorse2010/article/details/6590488 CPU地址空间 (一)地址的概念 1)物理地址:CPU地址总线传来的地址,由硬 ...

  3. 【memcache】windos下 memcache更改默认的端口和最大使用内存

    1>用内网ip的方式提供web应用服务器调用,不允许直接通过外网调用,如将memcache服务器放在192.168.1.55的服务器上 2>修改端口,如改为11200 3>分配内存, ...

  4. I/O 端口和 I/O 内存

    每个外设都是通过读写它的寄存器来控制. 大部分时间一个设备有几个寄存器, 并且在连 续地址存取它们, 或者在内存地址空间或者在 I/O 地址空间. 在硬件级别上, 内存区和 I/O 区域没有概念上的区 ...

  5. weblogic端口号修改和内存参数配置

    1 端口号修改 如图 是详细路径 注:我用的weblogic版本是10.3 当刚创建完域的时候这个配置文件下没有Listen-port参数  第一次去控制台修改端口后就这个参数了

  6. io端口与io内存详解

    (一)地址的概念 1)物理地址:CPU地址总线传来的地址,由硬件电路控制其具体含义.物理地址中很大一部分是留给内存条中的内存的,但也常被映射到其他存储器上(如显存.BIOS等).在程序指令中的虚拟地址 ...

  7. memcached for windows 修改端口和最大内存,以及常用命令

    在windows中使用memcached,必须先下载memcached for win32安装. PHP模块MemCache下载地址:http://downloads.php.net/pierre 服 ...

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

    每个外设都是通过读写其寄存器来控制的.外设寄存器也称为I/O端口,通常包括:控制寄存器.状态寄存器和数据寄存器三大类.根据访问外设寄存器的不同方式,可以把CPU分成两大类.一类CPU(如M68K,Po ...

  9. IO端口和IO内存的区别 转

      目录(?)[-] Linux系统对IO端口和IO内存的管理 一.I/O端口 二.IO内存 三.IO端口和IO内存的区分及联系 四.外设IO端口物理地址的编址方式 统一编址 独立编址 优缺点 五.L ...

随机推荐

  1. 问题-[Delphi]用LoadLibrary加载DLL时返回0的错误

    问题现象:用LoadLibrary加载DLL一直返回0句柄,无法进行下一步操作,但同样的代码可以访问到别的DLL.问题处理:1.你加载的路径是不对的,一定要看好路径.2.你是在虚拟机中操作的DLL,因 ...

  2. bzoj3926: [Zjoi2015]诸神眷顾的幻想乡 对[广义后缀自动机]的一些理解

    先说一下对后缀自动机的理解,主要是对构造过程的理解. 构造中,我们已经得到了前L个字符的后缀自动机,现在我们要得到L+1个字符的后缀自动机,什么需要改变呢? 首先,子串$[0,L+1)$对应的状态不存 ...

  3. 淘宝HSF服务的原理以及简单的实现

    淘宝HSF服务具体来说分三个应用:api接口,service服务,本地应用. 最基本的Api服务应该是十分干净的,不含方法,只有接口.它是要被打包(jar包的形式)到中央仓库去的. service服务 ...

  4. Ubuntu 12.04 安装搜狗输入法

    安装指南 Ubuntu / Ubuntu Kylin 14.04 LTS 版本 只需双击下载的 deb 软件包,即可直接安装搜狗输入法. Ubuntu 12.04 LTS 版本 由于 Ubuntu 1 ...

  5. 使用bash判断PATH中是否存在某个路径

    在source设置环境变量的时候,有些时候可能会设置两次,导致增加系统的路径搜索时间,或者让自己看环境变量的时候搞得怪不爽的. 为了解决这个问题,我们可以在设置相应的环境变量之前,先判断一下是否已经设 ...

  6. FormMove

    private    { Private declarations }    procedure WMMOVE(var Msg: TMessage); message WM_MOVE;  proced ...

  7. java程序查不出数据来

    同样的错误,不可再犯第三次!!! 数据库中是char,里面带空格,但在pl/sql中这样写可以查出来.如下: select ipostid from product t where ipostid= ...

  8. iOS开发之蓝牙通信

    一.引言 蓝牙是设备近距离通信的一种方便手段,在iPhone引入蓝牙4.0后,设备之间的通讯变得更加简单.相关的蓝牙操作由专门的 CoreBluetooth.framework进行统一管理.通过蓝牙进 ...

  9. linux下启动某个进程

    在关闭窗口的情况下,能够在后台继续运行,如 启动命令 node /home/node_modules/pixel-ping/lib/pixel-ping.js /home/node_modules/p ...

  10. 【转】C/C++求模求余运算符——2013-08-20

    http://blog.csdn.net/whealker/article/details/6203629 求模运算符(%),或称求余运算符,也就是数学上所谓的除法中的余数,%两侧均应为整数, |小| ...