Linux-PCI Driver
Angie An

Linux-PCI Driver

Linux PCI设备驱动包括:

  1. Linux PCI设备驱动

  2. 设备本身驱动

一、Linux PCI设备驱动程序

  • 是内核自带的
  • 这个伪设备驱动程序从总线0开始查询PCI系统,并定位系统中所有的PCI设备和PCI桥。它建立一个可以用来描述这个PCI系统拓朴层次的数据结构链表。并且对所有的发现的PCI桥编号

二、PCI设备驱动

1. 注册一个PCI驱动

为了正确地将驱动注册到kernel,每个PCI驱动必须创建 struct pci_driver主结构体。结构体中至少含有下面四个成员:

1
2
3
4
5
6
7
8
static struct pci_driver pcie_dev_driver = {
// a unique name, usually the same as the module name
.name = PCIE_DEVNAME,
// specify vendor id and device id
.id_table = pcie_dev_table,
.probe = pcie_dev_probe,
.remove = pcie_dev_remove,
};

2. 模块初始化

模块初始化时需要使用module_init函数。例如:

1
module_init(pcie_dev_init);

pcie_dev_init函数为手动加载驱动模块.ko时执行的函数,其中做的主要工作时注册pci驱动。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
static int __init pcie_dev_init(void)
{
int rc;

// register a range of char device numbers
rc = alloc_chrdev_region(&dev_first, 0, MAX_BOARD_NUM, PCIEX_DEVNAME);
if(rc < 0)
{
printk(PCIEX_ERRPFX"Function failed:alloc_chrdev_region\n");
return rc;
}

// alloc a char device
pcie_cdev = cdev_alloc();
pcie_cdev->ops = &fops;
cdev_init(pcie_cdev, &fops);
cdev_add(pcie_cdev, dev_first, 1);

rc = pci_register_driver(&pcie_dev_driver);
if(rc < 0)
{
printk(PCIEX_ERRPFX"Function failed:pci_register_driver\n");
}

printk(PCIEX_LOGPFX"Exit pcie_dev_init function\n");

return (rc);
}

3. 卸载模块

卸载模块时要使用module_exit函数。module_exit和module_init通常放在一起。例如:

1
module_exit(pcie_dev_exit);

pcie_dev_exit函数为手动卸载驱动模块时执行的函数,其中做的主要工作时注册pci驱动。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void __exit pcie_dev_exit(void)
{
printk(PCIEX_LOGPFX"Enter pcie_dev_exit function\n");

unregister_chrdev_region(dev_first, MAX_BOARD_NUM);
cdev_del(pcie_cdev);
pci_unregister_driver(&pcie_dev_driver);

// remove proc file in /proc
// proc file records process system information
remove_proc_entry(PCIEX_DEVNAME, NULL);

printk(PCIEX_LOGPFX"Exit pcie_dev_exit function\n");
}

4. Probe函数

在init函数中pci_register_driver()完成后,一旦检测到了与驱动匹配的设备并且驱动控制了设备,驱动通常会在probe函数中做以下的动作。

  • Enable the device

    pci_enable_device()

  • Request MMIO/IOP resources

    pci_request_regions()

  • Set the DMA mask size (for both coherent and streaming DMA)

    pci_set_dma_mask()

  • Allocate and initialize shared control data

    pci_allocate_coherent()

  • Access device configuration space (if needed)

  • Register IRQ handler

    request_irq())

  • Initialize non-PCI (i.e. LAN/SCSI/etc parts of the chip)

    Enable DMA/processing engines

4.1 Enable the device

在access任何设备寄存器之前,驱动程序需要通过调用pci_enable_device()来启用 PCI 设备。

This will:

  • wake up the device if it was in suspended state,
  • allocate I/O and memory regions of the device (if BIOS did not),
  • allocate an IRQ (if BIOS did not).

4.2 Request MMIO/IOP resources

4.3 Set the DMA mask size

4.4 Allocate and initialize shared control data

4.5 Access device configuration space

4.6 Register IRQ handler

4.7 Initialize non-PCI

 Comments