《精通linux设备驱动程序开发》第10章PCI 学习笔记

主要内容:

  • PCI系列
  • 寻址和识别
  • 访问PCI

1.PCI系列

PCIPeripheral Component Interconnect,外围组件互联)是一种CPU和外围设备通信的高速传输总线,串行通信比并行通信速度更快,更便宜。

PCI系列具有设备自动配置系统的优势,PCI驱动程序不需要实现复杂的检测逻辑。启动时,BIOS类的启动固件会遍历总线并分配资源,设备驱动程序查找叫做PCI配置空间的内存来找到资源分配情况。

2.寻址和识别

PCI设备的地址由总线号、设备号和功能号组成,分别称为厂家ID、设备ID、和设备类代码。配置空间中包含10字节用于表示设备类型的编码。表示PCI桥设备类型编码的第1字节是0x06,网络设备类编码的第1个字节是0x02,通信设备类编码的第1个字节是0x07,类编码定义在include/linux/pci_ids.h

3.访问PCI

PCI设备包括3个可寻址空间:配置空间、I/O端口和设备内存。

3.1配置区

要得到分配给某卡功能的中断号,操作如下:

unsigned char irq;

pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &irq);

读取PCI状态寄存器,操作如下:

unsigned short status;

pci_read_config_word(pdev, PCI_STATUS, &status);

3.2 I/O

PCI卡有6I/O或内存区域,I/O区域包含寄存器,内存区域存放数据。

PCI视频卡设备控制寄存器,驱动程序要完成如下事情:

(1)从配置区相应基址寄存器里得到I/O区域的基址:

unsigned long io_base = pci_resource_start(pdev, bar);

(2)用内核的request_region()常规机制获得这个I/O区域,并标明它对对应的设备:

request_region(io_base, length, "my_driver");

(3)用寄存器手册上的偏移地址加上第(1)步得到的基址,然后用inb()outb()函数访问这些寄存器:

/* Read */

register_data = inl(io_base + REGISTER_OFFSET);

/* Use */

/* ... */

/* Write*/

outl(register_data, io_base + REGISTER_OFFSET);

3.3内存

为了能操作PCI设备IDE内存区域,如前面PCI视频卡的帧缓冲,按下面步骤进行:
1)获得基址、内存区域长度即内存相关的标志:

unsigned long mmio_base = pci_resource_start(pdev, bar);

unsigned long mmio_length = pci_resource_length(pdev, bar);

unsigned long mmio_flags = pci_resource_flags(pdev, bar);

(2)用内核的request_mem_region()常规机制标记这片内存区的拥有者

request_mem_region(mmio_base, nmio_length, "my_driver");

(3)CPU访问第(1)步获得的设备内存。

stay hungry, stay foolish
原文地址:https://www.cnblogs.com/zygote/p/13642566.html