1. PCI驱动介绍
Peripherals Component Interconnect(PCI)是一种本地计算机总线标准,是一种用于连接计算机内部硬件设备的总线标准。PCI总线可在计算机的主板上提供连接,支持其他卡或板,如网卡,声卡,显卡等硬件扩展插件。
在Linux中,与PCI硬件交互的驱动程序称为PCI驱动程序,它是内核中的一部分。PCI驱动程序管理Linux内核和PCI卡之间的通信。PCI驱动程序的目的是将Linux内核的机制与PCI设备的硬件功能结合起来。
1.1 PCI驱动的注册和注销
PCI驱动程序的注册并不是一个自动的过程。每当内核加载一个PCI驱动程序时,驱动程序都需要向内核发出请求来注册它。同样,当驱动程序完成操作和处理后,驱动程序也需要向内核发出请求来注销它。
要注册PCI驱动程序,必须创建一个struct pci_driver对象,并使用pci_register_driver()函数向内核注册它。在驱动程序不再需要处理PCI设备时,使用pci_unregister_driver()函数可以将其从内核中注销。
static struct pci_driver pci_driver = {
.name = "driver-name",
.id_table = pci_device_id_table,
.probe = driver_probe,
.remove = driver_remove,
};
static int __init driver_init(void)
{
return pci_register_driver(&pci_driver);
}
static void __exit driver_exit(void)
{
pci_unregister_driver(&pci_driver);
}
2. PCI设备的访问方式
当一个PCI设备被检测到并加载了相应的PCI驱动程序后,PCI设备就可以被操作系统访问和控制。为了访问PCI设备,驱动程序需要保存一个对struct pci_dev结构的引用。它是内核中用于表示PCI设备的结构体。
2.1 PCI配置空间
在Linux下,要访问PCI设备的寄存器,必须首先访问PCI配置空间。
对PCI设备的访问是通过读写PCI配置空间寄存器进行的。要读取配置寄存器,需要使用pci_read_config_{byte, word, dword}()函数,而要写入配置寄存器,需要使用pci_write_config_{byte, word, dword}()函数。
以下是一个示例代码,用于在pci设备上读取和写入配置信息:
static int pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
int err;
u8 value;
err = pci_enable_device(pdev);
if (err)
goto err;
/* Read from configuration space */
pci_read_config_byte(pdev, PCI_CLASS_REVISION, &value);
/* Write to configuration space */
pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, 0x01);
return 0;
err:
return err;
}
2.2 PCI内存映射IO
PCI内存映射IO(MMIO)是Linux内核中PCI设备和CPU之间进行通信的最常用方法之一。PCI设备驱动程序使用ioremap()函数将显存映射到内存中,驱动程序通过获取对物理地址指针的访问权限来读写内存。
/* PCI设备驱动程序进行映射 */
static int pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
int err;
struct pci_bar bar;
void __iomem *ioaddr;
if (pci_request_region(pdev, BAR_NUM, "my_label")) {
printk(KERN_ERR "Unable to get PCI BAR 0\n");
goto err;
}
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar.base_addr);
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + 4, &bar.length);
bar.base_addr &= PCI_BASE_ADDRESS_MEM_MASK;
bar.length = ~(bar.length & PCI_BASE_ADDRESS_IO_MASK) + 1;
ioaddr = ioremap(bar.base_addr, bar.length);
// ...
pci_release_region(pdev, BAR_NUM);
return 0;
err:
return err;
}
3. 总结
PCI驱动程序是非常重要的,因为它们允许Linux内核与PCI硬件设备进行通信。最常用的方法是通过MMIO的方式进行通信。使用PCI驱动程序,可以从操作系统中访问PCI的硬件资源。在Linux下,要访问PCI设备的寄存器,必须首先访问PCI配置空间。驱动程序需要使用pci_read_config_{byte, word, dword}()函数来读取配置寄存器,并使用pci_write_config_{byte, word, dword}()函数来写入配置寄存器。