Linux下PCI IO内存读写

本文深入探讨了Linux内核中I/O端口和I/O内存的访问机制,包括访问函数、映射函数及示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文链接自:

http://qikee.blogbus.com/logs/37072405.html

I/O端口是驱动程序与许多设备之间的通信方式,Linux的内核为我们提供了I/O端口分配的操作接口,但对PCI设备来讲,它的配置地址空间已经为其指定了I/O端口范围,不需要额外的分配操作。Linux内核 
提供了如下一些访问I/O端口的内联函数: 
unsigned inb(unsigned port); 
void outb(unsigned char byte, unsigned port); 
unsigned inw(unsigned port); 
void outw(unsigned short word, unsigned port); 
unsigned inl(unsigned port); 
void outl(unsigned longword, unsigned port); 
下面我们重点来看一下2.6内核引入的ioport_map函数: 
void *ioport_map( unsigned long port, unsigned int count ); 
通过这个函数,可以把port开始的count个连续端口重映射为一段“内存空间”。然后就可以在其返回的地址上象访问I/O内存一样访问这几个I/O端口。当不需要这种映射时,需要调用下面的函数来撤消: 
void iport_unmap(void *addr); 
除了I/O端口之外,和设备通信的另一种主要机制是通过使用映射到内存的寄存器或设备内存。这两种都称为I/O内存,因为寄存器和内存的差别对软件是透明的。 
对于分配好的I/O内存,一般不鼓励直接使用指向I/O内存的指针进行访问,最好通过页表,用包装函数访问。要通过页表访问,那么需要对分配好的I/O内存进行映射,确保该I/O内存对内核而言是可访问的。完成I/O内存映射的函数是ioremap. 
#include <asm/io.h> 
void *ioremap(unsigned long phys_addr, unsigned long size); 
注册驱动程序成功后,rtl8139_init_one会被调用,在这个函数中,我们可以通过插入一些打印输出语句看到PCI的配置地址空间和I/O地址区域的一些情况。 
首先,插入以下语句: 
u16 vendor, device; 
pci_read_config_word(pdev, 0, &vendor); 
pci_read_config_word(pdev, 2, &device); 
printk(KERN_INFO "%x, %x/n", vendor, device); 
下面通过在 rtl8139_init_one在插入代码,以四种不同方式访问设备内存。第一种是通过访问I/O内存实现,后三种则是通过访问I/O端口的形式实现。 
第一种: 
unsigned long mmio_start, addr1, addr2; 
void __iomem *ioaddr; 
mmio_start = pci_resource_start( pdev, 1); 
ioaddr = pci_iomap(pdev, 1, 0); 
addr1 = ioread32( ioaddr ); 
addr2 = ioread32( ioaddr + 4 ); 
printk(KERN_INFO "mmio start: %lX/n", mmio_start); 
printk(KERN_INFO "ioaddr: %p/n", ioaddr); 
第二种: 
unsigned long pio_start, pio_len, addr1, addr2; 
void __iomem *ioaddr; 
pio_start = pci_resource_start( pdev, 0); 
pio_len = pci_resource_len (pdev, 0); 
ioaddr = ioport_map(pio_start, pio_len); 
addr1 = ioread32( ioaddr ); 
addr2 = ioread32( ioaddr + 4 ); 
printk(KERN_INFO "pio start: %lX/n", pio_start); 
printk(KERN_INFO "ioaddr: %p/n", ioaddr); 
第三种: 
unsigned long pio_start, addr1, addr2; 
pio_start = pci_resource_start( pdev, 0 ); 
addr1 = inl( pio_start ); 
addr2 = inl( pio_start + 4 ); 
printk(KERN_INFO "port io start: %lX/n", pio_start); 
第四种: 
unsigned long pio_start; 
u8 addr1, addr2, addr3, addr4, addr5, addr6; 
pio_start = pci_resource_start( pdev, 0 ); 
addr1 = inb( pio_start ); 
addr2 = inb( pio_start + 1 ); 
addr3 = inb( pio_start + 2 ); 
addr4 = inb( pio_start + 3 ); 
addr5 = inb( pio_start + 4 ); 
addr6 = inb( pio_start + 5 ); 
printk(KERN_INFO "port io start: %lX/n", pio_start);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值