diff options
author | Harald Welte <laforge@gnumonks.org> | 2009-05-19 17:12:58 +0800 |
---|---|---|
committer | Jonathan Corbet <corbet@lwn.net> | 2010-04-20 14:23:18 -0600 |
commit | 109771a68bedda77606500dc14455eca92df6769 (patch) | |
tree | 1ab712aaac8db6de0acadc16e14f2cb9595e1746 /drivers/video/via/viafbdev.c | |
parent | 2eaa9cfdf33b8d7fb7aff27792192e0019ae8fc6 (diff) |
viafb: Fix various resource leaks during module_init()
The current code executed from module_init() in viafb does not have
proper error checking and [partial] resoure release paths in case
an error happens half way through driver initialization.
This patch adresses the most obvious of those issues, such as a
leftover i2c bus if module_init (and thus module load) fails.
[jc: fixed merge conflicts]
[jc: also restored -ENOMEM return on ioremap() fail]
Cc: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Cc: ScottFang@viatech.com.cn
Cc: JosephChan@via.com.tw
Signed-off-by: Harald Welte <HaraldWelte@viatech.com>
Diffstat (limited to 'drivers/video/via/viafbdev.c')
-rw-r--r-- | drivers/video/via/viafbdev.c | 52 |
1 files changed, 39 insertions, 13 deletions
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index ce7783b63f6..b7018ef6977 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved. * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. * This program is free software; you can redistribute it and/or @@ -1737,6 +1737,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, u32 default_xres, default_yres; struct VideoModeTable *vmode_entry; struct fb_var_screeninfo default_var; + int rc; u32 viafb_par_length; DEBUG_MSG(KERN_INFO "VIAFB PCI Probe!!\n"); @@ -1751,7 +1752,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, &pdev->dev); if (!viafbinfo) { printk(KERN_ERR"Could not allocate memory for viafb_info.\n"); - return -ENODEV; + return -ENOMEM; } viaparinfo = (struct viafb_par *)viafbinfo->par; @@ -1774,7 +1775,9 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, viafb_dual_fb = 0; /* Set up I2C bus stuff */ - viafb_create_i2c_bus(viaparinfo); + rc = viafb_create_i2c_bus(viaparinfo); + if (rc) + goto out_fb_release; viafb_init_chip_info(pdev, ent); viaparinfo->fbmem = pci_resource_start(pdev, 0); @@ -1785,7 +1788,8 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, viaparinfo->memsize); if (!viafbinfo->screen_base) { printk(KERN_INFO "ioremap failed\n"); - return -ENOMEM; + rc = -ENOMEM; + goto out_delete_i2c; } viafbinfo->fix.mmio_start = pci_resource_start(pdev, 1); @@ -1861,8 +1865,8 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, if (!viafbinfo1) { printk(KERN_ERR "allocate the second framebuffer struct error\n"); - framebuffer_release(viafbinfo); - return -ENOMEM; + rc = -ENOMEM; + goto out_delete_i2c; } viaparinfo1 = viafbinfo1->par; memcpy(viaparinfo1, viaparinfo, viafb_par_length); @@ -1913,21 +1917,26 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, viaparinfo->depth = fb_get_color_depth(&viafbinfo->var, &viafbinfo->fix); default_var.activate = FB_ACTIVATE_NOW; - fb_alloc_cmap(&viafbinfo->cmap, 256, 0); + rc = fb_alloc_cmap(&viafbinfo->cmap, 256, 0); + if (rc) + goto out_fb1_release; if (viafb_dual_fb && (viafb_primary_dev == LCD_Device) && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)) { - if (register_framebuffer(viafbinfo1) < 0) - return -EINVAL; + rc = register_framebuffer(viafbinfo1); + if (rc) + goto out_dealloc_cmap; } - if (register_framebuffer(viafbinfo) < 0) - return -EINVAL; + rc = register_framebuffer(viafbinfo); + if (rc) + goto out_fb1_unreg_lcd_cle266; if (viafb_dual_fb && ((viafb_primary_dev != LCD_Device) || (viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266))) { - if (register_framebuffer(viafbinfo1) < 0) - return -EINVAL; + rc = register_framebuffer(viafbinfo1); + if (rc) + goto out_fb_unreg; } DEBUG_MSG(KERN_INFO "fb%d: %s frame buffer device %dx%d-%dbpp\n", viafbinfo->node, viafbinfo->fix.id, default_var.xres, @@ -1936,6 +1945,23 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, viafb_init_proc(&viaparinfo->shared->proc_entry); viafb_init_dac(IGA2); return 0; + +out_fb_unreg: + unregister_framebuffer(viafbinfo); +out_fb1_unreg_lcd_cle266: + if (viafb_dual_fb && (viafb_primary_dev == LCD_Device) + && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)) + unregister_framebuffer(viafbinfo1); +out_dealloc_cmap: + fb_dealloc_cmap(&viafbinfo->cmap); +out_fb1_release: + if (viafbinfo1) + framebuffer_release(viafbinfo1); +out_delete_i2c: + viafb_delete_i2c_buss(viaparinfo); +out_fb_release: + framebuffer_release(viafbinfo); + return rc; } static void __devexit via_pci_remove(struct pci_dev *pdev) |