USB: omap_udc: fix crashes on probe error and module removal
[ Upstream commit 99f700366fcea1aa2fa3c49c99f371670c3c62f8 ] We currently crash if usb_add_gadget_udc_release() fails, since the udc->done is not initialized until in the remove function. Furthermore, on module removal the udc data is accessed although the release function is already triggered by usb_del_gadget_udc() early in the function. Fix by rewriting the release and remove functions, basically moving all the cleanup into the release function, and doing the completion only in the module removal case. The patch fixes omap_udc module probe with a failing gadged, and also allows the removal of omap_udc. Tested by running "modprobe omap_udc; modprobe -r omap_udc" in a loop. Signed-off-by: Aaro Koskinen <aaro.koskinen@iki.fi> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
a20d7a308f
commit
39d5919321
1 changed files with 19 additions and 31 deletions
|
@ -2612,9 +2612,22 @@ omap_ep_setup(char *name, u8 addr, u8 type,
|
|||
|
||||
static void omap_udc_release(struct device *dev)
|
||||
{
|
||||
complete(udc->done);
|
||||
pullup_disable(udc);
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver)) {
|
||||
usb_put_phy(udc->transceiver);
|
||||
udc->transceiver = NULL;
|
||||
}
|
||||
omap_writew(0, UDC_SYSCON1);
|
||||
remove_proc_file();
|
||||
if (udc->dc_clk) {
|
||||
if (udc->clk_requested)
|
||||
omap_udc_enable_clock(0);
|
||||
clk_put(udc->hhc_clk);
|
||||
clk_put(udc->dc_clk);
|
||||
}
|
||||
if (udc->done)
|
||||
complete(udc->done);
|
||||
kfree(udc);
|
||||
udc = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -2919,12 +2932,8 @@ bad_on_1710:
|
|||
}
|
||||
|
||||
create_proc_file();
|
||||
status = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
|
||||
omap_udc_release);
|
||||
if (!status)
|
||||
return 0;
|
||||
|
||||
remove_proc_file();
|
||||
return usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
|
||||
omap_udc_release);
|
||||
|
||||
cleanup1:
|
||||
kfree(udc);
|
||||
|
@ -2951,36 +2960,15 @@ static int omap_udc_remove(struct platform_device *pdev)
|
|||
{
|
||||
DECLARE_COMPLETION_ONSTACK(done);
|
||||
|
||||
if (!udc)
|
||||
return -ENODEV;
|
||||
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
if (udc->driver)
|
||||
return -EBUSY;
|
||||
|
||||
udc->done = &done;
|
||||
|
||||
pullup_disable(udc);
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver)) {
|
||||
usb_put_phy(udc->transceiver);
|
||||
udc->transceiver = NULL;
|
||||
}
|
||||
omap_writew(0, UDC_SYSCON1);
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
|
||||
remove_proc_file();
|
||||
|
||||
if (udc->dc_clk) {
|
||||
if (udc->clk_requested)
|
||||
omap_udc_enable_clock(0);
|
||||
clk_put(udc->hhc_clk);
|
||||
clk_put(udc->dc_clk);
|
||||
}
|
||||
wait_for_completion(&done);
|
||||
|
||||
release_mem_region(pdev->resource[0].start,
|
||||
pdev->resource[0].end - pdev->resource[0].start + 1);
|
||||
|
||||
wait_for_completion(&done);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue