linux内核 端口,Linux内核中IO端口资源管理

读写I/O内存资源

由于在某些平台上,对I/O内存和系统内存有不同的访问处理,因此为了确保跨平台的兼容性,Linux实现了一系列读写I/O内存资源的函数,这些函数在不同的平台上有不同的实现。但在x86平台上,读写I/O内存与读写RAM无任何差别。如下所示(include/asm-i386/io.h):

#define readb(addr) (*(volatile unsigned char *) __io_virt(addr�

#define readw(addr) (*(volatile unsigned short *) __io_virt(addr�

#define readl(addr) (*(volatile unsigned int *) __io_virt(addr�

#define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b�

#define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b�

#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b�

#define memset_io(a,b,c)memset(__io_virt(a),(b),(c�

#define memcpy_fromio(a,b,c) memcpy

#define memcpy_toio(a,b,c)memcpy(__io_virt(a),(b),(c�

上述定义中的宏__io_virt()仅仅检查虚地址addr是否是核心空间中的虚地址。具体的实现函数在arch/i386/lib/iodebug.c文件。

显然,在x86平台上访问I/O内存资源与访问系统主存RAM是无差别的。但是为了保证驱动程序的跨平台的可移植性,我们应该使用上面的函数来访问I/O内存资源,而不应该通过指向核心虚地址的指针来访问。

大多数平台都区分8位、16位和32位宽度的I/O端口的。Linux在include/asm/io.h头文件(对于i386平台就是include/asm-i386/io.h)中定义了一系列读写不同宽度I/O端口的宏函数。如下所示:

(1)读写8位宽的I/O端口

unsigned char inb(unsigned port);

void outb(unsigned char value,unsigned port);

其中,port参数指定I/O端口空间中的端口地址。在大多数平台上(如x86)它都是unsigned short类型的,其它的一些平台上则是unsigned int类型的。显然,端口地址的类型是由I/O端口空间的大小来决定的。

(2)读写16位宽的I/O端口

unsigned short inw(unsigned port);

void outw(unsigned short value,unsigned port);

(3)读写32位宽的I/O端口

unsigned int inl(unsigned port);

void outl(unsigned int value,unsigned port);

Linux同样在io.h文件中定义了字符串I/O读写函数:

(1)8位宽的字符串I/O操作

void insb(unsigned port,void * addr,unsigned long count);

void outsb(unsigned port ,void * addr,unsigned long count);

(2)16位宽的字符串I/O操作

void insw(unsigned port,void * addr,unsigned long count);

void outsw(unsigned port ,void * addr,unsigned long count);

(3)32位宽的字符串I/O操作

void insl(unsigned port,void * addr,unsigned long count);

void outsl(unsigned port ,void * addr,unsigned long count);

在一些平台上(典型地如X86),对于慢速外设来说,如果CPU读写其I/O端口的速度太快,可能会发生丢失数据。这就要在两次连续的I/O操作之间插入时延。Linux在io.h头文件中定义了带延迟的I/O读写函数,以XXX_p命名,如:inb_p()、outb_p()等。下面以out_p()为例进行分析。

将io.h中的宏定义__OUT(b,"b"char)展开后可得如下定义:

extern inline void outb(unsigned char value, unsigned short port) {

__asm__ __volatile__ ("outb %" "b " "0,%" "w" "1"

: : "a" (value), "Nd" (port));

}

extern inline void outb_p(unsigned char value, unsigned short port) {

__asm__ __volatile__ ("outb %" "b " "0,%" "w" "1"

__FULL_SLOW_DOWN_IO

: : "a" (value), "Nd" (port));

}

可以看出,outb_p()函数的实现中被插入了宏__FULL_SLOWN_DOWN_IO,以实现微小的延时。宏__FULL_SLOWN_DOWN_IO在头文件io.h中一开始就被定义:

#ifdef SLOW_IO_BY_JUMPING

#define __SLOW_DOWN_IO "

jmp 1f

1:jmp 1f

1:"

#else

#define __SLOW_DOWN_IO "

outb %%al,$0x80"

#endif

#ifdef REALLY_SLOW_IO

#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO

__SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO

#else

#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO

#endif

显然,__FULL_SLOW_DOWN_IO就是一个或四个__SLOW_DOWN_IO(根据是否定义了宏REALLY_SLOW_IO来决定),而宏__SLOW_DOWN_IO则被定义成毫无意义的跳转语句或写端口0x80的操作(根据是否定义了宏SLOW_IO_BY_JUMPING来决定)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值