Index: sys/dev/pci/pci_user.c =================================================================== --- sys/dev/pci/pci_user.c +++ sys/dev/pci/pci_user.c @@ -923,6 +923,86 @@ return (error); } +static int +pci_bar_io(device_t pcidev, struct pci_ioport_io *pii) +{ + struct pci_map *pm; + struct resource *res; + bus_space_handle_t handle; + bus_space_tag_t tag; + uint32_t offset, width; + int error, bar; + + if (pii->pii_op != PCIIOPORT_READ && + pii->pii_op != PCIIOPORT_WRITE) + return (EINVAL); + if (pii->pii_bar > PCIR_MAX_BAR_0) + return (EINVAL); + + bar = PCIR_BAR(pii->pii_bar); + pm = pci_find_bar(pcidev, bar); + if (pm == NULL) + return (EINVAL); + if (!PCI_BAR_IO(pm->pm_value)) + return (EIO); + + res = bus_alloc_resource_any(pcidev, SYS_RES_IOPORT, &bar, RF_ACTIVE); + if (res == NULL) + return (ENOENT); + handle = rman_get_bushandle(res); + tag = rman_get_bustag(res); + + offset = pii->pii_offset; + width = pii->pii_width; + + if (offset + width < offset || + rman_get_size(res) < offset + width) { + error = EINVAL; + goto out; + } + + error = 0; + switch (pii->pii_op) { + case PCIIOPORT_READ: + switch (pii->pii_width) { + case 1: + pii->pii_value = bus_space_read_1(tag, handle, offset); + break; + case 2: + pii->pii_value = bus_space_read_2(tag, handle, offset); + break; + case 4: + pii->pii_value = bus_space_read_4(tag, handle, offset); + break; + default: + error = EINVAL; + break; + } + break; + case PCIIOPORT_WRITE: + switch (pii->pii_width) { + case 1: + bus_space_write_1(tag, handle, offset, pii->pii_value); + break; + case 2: + bus_space_write_2(tag, handle, offset, pii->pii_value); + break; + case 4: + bus_space_write_4(tag, handle, offset, pii->pii_value); + break; + default: + error = EINVAL; + break; + } + break; + } + +out: + bus_release_resource(pcidev, SYS_RES_IOPORT, bar, res); + + return (error); +} + static int pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) { @@ -932,6 +1012,7 @@ struct pci_conf_io *cio = NULL; struct pci_devinfo *dinfo; struct pci_io *io; + struct pci_ioport_io *pii; struct pci_bar_io *bio; struct pci_list_vpd_io *lvio; struct pci_match_conf *pattern_buf; @@ -1302,6 +1383,19 @@ error = pcidev == NULL ? ENODEV : pci_bar_mmap(pcidev, pbm); break; + case PCIOCIOPORTIO: + pii = (struct pci_ioport_io *)data; + + pcidev = pci_find_dbsf(pii->pii_sel.pc_domain, + pii->pii_sel.pc_bus, pii->pii_sel.pc_dev, + pii->pii_sel.pc_func); + if (pcidev == NULL) { + error = ENODEV; + break; + } + error = pci_bar_io(pcidev, pii); + break; + default: error = ENOTTY; break; Index: sys/sys/pciio.h =================================================================== --- sys/sys/pciio.h +++ sys/sys/pciio.h @@ -151,6 +151,17 @@ int pbm_memattr; }; +struct pci_ioport_io { + struct pcisel pii_sel; /* device to operate on */ +#define PCIIOPORT_READ 0x1 +#define PCIIOPORT_WRITE 0x2 + int pii_op; + uint32_t pii_bar; + uint32_t pii_offset; + uint32_t pii_width; + uint32_t pii_value; +}; + #define PCIIO_BAR_MMAP_FIXED 0x01 #define PCIIO_BAR_MMAP_EXCL 0x02 #define PCIIO_BAR_MMAP_RW 0x04 @@ -163,5 +174,6 @@ #define PCIOCGETBAR _IOWR('p', 6, struct pci_bar_io) #define PCIOCLISTVPD _IOWR('p', 7, struct pci_list_vpd_io) #define PCIOCBARMMAP _IOWR('p', 8, struct pci_bar_mmap) +#define PCIOCIOPORTIO _IOWR('p', 9, struct pci_ioport_io) #endif /* !_SYS_PCIIO_H_ */