From: Francois Romieu <romieu@fr.zoreil.com>

- fix unbalanced invocation of pci_enable_device();

- leaks plugged in cirrusfb_zorro_setup();

- move framebuffer_release() into cirrusfb_{pci/zorro}_unmap() to balance
  cirrusfb_{pci/zorro}_setup();

- make cirrusfb_{pci/zorro}_setup() return adequate error codes when
  something fails;

- cirrusfb_zorro_unmap: iounmap() now take as argument values previously
  returned by ioremap().

Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/drivers/video/cirrusfb.c |  131 +++++++++++++++++++++++++++------------
 1 files changed, 93 insertions(+), 38 deletions(-)

diff -puN drivers/video/cirrusfb.c~cirrusfb-minor-fixes drivers/video/cirrusfb.c
--- 25/drivers/video/cirrusfb.c~cirrusfb-minor-fixes	2004-06-28 13:31:26.356675632 -0700
+++ 25-akpm/drivers/video/cirrusfb.c	2004-06-28 13:31:26.365674264 -0700
@@ -2144,15 +2144,17 @@ static void get_pci_addrs (const struct 
 
 static void __devexit cirrusfb_pci_unmap (struct cirrusfb_info *cinfo)
 {
-	iounmap (cinfo->fbmem);
-	release_mem_region(cinfo->fbmem_phys, cinfo->size);
+	struct pci_dev *pdev = cinfo->pdev;
 
+	iounmap(cinfo->fbmem);
 #if 0 /* if system didn't claim this region, we would... */
 	release_mem_region(0xA0000, 65535);
 #endif
-
 	if (release_io_ports)
 		release_region(0x3C0, 32);
+	pci_release_regions(pdev);
+	framebuffer_release(cinfo->info);
+	pci_disable_device(pdev);
 }
 
 
@@ -2163,16 +2165,19 @@ static struct cirrusfb_info *cirrusfb_pc
 	struct fb_info *info;
 	cirrusfb_board_t btype;
 	unsigned long board_addr, board_size;
+	int ret;
 
-	if (pci_enable_device(pdev) != 0) {
+	ret = pci_enable_device(pdev);
+	if (ret < 0) {
 		printk(KERN_ERR "cirrusfb: Cannot enable PCI device\n");
-		return NULL;
+		goto err_out;
 	}
 
 	info = framebuffer_alloc(sizeof(struct cirrusfb_info), &pdev->dev);
 	if (!info) {
-		printk (KERN_ERR "cirrusfb: could not allocate memory\n");
-		return NULL;
+		printk(KERN_ERR "cirrusfb: could not allocate memory\n");
+		ret = -ENOMEM;
+		goto err_disable;
 	}
 
 	cinfo = info->par;
@@ -2202,25 +2207,30 @@ static struct cirrusfb_info *cirrusfb_pc
 	board_size = (btype == BT_GD5480) ?
 		32 * MB_ : cirrusfb_get_memsize (cinfo->regbase);
 
-	if (!request_mem_region(board_addr, board_size, "cirrusfb")) {
+	ret = pci_request_regions(pdev, "cirrusfb");
+	if (ret <0) {
 		printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n",
 		       board_addr);
-		framebuffer_release (info);
-		return NULL;
+		goto err_release_fb;
 	}
 #if 0 /* if the system didn't claim this region, we would... */
 	if (!request_mem_region(0xA0000, 65535, "cirrusfb")) {
-		printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n",
+		printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n"
+,
 		       0xA0000L);
-		release_mem_region(board_addr, board_size);
-		framebuffer_release (info);
-		return NULL;
+		ret = -EBUSY;
+		goto err_release_regions;
 	}
 #endif
 	if (request_region(0x3C0, 32, "cirrusfb"))
 		release_io_ports = 1;
 
-	cinfo->fbmem = ioremap (board_addr, board_size);
+	cinfo->fbmem = ioremap(board_addr, board_size);
+	if (!cinfo->fbmem) {
+		ret = -EIO;
+		goto err_release_legacy;
+	}
+
 	cinfo->fbmem_phys = board_addr;
 	cinfo->size = board_size;
 
@@ -2228,6 +2238,21 @@ static struct cirrusfb_info *cirrusfb_pc
 	printk ("Cirrus Logic chipset on PCI bus\n");
 
 	return cinfo;
+
+err_release_legacy:
+	if (release_io_ports)
+		release_region(0x3C0, 32);
+#if 0
+	release_mem_region(0xA0000, 65535);
+err_release_regions:
+#endif
+	pci_release_regions(pdev);
+err_release_fb:
+	framebuffer_release(info);
+err_disable:
+	pci_disable_device(pdev);
+err_out:
+	return ERR_PTR(ret);
 }
 #endif				/* CONFIG_PCI */
 
@@ -2266,7 +2291,7 @@ static int cirrusfb_zorro_find (struct z
 	}
 
 	printk (KERN_NOTICE "cirrusfb: no supported board found.\n");
-	return -1;
+	return -ENODEV;
 }
 
 
@@ -2275,30 +2300,35 @@ static void __devexit cirrusfb_zorro_unm
 	release_mem_region(cinfo->board_addr, cinfo->board_size);
 
 	if (cinfo->btype == BT_PICASSO4) {
-		iounmap ((void *)cinfo->board_addr);
-		iounmap ((void *)cinfo->fbmem_phys);
+		cinfo->regbase -= 0x600000;
+		iounmap ((void *)cinfo->regbase);
+		iounmap ((void *)cinfo->fbmem);
 	} else {
 		if (cinfo->board_addr > 0x01000000)
-			iounmap ((void *)cinfo->board_addr);
+			iounmap ((void *)cinfo->fbmem);
 	}
+	framebuffer_release(cinfo->info);
 }
 
 
-static struct cirrusfb_info *cirrusfb_zorro_setup ()
+static struct cirrusfb_info *cirrusfb_zorro_setup(void)
 {
 	struct cirrusfb_info *cinfo;
 	struct fb_info *info;
 	cirrusfb_board_t btype;
 	struct zorro_dev *z = NULL, *z2 = NULL;
 	unsigned long board_addr, board_size, size;
+	int ret;
 
-	if (cirrusfb_zorro_find (&z, &z2, &btype, &size))
-		return NULL;
+	ret = cirrusfb_zorro_find (&z, &z2, &btype, &size);
+	if (ret < 0)
+		goto err_out;
 
 	info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
 	if (!info) {
 		printk (KERN_ERR "cirrusfb: could not allocate memory\n");
-		return NULL;
+		ret = -ENOMEM;
+		goto err_out;
 	}
 
 	cinfo = info->par;
@@ -2316,11 +2346,14 @@ static struct cirrusfb_info *cirrusfb_zo
 	if (!request_mem_region(board_addr, board_size, "cirrusfb")) {
 		printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n",
 		       board_addr);
-		return -1;
+		ret = -EBUSY;
+		goto err_release_fb;
 	}
 
 	printk (" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr);
 
+	ret = -EIO;
+
 	if (btype == BT_PICASSO4) {
 		printk (" REG at $%lx\n", board_addr + 0x600000);
 
@@ -2329,12 +2362,17 @@ static struct cirrusfb_info *cirrusfb_zo
 		/* for P4, map in its address space in 2 chunks (### TEST! ) */
 		/* (note the ugly hardcoded 16M number) */
 		cinfo->regbase = ioremap (board_addr, 16777216);
+		if (!cinfo->regbase)
+			goto err_release_region;
+
 		DPRINTK ("cirrusfb: Virtual address for board set to: $%p\n", cinfo->regbase);
 		cinfo->regbase += 0x600000;
 		cinfo->fbregs_phys = board_addr + 0x600000;
 
 		cinfo->fbmem_phys = board_addr + 16777216;
 		cinfo->fbmem = ioremap (info->fbmem_phys, 16777216);
+		if (!cinfo->fbmem)
+			goto err_unmap_regbase;
 	} else {
 		printk (" REG at $%lx\n", (unsigned long) z2->resource.start);
 
@@ -2343,6 +2381,8 @@ static struct cirrusfb_info *cirrusfb_zo
 			cinfo->fbmem = ioremap (board_addr, board_size);
 		else
 			cinfo->fbmem = (caddr_t) ZTWO_VADDR (board_addr);
+		if (!cinfo->fbmem)
+			goto err_release_region;
 
 		/* set address for REG area of board */
 		cinfo->regbase = (caddr_t) ZTWO_VADDR (z2->resource.start);
@@ -2354,6 +2394,16 @@ static struct cirrusfb_info *cirrusfb_zo
 	printk (KERN_INFO "Cirrus Logic chipset on Zorro bus\n");
 
 	return 0;
+
+err_unmap_regbase:
+	/* Parental advisory: explicit hack */
+	iounmap(cinfo->regbase - 0x600000);
+err_release_region:
+	release_region(board_addr, board_size);
+err_release_fb:
+	framebuffer_release(info);
+err_out:
+	return ERR_PTR(ret);
 }
 #endif /* CONFIG_ZORRO */
 
@@ -2430,8 +2480,10 @@ static int cirrusfb_pci_register (struct
 
 	cinfo = cirrusfb_bus_setup(pdev, ent);
 
-	if (!cinfo)
-		return -ENODEV;
+	if (IS_ERR(cinfo)) {
+		err = PTR_ERR(cinfo);
+		goto err_out;
+	}
 
 	info = cinfo->info;
 	btype = cinfo->btype;
@@ -2446,13 +2498,12 @@ static int cirrusfb_pci_register (struct
 	/* state, even though we haven't written the mode to the hw yet...  */
 	info->var = cirrusfb_predefined[cirrusfb_def_mode].var;
 	info->var.activate = FB_ACTIVATE_NOW;
+
 	err = cirrusfb_decode_var(&info->var, &cinfo->currentmode, info);
-	if(err) {
+	if (err < 0) {
 		/* should never happen */
 		DPRINTK("choking on default var... umm, no good.\n");
-		cirrusfb_unmap (cinfo);
-		framebuffer_release (info);
-		return -EINVAL;
+		goto err_unmap_cirrusfb;
 	}
 
 	/* set all the vital stuff */
@@ -2460,16 +2511,21 @@ static int cirrusfb_pci_register (struct
 
 	pci_set_drvdata(pdev, info);
 
-	if ((err = register_framebuffer (info)) < 0) {
+	err = register_framebuffer(info);
+	if (err < 0) {
 		printk (KERN_ERR "cirrusfb: could not register fb device; err = %d!\n", err);
-		fb_dealloc_cmap(&info->cmap);
-		cirrusfb_unmap (cinfo);
-		framebuffer_release (info);
-		return -EINVAL;
+		goto err_dealloc_cmap;
 	}
 
 	DPRINTK ("EXIT, returning 0\n");
 	return 0;
+
+err_dealloc_cmap:
+	fb_dealloc_cmap(&info->cmap);
+err_unmap_cirrusfb:
+	cirrusfb_unmap(cinfo);
+err_out:
+	return err;
 }
 
 
@@ -2482,11 +2538,10 @@ static void __devexit cirrusfb_cleanup (
 	switch_monitor (cinfo, 0);
 #endif
 
-	cirrusfb_unmap (cinfo);
-	fb_dealloc_cmap (&info->cmap);
 	unregister_framebuffer (info);
+	fb_dealloc_cmap (&info->cmap);
 	printk ("Framebuffer unregistered\n");
-	framebuffer_release (info);
+	cirrusfb_unmap (cinfo);
 
 	DPRINTK ("EXIT\n");
 }
_