pci设备驱动例程
/*必須包含的兩個頭文件*/
#include <linux/module.h>
#include <linux/pci.h>/*自定義結構體,用在中斷服務函數里面*/
struct pci_Card {resource_size_t io; /*端口讀寫變量*/long range, flags; /*io地址范圍,標志位*/void __iomem *ioaddr; /*io映射地址*/int irq; /*中斷號*/
};/*驅動程序支持的設備列表,如果有匹配的設備,那么改驅動程序就會被執行*/
static struct pci_device_id ids[] = {{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, /*vendor id, 廠家ID*/0x100f) /*device id, 設備ID,可以通過lspci或者去相應的目錄里面看*/},{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_0) },{0,} /*最后一組為0,表示結束*/
};/*進行注冊,pci總線,ids為上面定義的設置*/
MODULE_DEVICE_TABLE(pci, ids);/*打印配置空間里面的一些信息*/
void skel_get_configs(struct pci_dev *dev) {uint8_t revisionId;uint16_t vendorId, deviceId;uint32_t classId;/*從參數dev里面也是可以打印vendorID等信息的,這個結構體里面包含這個成員變量,用下面的API獲取得到的結果也是一致的*/pci_read_config_word(dev, PCI_VENDOR_ID, &vendorId);printk("vendorID = %x", vendorId);pci_read_config_word(dev, PCI_DEVICE_ID, &deviceId);printk("deviceID = %x", deviceId);pci_read_config_byte(dev, PCI_REVISION_ID, &revisionId);printk("revisionID = %x",revisionId);pci_read_config_dword(dev, PCI_CLASS_REVISION, &classId);printk("classID = %x",classId);
}/*設備中斷服務函數*/
static irqreturn_t pci_Mcard_interrupt(int irq, void *dev_id) {struct pci_Card *pci_Mcard = (struct pci_Card *)dev_id;/*中斷函數里面打印中斷號*/printk("irq = %d, pci_Mcard_irq = %d\n", irq, pci_Mcard->irq);return IRQ_HANDLED;
}/*有匹配的設備,這個函數會執行*/
static int probe(struct pci_dev *dev, const struct pci_device_id *id) {int retval = 0;struct pci_Card *pci_Mcard;printk("probe func\n"); /*設備使能*/if(pci_enable_device(dev)) {printk (KERN_ERR "IO Error.\n");return -EIO;}pci_Mcard = kmalloc(sizeof(struct pci_Card),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;}/*申請中斷IRQ并設定中斷服務子函數*/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設備*/
static void remove(struct pci_dev *dev) {struct pci_Card *pci_Mcard = pci_get_drvdata(dev);free_irq (pci_Mcard->irq, pci_Mcard);iounmap(pci_Mcard->ioaddr);pci_release_regions(dev);kfree(pci_Mcard);pci_disable_device(dev);printk("remove pci device ok\n");
}/*結構體成員變量填充*/
static struct pci_driver pci_driver = {.name = "pci_module",.id_table = ids,.probe = probe,.remove = remove,
};/*模塊入口函數*/
static int __init pci_module_init(void) {printk("pci module entry function\n");return pci_register_driver(&pci_driver);
}/*模塊退出函數*/
static void __exit pci_module_exit(void) {printk("pci module exit function\n");pci_unregister_driver(&pci_driver);
}MODULE_LICENSE("GPL");module_init(pci_module_init);
module_exit(pci_module_exit);
makefile
obj-m := pci_module.oKERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd)all:$(MAKE) -C $(KERNELDIR) M=$(PWD) clean:執行前先把e1000卸載了
sudo rmmod e1000然后,執行
sudo insmod pci_module.ko dmesg
參考:
1:https://www.kernel.org/doc/html/latest/PCI/pci.html
2:http://blog.chinaaet.com/justlxy/p/5100053251
總結
- 上一篇: 【Uipath杂谈】用Datatable
- 下一篇: Activiti6.0(十二)子流程