diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2008-12-07 17:42:22 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2008-12-07 17:42:22 +0000 |
commit | 0e169201a1dc6b150da91010538b7a9a9797312b (patch) | |
tree | a55e3881d21970833383a6a512b6576160b564cc | |
parent | e65407cdbb6991d6656f448e8d19abfc59bf1ed2 (diff) |
Implement pci_device_read_rom() for arbitrary PCI cards, including
secondary VGA. With help from kettenis@. ok kettenis@, miod@.
-rw-r--r-- | lib/libpciaccess/src/openbsd_pci.c | 78 |
1 files changed, 61 insertions, 17 deletions
diff --git a/lib/libpciaccess/src/openbsd_pci.c b/lib/libpciaccess/src/openbsd_pci.c index e4f259224..1046c3ef7 100644 --- a/lib/libpciaccess/src/openbsd_pci.c +++ b/lib/libpciaccess/src/openbsd_pci.c @@ -75,35 +75,63 @@ pci_write(int bus, int dev, int func, uint32_t reg, uint32_t val) } /** - * Read a VGA rom using the 0xc0000 mapping. + * Read a VGA ROM * - * This function should be extended to handle access through PCI resources, - * which should be more reliable when available. */ static int -pci_device_openbsd_read_rom(struct pci_device * dev, void * buffer) +pci_device_openbsd_read_rom(struct pci_device *device, void *buffer) { -#if defined(__alpha__) || defined(__amd64__) || defined(__i386__) - void *bios; + struct pci_device_private *priv = (struct pci_device_private *)device; + unsigned char *bios; + pciaddr_t rom_base; + pciaddr_t rom_size; + u_int32_t csr, rom; + int pci_rom, bus, dev, func; - if ((dev->device_class & 0x00ffff00) != - ((PCI_CLASS_DISPLAY << 16) | (PCI_SUBCLASS_DISPLAY_VGA << 8))) { - return ENOSYS; - } + bus = device->bus; + dev = device->dev; + func = device->func; if (aperturefd == -1) return ENOSYS; - bios = mmap(NULL, dev->rom_size, PROT_READ, 0, aperturefd, 0xc0000); + if (priv->base.rom_size == 0) { +#if defined(__alpha__) || defined(__amd64__) || defined(__i386__) + if ((device->device_class & 0x00ffff00) == + ((PCI_CLASS_DISPLAY << 16) | + (PCI_SUBCLASS_DISPLAY_VGA << 8))) { + rom_base = 0xc0000; + rom_size = 0x10000; + pci_rom = 0; + } else +#endif + return ENOSYS; + } else { + rom_base = priv->rom_base; + rom_size = priv->base.rom_size; + pci_rom = 1; + + pci_read(bus, dev, func, PCI_COMMAND_STATUS_REG, &csr); + pci_write(bus, dev, func, PCI_COMMAND_STATUS_REG, + csr | PCI_COMMAND_MEM_ENABLE); + pci_read(bus, dev, func, PCI_ROM_REG, &rom); + pci_write(bus, dev, func, PCI_ROM_REG, rom | PCI_ROM_ENABLE); + } + + bios = mmap(NULL, rom_size, PROT_READ, MAP_SHARED, + aperturefd, (off_t)rom_base); if (bios == MAP_FAILED) return errno; - memcpy(buffer, bios, dev->rom_size); - munmap(bios, dev->rom_size); - + + memcpy(buffer, bios, device->rom_size); + munmap(bios, device->rom_size); + + if (pci_rom) { + /* Restore PCI config space */ + pci_write(bus, dev, func, PCI_ROM_REG, rom); + pci_write(bus, dev, func, PCI_COMMAND_STATUS_REG, csr); + } return 0; -#else - return ENOSYS; -#endif } static int @@ -332,6 +360,22 @@ pci_device_openbsd_probe(struct pci_device *device) } } + /* Probe expansion ROM if present */ + err = pci_read(bus, dev, func, PCI_ROM_REG, ®); + if (err) + return err; + if (reg != 0) { + err = pci_write(bus, dev, func, PCI_ROM_REG, ~PCI_ROM_ENABLE); + if (err) + return err; + pci_read(bus, dev, func, PCI_ROM_REG, &size); + pci_write(bus, dev, func, PCI_ROM_REG, reg); + + if (PCI_ROM_ADDR(reg) != 0) { + priv->rom_base = PCI_ROM_ADDR(reg); + device->rom_size = PCI_ROM_SIZE(size); + } + } return 0; } |