aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaro Koskinen <aaro.koskinen@iki.fi>2018-11-24 17:17:05 -0500
committerFelipe Balbi <felipe.balbi@linux.intel.com>2018-11-26 05:37:51 -0500
commit99f700366fcea1aa2fa3c49c99f371670c3c62f8 (patch)
tree93cb9de08385ac7139d3b1475d8aec97a47f428b
parent286afdde1640d8ea8916a0f05e811441fbbf4b9d (diff)
USB: omap_udc: fix crashes on probe error and module removal
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>
-rw-r--r--drivers/usb/gadget/udc/omap_udc.c50
1 files changed, 19 insertions, 31 deletions
diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c
index 1c77218c82af..240ccba44592 100644
--- a/drivers/usb/gadget/udc/omap_udc.c
+++ b/drivers/usb/gadget/udc/omap_udc.c
@@ -2593,9 +2593,22 @@ omap_ep_setup(char *name, u8 addr, u8 type,
2593 2593
2594static void omap_udc_release(struct device *dev) 2594static void omap_udc_release(struct device *dev)
2595{ 2595{
2596 complete(udc->done); 2596 pullup_disable(udc);
2597 if (!IS_ERR_OR_NULL(udc->transceiver)) {
2598 usb_put_phy(udc->transceiver);
2599 udc->transceiver = NULL;
2600 }
2601 omap_writew(0, UDC_SYSCON1);
2602 remove_proc_file();
2603 if (udc->dc_clk) {
2604 if (udc->clk_requested)
2605 omap_udc_enable_clock(0);
2606 clk_put(udc->hhc_clk);
2607 clk_put(udc->dc_clk);
2608 }
2609 if (udc->done)
2610 complete(udc->done);
2597 kfree(udc); 2611 kfree(udc);
2598 udc = NULL;
2599} 2612}
2600 2613
2601static int 2614static int
@@ -2900,12 +2913,8 @@ bad_on_1710:
2900 } 2913 }
2901 2914
2902 create_proc_file(); 2915 create_proc_file();
2903 status = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget, 2916 return usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
2904 omap_udc_release); 2917 omap_udc_release);
2905 if (!status)
2906 return 0;
2907
2908 remove_proc_file();
2909 2918
2910cleanup1: 2919cleanup1:
2911 kfree(udc); 2920 kfree(udc);
@@ -2932,36 +2941,15 @@ static int omap_udc_remove(struct platform_device *pdev)
2932{ 2941{
2933 DECLARE_COMPLETION_ONSTACK(done); 2942 DECLARE_COMPLETION_ONSTACK(done);
2934 2943
2935 if (!udc)
2936 return -ENODEV;
2937
2938 usb_del_gadget_udc(&udc->gadget);
2939 if (udc->driver)
2940 return -EBUSY;
2941
2942 udc->done = &done; 2944 udc->done = &done;
2943 2945
2944 pullup_disable(udc); 2946 usb_del_gadget_udc(&udc->gadget);
2945 if (!IS_ERR_OR_NULL(udc->transceiver)) {
2946 usb_put_phy(udc->transceiver);
2947 udc->transceiver = NULL;
2948 }
2949 omap_writew(0, UDC_SYSCON1);
2950
2951 remove_proc_file();
2952 2947
2953 if (udc->dc_clk) { 2948 wait_for_completion(&done);
2954 if (udc->clk_requested)
2955 omap_udc_enable_clock(0);
2956 clk_put(udc->hhc_clk);
2957 clk_put(udc->dc_clk);
2958 }
2959 2949
2960 release_mem_region(pdev->resource[0].start, 2950 release_mem_region(pdev->resource[0].start,
2961 pdev->resource[0].end - pdev->resource[0].start + 1); 2951 pdev->resource[0].end - pdev->resource[0].start + 1);
2962 2952
2963 wait_for_completion(&done);
2964
2965 return 0; 2953 return 0;
2966} 2954}
2967 2955