提交 6b777892 编写于 作者: P Peter Chen 提交者: Felipe Balbi

usb: cdns3: gadget: fix possible memory leak

If cdns3_gadget_start is failed, it never frees cdns3_device structure.
Meanwhile, there is no release function for gadget device, it causes
there is no sync with driver core.

To fix this, we add release function for gadget device, and free
cdns3_device structure at there. Meanwhile, With the new UDC core
APIs, we could work with driver core better to handle memory leak
issue.
Reviewed-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: NPeter Chen <peter.chen@nxp.com>
Signed-off-by: NFelipe Balbi <balbi@kernel.org>
上级 9b719c71
...@@ -2989,6 +2989,14 @@ static int cdns3_init_eps(struct cdns3_device *priv_dev) ...@@ -2989,6 +2989,14 @@ static int cdns3_init_eps(struct cdns3_device *priv_dev)
return -ENOMEM; return -ENOMEM;
} }
static void cdns3_gadget_release(struct device *dev)
{
struct cdns3_device *priv_dev = container_of(dev,
struct cdns3_device, gadget.dev);
kfree(priv_dev);
}
void cdns3_gadget_exit(struct cdns3 *cdns) void cdns3_gadget_exit(struct cdns3 *cdns)
{ {
struct cdns3_device *priv_dev; struct cdns3_device *priv_dev;
...@@ -2999,7 +3007,7 @@ void cdns3_gadget_exit(struct cdns3 *cdns) ...@@ -2999,7 +3007,7 @@ void cdns3_gadget_exit(struct cdns3 *cdns)
pm_runtime_mark_last_busy(cdns->dev); pm_runtime_mark_last_busy(cdns->dev);
pm_runtime_put_autosuspend(cdns->dev); pm_runtime_put_autosuspend(cdns->dev);
usb_del_gadget_udc(&priv_dev->gadget); usb_del_gadget(&priv_dev->gadget);
devm_free_irq(cdns->dev, cdns->dev_irq, priv_dev); devm_free_irq(cdns->dev, cdns->dev_irq, priv_dev);
cdns3_free_all_eps(priv_dev); cdns3_free_all_eps(priv_dev);
...@@ -3020,7 +3028,7 @@ void cdns3_gadget_exit(struct cdns3 *cdns) ...@@ -3020,7 +3028,7 @@ void cdns3_gadget_exit(struct cdns3 *cdns)
priv_dev->setup_dma); priv_dev->setup_dma);
kfree(priv_dev->zlp_buf); kfree(priv_dev->zlp_buf);
kfree(priv_dev); usb_put_gadget(&priv_dev->gadget);
cdns->gadget_dev = NULL; cdns->gadget_dev = NULL;
cdns3_drd_gadget_off(cdns); cdns3_drd_gadget_off(cdns);
} }
...@@ -3035,6 +3043,8 @@ static int cdns3_gadget_start(struct cdns3 *cdns) ...@@ -3035,6 +3043,8 @@ static int cdns3_gadget_start(struct cdns3 *cdns)
if (!priv_dev) if (!priv_dev)
return -ENOMEM; return -ENOMEM;
usb_initialize_gadget(cdns->dev, &priv_dev->gadget,
cdns3_gadget_release);
cdns->gadget_dev = priv_dev; cdns->gadget_dev = priv_dev;
priv_dev->sysdev = cdns->dev; priv_dev->sysdev = cdns->dev;
priv_dev->dev = cdns->dev; priv_dev->dev = cdns->dev;
...@@ -3122,10 +3132,9 @@ static int cdns3_gadget_start(struct cdns3 *cdns) ...@@ -3122,10 +3132,9 @@ static int cdns3_gadget_start(struct cdns3 *cdns)
} }
/* add USB gadget device */ /* add USB gadget device */
ret = usb_add_gadget_udc(priv_dev->dev, &priv_dev->gadget); ret = usb_add_gadget(&priv_dev->gadget);
if (ret < 0) { if (ret < 0) {
dev_err(priv_dev->dev, dev_err(priv_dev->dev, "Failed to add gadget\n");
"Failed to register USB device controller\n");
goto err4; goto err4;
} }
...@@ -3138,6 +3147,7 @@ static int cdns3_gadget_start(struct cdns3 *cdns) ...@@ -3138,6 +3147,7 @@ static int cdns3_gadget_start(struct cdns3 *cdns)
err2: err2:
cdns3_free_all_eps(priv_dev); cdns3_free_all_eps(priv_dev);
err1: err1:
usb_put_gadget(&priv_dev->gadget);
cdns->gadget_dev = NULL; cdns->gadget_dev = NULL;
return ret; return ret;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册