fsl_usb2_udc: Fix oops on probe failure.

In some circumstances when fsl_udc_probe fails udc_controller is freed but
the pointer remains non-NULL. fsl_udc_remove will then try and teardown
the partly initialized and freed controller structure resulting in an oops.
This patch ensures udc_controller is either NULL or fully initialized after
fsl_udc_probe.

Signed-off-by: Will Newton <will.newton@gmail.com>
Acked-by: Li Yang <leoli@freescale.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Will Newton 2008-08-12 15:39:17 +01:00 committed by Greg Kroah-Hartman
parent 59097fb73c
commit 23d7cd040e

View File

@ -2244,21 +2244,21 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) { if (!res) {
kfree(udc_controller); ret = -ENXIO;
return -ENXIO; goto err_kfree;
} }
if (!request_mem_region(res->start, res->end - res->start + 1, if (!request_mem_region(res->start, res->end - res->start + 1,
driver_name)) { driver_name)) {
ERR("request mem region for %s failed\n", pdev->name); ERR("request mem region for %s failed\n", pdev->name);
kfree(udc_controller); ret = -EBUSY;
return -EBUSY; goto err_kfree;
} }
dr_regs = ioremap(res->start, res->end - res->start + 1); dr_regs = ioremap(res->start, res->end - res->start + 1);
if (!dr_regs) { if (!dr_regs) {
ret = -ENOMEM; ret = -ENOMEM;
goto err1; goto err_release_mem_region;
} }
usb_sys_regs = (struct usb_sys_interface *) usb_sys_regs = (struct usb_sys_interface *)
@ -2269,7 +2269,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
if (!(dccparams & DCCPARAMS_DC)) { if (!(dccparams & DCCPARAMS_DC)) {
ERR("This SOC doesn't support device role\n"); ERR("This SOC doesn't support device role\n");
ret = -ENODEV; ret = -ENODEV;
goto err2; goto err_iounmap;
} }
/* Get max device endpoints */ /* Get max device endpoints */
/* DEN is bidirectional ep number, max_ep doubles the number */ /* DEN is bidirectional ep number, max_ep doubles the number */
@ -2278,7 +2278,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
udc_controller->irq = platform_get_irq(pdev, 0); udc_controller->irq = platform_get_irq(pdev, 0);
if (!udc_controller->irq) { if (!udc_controller->irq) {
ret = -ENODEV; ret = -ENODEV;
goto err2; goto err_iounmap;
} }
ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED, ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED,
@ -2286,14 +2286,14 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
if (ret != 0) { if (ret != 0) {
ERR("cannot request irq %d err %d\n", ERR("cannot request irq %d err %d\n",
udc_controller->irq, ret); udc_controller->irq, ret);
goto err2; goto err_iounmap;
} }
/* Initialize the udc structure including QH member and other member */ /* Initialize the udc structure including QH member and other member */
if (struct_udc_setup(udc_controller, pdev)) { if (struct_udc_setup(udc_controller, pdev)) {
ERR("Can't initialize udc data structure\n"); ERR("Can't initialize udc data structure\n");
ret = -ENOMEM; ret = -ENOMEM;
goto err3; goto err_free_irq;
} }
/* initialize usb hw reg except for regs for EP, /* initialize usb hw reg except for regs for EP,
@ -2314,7 +2314,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
udc_controller->gadget.dev.parent = &pdev->dev; udc_controller->gadget.dev.parent = &pdev->dev;
ret = device_register(&udc_controller->gadget.dev); ret = device_register(&udc_controller->gadget.dev);
if (ret < 0) if (ret < 0)
goto err3; goto err_free_irq;
/* setup QH and epctrl for ep0 */ /* setup QH and epctrl for ep0 */
ep0_setup(udc_controller); ep0_setup(udc_controller);
@ -2344,20 +2344,22 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
DTD_ALIGNMENT, UDC_DMA_BOUNDARY); DTD_ALIGNMENT, UDC_DMA_BOUNDARY);
if (udc_controller->td_pool == NULL) { if (udc_controller->td_pool == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto err4; goto err_unregister;
} }
create_proc_file(); create_proc_file();
return 0; return 0;
err4: err_unregister:
device_unregister(&udc_controller->gadget.dev); device_unregister(&udc_controller->gadget.dev);
err3: err_free_irq:
free_irq(udc_controller->irq, udc_controller); free_irq(udc_controller->irq, udc_controller);
err2: err_iounmap:
iounmap(dr_regs); iounmap(dr_regs);
err1: err_release_mem_region:
release_mem_region(res->start, res->end - res->start + 1); release_mem_region(res->start, res->end - res->start + 1);
err_kfree:
kfree(udc_controller); kfree(udc_controller);
udc_controller = NULL;
return ret; return ret;
} }