获取配置信息
- 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;
}
开启设备使能:使用pci_enable_device()函数来启用PCI设备。如果无法启动成功,则返回-EIO。
分配并初始化pci_card_t结构体:使用kmalloc()函数为pci_card_t结构体分配内存,并进行相应的错误处理。
获取中断号和IO内存相关信息:从PCI设备结构体dev中获取中断号、IO起始地址、地址范围以及标志位信息,并打印相关信息。
申请IO区域资源:使用pci_request_regions()函数申请IO区域资源,防止地址访问冲突。如果申请失败,则进行错误处理。
映射IO地址空间:使用pci_ioremap_bar()函数将物理地址映射到虚拟地址空间,并进行相应的错误处理。
请求IRQ(中断请求):使用request_irq()函数请求IRQ,并将自定义的中断函数pci_mcard_interrupt与之关联。如果请求失败,则进行错误处理。
设置驱动函数:使用pci_set_drvdata()函数将pci_mcard指针保存在设备结构体dev的私有数据字段中,以便后续在其他驱动程序调用时可以方便地获取。
获取配置信息:调用skel_get_configs()函数来获取PCI设备的配置信息。
返回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);
}
获取与 PCI 设备相关联的私有数据结构
pci_mcard
,该结构包含了一些设备相关的信息。使用
free_irq
函数释放之前注册的中断处理程序。使用
iounmap
函数解除之前映射的 I/O 内存地址。调用
pci_release_region
释放之前分配的 PCI 资源区域。使用
kfree
释放私有数据结构内存。使用
pci_disable_device
禁用 PCI 设备,防止进一步访问设备。打印调试信息,说明成功移除了 PCI 设备。
评论