PCIe设备驱动简要示例

张开发
2026/4/21 1:54:20 15 分钟阅读
PCIe设备驱动简要示例
lspci/setpci命令lspci命令选项-t显示总线树-k显示所有设备的内核驱动-x:十六进制形式显示“标准配置头”(前64字节)-xxx十六进制形式显示整个配置空间(256字节)-xxxx十六进制形式显示4096字节扩展配置空间-b总线为中心的视图-D始终显示域号-P显示桥接路径-PP显示总线路径-n:显示设备id-s只显示选中的槽查看PCIe设备树setpci命令选项--dumpregs显示“标准配置头”所有寄存器名称-s根据domain:bus:device.func设置配置空间寄存器-d根据vendor:device设置配置空间寄存器修改配置空间寄存器驱动基本流程PCIe初始化#define VENDOR_ID 0xabcd #define DEVICE_ID 0x1234 static int map_bars(struct pci_dev *pdev) { int i; for (i0; iPCI_STD_NUM_BARS; i) { if (pci_resource_flags(pdev, i) IORESOURCE_MEM) { void __iomem *addr pci_iomap(pdev, i, 0); if (!addr) { dev_err(pdev-dev, BAR%d mapping failed\n, i); return -ENOMEM; } dev_info(pdev-dev, BAR%d mapped virtaddr %px\n, i, addr); } } return 0; } static int demo_probe(struct pci_dev *pdev, const struct pci_device_id *id) { dev_info(pdev-dev, PCIe Device %04x:%04x detected\n, id-vendor, id-device); map_bars(pdev); //xxxxx return 0; } static void demo_remove(struct pci_dev *pdev) { dev_info(pdev-dev, Device driver removed\n); //xxx } static const struct pci_device_id demo_ids[] { { PCI_DEVICE(VENDOR_ID, DEVICE_ID) }, { 0, } }; MODULE_DEVICE_TABLE(pci, demo_ids); static struct pci_driver demo_driver { .name demo_drv, .id_table demo_ids, .probe demo_probe, .remove demo_remove, }; module_pci_driver(demo_driver); MODULE_LICENSE(GPL);中断申请和处理static irqreturn_t demo_isr(int irq, void *dev_id) { struct pci_dev *pdev dev_id; u32 status; pci_read_config_dword(pdev,PCI_STATUS,status);//只对传统中断PCI_IRQ_INTX有效 if (status 0x08) { // 检查中断标志 // 处理中断 } return IRQ_HANDLED; } static int request_irq_handler(struct pci_dev *pdev) { int ret pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_INTX);//PCI_IRQ_INTX、PCI_IRQ_MSI、PCI_IRQ_MSIX if (ret 0) return ret; retrequest_irq(pci_irq_vector(pdev,0), demo_isr, IRQF_SHARED, demo_pcie_irq, pdev); return ret; }DMA一致性内存struct dma_buffer { dma_addr_t dma_handle; void *virt_addr; size_t size; }; int alloc_dma_buffer(struct device *dev,struct dma_buffer *buf, size_t size) { buf-virt_addr dma_alloc_coherent(dev, size, buf-dma_handle, GFP_KERNEL); if (!buf-virt_addr) return -ENOMEM; buf-size size; return 0; } void free_dma_buffer(struct device *dev, struct dma_buffer *buf) { dma_free_coherent(dev, buf-size, buf-virt_addr, buf-dma_handle); }创建字符设备static int create_char_device(struct pci_dev *pdev) { dev_t devno MKDEV(MAJOR_NUM, MINOR_NUM); int ret register_chrdev_region(devno, 1, demo_dev); if (ret) return ret; cdev_init( demo_cdev, fops); ret cdev_add( demo_cdev, devno, 1); if (ret) unregister_chrdev_region(devno, 1); return ret; } static const struct file_operations fops { .owner THIS_MODULE, .read demo_read, .write demo_write, .map demo_mmap, .open demo_open, .release demo_release, }; static ssize_t demo_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { struct pci_dev *pdev filp-private_data; u32 reg_val ioread32(pdev-bar0, DATA_REG); copy_to_user(buf, reg_val, sizeof(reg_val)); return sizeof(reg_val); }内存映射到用户态static int demo_mmap(struct file *file, struct vm_area_struct *vma) { struct pci_dev *dev xxx-pdev; size_t size vma-vm_end - vma-vm_start; if(size~PAGE_MASK){ pr_err(mmap DMA Size error.\n); return -EINVAL; } return dma_mmap_coherent(pdev-dev, vma, buf-virt_addr, buf-dma_handle, size); }PCIe驱动常用内核APIAPI描述pci_enable_device()启用PCIe设备pci_request_regions()申请设备资源所有权pci_iomap()BAR映射成内核虚拟地址pci_set_master()启用设备主模式pci_write/read_config_word读写配置空间pci_alloc_irq_vectors()获取设备中断数量pci_irq_vector()获取中断号dma_alloc_coherent()分配一致性DMA内存dma_mmap_coherent一致性内存映射到用户空间

更多文章