From 20984756fff2cfe19aa09b046a52386e257a94bb Mon Sep 17 00:00:00 2001 From: Lena Salman Date: Mon, 12 Mar 2012 17:26:39 +0200 Subject: [PATCH 1/2] usb: gadget: ci13xxx_msm: allow to be loaded/unloaded as module Add support for the module to be dynamically loaded and unloaded. This change adds remove function to restore all initialized values. Change-Id: I0a311bac469aa87fa7892fa2b5f4db07f17abf0f Signed-off-by: Lena Salman --- drivers/usb/gadget/ci13xxx_msm.c | 43 ++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c index fac777c9560..eb727b855f8 100644 --- a/drivers/usb/gadget/ci13xxx_msm.c +++ b/drivers/usb/gadget/ci13xxx_msm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. +/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,6 +21,12 @@ #define MSM_USB_BASE (udc->regs) +struct ci13xxx_udc_context { + int irq; + void __iomem *regs; +}; +static struct ci13xxx_udc_context _udc_ctxt; + static irqreturn_t msm_udc_irq(int irq, void *data) { return udc_irq(); @@ -56,8 +62,6 @@ static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = { static int ci13xxx_msm_probe(struct platform_device *pdev) { struct resource *res; - void __iomem *regs; - int irq; int ret; dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n"); @@ -68,26 +72,27 @@ static int ci13xxx_msm_probe(struct platform_device *pdev) return -ENXIO; } - regs = ioremap(res->start, resource_size(res)); - if (!regs) { + _udc_ctxt.regs = ioremap(res->start, resource_size(res)); + if (!_udc_ctxt.regs) { dev_err(&pdev->dev, "ioremap failed\n"); return -ENOMEM; } - ret = udc_probe(&ci13xxx_msm_udc_driver, &pdev->dev, regs); + ret = udc_probe(&ci13xxx_msm_udc_driver, &pdev->dev, _udc_ctxt.regs); if (ret < 0) { dev_err(&pdev->dev, "udc_probe failed\n"); goto iounmap; } - irq = platform_get_irq(pdev, 0); - if (irq < 0) { + _udc_ctxt.irq = platform_get_irq(pdev, 0); + if (_udc_ctxt.irq < 0) { dev_err(&pdev->dev, "IRQ not found\n"); ret = -ENXIO; goto udc_remove; } - ret = request_irq(irq, msm_udc_irq, IRQF_SHARED, pdev->name, pdev); + ret = request_irq(_udc_ctxt.irq, msm_udc_irq, IRQF_SHARED, pdev->name, + pdev); if (ret < 0) { dev_err(&pdev->dev, "request_irq failed\n"); goto udc_remove; @@ -101,14 +106,24 @@ static int ci13xxx_msm_probe(struct platform_device *pdev) udc_remove: udc_remove(); iounmap: - iounmap(regs); + iounmap(_udc_ctxt.regs); return ret; } +int ci13xxx_msm_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + free_irq(_udc_ctxt.irq, pdev); + udc_remove(); + iounmap(_udc_ctxt.regs); + return 0; +} + static struct platform_driver ci13xxx_msm_driver = { .probe = ci13xxx_msm_probe, .driver = { .name = "msm_hsusb", }, + .remove = ci13xxx_msm_remove, }; static int __init ci13xxx_msm_init(void) @@ -116,3 +131,11 @@ static int __init ci13xxx_msm_init(void) return platform_driver_register(&ci13xxx_msm_driver); } module_init(ci13xxx_msm_init); + +static void __exit ci13xxx_msm_exit(void) +{ + platform_driver_unregister(&ci13xxx_msm_driver); +} +module_exit(ci13xxx_msm_exit); + +MODULE_LICENSE("GPL v2"); From d092f2d80b4abb5d1d68c229cf65003540a99466 Mon Sep 17 00:00:00 2001 From: Lena Salman Date: Mon, 12 Mar 2012 17:27:24 +0200 Subject: [PATCH 2/2] usb: gadget: allow android gadget to bind/unbind several times This is needed if we want to change the underlying udc, or insmod the dynamically linked udc after android gadget is already up. Change-Id: I71923764af85f4d50a2ebf7c7476cf0ef23fe819 Signed-off-by: Lena Salman --- drivers/usb/gadget/android.c | 97 +++++++++++++++++++++++----------- drivers/usb/gadget/composite.c | 7 ++- 2 files changed, 71 insertions(+), 33 deletions(-) diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index 91c3123d149..042eb4f2503 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -470,7 +470,7 @@ static int serial_function_bind_config(struct android_usb_function *f, } bind_config: - for (i = 0; i < ports; i++) { + for (i = 0; i < ports; i++) { err = gser_bind_config(c, i); if (err) { pr_err("serial: bind_config failed for port %d", i); @@ -989,6 +989,31 @@ static struct android_usb_function *supported_functions[] = { NULL }; +static void android_cleanup_functions(struct android_usb_function **functions) +{ + struct android_usb_function *f; + struct device_attribute **attrs; + struct device_attribute *attr; + + while (*functions) { + f = *functions++; + + if (f->dev) { + device_destroy(android_class, f->dev->devt); + kfree(f->dev_name); + } else + continue; + + if (f->cleanup) + f->cleanup(f); + + attrs = f->attributes; + if (attrs) { + while ((attr = *attrs++)) + device_remove_file(f->dev, attr); + } + } +} static int android_init_functions(struct android_usb_function **functions, struct usb_composite_dev *cdev) @@ -998,16 +1023,21 @@ static int android_init_functions(struct android_usb_function **functions, struct device_attribute **attrs; struct device_attribute *attr; int err = 0; - int index = 0; + int index = 1; /* index 0 is for android0 device */ for (; (f = *functions++); index++) { f->dev_name = kasprintf(GFP_KERNEL, "f_%s", f->name); + if (!f->dev_name) { + err = -ENOMEM; + goto err_out; + } f->dev = device_create(android_class, dev->dev, MKDEV(0, index), f, f->dev_name); if (IS_ERR(f->dev)) { pr_err("%s: Failed to create dev %s", __func__, f->dev_name); err = PTR_ERR(f->dev); + f->dev = NULL; goto err_create; } @@ -1016,7 +1046,7 @@ static int android_init_functions(struct android_usb_function **functions, if (err) { pr_err("%s: Failed to init %s", __func__, f->name); - goto err_out; + goto err_init; } } @@ -1028,35 +1058,26 @@ static int android_init_functions(struct android_usb_function **functions, if (err) { pr_err("%s: Failed to create function %s attributes", __func__, f->name); - goto err_out; + goto err_attrs; } } return 0; -err_out: +err_attrs: + for (attr = *(attrs -= 2); attrs != f->attributes; attr = *(attrs--)) + device_remove_file(f->dev, attr); + if (f->cleanup) + f->cleanup(f); +err_init: device_destroy(android_class, f->dev->devt); err_create: + f->dev = NULL; kfree(f->dev_name); +err_out: + android_cleanup_functions(dev->functions); return err; } -static void android_cleanup_functions(struct android_usb_function **functions) -{ - struct android_usb_function *f; - - while (*functions) { - f = *functions++; - - if (f->dev) { - device_destroy(android_class, f->dev->devt); - kfree(f->dev_name); - } - - if (f->cleanup) - f->cleanup(f); - } -} - static int android_bind_enabled_functions(struct android_dev *dev, struct usb_configuration *c) @@ -1393,6 +1414,9 @@ static int android_usb_unbind(struct usb_composite_dev *cdev) { struct android_dev *dev = _android_dev; + manufacturer_string[0] = '\0'; + product_string[0] = '\0'; + serial_string[0] = '0'; cancel_work_sync(&dev->work); android_cleanup_functions(dev->functions); return 0; @@ -1502,15 +1526,29 @@ static int __devinit android_probe(struct platform_device *pdev) { struct android_usb_platform_data *pdata = pdev->dev.platform_data; struct android_dev *dev = _android_dev; + int ret = 0; dev->pdata = pdata; + ret = usb_composite_probe(&android_usb_driver, android_bind); + if (ret) { + pr_err("%s(): Failed to register android " + "composite driver\n", __func__); + } + + return ret; +} + +static int android_remove(struct platform_device *pdev) +{ + usb_composite_unregister(&android_usb_driver); return 0; } static struct platform_driver android_platform_driver = { - .probe = android_probe, .driver = { .name = "android_usb"}, + .probe = android_probe, + .remove = android_remove, }; static int __init init(void) @@ -1550,13 +1588,7 @@ static int __init init(void) "platform driver\n", __func__); goto err_probe; } - ret = usb_composite_probe(&android_usb_driver, android_bind); - if (ret) { - pr_err("%s(): Failed to register android" - "composite driver\n", __func__); - platform_driver_unregister(&android_platform_driver); - goto err_probe; - } + return ret; err_probe: @@ -1570,9 +1602,10 @@ module_init(init); static void __exit cleanup(void) { - usb_composite_unregister(&android_usb_driver); - class_destroy(android_class); + platform_driver_unregister(&android_platform_driver); + android_destroy_device(_android_dev); kfree(_android_dev); + class_destroy(android_class); _android_dev = NULL; } module_exit(cleanup); diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index c9d9c07b1b0..4f2946cc637 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1634,6 +1634,8 @@ static struct usb_gadget_driver composite_driver = { int usb_composite_probe(struct usb_composite_driver *driver, int (*bind)(struct usb_composite_dev *cdev)) { + int retval; + if (!driver || !driver->dev || !bind || composite) return -EINVAL; @@ -1648,7 +1650,10 @@ int usb_composite_probe(struct usb_composite_driver *driver, composite = driver; composite_gadget_bind = bind; - return usb_gadget_probe_driver(&composite_driver, composite_bind); + retval = usb_gadget_probe_driver(&composite_driver, composite_bind); + if (retval) + composite = NULL; + return retval; } /**