/* Get pci port io resources described by bar #pci_bar in uio resource n. */ static int igbuio_pci_setup_ioport(struct pci_dev *dev, struct uio_info *info, int n, int pci_bar, const char *name) { unsigned long addr, len; if (sizeof(info->port) / sizeof(info->port[0]) <= n) return -EINVAL; addr = pci_resource_start(dev, pci_bar); len = pci_resource_len(dev, pci_bar); if (addr == 0 || len == 0) return -EINVAL; info->port[n].name = name; info->port[n].start = addr; info->port[n].size = len; info->port[n].porttype = UIO_PORT_X86; return 0; }
static int igbuio_setup_bars(struct pci_dev *dev, struct uio_info *info) { int i, iom, iop, ret; unsigned long flags; static const char *bar_names[PCI_STD_RESOURCE_END + 1] = { "BAR0", "BAR1", "BAR2", "BAR3", "BAR4", "BAR5", }; iom = 0; iop = 0; //遍历PCI设备的6个BAR for (i = 0; i < ARRAY_SIZE(bar_names); i++) { //PCI BAR空间不等于0且起始地址不等于0,认为为有效BAR if (pci_resource_len(dev, i) != 0 && pci_resource_start(dev, i) != 0) { //拿到BAR的标识,如果为0x00000200则为内存空间 flags = pci_resource_flags(dev, i); if (flags & IORESOURCE_MEM) { //对内存空间的PCI BAR进行映射 ret = igbuio_pci_setup_iomem(dev, info, iom, i, bar_names[i]); if (ret != 0) return ret; iom++; //IO空间不再讨论范围内 } else if (flags & IORESOURCE_IO) { ret = igbuio_pci_setup_ioport(dev, info, iop, i, bar_names[i]); if (ret != 0) return ret; iop++; } } } return (iom != 0 || iop != 0) ? ret : -ENOENT; } //对内存BAR进行映射,以及填充数据结构 static int igbuio_pci_setup_iomem(struct pci_dev *dev, struct uio_info *info, int n, int pci_bar, const char *name) { unsigned long addr, len; void *internal_addr; if (n >= ARRAY_SIZE(info->mem)) return -EINVAL; //拿到PCI BAR的起始地址 addr = pci_resource_start(dev, pci_bar); //拿到PCI BAR的长度 len = pci_resource_len(dev, pci_bar); if (addr == 0 || len == 0) return -1; //wc_activate为igb_uio.ko的参数,默认为0,会进入if条件 if (wc_activate == 0) { //对PCI BAR进行ioremap,映射到内核空间,得到可以在内核空间映射后的PCI BAR地址,虽然没什么用,因为igb_uio完全不需要操作PCI设备,因此获得此地址意义不大 internal_addr = ioremap(addr, len); if (internal_addr == NULL) return -1; } else { internal_addr = NULL; } //填充数据结构 info->mem[n].name = name; //PCI BAR名,例如BAR0、BAR1 info->mem[n].addr = addr; //PCI BAR起始地址,物理地址 info->mem[n].internal_addr = internal_addr; //经过ioremap映射后的PCI BAR,可以供内核空间访问 info->mem[n].size = len; //PCI BAR长度 info->mem[n].memtype = UIO_MEM_PHYS; //PCI BAR类型,为内存BAR return 0; }