staging: xgifb: copy PCI ROM properly
authorAaro Koskinen <aaro.koskinen@iki.fi>
Thu, 17 Feb 2011 21:29:13 +0000 (23:29 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 18 Feb 2011 20:38:17 +0000 (12:38 -0800)
Use proper helper functions to copy the PCI ROM. Also use dynamic memory
allocation. The original code mapped incorrect amount of memory and will
crash on some platforms.

Signed-off-by: Aaro Koskinen <aaro.koskinen@iki.fi>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/xgifb/XGI_main_26.c

index 2328926162f244c743ba63cac87a6afb616e8b21..90dca40c44944fc82158a5ae534e111600191590 100644 (file)
@@ -54,6 +54,8 @@ int XGIfb_accel = 0;
 #define GPIOG_READ  (1<<1)
 int XGIfb_GetXG21DefaultLVDSModeIdx(void);
 
+#define XGIFB_ROM_SIZE 65536
+
 /* -------------------- Macro definitions ---------------------------- */
 
 #undef XGIFBDEBUG
@@ -2881,52 +2883,26 @@ XGIINITSTATIC int __init XGIfb_setup(char *options)
        return 0;
 }
 
-static unsigned char VBIOS_BUF[65535];
-
-static unsigned char *attempt_map_rom(struct pci_dev *dev, void *copy_address)
+static unsigned char *xgifb_copy_rom(struct pci_dev *dev)
 {
-       u32 rom_size = 0;
-       u32 rom_address = 0;
-       int j;
-
-       /*  Get the size of the expansion rom */
-       pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0xFFFFFFFF);
-       pci_read_config_dword(dev, PCI_ROM_ADDRESS, &rom_size);
-       if ((rom_size & 0x01) == 0) {
-               printk("No ROM\n");
-               return NULL;
-       }
+       void __iomem *rom_address;
+       unsigned char *rom_copy;
+       size_t rom_size;
 
-       rom_size &= 0xFFFFF800;
-       rom_size = (~rom_size) + 1;
-
-       rom_address = pci_resource_start(dev, 0);
-       if (rom_address == 0 || rom_address == 0xFFFFFFF0) {
-               printk("No suitable rom address found\n");
+       rom_address = pci_map_rom(dev, &rom_size);
+       if (rom_address == NULL)
                return NULL;
-       }
 
-       printk("ROM Size is %dK, Address is %x\n", rom_size / 1024, rom_address);
+       rom_copy = vzalloc(XGIFB_ROM_SIZE);
+       if (rom_copy == NULL)
+               goto done;
 
-       /*  Map ROM */
-       pci_write_config_dword(dev, PCI_ROM_ADDRESS, rom_address
-                       | PCI_ROM_ADDRESS_ENABLE);
+       rom_size = min_t(size_t, rom_size, XGIFB_ROM_SIZE);
+       memcpy_fromio(rom_copy, rom_address, rom_size);
 
-       /* memcpy(copy_address, rom_address, rom_size); */
-       {
-               unsigned char *virt_addr = ioremap(rom_address, 0x8000000);
-
-               unsigned char *from = (unsigned char *) virt_addr;
-               unsigned char *to = (unsigned char *) copy_address;
-               for (j = 0; j < 65536 /*rom_size*/; j++)
-                       *to++ = *from++;
-       }
-
-       pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0);
-
-       printk("Copy is done\n");
-
-       return copy_address;
+done:
+       pci_unmap_rom(dev, rom_address);
+       return rom_copy;
 }
 
 static int __devinit xgifb_probe(struct pci_dev *pdev,
@@ -3039,8 +3015,7 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
 
        XGIhw_ext.pDevice = NULL;
        if ((xgi_video_info.chip == XG21) || (XGIfb_userom)) {
-               XGIhw_ext.pjVirtualRomBase = attempt_map_rom(pdev, VBIOS_BUF);
-
+               XGIhw_ext.pjVirtualRomBase = xgifb_copy_rom(pdev);
                if (XGIhw_ext.pjVirtualRomBase)
                        printk(KERN_INFO "XGIfb: Video ROM found and mapped to %p\n", XGIhw_ext.pjVirtualRomBase);
                else
@@ -3434,6 +3409,7 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
        return 0;
 
 error:
+       vfree(XGIhw_ext.pjVirtualRomBase);
        vfree(XGIhw_ext.pSR);
        vfree(XGIhw_ext.pCR);
        framebuffer_release(fb_info);
@@ -3449,6 +3425,7 @@ static void __devexit xgifb_remove(struct pci_dev *pdev)
        /* Unregister the framebuffer */
        /* if (xgi_video_info.registered) { */
        unregister_framebuffer(fb_info);
+       vfree(XGIhw_ext.pjVirtualRomBase);
        framebuffer_release(fb_info);
        /* } */