|
@@ -73,6 +73,107 @@ static struct resource video_rom_resource = {
|
|
|
.flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
|
|
|
};
|
|
|
|
|
|
+/* does this oprom support the given pci device, or any of the devices
|
|
|
+ * that the driver supports?
|
|
|
+ */
|
|
|
+static bool match_id(struct pci_dev *pdev, unsigned short vendor, unsigned short device)
|
|
|
+{
|
|
|
+ struct pci_driver *drv = pdev->driver;
|
|
|
+ const struct pci_device_id *id;
|
|
|
+
|
|
|
+ if (pdev->vendor == vendor && pdev->device == device)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ for (id = drv ? drv->id_table : NULL; id && id->vendor; id++)
|
|
|
+ if (id->vendor == vendor && id->device == device)
|
|
|
+ break;
|
|
|
+
|
|
|
+ return id && id->vendor;
|
|
|
+}
|
|
|
+
|
|
|
+static bool probe_list(struct pci_dev *pdev, unsigned short vendor,
|
|
|
+ const unsigned char *rom_list)
|
|
|
+{
|
|
|
+ unsigned short device;
|
|
|
+
|
|
|
+ do {
|
|
|
+ if (probe_kernel_address(rom_list, device) != 0)
|
|
|
+ device = 0;
|
|
|
+
|
|
|
+ if (device && match_id(pdev, vendor, device))
|
|
|
+ break;
|
|
|
+
|
|
|
+ rom_list += 2;
|
|
|
+ } while (device);
|
|
|
+
|
|
|
+ return !!device;
|
|
|
+}
|
|
|
+
|
|
|
+static struct resource *find_oprom(struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ struct resource *oprom = NULL;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(adapter_rom_resources); i++) {
|
|
|
+ struct resource *res = &adapter_rom_resources[i];
|
|
|
+ unsigned short offset, vendor, device, list, rev;
|
|
|
+ const unsigned char *rom;
|
|
|
+
|
|
|
+ if (res->end == 0)
|
|
|
+ break;
|
|
|
+
|
|
|
+ rom = isa_bus_to_virt(res->start);
|
|
|
+ if (probe_kernel_address(rom + 0x18, offset) != 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (probe_kernel_address(rom + offset + 0x4, vendor) != 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (probe_kernel_address(rom + offset + 0x6, device) != 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (match_id(pdev, vendor, device)) {
|
|
|
+ oprom = res;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (probe_kernel_address(rom + offset + 0x8, list) == 0 &&
|
|
|
+ probe_kernel_address(rom + offset + 0xc, rev) == 0 &&
|
|
|
+ rev >= 3 && list &&
|
|
|
+ probe_list(pdev, vendor, rom + offset + list)) {
|
|
|
+ oprom = res;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return oprom;
|
|
|
+}
|
|
|
+
|
|
|
+void *pci_map_biosrom(struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ struct resource *oprom = find_oprom(pdev);
|
|
|
+
|
|
|
+ if (!oprom)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ return ioremap(oprom->start, resource_size(oprom));
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(pci_map_biosrom);
|
|
|
+
|
|
|
+void pci_unmap_biosrom(void __iomem *image)
|
|
|
+{
|
|
|
+ iounmap(image);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(pci_unmap_biosrom);
|
|
|
+
|
|
|
+size_t pci_biosrom_size(struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ struct resource *oprom = find_oprom(pdev);
|
|
|
+
|
|
|
+ return oprom ? resource_size(oprom) : 0;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(pci_biosrom_size);
|
|
|
+
|
|
|
#define ROMSIGNATURE 0xaa55
|
|
|
|
|
|
static int __init romsignature(const unsigned char *rom)
|