获取配置信息

  • 01
  • 02
  • 03
  • 04
  • 05
  • 06
  • 07
  • 08
  • 09
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
// 打印配置空间信息 void skel_get_configs(struct pci_dev* dev) { uint8_t revisin_id; uint16_t vendor_id, device_id; uint32_t class_id; pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id); printk("vendorID = %x", vendor_id); pci_read_config_word(dev, PCI_DEVICE_ID, &device_id); printk("deviceID = %x", device_id); pci_read_config_word(dev, PCI_REVISION_ID, &revisin_id); printk("deviceID = %x", revisin_id); pci_read_config_word(dev, PCI_CLASS_REVISION, &class_id); printk("classID = %x", class_id); }

pci_read_config_word:从PCI设备配置空间中读取特定寄存器的值,并将其存储到对应的变量中。

  • 供应商ID(vendor ID)

  • 设备ID(device ID)

  • 修订ID(revision ID):修订ID(Revision ID)是PCI设备的一个标识符,用于指示设备的版本或修订级别。每个PCI设备都有一个唯一的修订ID,它反映了硬件设计上的变化、错误修复或其他更改。通过读取修订ID,可以确定具体使用的是哪个版本或修订级别的设备。(每个PCI设备都有一个唯一的修订ID,它反映了硬件设计上的变化、错误修复或其他更改。通过读取修订ID,可以确定具体使用的是哪个版本或修订级别的设备。)

  • 类别ID(class ID):类别ID(Class ID)是PCI设备的一个标识符,用于指示设备所属的设备类别。每个PCI设备都有一个唯一的类别ID,它定义了该设备的功能和特征。(PCI规范将所有可能的设备分为多个不同的类别,每个类别都有一个独特的16位标识符。这些类别包括网络控制器、声卡、图形卡、存储控制器等等。通过读取和解析设备的类别ID,可以确定该设备所属的具体类别。)

设备中断函数

  • 01
  • 02
  • 03
  • 04
  • 05
  • 06
  • 07
  • 08
static irqreturn_t pci_mcard_interrupt(int irq, void* dev_id) { pci_card_t* pci_mcard = (pci_card_t*)dev_id; //打印中断号 printk("irq = %d, pci_mcard_irq = %d\n", irq, pci_mcard->irq); return IRQ_HANDLED; }
  • irq:中断号

  • dev_id:设备标识符

探测和初始化PCI设备

  • 01
  • 02
  • 03
  • 04
  • 05
  • 06
  • 07
  • 08
  • 09
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
static int probe(struct pci_dev* dev, const struct pci_device_id* id) { int retval = 0; pci_card_t* pci_mcard; printk("probe func\n"); // 设备使能 if (pci_enable_device(dev)) { printk(KERN_ERR "IO Error.\n"); return -EIO; } pci_mcard = kmalloc(sizeof(pci_card_t), GFP_KERNEL); if (!pci_mcard) { printk("In %s, kmalloc err!", __func__); return -ENOMEM; } // 设备中断号 pci_mcard->irq = dev->irq; if (pci_mcard->irq < 0) { printk("IRQ is %d, it's invalid!\n", pci_mcard->irq); goto out_pci_mcard; } // 获取io内存相关信息 pci_mcard->io = pci_resource_start(dev, 0); pci_mcard->range = pci_resource_end(dev, 0) - pci_mcard->io + 1; pci_mcard->flags = pci_resource_flags(dev, 0); printk("start %llx %lx %lx\n", pci_mcard->io, pci_mcard->range, pci_mcard->flags); printk("PCI base addr 0 is io%s.\n", (pci_mcard->flags & IORESOURCE_MEM) ? "mem" : "port"); // 防止地址访问冲突 先申请 retval = pci_request_regions(dev, "pci_module"); if (retval) { printk("PCI request regions err!\n"); goto out_pci_mcard; } // 在此映射 pci_mcard->ioaddr = pci_ioremap_bar(dev, 0); if (!pci_mcard->ioaddr) { printk("ioremap err!\n"); retval = -ENOMEM; goto out_regions; } retval = request_irq(pci_mcard->irq, pci_mcard_interrupt, IRQF_SHARED, "pci_module", pci_mcard); if (retval) { printk(KERN_ERR, "Can't get assigned IRQ %d.\n", pci_mcard->irq); goto out_iounmap; } pci_set_drvdata(dev, pci_mcard); skel_get_configs(dev); return 0; out_iounmap: iounmap(pci_mcard->ioaddr); out_regions: pci_release_regions(dev); out_pci_mcard: kfree(pci_mcard); return retval; }
  1. 开启设备使能:使用pci_enable_device()函数来启用PCI设备。如果无法启动成功,则返回-EIO。

  2. 分配并初始化pci_card_t结构体:使用kmalloc()函数为pci_card_t结构体分配内存,并进行相应的错误处理。

  3. 获取中断号和IO内存相关信息:从PCI设备结构体dev中获取中断号、IO起始地址、地址范围以及标志位信息,并打印相关信息。

  4. 申请IO区域资源:使用pci_request_regions()函数申请IO区域资源,防止地址访问冲突。如果申请失败,则进行错误处理。

  5. 映射IO地址空间:使用pci_ioremap_bar()函数将物理地址映射到虚拟地址空间,并进行相应的错误处理。

  6. 请求IRQ(中断请求):使用request_irq()函数请求IRQ,并将自定义的中断函数pci_mcard_interrupt与之关联。如果请求失败,则进行错误处理。

  7. 设置驱动函数:使用pci_set_drvdata()函数将pci_mcard指针保存在设备结构体dev的私有数据字段中,以便后续在其他驱动程序调用时可以方便地获取。

  8. 获取配置信息:调用skel_get_configs()函数来获取PCI设备的配置信息。

  9. 返回0表示探测成果,否则进行错误处理返回相应错误码。

移除PCI设备

  • 01
  • 02
  • 03
  • 04
  • 05
  • 06
  • 07
  • 08
  • 09
  • 10
static void remove(struct pci_dev* dev) { pci_card_t* pci_mcard = pci_get_drvdata(dev); free_irq(pci_mcard->irq, pci_mcard); iounmap(pci_mcard->ioaddr); pci_release_region(dev); kfree(pci_mcard); pci_disable_device(dev); printk(remove pci device ok.\n); }
  1. 获取与 PCI 设备相关联的私有数据结构 pci_mcard,该结构包含了一些设备相关的信息。

  2. 使用 free_irq 函数释放之前注册的中断处理程序。

  3. 使用 iounmap 函数解除之前映射的 I/O 内存地址。

  4. 调用 pci_release_region 释放之前分配的 PCI 资源区域。

  5. 使用 kfree 释放私有数据结构内存。

  6. 使用 pci_disable_device 禁用 PCI 设备,防止进一步访问设备。

  7. 打印调试信息,说明成功移除了 PCI 设备。