SylixOS PCIe设备驱动注册和卸载入口
通过前面的介绍我们知道当驱动注册时,如果匹配通过会调用我们自己的probe初始化函数,同样在卸载时会调用我们自己的退出函数。我们先来看看我们自己的probe函数:
static int pci_driver_probe (PCI_DEV_HANDLE pci_dev, const PCI_DEV_ID_HANDLE id) { return 0; }
在SylixOS中,使用PCI_DEV_CB 来表示一个PCIe设备,在系统启动过程中,会扫描系统中所有的PCIe设备并为每一个PCIe设备生成一个PCI_DEV_CB 数据结构:
typedef struct { LW_LIST_LINE PCIDEV_lineDevNode; /* 设备管理节点 */ LW_OBJECT_HANDLE PCIDEV_hDevLock; /* 设备自身操作锁 */ UINT32 PCIDEV_uiDevVersion; /* 设备版本 */ UINT32 PCIDEV_uiUnitNumber; /* 设备编号 */ CHAR PCIDEV_cDevName[PCI_DEV_NAME_MAX]; /* 设备名称 */ INT PCIDEV_iDevBus; /* 总线号 */ INT PCIDEV_iDevDevice; /* 设备号 */ INT PCIDEV_iDevFunction; /* 功能号 */ PCI_HDR PCIDEV_phDevHdr; /* 设备头 */ /* * PCI_HEADER_TYPE_NORMAL PCI_HEADER_TYPE_BRIDGE PCI_HEADER_TYPE_CARDBUS */ INT PCIDEV_iType; /* 设备类型 */ UINT8 PCIDEV_ucPin; /* 中断引脚 */ UINT8 PCIDEV_ucLine; /* 中断线 */ UINT32 PCIDEV_uiIrq; /* 虚拟中断向量号 */ UINT8 PCIDEV_ucRomBaseReg; UINT32 PCIDEV_uiResourceNum; PCI_RESOURCE_CB PCIDEV_tResource[PCI_NUM_RESOURCES]; /* I/O and memory + ROMs */ INT PCIDEV_iDevIrqMsiEn; /* 是否使能 MSI */ ULONG PCIDEV_ulDevIrqVector; /* MSI 或 INTx 中断向量 */ UINT32 PCIDEV_uiDevIrqMsiNum; /* MSI 中断数量 */ PCI_MSI_DESC PCIDEV_pmdDevIrqMsiDesc; /* MSI 中断描述 */ CHAR PCIDEV_cDevIrqName[PCI_DEV_IRQ_NAME_MAX]; /* 中断名称 */ PINT_SVR_ROUTINE PCIDEV_pfuncDevIrqHandle; /* 中断服务句柄 */ PVOID PCIDEV_pvDevIrqArg; /* 中断服务参数 */ PVOID PCIDEV_pvDevDriver; /* 驱动句柄 */ PVOID PCIDEV_pvPrivate; /* 用户驱动使用 */ } PCI_DEV_CB; typedef PCI_DEV_CB *PCI_DEV_HANDLE;
通过上述结构信息我们可以看出从这个数据结构中包含了很多信息,比如设备在总线上的位置、中断号、资源等等。通过资源成员我们可以获取设备各个BAR空间中的起始地址和大小,这个在下一章节详解。
probe函数的第二个入参表示当前设备的ID信息。类似probe函数,我们来看看自己定义的退出函数:
static void pci_driver_remove (PCI_DEV_HANDLE pci_dev) { }
这两个函数定义完之后,还需要将其设置到pri_driver中:
static PCI_DRV_CB pci_driver = { .PCIDRV_hDrvIdTable = (PCI_DEV_ID_HANDLE)pci_devices, .PCIDRV_uiDrvIdTableSize = sizeof(pci_devices) / sizeof(PCI_DEV_ID_CB), .PCIDRV_pfuncDevProbe = pci_driver_probe, .PCIDRV_pfuncDevRemove = pci_driver_remove, };
我们可以在probe和remove函数中加调试信息然后在模拟器中加载驱动观察输出效果:
static int pci_driver_probe (PCI_DEV_HANDLE pci_dev, const PCI_DEV_ID_HANDLE id) { printk("probe: bus %d, dev %d, func %d.\r\n", pci_dev->PCIDEV_iDevBus, pci_dev->PCIDEV_iDevDevice, pci_dev->PCIDEV_iDevFunction); return 0; } static void pci_driver_remove (PCI_DEV_HANDLE pci_dev) { printk("remove: bus %d, dev %d, func %d.\r\n", pci_dev->PCIDEV_iDevBus, pci_dev->PCIDEV_iDevDevice, pci_dev->PCIDEV_iDevFunction); }
编译驱动上传x86模拟器然后加载驱动:
insmod /lib/modules/pci_driver_demo3.ko
可以在模拟器上看到probe函数中的打印:
使用pcidev和pcidrv可以查看到驱动的信息:
卸载驱动查看打印信息:
rmmod /lib/modules/pci_driver_demo3.ko
可以在模拟器上看到remove函数中的打印:
附源码
pci_driver_demo3.c源码:
#define __SYLIXOS_KERNEL #define __SYLIXOS_PCI_DRV #include <SylixOS.h> #include <module.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <linux/compat.h> #include <system/device/pci/pciBus.h> #include <system/device/pci/pciMsi.h> #include <system/device/pci/pciLib.h> #include <system/device/pci/pciIds.h> #include <system/device/pci/pciDev.h> #define PCI_DRV_NAME "pci_demo_drv" static PCI_DEV_ID_CB pci_devices[] = { {PCI_DEVICE(0x1013, 0x00b8)}, {} }; static int pci_driver_probe (PCI_DEV_HANDLE pci_dev, const PCI_DEV_ID_HANDLE id) { printk("probe: bus %d, dev %d, func %d.\r\n", pci_dev->PCIDEV_iDevBus, pci_dev->PCIDEV_iDevDevice, pci_dev->PCIDEV_iDevFunction); return 0; } static void pci_driver_remove (PCI_DEV_HANDLE pci_dev) { printk("remove: bus %d, dev %d, func %d.\r\n", pci_dev->PCIDEV_iDevBus, pci_dev->PCIDEV_iDevDevice, pci_dev->PCIDEV_iDevFunction); } static PCI_DRV_CB pci_driver = { .PCIDRV_hDrvIdTable = (PCI_DEV_ID_HANDLE)pci_devices, .PCIDRV_uiDrvIdTableSize = sizeof(pci_devices) / sizeof(PCI_DEV_ID_CB), .PCIDRV_pfuncDevProbe = pci_driver_probe, .PCIDRV_pfuncDevRemove = pci_driver_remove, }; int module_init (void) { strlcpy(pci_driver.PCIDRV_cDrvName, PCI_DRV_NAME, PCI_DRV_NAME_MAX); API_PciDrvRegister(&pci_driver); return 0; } void module_exit (void) { PCI_DRV_HANDLE pci_driver; pci_driver = API_PciDrvHandleGet(PCI_DRV_NAME); API_PciDrvUnregister(pci_driver); }
评论