diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-01-25 09:08:05 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-01-25 09:08:05 -0800 |
commit | cba6c85027057d4bf7029d32c64e2647859be07a (patch) | |
tree | 055c3f7614dde5ab48ea5ee148b6e0476ca24ca4 /drivers/usb/gadget | |
parent | a9b8676c17cee40ac78696bb56ab61d550382898 (diff) | |
parent | eeef45876631a446eaedce16675f4ff344e16cf0 (diff) |
Merge tag 'gadget-for-v3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
Felipe writes:
usb: gadget: patches for v3.9 merge window
finally getting rid of the old ->start()/->stop() methods
in favor of the better and improved ->udc_start()/->udc_stop().
There were surprisingly quite a few users left, but all of them
have been converted.
f_mass_storage removed some dead code, which is always great ;-)
There's also a big cleanup to the gadget framework from Sebastian
which gets us a lot closer to having only function drivers in
kernel and move over to configfs-based binding.
Other than these, there's the usual set of cleanups: s3c UDCs are
moving over to devm_regulator_bulk_get() API, at91_udc removed
an unnecessary check for work_pending() before scheduling and
there's the removal of an unused variable from uac2_pcm_trigger().
Diffstat (limited to 'drivers/usb/gadget')
50 files changed, 1648 insertions, 1413 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 14625fd2cec..6665d255d32 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -500,6 +500,15 @@ config USB_LIBCOMPOSITE tristate depends on USB_GADGET +config USB_F_ACM + tristate + +config USB_F_SS_LB + tristate + +config USB_U_SERIAL + tristate + choice tristate "USB Gadget Drivers" default USB_ETH @@ -524,6 +533,7 @@ choice config USB_ZERO tristate "Gadget Zero (DEVELOPMENT)" select USB_LIBCOMPOSITE + select USB_F_SS_LB help Gadget Zero is a two-configuration device. It either sinks and sources bulk data; or it loops back a configurable number of @@ -750,6 +760,8 @@ config USB_GADGET_TARGET config USB_G_SERIAL tristate "Serial Gadget (with CDC ACM and CDC OBEX support)" + select USB_U_SERIAL + select USB_F_ACM select USB_LIBCOMPOSITE help The Serial Gadget talks to the Linux-USB generic serial driver. @@ -803,6 +815,8 @@ config USB_CDC_COMPOSITE tristate "CDC Composite Device (Ethernet and ACM)" depends on NET select USB_LIBCOMPOSITE + select USB_U_SERIAL + select USB_F_ACM help This driver provides two functions in one configuration: a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link. @@ -818,6 +832,7 @@ config USB_G_NOKIA tristate "Nokia composite gadget" depends on PHONET select USB_LIBCOMPOSITE + select USB_U_SERIAL help The Nokia composite gadget provides support for acm, obex and phonet in only one composite gadget driver. @@ -829,6 +844,8 @@ config USB_G_ACM_MS tristate "CDC Composite Device (ACM and mass storage)" depends on BLOCK select USB_LIBCOMPOSITE + select USB_U_SERIAL + select USB_F_ACM help This driver provides two functions in one configuration: a mass storage, and a CDC ACM (serial port) link. @@ -841,6 +858,8 @@ config USB_G_MULTI depends on BLOCK && NET select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS select USB_LIBCOMPOSITE + select USB_U_SERIAL + select USB_F_ACM help The Multifunction Composite Gadget provides Ethernet (RNDIS and/or CDC Ethernet), mass storage and ACM serial link @@ -916,6 +935,7 @@ config USB_G_DBGP_PRINTK config USB_G_DBGP_SERIAL depends on USB_G_DBGP + select USB_U_SERIAL bool "serial" help Userland can interact using /dev/ttyGSxxx. diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 8b4acfd92aa..97a13c349cc 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -6,7 +6,7 @@ ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG obj-$(CONFIG_USB_GADGET) += udc-core.o obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o libcomposite-y := usbstring.o config.o epautoconf.o -libcomposite-y += composite.o +libcomposite-y += composite.o functions.o obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o obj-$(CONFIG_USB_NET2272) += net2272.o obj-$(CONFIG_USB_NET2280) += net2280.o @@ -74,3 +74,9 @@ obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o obj-$(CONFIG_USB_G_NCM) += g_ncm.o obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o + +# USB Functions +obj-$(CONFIG_USB_F_ACM) += f_acm.o +f_ss_lb-y := f_loopback.o f_sourcesink.o +obj-$(CONFIG_USB_F_SS_LB) += f_ss_lb.o +obj-$(CONFIG_USB_U_SERIAL) += u_serial.o diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c index 5a7f289805f..8f2b0e39153 100644 --- a/drivers/usb/gadget/acm_ms.c +++ b/drivers/usb/gadget/acm_ms.c @@ -40,9 +40,6 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ - -#include "u_serial.c" -#include "f_acm.c" #include "f_mass_storage.c" /*-------------------------------------------------------------------------*/ @@ -112,12 +109,15 @@ FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); static struct fsg_common fsg_common; /*-------------------------------------------------------------------------*/ - +static unsigned char tty_line; +static struct usb_function *f_acm; +static struct usb_function_instance *f_acm_inst; /* * We _always_ have both ACM and mass storage functions. */ static int __init acm_ms_do_config(struct usb_configuration *c) { + struct f_serial_opts *opts; int status; if (gadget_is_otg(c->cdev->gadget)) { @@ -125,16 +125,35 @@ static int __init acm_ms_do_config(struct usb_configuration *c) c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } + f_acm_inst = usb_get_function_instance("acm"); + if (IS_ERR(f_acm_inst)) + return PTR_ERR(f_acm_inst); + + opts = container_of(f_acm_inst, struct f_serial_opts, func_inst); + opts->port_num = tty_line; + + f_acm = usb_get_function(f_acm_inst); + if (IS_ERR(f_acm)) { + status = PTR_ERR(f_acm); + goto err_func; + } - status = acm_bind_config(c, 0); + status = usb_add_function(c, f_acm); if (status < 0) - return status; + goto err_conf; status = fsg_bind_config(c->cdev, c, &fsg_common); if (status < 0) - return status; + goto err_fsg; return 0; +err_fsg: + usb_remove_function(c, f_acm); +err_conf: + usb_put_function(f_acm); +err_func: + usb_put_function_instance(f_acm_inst); + return status; } static struct usb_configuration acm_ms_config_driver = { @@ -153,7 +172,7 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev) void *retp; /* set up serial link layer */ - status = gserial_setup(cdev->gadget, 1); + status = gserial_alloc_line(&tty_line); if (status < 0) return status; @@ -189,14 +208,15 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev) fail1: fsg_common_put(&fsg_common); fail0: - gserial_cleanup(); + gserial_free_line(tty_line); return status; } static int __exit acm_ms_unbind(struct usb_composite_dev *cdev) { - gserial_cleanup(); - + usb_put_function(f_acm); + usb_put_function_instance(f_acm_inst); + gserial_free_line(tty_line); return 0; } diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index d9f6b937249..75973f33a4c 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -1400,15 +1400,16 @@ static int udc_wakeup(struct usb_gadget *gadget) return 0; } -static int amd5536_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); -static int amd5536_stop(struct usb_gadget_driver *driver); +static int amd5536_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver); +static int amd5536_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver); /* gadget operations */ static const struct usb_gadget_ops udc_ops = { .wakeup = udc_wakeup, .get_frame = udc_get_frame, - .start = amd5536_start, - .stop = amd5536_stop, + .udc_start = amd5536_udc_start, + .udc_stop = amd5536_udc_stop, }; /* Setups endpoint parameters, adds endpoints to linked list */ @@ -1913,41 +1914,22 @@ static int setup_ep0(struct udc *dev) } /* Called by gadget driver to register itself */ -static int amd5536_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) +static int amd5536_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct udc *dev = udc; - int retval; + struct udc *dev = to_amd5536_udc(g); u32 tmp; - if (!driver || !bind || !driver->setup - || driver->max_speed < USB_SPEED_HIGH) - return -EINVAL; - if (!dev) - return -ENODEV; - if (dev->driver) - return -EBUSY; - driver->driver.bus = NULL; dev->driver = driver; dev->gadget.dev.driver = &driver->driver; - retval = bind(&dev->gadget, driver); - /* Some gadget drivers use both ep0 directions. * NOTE: to gadget driver, ep0 is just one endpoint... */ dev->ep[UDC_EP0OUT_IX].ep.driver_data = dev->ep[UDC_EP0IN_IX].ep.driver_data; - if (retval) { - DBG(dev, "binding to %s returning %d\n", - driver->driver.name, retval); - dev->driver = NULL; - dev->gadget.dev.driver = NULL; - return retval; - } - /* get ready for ep0 traffic */ setup_ep0(dev); @@ -1969,14 +1951,9 @@ __acquires(dev->lock) { int tmp; - if (dev->gadget.speed != USB_SPEED_UNKNOWN) { - spin_unlock(&dev->lock); - driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - } - /* empty queues and init hardware */ udc_basic_init(dev); + for (tmp = 0; tmp < UDC_EP_NUM; tmp++) empty_req_queue(&dev->ep[tmp]); @@ -1984,23 +1961,18 @@ __acquires(dev->lock) } /* Called by gadget driver to unregister itself */ -static int amd5536_stop(struct usb_gadget_driver *driver) +static int amd5536_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct udc *dev = udc; - unsigned long flags; + struct udc *dev = to_amd5536_udc(g); + unsigned long flags; u32 tmp; - if (!dev) - return -ENODEV; - if (!driver || driver != dev->driver || !driver->unbind) - return -EINVAL; - spin_lock_irqsave(&dev->lock, flags); udc_mask_unused_interrupts(dev); shutdown(dev, driver); spin_unlock_irqrestore(&dev->lock, flags); - driver->unbind(&dev->gadget); dev->gadget.dev.driver = NULL; dev->driver = NULL; @@ -2009,9 +1981,6 @@ static int amd5536_stop(struct usb_gadget_driver *driver) tmp |= AMD_BIT(UDC_DEVCTL_SD); writel(tmp, &dev->regs->ctl); - - DBG(dev, "%s: unregistered\n", driver->driver.name); - return 0; } diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h index 14af87d65ca..f1bf32e6b8d 100644 --- a/drivers/usb/gadget/amd5536udc.h +++ b/drivers/usb/gadget/amd5536udc.h @@ -563,6 +563,8 @@ struct udc { u16 cur_alt; }; +#define to_amd5536_udc(g) (container_of((g), struct udc, gadget)) + /* setup request data */ union udc_setup_data { u32 data[2]; diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index f4a21f6f081..10f45fa01ab 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1621,8 +1621,7 @@ static void at91_vbus_timer(unsigned long data) * bus such as i2c or spi which may sleep, so schedule some work * to read the vbus gpio */ - if (!work_pending(&udc->vbus_timer_work)) - schedule_work(&udc->vbus_timer_work); + schedule_work(&udc->vbus_timer_work); } static int at91_start(struct usb_gadget *gadget, @@ -1739,7 +1738,7 @@ static int at91udc_probe(struct platform_device *pdev) /* rm9200 needs manual D+ pullup; off by default */ if (cpu_is_at91rm9200()) { - if (gpio_is_valid(udc->board.pullup_pin)) { + if (!gpio_is_valid(udc->board.pullup_pin)) { DBG("no D+ pullup?\n"); retval = -ENODEV; goto fail0; diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c index 1e4bb77f00b..a7d6f702675 100644 --- a/drivers/usb/gadget/cdc2.c +++ b/drivers/usb/gadget/cdc2.c @@ -42,9 +42,6 @@ USB_GADGET_COMPOSITE_OPTIONS(); * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ - -#include "u_serial.c" -#include "f_acm.c" #include "f_ecm.c" #include "u_ether.c" @@ -108,12 +105,16 @@ static struct usb_gadget_strings *dev_strings[] = { static u8 hostaddr[ETH_ALEN]; /*-------------------------------------------------------------------------*/ +static struct usb_function *f_acm; +static struct usb_function_instance *fi_serial; +static unsigned char tty_line; /* * We _always_ have both CDC ECM and CDC ACM functions. */ static int __init cdc_do_config(struct usb_configuration *c) { + struct f_serial_opts *opts; int status; if (gadget_is_otg(c->cdev->gadget)) { @@ -125,11 +126,26 @@ static int __init cdc_do_config(struct usb_configuration *c) if (status < 0) return status; - status = acm_bind_config(c, 0); - if (status < 0) - return status; + fi_serial = usb_get_function_instance("acm"); + if (IS_ERR(fi_serial)) + return PTR_ERR(fi_serial); + opts = container_of(fi_serial, struct f_serial_opts, func_inst); + opts->port_num = tty_line; + + f_acm = usb_get_function(fi_serial); + if (IS_ERR(f_acm)) + goto err_func_acm; + + status = usb_add_function(c, f_acm); + if (status) + goto err_conf; return 0; +err_conf: + usb_put_function(f_acm); +err_func_acm: + usb_put_function_instance(fi_serial); + return status; } static struct usb_configuration cdc_config_driver = { @@ -158,7 +174,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev) return status; /* set up serial link layer */ - status = gserial_setup(cdev->gadget, 1); + status = gserial_alloc_line(&tty_line); if (status < 0) goto fail0; @@ -184,7 +200,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev) return 0; fail1: - gserial_cleanup(); + gserial_free_line(tty_line); fail0: gether_cleanup(); return status; @@ -192,7 +208,9 @@ fail0: static int __exit cdc_unbind(struct usb_composite_dev *cdev) { - gserial_cleanup(); + usb_put_function(f_acm); + usb_put_function_instance(fi_serial); + gserial_free_line(tty_line); gether_cleanup(); return 0; } diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 2a6bfe759c2..7c821de8ce3 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -28,6 +28,12 @@ * with the relevant device-wide data. */ +static struct usb_gadget_strings **get_containers_gs( + struct usb_gadget_string_container *uc) +{ + return (struct usb_gadget_strings **)uc->stash; +} + /** * next_ep_desc() - advance to the next EP descriptor * @t: currect pointer within descriptor array @@ -215,6 +221,18 @@ done: } EXPORT_SYMBOL_GPL(usb_add_function); +void usb_remove_function(struct usb_configuration *c, struct usb_function *f) +{ + if (f->disable) + f->disable(f); + + bitmap_zero(f->endpoints, 32); + list_del(&f->list); + if (f->unbind) + f->unbind(c, f); +} +EXPORT_SYMBOL_GPL(usb_remove_function); + /** * usb_function_deactivate - prevent function and gadget enumeration * @function: the function that isn't yet ready to respond @@ -320,6 +338,25 @@ int usb_interface_id(struct usb_configuration *config, } EXPORT_SYMBOL_GPL(usb_interface_id); +static u8 encode_bMaxPower(enum usb_device_speed speed, + struct usb_configuration *c) +{ + unsigned val; + + if (c->MaxPower) + val = c->MaxPower; + else + val = CONFIG_USB_GADGET_VBUS_DRAW; + if (!val) + return 0; + switch (speed) { + case USB_SPEED_SUPER: + return DIV_ROUND_UP(val, 8); + default: + return DIV_ROUND_UP(val, 2); + }; +} + static int config_buf(struct usb_configuration *config, enum usb_device_speed speed, void *buf, u8 type) { @@ -339,7 +376,7 @@ static int config_buf(struct usb_configuration *config, c->bConfigurationValue = config->bConfigurationValue; c->iConfiguration = config->iConfiguration; c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes; - c->bMaxPower = config->bMaxPower ? : (CONFIG_USB_GADGET_VBUS_DRAW / 2); + c->bMaxPower = encode_bMaxPower(speed, config); /* There may be e.g. OTG descriptors */ if (config->descriptors) { @@ -656,7 +693,7 @@ static int set_config(struct usb_composite_dev *cdev, } /* when we return, be sure our power usage is valid */ - power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW; + power = c->MaxPower ? c->MaxPower : CONFIG_USB_GADGET_VBUS_DRAW; done: usb_gadget_vbus_draw(gadget, power); if (result >= 0 && cdev->delayed_status) @@ -664,6 +701,31 @@ done: return result; } +int usb_add_config_only(struct usb_composite_dev *cdev, + struct usb_configuration *config) +{ + struct usb_configuration *c; + + if (!config->bConfigurationValue) + return -EINVAL; + + /* Prevent duplicate configuration identifiers */ + list_for_each_entry(c, &cdev->configs, list) { + if (c->bConfigurationValue == config->bConfigurationValue) + return -EBUSY; + } + + config->cdev = cdev; + list_add_tail(&config->list, &cdev->configs); + + INIT_LIST_HEAD(&config->functions); + config->next_interface_id = 0; + memset(config->interface, 0, sizeof(config->interface)); + + return 0; +} +EXPORT_SYMBOL_GPL(usb_add_config_only); + /** * usb_add_config() - add a configuration to a device. * @cdev: wraps the USB gadget @@ -684,30 +746,18 @@ int usb_add_config(struct usb_composite_dev *cdev, int (*bind)(struct usb_configuration *)) { int status = -EINVAL; - struct usb_configuration *c; + + if (!bind) + goto done; DBG(cdev, "adding config #%u '%s'/%p\n", config->bConfigurationValue, config->label, config); - if (!config->bConfigurationValue || !bind) + status = usb_add_config_only(cdev, config); + if (status) goto done; - /* Prevent duplicate configuration identifiers */ - list_for_each_entry(c, &cdev->configs, list) { - if (c->bConfigurationValue == config->bConfigurationValue) { - status = -EBUSY; - goto done; - } - } - - config->cdev = cdev; - list_add_tail(&config->list, &cdev->configs); - - INIT_LIST_HEAD(&config->functions); - config->next_interface_id = 0; - memset(config->interface, 0, sizeof(config->interface)); - status = bind(config); if (status < 0) { while (!list_empty(&config->functions)) { @@ -860,6 +910,7 @@ static int get_string(struct usb_composite_dev *cdev, void *buf, u16 language, int id) { struct usb_composite_driver *composite = cdev->driver; + struct usb_gadget_string_container *uc; struct usb_configuration *c; struct usb_function *f; int len; @@ -892,6 +943,12 @@ static int get_string(struct usb_composite_dev *cdev, collect_langs(sp, s->wData); } } + list_for_each_entry(uc, &cdev->gstrings, list) { + struct usb_gadget_strings **sp; + + sp = get_containers_gs(uc); + collect_langs(sp, s->wData); + } for (len = 0; len <= 126 && s->wData[len]; len++) continue; @@ -902,6 +959,15 @@ static int get_string(struct usb_composite_dev *cdev, return s->bLength; } + list_for_each_entry(uc, &cdev->gstrings, list) { + struct usb_gadget_strings **sp; + + sp = get_containers_gs(uc); + len = lookup_string(sp, buf, language, id); + if (len > 0) + return len; + } + /* String IDs are device-scoped, so we look up each string * table we're told about. These lookups are infrequent; * simpler-is-better here. @@ -987,6 +1053,119 @@ int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str) } EXPORT_SYMBOL_GPL(usb_string_ids_tab); +static struct usb_gadget_string_container *copy_gadget_strings( + struct usb_gadget_strings **sp, unsigned n_gstrings, + unsigned n_strings) +{ + struct usb_gadget_string_container *uc; + struct usb_gadget_strings **gs_array; + struct usb_gadget_strings *gs; + struct usb_string *s; + unsigned mem; + unsigned n_gs; + unsigned n_s; + void *stash; + + mem = sizeof(*uc); + mem += sizeof(void *) * (n_gstrings + 1); + mem += sizeof(struct usb_gadget_strings) * n_gstrings; + mem += sizeof(struct usb_string) * (n_strings + 1) * (n_gstrings); + uc = kmalloc(mem, GFP_KERNEL); + if (!uc) + return ERR_PTR(-ENOMEM); + gs_array = get_containers_gs(uc); + stash = uc->stash; + stash += sizeof(void *) * (n_gstrings + 1); + for (n_gs = 0; n_gs < n_gstrings; n_gs++) { + struct usb_string *org_s; + + gs_array[n_gs] = stash; + gs = gs_array[n_gs]; + stash += sizeof(struct usb_gadget_strings); + gs->language = sp[n_gs]->language; + gs->strings = stash; + org_s = sp[n_gs]->strings; + + for (n_s = 0; n_s < n_strings; n_s++) { + s = stash; + stash += sizeof(struct usb_string); + if (org_s->s) + s->s = org_s->s; + else + s->s = ""; + org_s++; + } + s = stash; + s->s = NULL; + stash += sizeof(struct usb_string); + + } + gs_array[n_gs] = NULL; + return uc; +} + +/** + * usb_gstrings_attach() - attach gadget strings to a cdev and assign ids + * @cdev: the device whose string descriptor IDs are being allocated + * and attached. + * @sp: an array of usb_gadget_strings to attach. + * @n_strings: number of entries in each usb_strings array (sp[]->strings) + * + * This function will create a deep copy of usb_gadget_strings and usb_string + * and attach it to the cdev. The actual string (usb_string.s) will not be + * copied but only a referenced will be made. The struct usb_gadget_strings + * array may contain multiple languges and should be NULL terminated. + * The ->language pointer of each struct usb_gadget_strings has to contain the + * same amount of entries. + * For instance: sp[0] is en-US, sp[1] is es-ES. It is expected that the first + * usb_string entry of es-ES containts the translation of the first usb_string + * entry of en-US. Therefore both entries become the same id assign. + */ +struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev, + struct usb_gadget_strings **sp, unsigned n_strings) +{ + struct usb_gadget_string_container *uc; + struct usb_gadget_strings **n_gs; + unsigned n_gstrings = 0; + unsigned i; + int ret; + + for (i = 0; sp[i]; i++) + n_gstrings++; + + if (!n_gstrings) + return ERR_PTR(-EINVAL); + + uc = copy_gadget_strings(sp, n_gstrings, n_strings); + if (IS_ERR(uc)) + return ERR_PTR(PTR_ERR(uc)); + + n_gs = get_containers_gs(uc); + ret = usb_string_ids_tab(cdev, n_gs[0]->strings); + if (ret) + goto err; + + for (i = 1; i < n_gstrings; i++) { + struct usb_string *m_s; + struct usb_string *s; + unsigned n; + + m_s = n_gs[0]->strings; + s = n_gs[i]->strings; + for (n = 0; n < n_strings; n++) { + s->id = m_s->id; + s++; + m_s++; + } + } + list_add_tail(&uc->list, &cdev->gstrings); + return n_gs[0]->strings; +err: + kfree(uc); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(usb_gstrings_attach); + /** * usb_string_ids_n() - allocate unused string IDs in batch * @c: the device whose string descriptor IDs are being allocated @@ -1033,7 +1212,7 @@ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req) * housekeeping for the gadget function we're implementing. Most of * the work is in config and function specific setup. */ -static int +int composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) { struct usb_composite_dev *cdev = get_gadget_data(gadget); @@ -1300,7 +1479,7 @@ done: return value; } -static void composite_disconnect(struct usb_gadget *gadget) +void composite_disconnect(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); unsigned long flags; @@ -1330,8 +1509,7 @@ static ssize_t composite_show_suspended(struct device *dev, static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL); -static void -composite_unbind(struct usb_gadget *gadget) +static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver) { struct usb_composite_dev *cdev = get_gadget_data(gadget); @@ -1348,19 +1526,21 @@ composite_unbind(struct usb_gadget *gadget) struct usb_configuration, list); remove_config(cdev, c); } - if (cdev->driver->unbind) + if (cdev->driver->unbind && unbind_driver) cdev->driver->unbind(cdev); - if (cdev->req) { - kfree(cdev->req->buf); - usb_ep_free_request(gadget->ep0, cdev->req); - } - device_remove_file(&gadget->dev, &dev_attr_suspended); + composite_dev_cleanup(cdev); + kfree(cdev->def_manufacturer); kfree(cdev); set_gadget_data(gadget, NULL); } +static void composite_unbind(struct usb_gadget *gadget) +{ + __composite_unbind(gadget, true); +} + static void update_unchanged_dev_desc(struct usb_device_descriptor *new, const struct usb_device_descriptor *old) { @@ -1399,34 +1579,25 @@ static void update_unchanged_dev_desc(struct usb_device_descriptor *new, new->iProduct = iProduct; } -static struct usb_composite_driver *to_cdriver(struct usb_gadget_driver *gdrv) -{ - return container_of(gdrv, struct usb_composite_driver, gadget_driver); -} - -static int composite_bind(struct usb_gadget *gadget, - struct usb_gadget_driver *gdriver) +int composite_dev_prepare(struct usb_composite_driver *composite, + struct usb_composite_dev *cdev) { - struct usb_composite_dev *cdev; - struct usb_composite_driver *composite = to_cdriver(gdriver); - int status = -ENOMEM; - - cdev = kzalloc(sizeof *cdev, GFP_KERNEL); - if (!cdev) - return status; - - spin_lock_init(&cdev->lock); - cdev->gadget = gadget; - set_gadget_data(gadget, cdev); - INIT_LIST_HEAD(&cdev->configs); + struct usb_gadget *gadget = cdev->gadget; + int ret = -ENOMEM; /* preallocate control response and buffer */ cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); if (!cdev->req) - goto fail; + return -ENOMEM; + cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL); if (!cdev->req->buf) goto fail; + + ret = device_create_file(&gadget->dev, &dev_attr_suspended); + if (ret) + goto fail_dev; + cdev->req->complete = composite_setup_complete; gadget->ep0->driver_data = cdev; @@ -1444,7 +1615,51 @@ static int composite_bind(struct usb_gadget *gadget, * we force endpoints to start unassigned; few controller * drivers will zero ep->driver_data. */ - usb_ep_autoconfig_reset(cdev->gadget); + usb_ep_autoconfig_reset(gadget); + return 0; +fail_dev: + kfree(cdev->req->buf); +fail: + usb_ep_free_request(gadget->ep0, cdev->req); + cdev->req = NULL; + return ret; +} + +void composite_dev_cleanup(struct usb_composite_dev *cdev) +{ + struct usb_gadget_string_container *uc, *tmp; + + list_for_each_entry_safe(uc, tmp, &cdev->gstrings, list) { + list_del(&uc->list); + kfree(uc); + } + if (cdev->req) { + kfree(cdev->req->buf); + usb_ep_free_request(cdev->gadget->ep0, cdev->req); + } + device_remove_file(&cdev->gadget->dev, &dev_attr_suspended); +} + +static int composite_bind(struct usb_gadget *gadget, + struct usb_gadget_driver *gdriver) +{ + struct usb_composite_dev *cdev; + struct usb_composite_driver *composite = to_cdriver(gdriver); + int status = -ENOMEM; + + cdev = kzalloc(sizeof *cdev, GFP_KERNEL); + if (!cdev) + return status; + + spin_lock_init(&cdev->lock); + cdev->gadget = gadget; + set_gadget_data(gadget, cdev); + INIT_LIST_HEAD(&cdev->configs); + INIT_LIST_HEAD(&cdev->gstrings); + + status = composite_dev_prepare(composite, cdev); + if (status) + goto fail; /* composite gadget needs to assign strings for whole device (like * serial number), register function drivers, potentially update @@ -1460,16 +1675,11 @@ static int composite_bind(struct usb_gadget *gadget, if (composite->needs_serial && !cdev->desc.iSerialNumber) WARNING(cdev, "userspace failed to provide iSerialNumber\n"); - /* finish up */ - status = device_create_file(&gadget->dev, &dev_attr_suspended); - if (status) - goto fail; - INFO(cdev, "%s ready\n", composite->name); return 0; fail: - composite_unbind(gadget); + __composite_unbind(gadget, false); return status; } @@ -1518,10 +1728,10 @@ composite_resume(struct usb_gadget *gadget) f->resume(f); } - maxpower = cdev->config->bMaxPower; + maxpower = cdev->config->MaxPower; usb_gadget_vbus_draw(gadget, maxpower ? - (2 * maxpower) : CONFIG_USB_GADGET_VBUS_DRAW); + maxpower : CONFIG_USB_GADGET_VBUS_DRAW); } cdev->suspended = 0; diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c index 87d16502816..986fc511a2e 100644 --- a/drivers/usb/gadget/dbgp.c +++ b/drivers/usb/gadget/dbgp.c @@ -13,9 +13,7 @@ #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> -#ifdef CONFIG_USB_G_DBGP_SERIAL -#include "u_serial.c" -#endif +#include "u_serial.h" #define DRIVER_VENDOR_ID 0x0525 /* NetChip */ #define DRIVER_PRODUCT_ID 0xc0de /* undefined */ @@ -233,6 +231,10 @@ static void dbgp_unbind(struct usb_gadget *gadget) gadget->ep0->driver_data = NULL; } +#ifdef CONFIG_USB_G_DBGP_SERIAL +static unsigned char tty_line; +#endif + static int __init dbgp_configure_endpoints(struct usb_gadget *gadget) { int stp; @@ -270,7 +272,7 @@ static int __init dbgp_configure_endpoints(struct usb_gadget *gadget) dbgp.serial->in->desc = &i_desc; dbgp.serial->out->desc = &o_desc; - if (gserial_setup(gadget, 1) < 0) { + if (gserial_alloc_line(&tty_line)) { stp = 3; goto fail_3; } @@ -379,7 +381,7 @@ static int dbgp_setup(struct usb_gadget *gadget, #ifdef CONFIG_USB_G_DBGP_PRINTK err = dbgp_enable_ep(); #else - err = gserial_connect(dbgp.serial, 0); + err = gserial_connect(dbgp.serial, tty_line); #endif if (err < 0) goto fail; @@ -422,7 +424,7 @@ static void __exit dbgp_exit(void) { usb_gadget_unregister_driver(&dbgp_driver); #ifdef CONFIG_USB_G_DBGP_SERIAL - gserial_cleanup(); + gserial_free_line(tty_line); #endif } diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index 549174466c2..1ae180baa59 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c @@ -16,7 +16,9 @@ #include <linux/slab.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/device.h> +#include <linux/err.h> #include "u_serial.h" #include "gadget_chips.h" @@ -283,7 +285,6 @@ static struct usb_string acm_string_defs[] = { [ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)", [ACM_DATA_IDX].s = "CDC ACM Data", [ACM_IAD_IDX ].s = "CDC Serial", - { /* ZEROES END LIST */ }, }; static struct usb_gadget_strings acm_string_table = { @@ -605,9 +606,23 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct f_acm *acm = func_to_acm(f); + struct usb_string *us; int status; struct usb_ep *ep; + /* REVISIT might want instance-specific strings to help + * distinguish instances ... + */ + + /* maybe allocate device-global string IDs, and patch descriptors */ + us = usb_gstrings_attach(cdev, acm_strings, + ARRAY_SIZE(acm_string_defs)); + if (IS_ERR(us)) + return PTR_ERR(us); + acm_control_interface_desc.iInterface = us[ACM_CTRL_IDX].id; + acm_data_interface_desc.iInterface = us[ACM_DATA_IDX].id; + acm_iad_descriptor.iFunction = us[ACM_IAD_IDX].id; + /* allocate instance-specific interface IDs, and patch descriptors */ status = usb_interface_id(c, f); if (status < 0) @@ -700,24 +715,42 @@ fail: return status; } +static struct f_acm *acm_alloc_basic_func(void) +{ + struct f_acm *acm; + + acm = kzalloc(sizeof(*acm), GFP_KERNEL); + if (!acm) + return NULL; + + spin_lock_init(&acm->lock); + + acm->port.connect = acm_connect; + acm->port.disconnect = acm_disconnect; + acm->port.send_break = acm_send_break; + + acm->port.func.name = "acm"; + /* descriptors are per-instance copies */ + acm->port.func.bind = acm_bind; + acm->port.func.set_alt = acm_set_alt; + acm->port.func.setup = acm_setup; + acm->port.func.disable = acm_disable; + + return acm; +} + +#ifdef USB_FACM_INCLUDED static void -acm_unbind(struct usb_configuration *c, struct usb_function *f) +acm_old_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_acm *acm = func_to_acm(f); - acm_string_defs[0].id = 0; usb_free_all_descriptors(f); - gs_free_req(acm->notify, acm->notify_req); + if (acm->notify_req) + gs_free_req(acm->notify, acm->notify_req); kfree(acm); } -/* Some controllers can't support CDC ACM ... */ -static inline bool can_support_cdc(struct usb_configuration *c) -{ - /* everything else is *probably* fine ... */ - return true; -} - /** * acm_bind_config - add a CDC ACM function to a configuration * @c: the configuration to support the CDC ACM instance @@ -726,58 +759,80 @@ static inline bool can_support_cdc(struct usb_configuration *c) * * Returns zero on success, else negative errno. * - * Caller must have called @gserial_setup() with enough ports to - * handle all the ones it binds. Caller is also responsible - * for calling @gserial_cleanup() before module unload. */ int acm_bind_config(struct usb_configuration *c, u8 port_num) { struct f_acm *acm; int status; - if (!can_support_cdc(c)) - return -EINVAL; - - /* REVISIT might want instance-specific strings to help - * distinguish instances ... - */ - - /* maybe allocate device-global string IDs, and patch descriptors */ - if (acm_string_defs[0].id == 0) { - status = usb_string_ids_tab(c->cdev, acm_string_defs); - if (status < 0) - return status; - acm_control_interface_desc.iInterface = - acm_string_defs[ACM_CTRL_IDX].id; - acm_data_interface_desc.iInterface = - acm_string_defs[ACM_DATA_IDX].id; - acm_iad_descriptor.iFunction = acm_string_defs[ACM_IAD_IDX].id; - } - /* allocate and initialize one new instance */ - acm = kzalloc(sizeof *acm, GFP_KERNEL); + acm = acm_alloc_basic_func(); if (!acm) return -ENOMEM; - spin_lock_init(&acm->lock); - acm->port_num = port_num; - - acm->port.connect = acm_connect; - acm->port.disconnect = acm_disconnect; - acm->port.send_break = acm_send_break; - - acm->port.func.name = "acm"; - acm->port.func.strings = acm_strings; - /* descriptors are per-instance copies */ - acm->port.func.bind = acm_bind; - acm->port.func.unbind = acm_unbind; - acm->port.func.set_alt = acm_set_alt; - acm->port.func.setup = acm_setup; - acm->port.func.disable = acm_disable; + acm->port.func.unbind = acm_old_unbind; status = usb_add_function(c, &acm->port.func); if (status) kfree(acm); return status; } + +#else + +static void acm_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_acm *acm = func_to_acm(f); + + acm_string_defs[0].id = 0; + usb_free_all_descriptors(f); + if (acm->notify_req) + gs_free_req(acm->notify, acm->notify_req); +} + +static void acm_free_func(struct usb_function *f) +{ + struct f_acm *acm = func_to_acm(f); + + kfree(acm); +} + +static struct usb_function *acm_alloc_func(struct usb_function_instance *fi) +{ + struct f_serial_opts *opts; + struct f_acm *acm; + + acm = acm_alloc_basic_func(); + if (!acm) + return ERR_PTR(-ENOMEM); + + opts = container_of(fi, struct f_serial_opts, func_inst); + acm->port_num = opts->port_num; + acm->port.func.unbind = acm_unbind; + acm->port.func.free_func = acm_free_func; + + return &acm->port.func; +} + +static void acm_free_instance(struct usb_function_instance *fi) +{ + struct f_serial_opts *opts; + + opts = container_of(fi, struct f_serial_opts, func_inst); + kfree(opts); +} + +static struct usb_function_instance *acm_alloc_instance(void) +{ + struct f_serial_opts *opts; + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); + opts->func_inst.free_func_inst = acm_free_instance; + return &opts->func_inst; +} +DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func); +MODULE_LICENSE("GPL"); +#endif diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 4a6961c517f..449186c9fd6 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -1103,8 +1103,8 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts) return 0; for (;;) { - char *end, *eq, *comma; unsigned long value; + char *eq, *comma; /* Option limit */ comma = strchr(opts, ','); @@ -1120,8 +1120,7 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts) *eq = 0; /* Parse value */ - value = simple_strtoul(eq + 1, &end, 0); - if (unlikely(*end != ',' && *end != 0)) { + if (kstrtoul(eq + 1, 0, &value)) { pr_err("%s: invalid value: %s\n", opts, eq + 1); return -EINVAL; } diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index bb39cb2bb3a..4a3873a0f2d 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c @@ -15,10 +15,11 @@ #include <linux/slab.h> #include <linux/kernel.h> #include <linux/device.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/usb/composite.h> #include "g_zero.h" -#include "gadget_chips.h" - /* * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals, @@ -44,9 +45,8 @@ static inline struct f_loopback *func_to_loop(struct usb_function *f) return container_of(f, struct f_loopback, function); } -static unsigned qlen = 32; -module_param(qlen, uint, 0); -MODULE_PARM_DESC(qlenn, "depth of loopback queue"); +static unsigned qlen; +static unsigned buflen; /*-------------------------------------------------------------------------*/ @@ -171,8 +171,7 @@ static struct usb_gadget_strings *loopback_strings[] = { /*-------------------------------------------------------------------------*/ -static int __init -loopback_bind(struct usb_configuration *c, struct usb_function *f) +static int loopback_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct f_loopback *loop = func_to_loop(f); @@ -185,6 +184,12 @@ loopback_bind(struct usb_configuration *c, struct usb_function *f) return id; loopback_intf.bInterfaceNumber = id; + id = usb_string_id(cdev); + if (id < 0) + return id; + strings_loopback[0].id = id; + loopback_intf.iInterface = id; + /* allocate endpoints */ loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc); @@ -223,8 +228,7 @@ autoconf_fail: return 0; } -static void -loopback_unbind(struct usb_configuration *c, struct usb_function *f) +static void lb_free_func(struct usb_function *f) { usb_free_all_descriptors(f); kfree(func_to_loop(f)); @@ -366,63 +370,64 @@ static void loopback_disable(struct usb_function *f) disable_loopback(loop); } -/*-------------------------------------------------------------------------*/ - -static int __init loopback_bind_config(struct usb_configuration *c) +static struct usb_function *loopback_alloc(struct usb_function_instance *fi) { struct f_loopback *loop; - int status; + struct f_lb_opts *lb_opts; loop = kzalloc(sizeof *loop, GFP_KERNEL); if (!loop) - return -ENOMEM; + return ERR_PTR(-ENOMEM); + + lb_opts = container_of(fi, struct f_lb_opts, func_inst); + buflen = lb_opts->bulk_buflen; + qlen = lb_opts->qlen; + if (!qlen) + qlen = 32; loop->function.name = "loopback"; loop->function.bind = loopback_bind; - loop->function.unbind = loopback_unbind; loop->function.set_alt = loopback_set_alt; loop->function.disable = loopback_disable; + loop->function.strings = loopback_strings; - status = usb_add_function(c, &loop->function); - if (status) - kfree(loop); - return status; -} + loop->function.free_func = lb_free_func; -static struct usb_configuration loopback_driver = { - .label = "loopback", - .strings = loopback_strings, - .bConfigurationValue = 2, - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, - /* .iConfiguration = DYNAMIC */ -}; + return &loop->function; +} -/** - * loopback_add - add a loopback testing configuration to a device - * @cdev: the device to support the loopback configuration - */ -int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume) +static void lb_free_instance(struct usb_function_instance *fi) { - int id; + struct f_lb_opts *lb_opts; - /* allocate string ID(s) */ - id = usb_string_id(cdev); - if (id < 0) - return id; - strings_loopback[0].id = id; + lb_opts = container_of(fi, struct f_lb_opts, func_inst); + kfree(lb_opts); +} - loopback_intf.iInterface = id; - loopback_driver.iConfiguration = id; +static struct usb_function_instance *loopback_alloc_instance(void) +{ + struct f_lb_opts *lb_opts; - /* support autoresume for remote wakeup testing */ - if (autoresume) - loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + lb_opts = kzalloc(sizeof(*lb_opts), GFP_KERNEL); + if (!lb_opts) + return ERR_PTR(-ENOMEM); + lb_opts->func_inst.free_func_inst = lb_free_instance; + return &lb_opts->func_inst; +} +DECLARE_USB_FUNCTION(Loopback, loopback_alloc_instance, loopback_alloc); - /* support OTG systems */ - if (gadget_is_otg(cdev->gadget)) { - loopback_driver.descriptors = otg_desc; - loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; - } +int __init lb_modinit(void) +{ + int ret; - return usb_add_config(cdev, &loopback_driver, loopback_bind_config); + ret = usb_function_register(&Loopbackusb_func); + if (ret) + return ret; + return ret; } +void __exit lb_modexit(void) +{ + usb_function_unregister(&Loopbackusb_func); +} + +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 5d027b3e1ef..fc5c16ca5e0 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -246,20 +246,6 @@ struct fsg_operations { * set). */ int (*thread_exits)(struct fsg_common *common); - - /* - * Called prior to ejection. Negative return means error, - * zero means to continue with ejection, positive means not to - * eject. - */ - int (*pre_eject)(struct fsg_common *common, - struct fsg_lun *lun, int num); - /* - * Called after ejection. Negative return means error, zero - * or positive is just a success. - */ - int (*post_eject)(struct fsg_common *common, - struct fsg_lun *lun, int num); }; /* Data shared by all the FSG instances. */ @@ -1374,26 +1360,13 @@ static int do_start_stop(struct fsg_common *common) if (!loej) return 0; - /* Simulate an unload/eject */ - if (common->ops && common->ops->pre_eject) { - int r = common->ops->pre_eject(common, curlun, - curlun - common->luns); - if (unlikely(r < 0)) - return r; - else if (r) - return 0; - } - up_read(&common->filesem); down_write(&common->filesem); fsg_lun_close(curlun); up_write(&common->filesem); down_read(&common->filesem); - return common->ops && common->ops->post_eject - ? min(0, common->ops->post_eject(common, curlun, - curlun - common->luns)) - : 0; + return 0; } static int do_prevent_allow(struct fsg_common *common) @@ -1718,7 +1691,7 @@ static int check_command(struct fsg_common *common, int cmnd_size, int needs_medium, const char *name) { int i; - int lun = common->cmnd[1] >> 5; + unsigned int lun = common->cmnd[1] >> 5; static const char dirletter[4] = {'u', 'o', 'i', 'n'}; char hdlen[20]; struct fsg_lun *curlun; @@ -1784,7 +1757,7 @@ static int check_command(struct fsg_common *common, int cmnd_size, /* Check that the LUN values are consistent */ if (common->lun != lun) - DBG(common, "using LUN %d from CBW, not LUN %d from CDB\n", + DBG(common, "using LUN %u from CBW, not LUN %u from CDB\n", common->lun, lun); /* Check the LUN */ @@ -1804,7 +1777,7 @@ static int check_command(struct fsg_common *common, int cmnd_size, */ if (common->cmnd[0] != INQUIRY && common->cmnd[0] != REQUEST_SENSE) { - DBG(common, "unsupported LUN %d\n", common->lun); + DBG(common, "unsupported LUN %u\n", common->lun); return -EINVAL; } } @@ -2196,7 +2169,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) if (common->data_size == 0) common->data_dir = DATA_DIR_NONE; common->lun = cbw->Lun; - if (common->lun >= 0 && common->lun < common->nluns) + if (common->lun < common->nluns) common->curlun = &common->luns[common->lun]; else common->curlun = NULL; diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index 6c8362f937b..5e7557e23ec 100644 --- a/drivers/usb/gadget/f_ncm.c +++ b/drivers/usb/gadget/f_ncm.c @@ -56,8 +56,9 @@ struct f_ncm { u8 notify_state; bool is_open; - struct ndp_parser_opts *parser_opts; + const struct ndp_parser_opts *parser_opts; bool is_crc; + u32 ndp_sign; /* * for notification, it is accessed from both @@ -390,8 +391,8 @@ struct ndp_parser_opts { .next_fp_index = 2, \ } -static struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS; -static struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS; +static const struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS; +static const struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS; static inline void put_ncm(__le16 **p, unsigned size, unsigned val) { @@ -732,8 +733,7 @@ static int ncm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) default: goto invalid; } - ncm->parser_opts->ndp_sign &= ~NCM_NDP_HDR_CRC_MASK; - ncm->parser_opts->ndp_sign |= ndp_hdr_crc; + ncm->ndp_sign = ncm->parser_opts->ndp_sign | ndp_hdr_crc; value = 0; break; } @@ -875,7 +875,7 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port, int ndp_align; int ndp_pad; unsigned max_size = ncm->port.fixed_in_len; - struct ndp_parser_opts *opts = ncm->parser_opts; + const struct ndp_parser_opts *opts = ncm->parser_opts; unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0; div = le16_to_cpu(ntb_parameters.wNdpInDivisor); @@ -921,7 +921,7 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port, tmp = (void *)tmp + ndp_pad; /* NDP */ - put_unaligned_le32(opts->ndp_sign, tmp); /* dwSignature */ + put_unaligned_le32(ncm->ndp_sign, tmp); /* dwSignature */ tmp += 2; /* wLength */ put_unaligned_le16(ncb_len - opts->nth_size - pad, tmp++); @@ -965,7 +965,7 @@ static int ncm_unwrap_ntb(struct gether *port, struct sk_buff *skb2; int ret = -EINVAL; unsigned max_size = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize); - struct ndp_parser_opts *opts = ncm->parser_opts; + const struct ndp_parser_opts *opts = ncm->parser_opts; unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0; int dgram_counter; @@ -1002,7 +1002,7 @@ static int ncm_unwrap_ntb(struct gether *port, /* walk through NDP */ tmp = ((void *)skb->data) + index; - if (get_unaligned_le32(tmp) != opts->ndp_sign) { + if (get_unaligned_le32(tmp) != ncm->ndp_sign) { INFO(port->func.config->cdev, "Wrong NDP SIGN\n"); goto err; } diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c index d8dd8782768..36a004563b8 100644 --- a/drivers/usb/gadget/f_obex.c +++ b/drivers/usb/gadget/f_obex.c @@ -406,10 +406,6 @@ static inline bool can_support_obex(struct usb_configuration *c) * Context: single threaded during gadget setup * * Returns zero on success, else negative errno. - * - * Caller must have called @gserial_setup() with enough ports to - * handle all the ones it binds. Caller is also responsible - * for calling @gserial_cleanup() before module unload. */ int __init obex_bind_config(struct usb_configuration *c, u8 port_num) { diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c index 98fa7795df5..da33cfb3031 100644 --- a/drivers/usb/gadget/f_serial.c +++ b/drivers/usb/gadget/f_serial.c @@ -260,10 +260,6 @@ gser_unbind(struct usb_configuration *c, struct usb_function *f) * Context: single threaded during gadget setup * * Returns zero on success, else negative errno. - * - * Caller must have called @gserial_setup() with enough ports to - * handle all the ones it binds. Caller is also responsible - * for calling @gserial_cleanup() before module unload. */ int __init gser_bind_config(struct usb_configuration *c, u8 port_num) { diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index 102d49beb9d..41adf3ef96c 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -16,11 +16,12 @@ #include <linux/kernel.h> #include <linux/device.h> #include <linux/module.h> +#include <linux/usb/composite.h> +#include <linux/err.h> #include "g_zero.h" #include "gadget_chips.h" - /* * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral * controller drivers. @@ -62,24 +63,11 @@ static inline struct f_sourcesink *func_to_ss(struct usb_function *f) } static unsigned pattern; -module_param(pattern, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none"); - -static unsigned isoc_interval = 4; -module_param(isoc_interval, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(isoc_interval, "1 - 16"); - -static unsigned isoc_maxpacket = 1024; -module_param(isoc_maxpacket, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)"); - +static unsigned isoc_interval; +static unsigned isoc_maxpacket; static unsigned isoc_mult; -module_param(isoc_mult, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)"); - static unsigned isoc_maxburst; -module_param(isoc_maxburst, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)"); +static unsigned buflen; /*-------------------------------------------------------------------------*/ @@ -313,7 +301,57 @@ static struct usb_gadget_strings *sourcesink_strings[] = { /*-------------------------------------------------------------------------*/ -static int __init +struct usb_request *alloc_ep_req(struct usb_ep *ep, int len) +{ + struct usb_request *req; + + req = usb_ep_alloc_request(ep, GFP_ATOMIC); + if (req) { + if (len) + req->length = len; + else + req->length = buflen; + req->buf = kmalloc(req->length, GFP_ATOMIC); + if (!req->buf) { + usb_ep_free_request(ep, req); + req = NULL; + } + } + return req; +} + +void free_ep_req(struct usb_ep *ep, struct usb_request *req) +{ + kfree(req->buf); + usb_ep_free_request(ep, req); +} + +static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep) +{ + int value; + + if (ep->driver_data) { + value = usb_ep_disable(ep); + if (value < 0) + DBG(cdev, "disable %s --> %d\n", + ep->name, value); + ep->driver_data = NULL; + } +} + +void disable_endpoints(struct usb_composite_dev *cdev, + struct usb_ep *in, struct usb_ep *out, + struct usb_ep *iso_in, struct usb_ep *iso_out) +{ + disable_ep(cdev, in); + disable_ep(cdev, out); + if (iso_in) + disable_ep(cdev, iso_in); + if (iso_out) + disable_ep(cdev, iso_out); +} + +static int sourcesink_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; @@ -450,7 +488,7 @@ no_iso: } static void -sourcesink_unbind(struct usb_configuration *c, struct usb_function *f) +sourcesink_free_func(struct usb_function *f) { usb_free_all_descriptors(f); kfree(func_to_ss(f)); @@ -531,8 +569,7 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req) check_read_data(ss, req); if (pattern != 2) memset(req->buf, 0x55, req->length); - } else - reinit_write_data(ep, req); + } break; /* this endpoint is normally active while we're configured */ @@ -758,31 +795,10 @@ static void sourcesink_disable(struct usb_function *f) /*-------------------------------------------------------------------------*/ -static int __init sourcesink_bind_config(struct usb_configuration *c) -{ - struct f_sourcesink *ss; - int status; - - ss = kzalloc(sizeof *ss, GFP_KERNEL); - if (!ss) - return -ENOMEM; - - ss->function.name = "source/sink"; - ss->function.bind = sourcesink_bind; - ss->function.unbind = sourcesink_unbind; - ss->function.set_alt = sourcesink_set_alt; - ss->function.get_alt = sourcesink_get_alt; - ss->function.disable = sourcesink_disable; - - status = usb_add_function(c, &ss->function); - if (status) - kfree(ss); - return status; -} - -static int sourcesink_setup(struct usb_configuration *c, +static int sourcesink_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) { + struct usb_configuration *c = f->config; struct usb_request *req = c->cdev->req; int value = -EOPNOTSUPP; u16 w_index = le16_to_cpu(ctrl->wIndex); @@ -851,42 +867,76 @@ unknown: return value; } -static struct usb_configuration sourcesink_driver = { - .label = "source/sink", - .strings = sourcesink_strings, - .setup = sourcesink_setup, - .bConfigurationValue = 3, - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, - /* .iConfiguration = DYNAMIC */ -}; +static struct usb_function *source_sink_alloc_func( + struct usb_function_instance *fi) +{ + struct f_sourcesink *ss; + struct f_ss_opts *ss_opts; -/** - * sourcesink_add - add a source/sink testing configuration to a device - * @cdev: the device to support the configuration - */ -int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume) + ss = kzalloc(sizeof(*ss), GFP_KERNEL); + if (!ss) + return NULL; + + ss_opts = container_of(fi, struct f_ss_opts, func_inst); + pattern = ss_opts->pattern; + isoc_interval = ss_opts->isoc_interval; + isoc_maxpacket = ss_opts->isoc_maxpacket; + isoc_mult = ss_opts->isoc_mult; + isoc_maxburst = ss_opts->isoc_maxburst; + buflen = ss_opts->bulk_buflen; + + ss->function.name = "source/sink"; + ss->function.bind = sourcesink_bind; + ss->function.set_alt = sourcesink_set_alt; + ss->function.get_alt = sourcesink_get_alt; + ss->function.disable = sourcesink_disable; + ss->function.setup = sourcesink_setup; + ss->function.strings = sourcesink_strings; + + ss->function.free_func = sourcesink_free_func; + + return &ss->function; +} + +static void acm_free_instance(struct usb_function_instance *fi) { - int id; + struct f_ss_opts *ss_opts; - /* allocate string ID(s) */ - id = usb_string_id(cdev); - if (id < 0) - return id; - strings_sourcesink[0].id = id; + ss_opts = container_of(fi, struct f_ss_opts, func_inst); + kfree(ss_opts); +} - source_sink_intf_alt0.iInterface = id; - source_sink_intf_alt1.iInterface = id; - sourcesink_driver.iConfiguration = id; +static struct usb_function_instance *source_sink_alloc_inst(void) +{ + struct f_ss_opts *ss_opts; - /* support autoresume for remote wakeup testing */ - if (autoresume) - sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + ss_opts = kzalloc(sizeof(*ss_opts), GFP_KERNEL); + if (!ss_opts) + return ERR_PTR(-ENOMEM); + ss_opts->func_inst.free_func_inst = acm_free_instance; + return &ss_opts->func_inst; +} +DECLARE_USB_FUNCTION(SourceSink, source_sink_alloc_inst, + source_sink_alloc_func); - /* support OTG systems */ - if (gadget_is_otg(cdev->gadget)) { - sourcesink_driver.descriptors = otg_desc; - sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; - } +static int __init sslb_modinit(void) +{ + int ret; - return usb_add_config(cdev, &sourcesink_driver, sourcesink_bind_config); + ret = usb_function_register(&SourceSinkusb_func); + if (ret) + return ret; + ret = lb_modinit(); + if (ret) + usb_function_unregister(&SourceSinkusb_func); + return ret; +} +static void __exit sslb_modexit(void) +{ + usb_function_unregister(&SourceSinkusb_func); + lb_modexit(); } +module_init(sslb_modinit); +module_exit(sslb_modexit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/f_uac2.c index d7da258fa3f..c7468b6c07b 100644 --- a/drivers/usb/gadget/f_uac2.c +++ b/drivers/usb/gadget/f_uac2.c @@ -260,19 +260,14 @@ static int uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream); - struct audio_dev *agdev = uac2_to_agdev(uac2); struct uac2_rtd_params *prm; unsigned long flags; - struct usb_ep *ep; int err = 0; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - ep = agdev->in_ep; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) prm = &uac2->p_prm; - } else { - ep = agdev->out_ep; + else prm = &uac2->c_prm; - } spin_lock_irqsave(&prm->lock, flags); diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index ec50f18c889..034477ce77c 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -1894,7 +1894,7 @@ static int fsl_qe_stop(struct usb_gadget *gadget, struct usb_gadget_driver *driver); /* defined in usb_gadget.h */ -static struct usb_gadget_ops qe_gadget_ops = { +static const struct usb_gadget_ops qe_gadget_ops = { .get_frame = qe_get_frame, .udc_start = fsl_qe_start, .udc_stop = fsl_qe_stop, diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index c19f7f13790..38939561cff 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -1254,19 +1254,20 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on) return 0; } -static int fsl_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); -static int fsl_stop(struct usb_gadget_driver *driver); +static int fsl_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver); +static int fsl_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver); /* defined in gadget.h */ -static struct usb_gadget_ops fsl_gadget_ops = { +static const struct usb_gadget_ops fsl_gadget_ops = { .get_frame = fsl_get_frame, .wakeup = fsl_wakeup, /* .set_selfpowered = fsl_set_selfpowered, */ /* Always selfpowered */ .vbus_session = fsl_vbus_session, .vbus_draw = fsl_vbus_draw, .pullup = fsl_pullup, - .start = fsl_start, - .stop = fsl_stop, + .udc_start = fsl_udc_start, + .udc_stop = fsl_udc_stop, }; /* Set protocol stall on ep0, protocol stall will automatically be cleared @@ -1950,22 +1951,12 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) * Hook to gadget drivers * Called by initialization code of gadget drivers *----------------------------------------------------------------*/ -static int fsl_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) +static int fsl_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - int retval = -ENODEV; + int retval = 0; unsigned long flags = 0; - if (!udc_controller) - return -ENODEV; - - if (!driver || driver->max_speed < USB_SPEED_FULL - || !bind || !driver->disconnect || !driver->setup) - return -EINVAL; - - if (udc_controller->driver) - return -EBUSY; - /* lock is needed but whether should use this lock or another */ spin_lock_irqsave(&udc_controller->lock, flags); @@ -1975,15 +1966,6 @@ static int fsl_start(struct usb_gadget_driver *driver, udc_controller->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc_controller->lock, flags); - /* bind udc driver to gadget driver */ - retval = bind(&udc_controller->gadget, driver); - if (retval) { - VDBG("bind to %s --> %d", driver->driver.name, retval); - udc_controller->gadget.dev.driver = NULL; - udc_controller->driver = NULL; - goto out; - } - if (!IS_ERR_OR_NULL(udc_controller->transceiver)) { /* Suspend the controller until OTG enable it */ udc_controller->stopped = 1; @@ -2009,28 +1991,17 @@ static int fsl_start(struct usb_gadget_driver *driver, udc_controller->ep0_state = WAIT_FOR_SETUP; udc_controller->ep0_dir = 0; } - printk(KERN_INFO "%s: bind to driver %s\n", - udc_controller->gadget.name, driver->driver.name); -out: - if (retval) - printk(KERN_WARNING "gadget driver register failed %d\n", - retval); return retval; } /* Disconnect from gadget driver */ -static int fsl_stop(struct usb_gadget_driver *driver) +static int fsl_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver) { struct fsl_ep *loop_ep; unsigned long flags; - if (!udc_controller) - return -ENODEV; - - if (!driver || driver != udc_controller->driver || !driver->unbind) - return -EINVAL; - if (!IS_ERR_OR_NULL(udc_controller->transceiver)) otg_set_peripheral(udc_controller->transceiver->otg, NULL); @@ -2051,16 +2022,9 @@ static int fsl_stop(struct usb_gadget_driver *driver) nuke(loop_ep, -ESHUTDOWN); spin_unlock_irqrestore(&udc_controller->lock, flags); - /* report disconnect; the controller is already quiesced */ - driver->disconnect(&udc_controller->gadget); - - /* unbind gadget and unhook driver. */ - driver->unbind(&udc_controller->gadget); udc_controller->gadget.dev.driver = NULL; udc_controller->driver = NULL; - printk(KERN_WARNING "unregistered gadget driver '%s'\n", - driver->driver.name); return 0; } diff --git a/drivers/usb/gadget/functions.c b/drivers/usb/gadget/functions.c new file mode 100644 index 00000000000..b13f839e736 --- /dev/null +++ b/drivers/usb/gadget/functions.c @@ -0,0 +1,116 @@ +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/err.h> + +#include <linux/usb/composite.h> + +static LIST_HEAD(func_list); +static DEFINE_MUTEX(func_lock); + +static struct usb_function_instance *try_get_usb_function_instance(const char *name) +{ + struct usb_function_driver *fd; + struct usb_function_instance *fi; + + fi = ERR_PTR(-ENOENT); + mutex_lock(&func_lock); + list_for_each_entry(fd, &func_list, list) { + + if (strcmp(name, fd->name)) + continue; + + if (!try_module_get(fd->mod)) { + fi = ERR_PTR(-EBUSY); + break; + } + fi = fd->alloc_inst(); + if (IS_ERR(fi)) + module_put(fd->mod); + else + fi->fd = fd; + break; + } + mutex_unlock(&func_lock); + return fi; +} + +struct usb_function_instance *usb_get_function_instance(const char *name) +{ + struct usb_function_instance *fi; + int ret; + + fi = try_get_usb_function_instance(name); + if (!IS_ERR(fi)) + return fi; + ret = PTR_ERR(fi); + if (ret != -ENOENT) + return fi; + ret = request_module("usbfunc:%s", name); + if (ret < 0) + return ERR_PTR(ret); + return try_get_usb_function_instance(name); +} +EXPORT_SYMBOL_GPL(usb_get_function_instance); + +struct usb_function *usb_get_function(struct usb_function_instance *fi) +{ + struct usb_function *f; + + f = fi->fd->alloc_func(fi); + if (IS_ERR(f)) + return f; + f->fi = fi; + return f; +} +EXPORT_SYMBOL_GPL(usb_get_function); + +void usb_put_function_instance(struct usb_function_instance *fi) +{ + struct module *mod; + + if (!fi) + return; + + mod = fi->fd->mod; + fi->free_func_inst(fi); + module_put(mod); +} +EXPORT_SYMBOL_GPL(usb_put_function_instance); + +void usb_put_function(struct usb_function *f) +{ + if (!f) + return; + + f->free_func(f); +} +EXPORT_SYMBOL_GPL(usb_put_function); + +int usb_function_register(struct usb_function_driver *newf) +{ + struct usb_function_driver *fd; + int ret; + + ret = -EEXIST; + + mutex_lock(&func_lock); + list_for_each_entry(fd, &func_list, list) { + if (!strcmp(fd->name, newf->name)) + goto out; + } + ret = 0; + list_add_tail(&newf->list, &func_list); +out: + mutex_unlock(&func_lock); + return ret; +} +EXPORT_SYMBOL_GPL(usb_function_register); + +void usb_function_unregister(struct usb_function_driver *fd) +{ + mutex_lock(&func_lock); + list_del(&fd->list); + mutex_unlock(&func_lock); +} +EXPORT_SYMBOL_GPL(usb_function_unregister); diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index 72cd5e6719d..9fafb00d3c7 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -1308,65 +1308,28 @@ static void init_controller(struct fusb300 *fusb300) iowrite32(0xcfffff9f, fusb300->reg + FUSB300_OFFSET_IGER1); } /*------------------------------------------------------------------------*/ -static struct fusb300 *the_controller; - -static int fusb300_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) +static int fusb300_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct fusb300 *fusb300 = the_controller; - int retval; - - if (!driver - || driver->max_speed < USB_SPEED_FULL - || !bind - || !driver->setup) - return -EINVAL; - - if (!fusb300) - return -ENODEV; - - if (fusb300->driver) - return -EBUSY; + struct fusb300 *fusb300 = to_fusb300(g); /* hook up the driver */ driver->driver.bus = NULL; fusb300->driver = driver; fusb300->gadget.dev.driver = &driver->driver; - retval = device_add(&fusb300->gadget.dev); - if (retval) { - pr_err("device_add error (%d)\n", retval); - goto error; - } - - retval = bind(&fusb300->gadget, driver); - if (retval) { - pr_err("bind to driver error (%d)\n", retval); - device_del(&fusb300->gadget.dev); - goto error; - } - return 0; - -error: - fusb300->driver = NULL; - fusb300->gadget.dev.driver = NULL; - - return retval; } -static int fusb300_udc_stop(struct usb_gadget_driver *driver) +static int fusb300_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct fusb300 *fusb300 = the_controller; - - if (driver != fusb300->driver || !driver->unbind) - return -EINVAL; + struct fusb300 *fusb300 = to_fusb300(g); driver->unbind(&fusb300->gadget); fusb300->gadget.dev.driver = NULL; init_controller(fusb300); - device_del(&fusb300->gadget.dev); fusb300->driver = NULL; return 0; @@ -1378,10 +1341,10 @@ static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active) return 0; } -static struct usb_gadget_ops fusb300_gadget_ops = { +static const struct usb_gadget_ops fusb300_gadget_ops = { .pullup = fusb300_udc_pullup, - .start = fusb300_udc_start, - .stop = fusb300_udc_stop, + .udc_start = fusb300_udc_start, + .udc_stop = fusb300_udc_stop, }; static int __exit fusb300_remove(struct platform_device *pdev) @@ -1505,8 +1468,6 @@ static int __init fusb300_probe(struct platform_device *pdev) fusb300->gadget.ep0 = &fusb300->ep[0]->ep; INIT_LIST_HEAD(&fusb300->gadget.ep0->ep_list); - the_controller = fusb300; - fusb300->ep0_req = fusb300_alloc_request(&fusb300->ep[0]->ep, GFP_KERNEL); if (fusb300->ep0_req == NULL) @@ -1517,9 +1478,19 @@ static int __init fusb300_probe(struct platform_device *pdev) if (ret) goto err_add_udc; + ret = device_add(&fusb300->gadget.dev); + if (ret) { + pr_err("device_add error (%d)\n", ret); + goto err_add_device; + } + dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); return 0; + +err_add_device: + usb_del_gadget_udc(&fusb300->gadget); + err_add_udc: fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req); diff --git a/drivers/usb/gadget/fusb300_udc.h b/drivers/usb/gadget/fusb300_udc.h index 542cd83cc80..6ba444ae8dd 100644 --- a/drivers/usb/gadget/fusb300_udc.h +++ b/drivers/usb/gadget/fusb300_udc.h @@ -673,4 +673,6 @@ struct fusb300 { u8 reenum; /* if re-enumeration */ }; +#define to_fusb300(g) (container_of((g), struct fusb300, gadget)) + #endif diff --git a/drivers/usb/gadget/g_zero.h b/drivers/usb/gadget/g_zero.h index 71ca193358b..ef3e8515272 100644 --- a/drivers/usb/gadget/g_zero.h +++ b/drivers/usb/gadget/g_zero.h @@ -6,11 +6,34 @@ #ifndef __G_ZERO_H #define __G_ZERO_H -#include <linux/usb/composite.h> +struct usb_zero_options { + unsigned pattern; + unsigned isoc_interval; + unsigned isoc_maxpacket; + unsigned isoc_mult; + unsigned isoc_maxburst; + unsigned bulk_buflen; + unsigned qlen; +}; -/* global state */ -extern unsigned buflen; -extern const struct usb_descriptor_header *otg_desc[]; +struct f_ss_opts { + struct usb_function_instance func_inst; + unsigned pattern; + unsigned isoc_interval; + unsigned isoc_maxpacket; + unsigned isoc_mult; + unsigned isoc_maxburst; + unsigned bulk_buflen; +}; + +struct f_lb_opts { + struct usb_function_instance func_inst; + unsigned bulk_buflen; + unsigned qlen; +}; + +void lb_modexit(void); +int lb_modinit(void); /* common utilities */ struct usb_request *alloc_ep_req(struct usb_ep *ep, int len); @@ -19,8 +42,4 @@ void disable_endpoints(struct usb_composite_dev *cdev, struct usb_ep *in, struct usb_ep *out, struct usb_ep *iso_in, struct usb_ep *iso_out); -/* configuration-specific linkup */ -int sourcesink_add(struct usb_composite_dev *cdev, bool autoresume); -int loopback_add(struct usb_composite_dev *cdev, bool autoresume); - #endif /* __G_ZERO_H */ diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 881aab86ae9..e879e2c9f46 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -125,7 +125,7 @@ static struct usb_configuration midi_config = { .bConfigurationValue = 1, /* .iConfiguration = DYNAMIC */ .bmAttributes = USB_CONFIG_ATT_ONE, - .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, + .MaxPower = CONFIG_USB_GADGET_VBUS_DRAW, }; static int __init midi_bind_config(struct usb_configuration *c) diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 51037cb7860..85742d4c67d 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -993,14 +993,15 @@ static int goku_get_frame(struct usb_gadget *_gadget) return -EOPNOTSUPP; } -static int goku_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); -static int goku_stop(struct usb_gadget_driver *driver); +static int goku_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver); +static int goku_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver); static const struct usb_gadget_ops goku_ops = { .get_frame = goku_get_frame, - .start = goku_start, - .stop = goku_stop, + .udc_start = goku_udc_start, + .udc_stop = goku_udc_stop, // no remote wakeup // not selfpowered }; @@ -1339,50 +1340,28 @@ static void udc_enable(struct goku_udc *dev) * - one function driver, initted second */ -static struct goku_udc *the_controller; - /* when a driver is successfully registered, it will receive * control requests including set_configuration(), which enables * non-control requests. then usb traffic follows until a * disconnect is reported. then a host may connect again, or * the driver might get unbound. */ -static int goku_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) +static int goku_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct goku_udc *dev = the_controller; - int retval; - - if (!driver - || driver->max_speed < USB_SPEED_FULL - || !bind - || !driver->disconnect - || !driver->setup) - return -EINVAL; - if (!dev) - return -ENODEV; - if (dev->driver) - return -EBUSY; + struct goku_udc *dev = to_goku_udc(g); /* hook up the driver */ driver->driver.bus = NULL; dev->driver = driver; dev->gadget.dev.driver = &driver->driver; - retval = bind(&dev->gadget, driver); - if (retval) { - DBG(dev, "bind to driver %s --> error %d\n", - driver->driver.name, retval); - dev->driver = NULL; - dev->gadget.dev.driver = NULL; - return retval; - } - /* then enable host detection and ep0; and we're ready + /* + * then enable host detection and ep0; and we're ready * for set_configuration as well as eventual disconnect. */ udc_enable(dev); - DBG(dev, "registered gadget driver '%s'\n", driver->driver.name); return 0; } @@ -1400,35 +1379,23 @@ stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver) udc_reset (dev); for (i = 0; i < 4; i++) nuke(&dev->ep [i], -ESHUTDOWN); - if (driver) { - spin_unlock(&dev->lock); - driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - } if (dev->driver) udc_enable(dev); } -static int goku_stop(struct usb_gadget_driver *driver) +static int goku_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct goku_udc *dev = the_controller; + struct goku_udc *dev = to_goku_udc(g); unsigned long flags; - if (!dev) - return -ENODEV; - if (!driver || driver != dev->driver || !driver->unbind) - return -EINVAL; - spin_lock_irqsave(&dev->lock, flags); dev->driver = NULL; stop_activity(dev, driver); spin_unlock_irqrestore(&dev->lock, flags); - - driver->unbind(&dev->gadget); dev->gadget.dev.driver = NULL; - DBG(dev, "unregistered driver '%s'\n", driver->driver.name); return 0; } @@ -1754,7 +1721,6 @@ static void goku_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); dev->regs = NULL; - the_controller = NULL; INFO(dev, "unbind\n"); } @@ -1770,13 +1736,6 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) void __iomem *base = NULL; int retval; - /* if you want to support more than one controller in a system, - * usb_gadget_driver_{register,unregister}() must change. - */ - if (the_controller) { - pr_warning("ignoring %s\n", pci_name(pdev)); - return -EBUSY; - } if (!pdev->irq) { printk(KERN_ERR "Check PCI %s IRQ setup!\n", pci_name(pdev)); retval = -ENODEV; @@ -1851,7 +1810,6 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev); #endif - the_controller = dev; retval = device_register(&dev->gadget.dev); if (retval) { put_device(&dev->gadget.dev); diff --git a/drivers/usb/gadget/goku_udc.h b/drivers/usb/gadget/goku_udc.h index 85cdce0d190..b4470d2b1d8 100644 --- a/drivers/usb/gadget/goku_udc.h +++ b/drivers/usb/gadget/goku_udc.h @@ -261,6 +261,7 @@ struct goku_udc { /* statistics... */ unsigned long irqs; }; +#define to_goku_udc(g) (container_of((g), struct goku_udc, gadget)) /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index b6401f1b56c..34a0cb9382d 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1463,42 +1463,16 @@ static struct usb_ep_ops m66592_ep_ops = { }; /*-------------------------------------------------------------------------*/ -static struct m66592 *the_controller; - -static int m66592_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) +static int m66592_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct m66592 *m66592 = the_controller; - int retval; - - if (!driver - || driver->max_speed < USB_SPEED_HIGH - || !bind - || !driver->setup) - return -EINVAL; - if (!m66592) - return -ENODEV; - if (m66592->driver) - return -EBUSY; + struct m66592 *m66592 = to_m66592(g); /* hook up the driver */ driver->driver.bus = NULL; m66592->driver = driver; m66592->gadget.dev.driver = &driver->driver; - retval = device_add(&m66592->gadget.dev); - if (retval) { - pr_err("device_add error (%d)\n", retval); - goto error; - } - - retval = bind(&m66592->gadget, driver); - if (retval) { - pr_err("bind to driver error (%d)\n", retval); - device_del(&m66592->gadget.dev); - goto error; - } - m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) { m66592_start_xclock(m66592); @@ -1510,26 +1484,12 @@ static int m66592_start(struct usb_gadget_driver *driver, } return 0; - -error: - m66592->driver = NULL; - m66592->gadget.dev.driver = NULL; - - return retval; } -static int m66592_stop(struct usb_gadget_driver *driver) +static int m66592_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct m66592 *m66592 = the_controller; - unsigned long flags; - - if (driver != m66592->driver || !driver->unbind) - return -EINVAL; - - spin_lock_irqsave(&m66592->lock, flags); - if (m66592->gadget.speed != USB_SPEED_UNKNOWN) - m66592_usb_disconnect(m66592); - spin_unlock_irqrestore(&m66592->lock, flags); + struct m66592 *m66592 = to_m66592(g); m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); @@ -1539,8 +1499,8 @@ static int m66592_stop(struct usb_gadget_driver *driver) init_controller(m66592); disable_controller(m66592); - device_del(&m66592->gadget.dev); m66592->driver = NULL; + return 0; } @@ -1566,10 +1526,10 @@ static int m66592_pullup(struct usb_gadget *gadget, int is_on) return 0; } -static struct usb_gadget_ops m66592_gadget_ops = { +static const struct usb_gadget_ops m66592_gadget_ops = { .get_frame = m66592_get_frame, - .start = m66592_start, - .stop = m66592_stop, + .udc_start = m66592_udc_start, + .udc_stop = m66592_udc_stop, .pullup = m66592_pullup, }; @@ -1578,6 +1538,7 @@ static int __exit m66592_remove(struct platform_device *pdev) struct m66592 *m66592 = dev_get_drvdata(&pdev->dev); usb_del_gadget_udc(&m66592->gadget); + device_del(&m66592->gadget.dev); del_timer_sync(&m66592->timer); iounmap(m66592->reg); @@ -1706,8 +1667,6 @@ static int __init m66592_probe(struct platform_device *pdev) m66592->pipenum2ep[0] = &m66592->ep[0]; m66592->epaddr2ep[0] = &m66592->ep[0]; - the_controller = m66592; - m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL); if (m66592->ep0_req == NULL) goto clean_up3; @@ -1715,6 +1674,12 @@ static int __init m66592_probe(struct platform_device *pdev) init_controller(m66592); + ret = device_add(&m66592->gadget.dev); + if (ret) { + pr_err("device_add error (%d)\n", ret); + goto err_device_add; + } + ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget); if (ret) goto err_add_udc; @@ -1723,6 +1688,9 @@ static int __init m66592_probe(struct platform_device *pdev) return 0; err_add_udc: + device_del(&m66592->gadget.dev); + +err_device_add: m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); clean_up3: diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index 16c7e14678b..96d49d7bfb6 100644 --- a/drivers/usb/gadget/m66592-udc.h +++ b/drivers/usb/gadget/m66592-udc.h @@ -492,6 +492,7 @@ struct m66592 { int isochronous; int num_dma; }; +#define to_m66592(g) (container_of((g), struct m66592, gadget)) #define gadget_to_m66592(_gadget) container_of(_gadget, struct m66592, gadget) #define m66592_to_gadget(m66592) (&m66592->gadget) diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 88472bf7dbb..20bbbf917fc 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -16,6 +16,7 @@ #include <linux/kernel.h> #include <linux/module.h> +#include "u_serial.h" #if defined USB_ETH_RNDIS # undef USB_ETH_RNDIS #endif @@ -42,9 +43,6 @@ MODULE_LICENSE("GPL"); */ #include "f_mass_storage.c" -#include "u_serial.c" -#include "f_acm.c" - #include "f_ecm.c" #include "f_subset.c" #ifdef USB_ETH_RNDIS @@ -137,10 +135,13 @@ static struct fsg_common fsg_common; static u8 hostaddr[ETH_ALEN]; +static unsigned char tty_line; +static struct usb_function_instance *fi_acm; /********** RNDIS **********/ #ifdef USB_ETH_RNDIS +static struct usb_function *f_acm_rndis; static __init int rndis_do_config(struct usb_configuration *c) { @@ -155,15 +156,25 @@ static __init int rndis_do_config(struct usb_configuration *c) if (ret < 0) return ret; - ret = acm_bind_config(c, 0); - if (ret < 0) - return ret; + f_acm_rndis = usb_get_function(fi_acm); + if (IS_ERR(f_acm_rndis)) + goto err_func_acm; + + ret = usb_add_function(c, f_acm_rndis); + if (ret) + goto err_conf; ret = fsg_bind_config(c->cdev, c, &fsg_common); if (ret < 0) - return ret; + goto err_fsg; return 0; +err_fsg: + usb_remove_function(c, f_acm_rndis); +err_conf: + usb_put_function(f_acm_rndis); +err_func_acm: + return ret; } static int rndis_config_register(struct usb_composite_dev *cdev) @@ -192,6 +203,7 @@ static int rndis_config_register(struct usb_composite_dev *cdev) /********** CDC ECM **********/ #ifdef CONFIG_USB_G_MULTI_CDC +static struct usb_function *f_acm_multi; static __init int cdc_do_config(struct usb_configuration *c) { @@ -206,15 +218,26 @@ static __init int cdc_do_config(struct usb_configuration *c) if (ret < 0) return ret; - ret = acm_bind_config(c, 0); - if (ret < 0) - return ret; + /* implicit port_num is zero */ + f_acm_multi = usb_get_function(fi_acm); + if (IS_ERR(f_acm_multi)) + goto err_func_acm; + + ret = usb_add_function(c, f_acm_multi); + if (ret) + goto err_conf; ret = fsg_bind_config(c->cdev, c, &fsg_common); if (ret < 0) - return ret; + goto err_fsg; return 0; +err_fsg: + usb_remove_function(c, f_acm_multi); +err_conf: + usb_put_function(f_acm_multi); +err_func_acm: + return ret; } static int cdc_config_register(struct usb_composite_dev *cdev) @@ -243,10 +266,10 @@ static int cdc_config_register(struct usb_composite_dev *cdev) /****************************** Gadget Bind ******************************/ - static int __ref multi_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; + struct f_serial_opts *opts; int status; if (!can_support_ecm(cdev->gadget)) { @@ -261,10 +284,19 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) return status; /* set up serial link layer */ - status = gserial_setup(cdev->gadget, 1); + status = gserial_alloc_line(&tty_line); if (status < 0) goto fail0; + fi_acm = usb_get_function_instance("acm"); + if (IS_ERR(fi_acm)) { + status = PTR_ERR(fi_acm); + goto fail0dot5; + } + + opts = container_of(fi_acm, struct f_serial_opts, func_inst); + opts->port_num = tty_line; + /* set up mass storage function */ { void *retp; @@ -301,7 +333,9 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) fail2: fsg_common_put(&fsg_common); fail1: - gserial_cleanup(); + usb_put_function_instance(fi_acm); +fail0dot5: + gserial_free_line(tty_line); fail0: gether_cleanup(); return status; @@ -309,7 +343,14 @@ fail0: static int __exit multi_unbind(struct usb_composite_dev *cdev) { - gserial_cleanup(); +#ifdef CONFIG_USB_G_MULTI_CDC + usb_put_function(f_acm_multi); +#endif +#ifdef USB_ETH_RNDIS + usb_put_function(f_acm_rndis); +#endif + usb_put_function_instance(fi_acm); + gserial_free_line(tty_line); gether_cleanup(); return 0; } diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 6e8b1272ebc..c8cf959057f 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -61,9 +61,6 @@ static DECLARE_COMPLETION(release_done); static const char driver_name[] = "mv_udc"; static const char driver_desc[] = DRIVER_DESC; -/* controller device global variable */ -static struct mv_udc *the_controller; - static void nuke(struct mv_ep *ep, int status); static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver); @@ -1268,9 +1265,8 @@ static int mv_udc_pullup(struct usb_gadget *gadget, int is_on) return retval; } -static int mv_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); -static int mv_udc_stop(struct usb_gadget_driver *driver); +static int mv_udc_start(struct usb_gadget *, struct usb_gadget_driver *); +static int mv_udc_stop(struct usb_gadget *, struct usb_gadget_driver *); /* device controller usb_gadget_ops structure */ static const struct usb_gadget_ops mv_ops = { @@ -1285,8 +1281,8 @@ static const struct usb_gadget_ops mv_ops = { /* D+ pullup, software-controlled connect/disconnect to USB host */ .pullup = mv_udc_pullup, - .start = mv_udc_start, - .stop = mv_udc_stop, + .udc_start = mv_udc_start, + .udc_stop = mv_udc_stop, }; static int eps_init(struct mv_udc *udc) @@ -1373,15 +1369,14 @@ static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver) } } -static int mv_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) +static int mv_udc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct mv_udc *udc = the_controller; + struct mv_udc *udc; int retval = 0; unsigned long flags; - if (!udc) - return -ENODEV; + udc = container_of(gadget, struct mv_udc, gadget); if (udc->driver) return -EBUSY; @@ -1399,26 +1394,14 @@ static int mv_udc_start(struct usb_gadget_driver *driver, spin_unlock_irqrestore(&udc->lock, flags); - retval = bind(&udc->gadget, driver); - if (retval) { - dev_err(&udc->dev->dev, "bind to driver %s --> %d\n", - driver->driver.name, retval); - udc->driver = NULL; - udc->gadget.dev.driver = NULL; - return retval; - } - - if (!IS_ERR_OR_NULL(udc->transceiver)) { + if (udc->transceiver) { retval = otg_set_peripheral(udc->transceiver->otg, &udc->gadget); if (retval) { dev_err(&udc->dev->dev, "unable to register peripheral to otg\n"); - if (driver->unbind) { - driver->unbind(&udc->gadget); - udc->gadget.dev.driver = NULL; - udc->driver = NULL; - } + udc->driver = NULL; + udc->gadget.dev.driver = NULL; return retval; } } @@ -1433,13 +1416,13 @@ static int mv_udc_start(struct usb_gadget_driver *driver, return 0; } -static int mv_udc_stop(struct usb_gadget_driver *driver) +static int mv_udc_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct mv_udc *udc = the_controller; + struct mv_udc *udc; unsigned long flags; - if (!udc) - return -ENODEV; + udc = container_of(gadget, struct mv_udc, gadget); spin_lock_irqsave(&udc->lock, flags); @@ -1454,7 +1437,6 @@ static int mv_udc_stop(struct usb_gadget_driver *driver) spin_unlock_irqrestore(&udc->lock, flags); /* unbind gadget driver */ - driver->unbind(&udc->gadget); udc->gadget.dev.driver = NULL; udc->driver = NULL; @@ -1472,10 +1454,13 @@ static void mv_set_ptc(struct mv_udc *udc, u32 mode) static void prime_status_complete(struct usb_ep *ep, struct usb_request *_req) { - struct mv_udc *udc = the_controller; + struct mv_ep *mvep = container_of(ep, struct mv_ep, ep); struct mv_req *req = container_of(_req, struct mv_req, req); + struct mv_udc *udc; unsigned long flags; + udc = mvep->udc; + dev_info(&udc->dev->dev, "switch to test mode %d\n", req->test_mode); spin_lock_irqsave(&udc->lock, flags); @@ -2123,15 +2108,18 @@ static void mv_udc_vbus_work(struct work_struct *work) /* release device structure */ static void gadget_release(struct device *_dev) { - struct mv_udc *udc = the_controller; + struct mv_udc *udc; + + udc = dev_get_drvdata(_dev); complete(udc->done); } -static int mv_udc_remove(struct platform_device *dev) +static int mv_udc_remove(struct platform_device *pdev) { - struct mv_udc *udc = the_controller; - int clk_i; + struct mv_udc *udc; + + udc = platform_get_drvdata(pdev); usb_del_gadget_udc(&udc->gadget); @@ -2140,57 +2128,27 @@ static int mv_udc_remove(struct platform_device *dev) destroy_workqueue(udc->qwork); } - /* - * If we have transceiver inited, - * then vbus irq will not be requested in udc driver. - */ - if (udc->pdata && udc->pdata->vbus - && udc->clock_gating && IS_ERR_OR_NULL(udc->transceiver)) - free_irq(udc->pdata->vbus->irq, &dev->dev); - /* free memory allocated in probe */ if (udc->dtd_pool) dma_pool_destroy(udc->dtd_pool); if (udc->ep_dqh) - dma_free_coherent(&dev->dev, udc->ep_dqh_size, + dma_free_coherent(&pdev->dev, udc->ep_dqh_size, udc->ep_dqh, udc->ep_dqh_dma); - kfree(udc->eps); - - if (udc->irq) - free_irq(udc->irq, &dev->dev); - mv_udc_disable(udc); - if (udc->cap_regs) - iounmap(udc->cap_regs); - - if (udc->phy_regs) - iounmap(udc->phy_regs); - - if (udc->status_req) { - kfree(udc->status_req->req.buf); - kfree(udc->status_req); - } - - for (clk_i = 0; clk_i <= udc->clknum; clk_i++) - clk_put(udc->clk[clk_i]); - device_unregister(&udc->gadget.dev); /* free dev, wait for the release() finished */ wait_for_completion(udc->done); - kfree(udc); - - the_controller = NULL; return 0; } -static int mv_udc_probe(struct platform_device *dev) +static int mv_udc_probe(struct platform_device *pdev) { - struct mv_usb_platform_data *pdata = dev->dev.platform_data; + struct mv_usb_platform_data *pdata = pdev->dev.platform_data; struct mv_udc *udc; int retval = 0; int clk_i = 0; @@ -2198,71 +2156,73 @@ static int mv_udc_probe(struct platform_device *dev) size_t size; if (pdata == NULL) { - dev_err(&dev->dev, "missing platform_data\n"); + dev_err(&pdev->dev, "missing platform_data\n"); return -ENODEV; } size = sizeof(*udc) + sizeof(struct clk *) * pdata->clknum; - udc = kzalloc(size, GFP_KERNEL); + udc = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); if (udc == NULL) { - dev_err(&dev->dev, "failed to allocate memory for udc\n"); + dev_err(&pdev->dev, "failed to allocate memory for udc\n"); return -ENOMEM; } - the_controller = udc; udc->done = &release_done; - udc->pdata = dev->dev.platform_data; + udc->pdata = pdev->dev.platform_data; spin_lock_init(&udc->lock); - udc->dev = dev; + udc->dev = pdev; #ifdef CONFIG_USB_OTG_UTILS - if (pdata->mode == MV_USB_MODE_OTG) - udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); + if (pdata->mode == MV_USB_MODE_OTG) { + udc->transceiver = devm_usb_get_phy(&pdev->dev, + USB_PHY_TYPE_USB2); + if (IS_ERR_OR_NULL(udc->transceiver)) { + udc->transceiver = NULL; + return -ENODEV; + } + } #endif udc->clknum = pdata->clknum; for (clk_i = 0; clk_i < udc->clknum; clk_i++) { - udc->clk[clk_i] = clk_get(&dev->dev, pdata->clkname[clk_i]); + udc->clk[clk_i] = devm_clk_get(&pdev->dev, + pdata->clkname[clk_i]); if (IS_ERR(udc->clk[clk_i])) { retval = PTR_ERR(udc->clk[clk_i]); - goto err_put_clk; + return retval; } } r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs"); if (r == NULL) { - dev_err(&dev->dev, "no I/O memory resource defined\n"); - retval = -ENODEV; - goto err_put_clk; + dev_err(&pdev->dev, "no I/O memory resource defined\n"); + return -ENODEV; } udc->cap_regs = (struct mv_cap_regs __iomem *) - ioremap(r->start, resource_size(r)); + devm_ioremap(&pdev->dev, r->start, resource_size(r)); if (udc->cap_regs == NULL) { - dev_err(&dev->dev, "failed to map I/O memory\n"); - retval = -EBUSY; - goto err_put_clk; + dev_err(&pdev->dev, "failed to map I/O memory\n"); + return -EBUSY; } r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "phyregs"); if (r == NULL) { - dev_err(&dev->dev, "no phy I/O memory resource defined\n"); - retval = -ENODEV; - goto err_iounmap_capreg; + dev_err(&pdev->dev, "no phy I/O memory resource defined\n"); + return -ENODEV; } udc->phy_regs = ioremap(r->start, resource_size(r)); if (udc->phy_regs == NULL) { - dev_err(&dev->dev, "failed to map phy I/O memory\n"); - retval = -EBUSY; - goto err_iounmap_capreg; + dev_err(&pdev->dev, "failed to map phy I/O memory\n"); + return -EBUSY; } /* we will acces controller register, so enable the clk */ retval = mv_udc_enable_internal(udc); if (retval) - goto err_iounmap_phyreg; + return retval; udc->op_regs = (struct mv_op_regs __iomem *)((unsigned long)udc->cap_regs @@ -2279,11 +2239,11 @@ static int mv_udc_probe(struct platform_device *dev) size = udc->max_eps * sizeof(struct mv_dqh) *2; size = (size + DQH_ALIGNMENT - 1) & ~(DQH_ALIGNMENT - 1); - udc->ep_dqh = dma_alloc_coherent(&dev->dev, size, + udc->ep_dqh = dma_alloc_coherent(&pdev->dev, size, &udc->ep_dqh_dma, GFP_KERNEL); if (udc->ep_dqh == NULL) { - dev_err(&dev->dev, "allocate dQH memory failed\n"); + dev_err(&pdev->dev, "allocate dQH memory failed\n"); retval = -ENOMEM; goto err_disable_clock; } @@ -2291,7 +2251,7 @@ static int mv_udc_probe(struct platform_device *dev) /* create dTD dma_pool resource */ udc->dtd_pool = dma_pool_create("mv_dtd", - &dev->dev, + &pdev->dev, sizeof(struct mv_dtd), DTD_ALIGNMENT, DMA_BOUNDARY); @@ -2302,19 +2262,20 @@ static int mv_udc_probe(struct platform_device *dev) } size = udc->max_eps * sizeof(struct mv_ep) *2; - udc->eps = kzalloc(size, GFP_KERNEL); + udc->eps = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); if (udc->eps == NULL) { - dev_err(&dev->dev, "allocate ep memory failed\n"); + dev_err(&pdev->dev, "allocate ep memory failed\n"); retval = -ENOMEM; goto err_destroy_dma; } /* initialize ep0 status request structure */ - udc->status_req = kzalloc(sizeof(struct mv_req), GFP_KERNEL); + udc->status_req = devm_kzalloc(&pdev->dev, sizeof(struct mv_req), + GFP_KERNEL); if (!udc->status_req) { - dev_err(&dev->dev, "allocate status_req memory failed\n"); + dev_err(&pdev->dev, "allocate status_req memory failed\n"); retval = -ENOMEM; - goto err_free_eps; + goto err_destroy_dma; } INIT_LIST_HEAD(&udc->status_req->queue); @@ -2329,17 +2290,17 @@ static int mv_udc_probe(struct platform_device *dev) r = platform_get_resource(udc->dev, IORESOURCE_IRQ, 0); if (r == NULL) { - dev_err(&dev->dev, "no IRQ resource defined\n"); + dev_err(&pdev->dev, "no IRQ resource defined\n"); retval = -ENODEV; - goto err_free_status_req; + goto err_destroy_dma; } udc->irq = r->start; - if (request_irq(udc->irq, mv_udc_irq, + if (devm_request_irq(&pdev->dev, udc->irq, mv_udc_irq, IRQF_SHARED, driver_name, udc)) { - dev_err(&dev->dev, "Request irq %d for UDC failed\n", + dev_err(&pdev->dev, "Request irq %d for UDC failed\n", udc->irq); retval = -ENODEV; - goto err_free_status_req; + goto err_destroy_dma; } /* initialize gadget structure */ @@ -2351,26 +2312,27 @@ static int mv_udc_probe(struct platform_device *dev) /* the "gadget" abstracts/virtualizes the controller */ dev_set_name(&udc->gadget.dev, "gadget"); - udc->gadget.dev.parent = &dev->dev; - udc->gadget.dev.dma_mask = dev->dev.dma_mask; + udc->gadget.dev.parent = &pdev->dev; + udc->gadget.dev.dma_mask = pdev->dev.dma_mask; udc->gadget.dev.release = gadget_release; udc->gadget.name = driver_name; /* gadget name */ retval = device_register(&udc->gadget.dev); if (retval) - goto err_free_irq; + goto err_destroy_dma; eps_init(udc); /* VBUS detect: we can disable/enable clock on demand.*/ - if (!IS_ERR_OR_NULL(udc->transceiver)) + if (udc->transceiver) udc->clock_gating = 1; else if (pdata->vbus) { udc->clock_gating = 1; - retval = request_threaded_irq(pdata->vbus->irq, NULL, + retval = devm_request_threaded_irq(&pdev->dev, + pdata->vbus->irq, NULL, mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc); if (retval) { - dev_info(&dev->dev, + dev_info(&pdev->dev, "Can not request irq for VBUS, " "disable clock gating\n"); udc->clock_gating = 0; @@ -2378,7 +2340,7 @@ static int mv_udc_probe(struct platform_device *dev) udc->qwork = create_singlethread_workqueue("mv_udc_queue"); if (!udc->qwork) { - dev_err(&dev->dev, "cannot create workqueue\n"); + dev_err(&pdev->dev, "cannot create workqueue\n"); retval = -ENOMEM; goto err_unregister; } @@ -2396,53 +2358,40 @@ static int mv_udc_probe(struct platform_device *dev) else udc->vbus_active = 1; - retval = usb_add_gadget_udc(&dev->dev, &udc->gadget); + retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); if (retval) - goto err_unregister; + goto err_create_workqueue; - dev_info(&dev->dev, "successful probe UDC device %s clock gating.\n", + platform_set_drvdata(pdev, udc); + dev_info(&pdev->dev, "successful probe UDC device %s clock gating.\n", udc->clock_gating ? "with" : "without"); return 0; +err_create_workqueue: + destroy_workqueue(udc->qwork); err_unregister: - if (udc->pdata && udc->pdata->vbus - && udc->clock_gating && IS_ERR_OR_NULL(udc->transceiver)) - free_irq(pdata->vbus->irq, &dev->dev); device_unregister(&udc->gadget.dev); -err_free_irq: - free_irq(udc->irq, &dev->dev); -err_free_status_req: - kfree(udc->status_req->req.buf); - kfree(udc->status_req); -err_free_eps: - kfree(udc->eps); err_destroy_dma: dma_pool_destroy(udc->dtd_pool); err_free_dma: - dma_free_coherent(&dev->dev, udc->ep_dqh_size, + dma_free_coherent(&pdev->dev, udc->ep_dqh_size, udc->ep_dqh, udc->ep_dqh_dma); err_disable_clock: mv_udc_disable_internal(udc); -err_iounmap_phyreg: - iounmap(udc->phy_regs); -err_iounmap_capreg: - iounmap(udc->cap_regs); -err_put_clk: - for (clk_i--; clk_i >= 0; clk_i--) - clk_put(udc->clk[clk_i]); - the_controller = NULL; - kfree(udc); + return retval; } #ifdef CONFIG_PM -static int mv_udc_suspend(struct device *_dev) +static int mv_udc_suspend(struct device *dev) { - struct mv_udc *udc = the_controller; + struct mv_udc *udc; + + udc = dev_get_drvdata(dev); /* if OTG is enabled, the following will be done in OTG driver*/ - if (!IS_ERR_OR_NULL(udc->transceiver)) + if (udc->transceiver) return 0; if (udc->pdata->vbus && udc->pdata->vbus->poll) @@ -2469,13 +2418,15 @@ static int mv_udc_suspend(struct device *_dev) return 0; } -static int mv_udc_resume(struct device *_dev) +static int mv_udc_resume(struct device *dev) { - struct mv_udc *udc = the_controller; + struct mv_udc *udc; int retval; + udc = dev_get_drvdata(dev); + /* if OTG is enabled, the following will be done in OTG driver*/ - if (!IS_ERR_OR_NULL(udc->transceiver)) + if (udc->transceiver) return 0; if (!udc->clock_gating) { @@ -2499,11 +2450,12 @@ static const struct dev_pm_ops mv_udc_pm_ops = { }; #endif -static void mv_udc_shutdown(struct platform_device *dev) +static void mv_udc_shutdown(struct platform_device *pdev) { - struct mv_udc *udc = the_controller; + struct mv_udc *udc; u32 mode; + udc = platform_get_drvdata(pdev); /* reset controller mode to IDLE */ mv_udc_enable(udc); mode = readl(&udc->op_regs->usbmode); @@ -2514,7 +2466,7 @@ static void mv_udc_shutdown(struct platform_device *dev) static struct platform_driver udc_driver = { .probe = mv_udc_probe, - .remove = __exit_p(mv_udc_remove), + .remove = mv_udc_remove, .shutdown = mv_udc_shutdown, .driver = { .owner = THIS_MODULE, diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c index 661600abace..def37403989 100644 --- a/drivers/usb/gadget/nokia.c +++ b/drivers/usb/gadget/nokia.c @@ -37,7 +37,7 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ -#include "u_serial.c" +#define USB_FACM_INCLUDED #include "f_acm.c" #include "f_ecm.c" #include "f_obex.c" @@ -101,6 +101,15 @@ MODULE_LICENSE("GPL"); static u8 hostaddr[ETH_ALEN]; +enum { + TTY_PORT_OBEX0, + TTY_PORT_OBEX1, + TTY_PORT_ACM, + TTY_PORTS_MAX, +}; + +static unsigned char tty_lines[TTY_PORTS_MAX]; + static int __init nokia_bind_config(struct usb_configuration *c) { int status = 0; @@ -109,15 +118,15 @@ static int __init nokia_bind_config(struct usb_configuration *c) if (status) printk(KERN_DEBUG "could not bind phonet config\n"); - status = obex_bind_config(c, 0); + status = obex_bind_config(c, tty_lines[TTY_PORT_OBEX0]); if (status) printk(KERN_DEBUG "could not bind obex config %d\n", 0); - status = obex_bind_config(c, 1); + status = obex_bind_config(c, tty_lines[TTY_PORT_OBEX1]); if (status) printk(KERN_DEBUG "could not bind obex config %d\n", 0); - status = acm_bind_config(c, 2); + status = acm_bind_config(c, tty_lines[TTY_PORT_ACM]); if (status) printk(KERN_DEBUG "could not bind acm config\n"); @@ -133,7 +142,7 @@ static struct usb_configuration nokia_config_500ma_driver = { .bConfigurationValue = 1, /* .iConfiguration = DYNAMIC */ .bmAttributes = USB_CONFIG_ATT_ONE, - .bMaxPower = 250, /* 500mA */ + .MaxPower = 500, }; static struct usb_configuration nokia_config_100ma_driver = { @@ -141,21 +150,24 @@ static struct usb_configuration nokia_config_100ma_driver = { .bConfigurationValue = 2, /* .iConfiguration = DYNAMIC */ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = 50, /* 100 mA */ + .MaxPower = 100, }; static int __init nokia_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; int status; + int cur_line; status = gphonet_setup(cdev->gadget); if (status < 0) goto err_phonet; - status = gserial_setup(cdev->gadget, 3); - if (status < 0) - goto err_serial; + for (cur_line = 0; cur_line < TTY_PORTS_MAX; cur_line++) { + status = gserial_alloc_line(&tty_lines[cur_line]); + if (status) + goto err_ether; + } status = gether_setup(cdev->gadget, hostaddr); if (status < 0) @@ -192,8 +204,10 @@ static int __init nokia_bind(struct usb_composite_dev *cdev) err_usb: gether_cleanup(); err_ether: - gserial_cleanup(); -err_serial: + cur_line--; + while (cur_line >= 0) + gserial_free_line(tty_lines[cur_line--]); + gphonet_cleanup(); err_phonet: return status; @@ -201,8 +215,13 @@ err_phonet: static int __exit nokia_unbind(struct usb_composite_dev *cdev) { + int i; + gphonet_cleanup(); - gserial_cleanup(); + + for (i = 0; i < TTY_PORTS_MAX; i++) + gserial_free_line(tty_lines[i]); + gether_cleanup(); return 0; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 8bfe990caf1..06be85c2b23 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -1309,19 +1309,20 @@ static int omap_pullup(struct usb_gadget *gadget, int is_on) return 0; } -static int omap_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); -static int omap_udc_stop(struct usb_gadget_driver *driver); +static int omap_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) +static int omap_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver); -static struct usb_gadget_ops omap_gadget_ops = { +static const struct usb_gadget_ops omap_gadget_ops = { .get_frame = omap_get_frame, .wakeup = omap_wakeup, .set_selfpowered = omap_set_selfpowered, .vbus_session = omap_vbus_session, .vbus_draw = omap_vbus_draw, .pullup = omap_pullup, - .start = omap_udc_start, - .stop = omap_udc_stop, + .udc_start = omap_udc_start, + .udc_stop = omap_udc_stop, }; /*-------------------------------------------------------------------------*/ @@ -2041,28 +2042,15 @@ static inline int machine_without_vbus_sense(void) || cpu_is_omap7xx(); } -static int omap_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) +static int omap_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) { int status = -ENODEV; struct omap_ep *ep; unsigned long flags; - /* basic sanity tests */ - if (!udc) - return -ENODEV; - if (!driver - /* FIXME if otg, check: driver->is_otg */ - || driver->max_speed < USB_SPEED_FULL - || !bind || !driver->setup) - return -EINVAL; spin_lock_irqsave(&udc->lock, flags); - if (udc->driver) { - spin_unlock_irqrestore(&udc->lock, flags); - return -EBUSY; - } - /* reset state */ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { ep->irqs = 0; @@ -2084,15 +2072,6 @@ static int omap_udc_start(struct usb_gadget_driver *driver, if (udc->dc_clk != NULL) omap_udc_enable_clock(1); - status = bind(&udc->gadget, driver); - if (status) { - DBG("bind to %s --> %d\n", driver->driver.name, status); - udc->gadget.dev.driver = NULL; - udc->driver = NULL; - goto done; - } - DBG("bound to driver %s\n", driver->driver.name); - omap_writew(UDC_IRQ_SRC_MASK, UDC_IRQ_SRC); /* connect to bus through transceiver */ @@ -2124,19 +2103,16 @@ static int omap_udc_start(struct usb_gadget_driver *driver, done: if (udc->dc_clk != NULL) omap_udc_enable_clock(0); + return status; } -static int omap_udc_stop(struct usb_gadget_driver *driver) +static int omap_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver) { unsigned long flags; int status = -ENODEV; - if (!udc) - return -ENODEV; - if (!driver || driver != udc->driver || !driver->unbind) - return -EINVAL; - if (udc->dc_clk != NULL) omap_udc_enable_clock(1); @@ -2152,13 +2128,12 @@ static int omap_udc_stop(struct usb_gadget_driver *driver) udc_quiesce(udc); spin_unlock_irqrestore(&udc->lock, flags); - driver->unbind(&udc->gadget); udc->gadget.dev.driver = NULL; udc->driver = NULL; if (udc->dc_clk != NULL) omap_udc_enable_clock(0); - DBG("unregistered driver '%s'\n", driver->driver.name); + return status; } diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 6490c0040e3..a787a8ef672 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -375,6 +375,7 @@ struct pch_udc_dev { struct pch_udc_cfg_data cfg_data; struct pch_vbus_gpio_data vbus_gpio; }; +#define to_pch_udc(g) (container_of((g), struct pch_udc_dev, gadget)) #define PCH_UDC_PCI_BAR 1 #define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808 @@ -384,7 +385,6 @@ struct pch_udc_dev { static const char ep0_string[] = "ep0in"; static DEFINE_SPINLOCK(udc_stall_spinlock); /* stall spin lock */ -struct pch_udc_dev *pch_udc; /* pointer to device object */ static bool speed_fs; module_param_named(speed_fs, speed_fs, bool, S_IRUGO); MODULE_PARM_DESC(speed_fs, "true for Full speed operation"); @@ -1235,9 +1235,10 @@ static int pch_udc_pcd_vbus_draw(struct usb_gadget *gadget, unsigned int mA) return -EOPNOTSUPP; } -static int pch_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); -static int pch_udc_stop(struct usb_gadget_driver *driver); +static int pch_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver); +static int pch_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver); static const struct usb_gadget_ops pch_udc_ops = { .get_frame = pch_udc_pcd_get_frame, .wakeup = pch_udc_pcd_wakeup, @@ -1245,8 +1246,8 @@ static const struct usb_gadget_ops pch_udc_ops = { .pullup = pch_udc_pcd_pullup, .vbus_session = pch_udc_pcd_vbus_session, .vbus_draw = pch_udc_pcd_vbus_draw, - .start = pch_udc_start, - .stop = pch_udc_stop, + .udc_start = pch_udc_start, + .udc_stop = pch_udc_stop, }; /** @@ -2981,40 +2982,15 @@ static int init_dma_pools(struct pch_udc_dev *dev) return 0; } -static int pch_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) +static int pch_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct pch_udc_dev *dev = pch_udc; - int retval; - - if (!driver || (driver->max_speed == USB_SPEED_UNKNOWN) || !bind || - !driver->setup || !driver->unbind || !driver->disconnect) { - dev_err(&dev->pdev->dev, - "%s: invalid driver parameter\n", __func__); - return -EINVAL; - } + struct pch_udc_dev *dev = to_pch_udc(g); - if (!dev) - return -ENODEV; - - if (dev->driver) { - dev_err(&dev->pdev->dev, "%s: already bound\n", __func__); - return -EBUSY; - } driver->driver.bus = NULL; dev->driver = driver; dev->gadget.dev.driver = &driver->driver; - /* Invoke the bind routine of the gadget driver */ - retval = bind(&dev->gadget, driver); - - if (retval) { - dev_err(&dev->pdev->dev, "%s: binding to %s returning %d\n", - __func__, driver->driver.name, retval); - dev->driver = NULL; - dev->gadget.dev.driver = NULL; - return retval; - } /* get ready for ep0 traffic */ pch_udc_setup_ep0(dev); @@ -3026,30 +3002,21 @@ static int pch_udc_start(struct usb_gadget_driver *driver, return 0; } -static int pch_udc_stop(struct usb_gadget_driver *driver) +static int pch_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct pch_udc_dev *dev = pch_udc; - - if (!dev) - return -ENODEV; - - if (!driver || (driver != dev->driver)) { - dev_err(&dev->pdev->dev, - "%s: invalid driver parameter\n", __func__); - return -EINVAL; - } + struct pch_udc_dev *dev = to_pch_udc(g); pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK); /* Assures that there are no pending requests with this driver */ - driver->disconnect(&dev->gadget); - driver->unbind(&dev->gadget); dev->gadget.dev.driver = NULL; dev->driver = NULL; dev->connected = 0; /* set SD */ pch_udc_set_disconnect(dev); + return 0; } @@ -3164,11 +3131,6 @@ static int pch_udc_probe(struct pci_dev *pdev, int retval; struct pch_udc_dev *dev; - /* one udc only */ - if (pch_udc) { - pr_err("%s: already probed\n", __func__); - return -EBUSY; - } /* init */ dev = kzalloc(sizeof *dev, GFP_KERNEL); if (!dev) { @@ -3207,7 +3169,6 @@ static int pch_udc_probe(struct pci_dev *pdev, retval = -ENODEV; goto finished; } - pch_udc = dev; /* initialize the hardware */ if (pch_udc_pcd_init(dev)) { retval = -ENODEV; diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index d4ca9f1f7f2..fa9c34469a8 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -996,9 +996,10 @@ static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) return -EOPNOTSUPP; } -static int pxa25x_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); -static int pxa25x_stop(struct usb_gadget_driver *driver); +static int pxa25x_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver); +static int pxa25x_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver); static const struct usb_gadget_ops pxa25x_udc_ops = { .get_frame = pxa25x_udc_get_frame, @@ -1006,8 +1007,8 @@ static const struct usb_gadget_ops pxa25x_udc_ops = { .vbus_session = pxa25x_udc_vbus_session, .pullup = pxa25x_udc_pullup, .vbus_draw = pxa25x_udc_vbus_draw, - .start = pxa25x_start, - .stop = pxa25x_stop, + .udc_start = pxa25x_udc_start, + .udc_stop = pxa25x_udc_stop, }; /*-------------------------------------------------------------------------*/ @@ -1254,23 +1255,12 @@ static void udc_enable (struct pxa25x_udc *dev) * disconnect is reported. then a host may connect again, or * the driver might get unbound. */ -static int pxa25x_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) +static int pxa25x_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct pxa25x_udc *dev = the_controller; + struct pxa25x_udc *dev = to_pxa25x(g); int retval; - if (!driver - || driver->max_speed < USB_SPEED_FULL - || !bind - || !driver->disconnect - || !driver->setup) - return -EINVAL; - if (!dev) - return -ENODEV; - if (dev->driver) - return -EBUSY; - /* first hook up the driver ... */ dev->driver = driver; dev->gadget.dev.driver = &driver->driver; @@ -1278,34 +1268,20 @@ static int pxa25x_start(struct usb_gadget_driver *driver, retval = device_add (&dev->gadget.dev); if (retval) { -fail: dev->driver = NULL; dev->gadget.dev.driver = NULL; return retval; } - retval = bind(&dev->gadget, driver); - if (retval) { - DMSG("bind to driver %s --> error %d\n", - driver->driver.name, retval); - device_del (&dev->gadget.dev); - goto fail; - } /* ... then enable host detection and ep0; and we're ready * for set_configuration as well as eventual disconnect. */ - DMSG("registered gadget driver '%s'\n", driver->driver.name); - /* connect to bus through transceiver */ if (!IS_ERR_OR_NULL(dev->transceiver)) { retval = otg_set_peripheral(dev->transceiver->otg, &dev->gadget); - if (retval) { - DMSG("can't bind to transceiver\n"); - if (driver->unbind) - driver->unbind(&dev->gadget); + if (retval) goto bind_fail; - } } pullup(dev); @@ -1334,22 +1310,14 @@ stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver) } del_timer_sync(&dev->timer); - /* report disconnect; the driver is already quiesced */ - if (driver) - driver->disconnect(&dev->gadget); - /* re-init driver-visible data structures */ udc_reinit(dev); } -static int pxa25x_stop(struct usb_gadget_driver *driver) +static int pxa25x_udc_stop(struct usb_gadget*g, + struct usb_gadget_driver *driver) { - struct pxa25x_udc *dev = the_controller; - - if (!dev) - return -ENODEV; - if (!driver || driver != dev->driver || !driver->unbind) - return -EINVAL; + struct pxa25x_udc *dev = to_pxa25x(g); local_irq_disable(); dev->pullup = 0; @@ -1360,14 +1328,12 @@ static int pxa25x_stop(struct usb_gadget_driver *driver) if (!IS_ERR_OR_NULL(dev->transceiver)) (void) otg_set_peripheral(dev->transceiver->otg, NULL); - driver->unbind(&dev->gadget); dev->gadget.dev.driver = NULL; dev->driver = NULL; device_del (&dev->gadget.dev); - - DMSG("unregistered gadget driver '%s'\n", driver->driver.name); dump_state(dev); + return 0; } diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/pxa25x_udc.h index 2eca1e71fec..3fe5931dc21 100644 --- a/drivers/usb/gadget/pxa25x_udc.h +++ b/drivers/usb/gadget/pxa25x_udc.h @@ -126,6 +126,7 @@ struct pxa25x_udc { struct dentry *debugfs_udc; #endif }; +#define to_pxa25x(g) (container_of((g), struct pxa25x_udc, gadget)) /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 2b3b01d5f40..f7d25795821 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -1671,9 +1671,10 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) return -EOPNOTSUPP; } -static int pxa27x_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); -static int pxa27x_udc_stop(struct usb_gadget_driver *driver); +static int pxa27x_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver); +static int pxa27x_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver); static const struct usb_gadget_ops pxa_udc_ops = { .get_frame = pxa_udc_get_frame, @@ -1681,8 +1682,8 @@ static const struct usb_gadget_ops pxa_udc_ops = { .pullup = pxa_udc_pullup, .vbus_session = pxa_udc_vbus_session, .vbus_draw = pxa_udc_vbus_draw, - .start = pxa27x_udc_start, - .stop = pxa27x_udc_stop, + .udc_start = pxa27x_udc_start, + .udc_stop = pxa27x_udc_stop, }; /** @@ -1802,20 +1803,12 @@ static void udc_enable(struct pxa_udc *udc) * * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise */ -static int pxa27x_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) +static int pxa27x_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct pxa_udc *udc = the_controller; + struct pxa_udc *udc = to_pxa(g); int retval; - if (!driver || driver->max_speed < USB_SPEED_FULL || !bind - || !driver->disconnect || !driver->setup) - return -EINVAL; - if (!udc) - return -ENODEV; - if (udc->driver) - return -EBUSY; - /* first hook up the driver ... */ udc->driver = driver; udc->gadget.dev.driver = &driver->driver; @@ -1824,23 +1817,14 @@ static int pxa27x_udc_start(struct usb_gadget_driver *driver, retval = device_add(&udc->gadget.dev); if (retval) { dev_err(udc->dev, "device_add error %d\n", retval); - goto add_fail; + goto fail; } - retval = bind(&udc->gadget, driver); - if (retval) { - dev_err(udc->dev, "bind to driver %s --> error %d\n", - driver->driver.name, retval); - goto bind_fail; - } - dev_dbg(udc->dev, "registered gadget driver '%s'\n", - driver->driver.name); - if (!IS_ERR_OR_NULL(udc->transceiver)) { retval = otg_set_peripheral(udc->transceiver->otg, &udc->gadget); if (retval) { dev_err(udc->dev, "can't bind to transceiver\n"); - goto transceiver_fail; + goto fail; } } @@ -1848,12 +1832,7 @@ static int pxa27x_udc_start(struct usb_gadget_driver *driver, udc_enable(udc); return 0; -transceiver_fail: - if (driver->unbind) - driver->unbind(&udc->gadget); -bind_fail: - device_del(&udc->gadget.dev); -add_fail: +fail: udc->driver = NULL; udc->gadget.dev.driver = NULL; return retval; @@ -1878,9 +1857,6 @@ static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver) for (i = 0; i < NR_USB_ENDPOINTS; i++) pxa_ep_disable(&udc->udc_usb_ep[i].usb_ep); - - if (driver) - driver->disconnect(&udc->gadget); } /** @@ -1889,25 +1865,18 @@ static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver) * * Returns 0 if no error, -ENODEV, -EINVAL otherwise */ -static int pxa27x_udc_stop(struct usb_gadget_driver *driver) +static int pxa27x_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct pxa_udc *udc = the_controller; - - if (!udc) - return -ENODEV; - if (!driver || driver != udc->driver || !driver->unbind) - return -EINVAL; + struct pxa_udc *udc = to_pxa(g); stop_activity(udc, driver); udc_disable(udc); dplus_pullup(udc, 0); - driver->unbind(&udc->gadget); udc->driver = NULL; device_del(&udc->gadget.dev); - dev_info(udc->dev, "unregistered gadget driver '%s'\n", - driver->driver.name); if (!IS_ERR_OR_NULL(udc->transceiver)) return otg_set_peripheral(udc->transceiver->otg, NULL); diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h index 79d81a4b234..28f2b53530f 100644 --- a/drivers/usb/gadget/pxa27x_udc.h +++ b/drivers/usb/gadget/pxa27x_udc.h @@ -473,6 +473,7 @@ struct pxa_udc { struct dentry *debugfs_eps; #endif }; +#define to_pxa(g) (container_of((g), struct pxa_udc, gadget)) static inline struct pxa_udc *to_gadget_udc(struct usb_gadget *gadget) { diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 5a80751accb..234838da6d5 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1812,7 +1812,7 @@ static int r8a66597_set_selfpowered(struct usb_gadget *gadget, int is_self) return 0; } -static struct usb_gadget_ops r8a66597_gadget_ops = { +static const struct usb_gadget_ops r8a66597_gadget_ops = { .get_frame = r8a66597_get_frame, .udc_start = r8a66597_start, .udc_stop = r8a66597_stop, diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 439c3f972f8..e1cd0f1adfb 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -3055,7 +3055,7 @@ static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on) return 0; } -static struct usb_gadget_ops s3c_hsotg_gadget_ops = { +static const struct usb_gadget_ops s3c_hsotg_gadget_ops = { .get_frame = s3c_hsotg_gadget_getframe, .udc_start = s3c_hsotg_udc_start, .udc_stop = s3c_hsotg_udc_stop, @@ -3572,7 +3572,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++) hsotg->supplies[i].supply = s3c_hsotg_supply_names[i]; - ret = regulator_bulk_get(dev, ARRAY_SIZE(hsotg->supplies), + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hsotg->supplies), hsotg->supplies); if (ret) { dev_err(dev, "failed to request supplies: %d\n", ret); @@ -3662,8 +3662,6 @@ err_ep_mem: kfree(eps); err_supplies: s3c_hsotg_phy_disable(hsotg); - regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); - err_clk: clk_disable_unprepare(hsotg->clk); @@ -3688,7 +3686,6 @@ static int s3c_hsotg_remove(struct platform_device *pdev) } s3c_hsotg_phy_disable(hsotg); - regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); clk_disable_unprepare(hsotg->clk); diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index 52379b11f08..3ed5a397296 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -435,7 +435,7 @@ static void s3c_hsudc_epin_intr(struct s3c_hsudc *hsudc, u32 ep_idx) struct s3c_hsudc_req *hsreq; u32 csr; - csr = readl((u32)hsudc->regs + S3C_ESR); + csr = readl(hsudc->regs + S3C_ESR); if (csr & S3C_ESR_STALL) { writel(S3C_ESR_STALL, hsudc->regs + S3C_ESR); return; @@ -468,7 +468,7 @@ static void s3c_hsudc_epout_intr(struct s3c_hsudc *hsudc, u32 ep_idx) struct s3c_hsudc_req *hsreq; u32 csr; - csr = readl((u32)hsudc->regs + S3C_ESR); + csr = readl(hsudc->regs + S3C_ESR); if (csr & S3C_ESR_STALL) { writel(S3C_ESR_STALL, hsudc->regs + S3C_ESR); return; @@ -901,12 +901,12 @@ static int s3c_hsudc_queue(struct usb_ep *_ep, struct usb_request *_req, if (list_empty(&hsep->queue) && !hsep->stopped) { offset = (ep_index(hsep)) ? S3C_ESR : S3C_EP0SR; if (ep_is_in(hsep)) { - csr = readl((u32)hsudc->regs + offset); + csr = readl(hsudc->regs + offset); if (!(csr & S3C_ESR_TX_SUCCESS) && (s3c_hsudc_write_fifo(hsep, hsreq) == 1)) hsreq = NULL; } else { - csr = readl((u32)hsudc->regs + offset); + csr = readl(hsudc->regs + offset); if ((csr & S3C_ESR_RX_SUCCESS) && (s3c_hsudc_read_fifo(hsep, hsreq) == 1)) hsreq = NULL; @@ -1254,7 +1254,7 @@ static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA) return -EOPNOTSUPP; } -static struct usb_gadget_ops s3c_hsudc_gadget_ops = { +static const struct usb_gadget_ops s3c_hsudc_gadget_ops = { .get_frame = s3c_hsudc_gadget_getframe, .udc_start = s3c_hsudc_start, .udc_stop = s3c_hsudc_stop, @@ -1286,7 +1286,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++) hsudc->supplies[i].supply = s3c_hsudc_supply_names[i]; - ret = regulator_bulk_get(dev, ARRAY_SIZE(hsudc->supplies), + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hsudc->supplies), hsudc->supplies); if (ret != 0) { dev_err(dev, "failed to request supplies: %d\n", ret); @@ -1367,7 +1367,6 @@ err_res: if (!IS_ERR_OR_NULL(hsudc->transceiver)) usb_put_phy(hsudc->transceiver); - regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies); err_supplies: return ret; } diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index a2fa6e16d01..fc07b438128 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1538,9 +1538,10 @@ static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma) return -ENOTSUPP; } -static int s3c2410_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); -static int s3c2410_udc_stop(struct usb_gadget_driver *driver); +static int s3c2410_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver); +static int s3c2410_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver); static const struct usb_gadget_ops s3c2410_ops = { .get_frame = s3c2410_udc_get_frame, @@ -1549,8 +1550,8 @@ static const struct usb_gadget_ops s3c2410_ops = { .pullup = s3c2410_udc_pullup, .vbus_session = s3c2410_udc_vbus_session, .vbus_draw = s3c2410_vbus_draw, - .start = s3c2410_udc_start, - .stop = s3c2410_udc_stop, + .udc_start = s3c2410_udc_start, + .udc_stop = s3c2410_udc_stop, }; static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd) @@ -1664,33 +1665,14 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev) s3c2410_udc_command(S3C2410_UDC_P_ENABLE); } -static int s3c2410_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) +static int s3c2410_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct s3c2410_udc *udc = the_controller; + struct s3c2410_udc *udc = to_s3c2410(g) int retval; dprintk(DEBUG_NORMAL, "%s() '%s'\n", __func__, driver->driver.name); - /* Sanity checks */ - if (!udc) - return -ENODEV; - - if (udc->driver) - return -EBUSY; - - if (!bind || !driver->setup || driver->max_speed < USB_SPEED_FULL) { - dev_err(&udc->gadget.dev, "Invalid driver: bind %p setup %p speed %d\n", - bind, driver->setup, driver->max_speed); - return -EINVAL; - } -#if defined(MODULE) - if (!driver->unbind) { - dev_err(&udc->gadget.dev, "Invalid driver: no unbind method\n"); - return -EINVAL; - } -#endif - /* Hook the driver */ udc->driver = driver; udc->gadget.dev.driver = &driver->driver; @@ -1702,15 +1684,6 @@ static int s3c2410_udc_start(struct usb_gadget_driver *driver, goto register_error; } - dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n", - driver->driver.name); - - retval = bind(&udc->gadget, driver); - if (retval) { - device_del(&udc->gadget.dev); - goto register_error; - } - /* Enable udc */ s3c2410_udc_enable(udc); @@ -1722,24 +1695,10 @@ register_error: return retval; } -static int s3c2410_udc_stop(struct usb_gadget_driver *driver) +static int s3c2410_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct s3c2410_udc *udc = the_controller; - - if (!udc) - return -ENODEV; - - if (!driver || driver != udc->driver || !driver->unbind) - return -EINVAL; - - dprintk(DEBUG_NORMAL, "usb_gadget_unregister_driver() '%s'\n", - driver->driver.name); - - /* report disconnect */ - if (driver->disconnect) - driver->disconnect(&udc->gadget); - - driver->unbind(&udc->gadget); + struct s3c2410_udc *udc = to_s3c2410(g); device_del(&udc->gadget.dev); udc->driver = NULL; diff --git a/drivers/usb/gadget/s3c2410_udc.h b/drivers/usb/gadget/s3c2410_udc.h index 3e80fd5c820..93bf225f196 100644 --- a/drivers/usb/gadget/s3c2410_udc.h +++ b/drivers/usb/gadget/s3c2410_udc.h @@ -95,5 +95,6 @@ struct s3c2410_udc { u8 vbus; struct dentry *regs_info; }; +#define to_s3c2410(g) (container_of((g), struct s3c2410_udc, gadget)) #endif diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 44752f531e8..68d7bb06ebc 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -36,10 +36,8 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ -#include "f_acm.c" #include "f_obex.c" #include "f_serial.c" -#include "u_serial.c" /*-------------------------------------------------------------------------*/ USB_GADGET_COMPOSITE_OPTIONS(); @@ -128,20 +126,25 @@ module_param(n_ports, uint, 0); MODULE_PARM_DESC(n_ports, "number of ports to create, default=1"); /*-------------------------------------------------------------------------*/ +static unsigned char tty_lines[MAX_U_SERIAL_PORTS]; -static int __init serial_bind_config(struct usb_configuration *c) +static int __init serial_bind_obex_config(struct usb_configuration *c) { unsigned i; int status = 0; - for (i = 0; i < n_ports && status == 0; i++) { - if (use_acm) - status = acm_bind_config(c, i); - else if (use_obex) - status = obex_bind_config(c, i); - else - status = gser_bind_config(c, i); - } + for (i = 0; i < n_ports && status == 0; i++) + status = obex_bind_config(c, tty_lines[i]); + return status; +} + +static int __init serial_bind_gser_config(struct usb_configuration *c) +{ + unsigned i; + int status = 0; + + for (i = 0; i < n_ports && status == 0; i++) + status = gser_bind_config(c, tty_lines[i]); return status; } @@ -152,13 +155,70 @@ static struct usb_configuration serial_config_driver = { .bmAttributes = USB_CONFIG_ATT_SELFPOWER, }; +static struct usb_function_instance *fi_serial[MAX_U_SERIAL_PORTS]; +static struct usb_function *f_serial[MAX_U_SERIAL_PORTS]; + +static int serial_register_ports(struct usb_composite_dev *cdev, + struct usb_configuration *c, const char *f_name) +{ + int i; + int ret; + + ret = usb_add_config_only(cdev, c); + if (ret) + goto out; + + for (i = 0; i < n_ports; i++) { + struct f_serial_opts *opts; + + fi_serial[i] = usb_get_function_instance(f_name); + if (IS_ERR(fi_serial[i])) { + ret = PTR_ERR(fi_serial[i]); + goto fail; + } + opts = container_of(fi_serial[i], struct f_serial_opts, func_inst); + opts->port_num = tty_lines[i]; + + f_serial[i] = usb_get_function(fi_serial[i]); + if (IS_ERR(f_serial[i])) { + ret = PTR_ERR(f_serial[i]); + goto err_get_func; + } + + ret = usb_add_function(c, f_serial[i]); + if (ret) + goto err_add_func; + } + + return 0; + +err_add_func: + usb_put_function(f_serial[i]); +err_get_func: + usb_put_function_instance(fi_serial[i]); + +fail: + i--; + while (i >= 0) { + usb_remove_function(c, f_serial[i]); + usb_put_function(f_serial[i]); + usb_put_function_instance(fi_serial[i]); + i--; + } +out: + return ret; +} + static int __init gs_bind(struct usb_composite_dev *cdev) { int status; + int cur_line; - status = gserial_setup(cdev->gadget, n_ports); - if (status < 0) - return status; + for (cur_line = 0; cur_line < n_ports; cur_line++) { + status = gserial_alloc_line(&tty_lines[cur_line]); + if (status) + goto fail; + } /* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue. @@ -178,8 +238,16 @@ static int __init gs_bind(struct usb_composite_dev *cdev) } /* register our configuration */ - status = usb_add_config(cdev, &serial_config_driver, - serial_bind_config); + if (use_acm) { + status = serial_register_ports(cdev, &serial_config_driver, + "acm"); + usb_ep_autoconfig_reset(cdev->gadget); + } else if (use_obex) + status = usb_add_config(cdev, &serial_config_driver, + serial_bind_obex_config); + else + status = usb_add_config(cdev, &serial_config_driver, + serial_bind_gser_config); if (status < 0) goto fail; @@ -189,16 +257,31 @@ static int __init gs_bind(struct usb_composite_dev *cdev) return 0; fail: - gserial_cleanup(); + cur_line--; + while (cur_line >= 0) + gserial_free_line(tty_lines[cur_line--]); return status; } +static int gs_unbind(struct usb_composite_dev *cdev) +{ + int i; + + for (i = 0; i < n_ports; i++) { + usb_put_function(f_serial[i]); + usb_put_function_instance(fi_serial[i]); + gserial_free_line(tty_lines[i]); + } + return 0; +} + static __refdata struct usb_composite_driver gserial_driver = { .name = "g_serial", .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_SUPER, .bind = gs_bind, + .unbind = gs_unbind, }; static int __init init(void) @@ -234,6 +317,5 @@ module_init(init); static void __exit cleanup(void) { usb_composite_unregister(&gserial_driver); - gserial_cleanup(); } module_exit(cleanup); diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 0e3ae43454a..4ecbf8496f4 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -93,18 +93,6 @@ /*-------------------------------------------------------------------------*/ -/* CBI Interrupt data structure */ -struct interrupt_data { - u8 bType; - u8 bValue; -}; - -#define CBI_INTERRUPT_DATA_LEN 2 - -/* CBI Accept Device-Specific Command request */ -#define USB_CBI_ADSC_REQUEST 0x00 - - /* Length of a SCSI Command Data Block */ #define MAX_COMMAND_SIZE 16 @@ -385,41 +373,6 @@ static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { /*.bMaxBurst = DYNAMIC, */ }; -static __maybe_unused struct usb_ext_cap_descriptor fsg_ext_cap_desc = { - .bLength = USB_DT_USB_EXT_CAP_SIZE, - .bDescriptorType = USB_DT_DEVICE_CAPABILITY, - .bDevCapabilityType = USB_CAP_TYPE_EXT, - - .bmAttributes = cpu_to_le32(USB_LPM_SUPPORT), -}; - -static __maybe_unused struct usb_ss_cap_descriptor fsg_ss_cap_desc = { - .bLength = USB_DT_USB_SS_CAP_SIZE, - .bDescriptorType = USB_DT_DEVICE_CAPABILITY, - .bDevCapabilityType = USB_SS_CAP_TYPE, - - /* .bmAttributes = LTM is not supported yet */ - - .wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION - | USB_FULL_SPEED_OPERATION - | USB_HIGH_SPEED_OPERATION - | USB_5GBPS_OPERATION), - .bFunctionalitySupport = USB_LOW_SPEED_OPERATION, - .bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT, - .bU2DevExitLat = cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT), -}; - -static __maybe_unused struct usb_bos_descriptor fsg_bos_desc = { - .bLength = USB_DT_BOS_SIZE, - .bDescriptorType = USB_DT_BOS, - - .wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE - + USB_DT_USB_EXT_CAP_SIZE - + USB_DT_USB_SS_CAP_SIZE), - - .bNumDeviceCaps = 2, -}; - static struct usb_descriptor_header *fsg_ss_function[] = { (struct usb_descriptor_header *) &fsg_intf_desc, (struct usb_descriptor_header *) &fsg_ss_bulk_in_desc, @@ -429,20 +382,6 @@ static struct usb_descriptor_header *fsg_ss_function[] = { NULL, }; -/* Maxpacket and other transfer characteristics vary by speed. */ -static __maybe_unused struct usb_endpoint_descriptor * -fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, - struct usb_endpoint_descriptor *hs, - struct usb_endpoint_descriptor *ss) -{ - if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) - return ss; - else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) - return hs; - return fs; -} - - /* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ static struct usb_string fsg_strings[] = { {FSG_STRING_INTERFACE, fsg_string_interface}, diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 598dcc1212f..588a9be18ef 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -26,6 +26,7 @@ #include <linux/tty_flip.h> #include <linux/slab.h> #include <linux/export.h> +#include <linux/module.h> #include "u_serial.h" @@ -35,11 +36,12 @@ * "serial port" functionality through the USB gadget stack. Each such * port is exposed through a /dev/ttyGS* node. * - * After initialization (gserial_setup), these TTY port devices stay - * available until they are removed (gserial_cleanup). Each one may be - * connected to a USB function (gserial_connect), or disconnected (with - * gserial_disconnect) when the USB host issues a config change event. - * Data can only flow when the port is connected to the host. + * After this module has been loaded, the individual TTY port can be requested + * (gserial_alloc_line()) and it will stay available until they are removed + * (gserial_free_line()). Each one may be connected to a USB function + * (gserial_connect), or disconnected (with gserial_disconnect) when the USB + * host issues a config change event. Data can only flow when the port is + * connected to the host. * * A given TTY port can be made available in multiple configurations. * For example, each one might expose a ttyGS0 node which provides a @@ -119,13 +121,10 @@ struct gs_port { struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */ }; -/* increase N_PORTS if you need more */ -#define N_PORTS 4 static struct portmaster { struct mutex lock; /* protect open/close */ struct gs_port *port; -} ports[N_PORTS]; -static unsigned n_ports; +} ports[MAX_U_SERIAL_PORTS]; #define GS_CLOSE_TIMEOUT 15 /* seconds */ @@ -309,6 +308,7 @@ gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags) return req; } +EXPORT_SYMBOL_GPL(gs_alloc_req); /* * gs_free_req @@ -320,6 +320,7 @@ void gs_free_req(struct usb_ep *ep, struct usb_request *req) kfree(req->buf); usb_ep_free_request(ep, req); } +EXPORT_SYMBOL_GPL(gs_free_req); /* * gs_send_packet @@ -1030,10 +1031,19 @@ static int gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) { struct gs_port *port; + int ret = 0; + + mutex_lock(&ports[port_num].lock); + if (ports[port_num].port) { + ret = -EBUSY; + goto out; + } port = kzalloc(sizeof(struct gs_port), GFP_KERNEL); - if (port == NULL) - return -ENOMEM; + if (port == NULL) { + ret = -ENOMEM; + goto out; + } tty_port_init(&port->port); spin_lock_init(&port->port_lock); @@ -1049,109 +1059,9 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) port->port_line_coding = *coding; ports[port_num].port = port; - - return 0; -} - -/** - * gserial_setup - initialize TTY driver for one or more ports - * @g: gadget to associate with these ports - * @count: how many ports to support - * Context: may sleep - * - * The TTY stack needs to know in advance how many devices it should - * plan to manage. Use this call to set up the ports you will be - * exporting through USB. Later, connect them to functions based - * on what configuration is activated by the USB host; and disconnect - * them as appropriate. - * - * An example would be a two-configuration device in which both - * configurations expose port 0, but through different functions. - * One configuration could even expose port 1 while the other - * one doesn't. - * - * Returns negative errno or zero. - */ -int gserial_setup(struct usb_gadget *g, unsigned count) -{ - unsigned i; - struct usb_cdc_line_coding coding; - int status; - - if (count == 0 || count > N_PORTS) - return -EINVAL; - - gs_tty_driver = alloc_tty_driver(count); - if (!gs_tty_driver) - return -ENOMEM; - - gs_tty_driver->driver_name = "g_serial"; - gs_tty_driver->name = PREFIX; - /* uses dynamically assigned dev_t values */ - - gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; - gs_tty_driver->subtype = SERIAL_TYPE_NORMAL; - gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - gs_tty_driver->init_termios = tty_std_termios; - - /* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on - * MS-Windows. Otherwise, most of these flags shouldn't affect - * anything unless we were to actually hook up to a serial line. - */ - gs_tty_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - gs_tty_driver->init_termios.c_ispeed = 9600; - gs_tty_driver->init_termios.c_ospeed = 9600; - - coding.dwDTERate = cpu_to_le32(9600); - coding.bCharFormat = 8; - coding.bParityType = USB_CDC_NO_PARITY; - coding.bDataBits = USB_CDC_1_STOP_BITS; - - tty_set_operations(gs_tty_driver, &gs_tty_ops); - - /* make devices be openable */ - for (i = 0; i < count; i++) { - mutex_init(&ports[i].lock); - status = gs_port_alloc(i, &coding); - if (status) { - count = i; - goto fail; - } - } - n_ports = count; - - /* export the driver ... */ - status = tty_register_driver(gs_tty_driver); - if (status) { - pr_err("%s: cannot register, err %d\n", - __func__, status); - goto fail; - } - - /* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */ - for (i = 0; i < count; i++) { - struct device *tty_dev; - - tty_dev = tty_port_register_device(&ports[i].port->port, - gs_tty_driver, i, &g->dev); - if (IS_ERR(tty_dev)) - pr_warning("%s: no classdev for port %d, err %ld\n", - __func__, i, PTR_ERR(tty_dev)); - } - - pr_debug("%s: registered %d ttyGS* device%s\n", __func__, - count, (count == 1) ? "" : "s"); - - return status; -fail: - while (count--) { - tty_port_destroy(&ports[count].port->port); - kfree(ports[count].port); - } - put_tty_driver(gs_tty_driver); - gs_tty_driver = NULL; - return status; +out: + mutex_unlock(&ports[port_num].lock); + return ret; } static int gs_closed(struct gs_port *port) @@ -1164,55 +1074,77 @@ static int gs_closed(struct gs_port *port) return cond; } -/** - * gserial_cleanup - remove TTY-over-USB driver and devices - * Context: may sleep - * - * This is called to free all resources allocated by @gserial_setup(). - * Accordingly, it may need to wait until some open /dev/ files have - * closed. - * - * The caller must have issued @gserial_disconnect() for any ports - * that had previously been connected, so that there is never any - * I/O pending when it's called. - */ -void gserial_cleanup(void) +static void gserial_free_port(struct gs_port *port) +{ + tasklet_kill(&port->push); + /* wait for old opens to finish */ + wait_event(port->port.close_wait, gs_closed(port)); + WARN_ON(port->port_usb != NULL); + tty_port_destroy(&port->port); + kfree(port); +} + +void gserial_free_line(unsigned char port_num) { - unsigned i; struct gs_port *port; - if (!gs_tty_driver) + mutex_lock(&ports[port_num].lock); + if (WARN_ON(!ports[port_num].port)) { + mutex_unlock(&ports[port_num].lock); return; + } + port = ports[port_num].port; + ports[port_num].port = NULL; + mutex_unlock(&ports[port_num].lock); - /* start sysfs and /dev/ttyGS* node removal */ - for (i = 0; i < n_ports; i++) - tty_unregister_device(gs_tty_driver, i); - - for (i = 0; i < n_ports; i++) { - /* prevent new opens */ - mutex_lock(&ports[i].lock); - port = ports[i].port; - ports[i].port = NULL; - mutex_unlock(&ports[i].lock); - - tasklet_kill(&port->push); + gserial_free_port(port); + tty_unregister_device(gs_tty_driver, port_num); +} +EXPORT_SYMBOL_GPL(gserial_free_line); - /* wait for old opens to finish */ - wait_event(port->port.close_wait, gs_closed(port)); +int gserial_alloc_line(unsigned char *line_num) +{ + struct usb_cdc_line_coding coding; + struct device *tty_dev; + int ret; + int port_num; - WARN_ON(port->port_usb != NULL); + coding.dwDTERate = cpu_to_le32(9600); + coding.bCharFormat = 8; + coding.bParityType = USB_CDC_NO_PARITY; + coding.bDataBits = USB_CDC_1_STOP_BITS; - tty_port_destroy(&port->port); - kfree(port); + for (port_num = 0; port_num < MAX_U_SERIAL_PORTS; port_num++) { + ret = gs_port_alloc(port_num, &coding); + if (ret == -EBUSY) + continue; + if (ret) + return ret; + break; } - n_ports = 0; + if (ret) + return ret; - tty_unregister_driver(gs_tty_driver); - put_tty_driver(gs_tty_driver); - gs_tty_driver = NULL; + /* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */ + + tty_dev = tty_port_register_device(&ports[port_num].port->port, + gs_tty_driver, port_num, NULL); + if (IS_ERR(tty_dev)) { + struct gs_port *port; + pr_err("%s: failed to register tty for port %d, err %ld\n", + __func__, port_num, PTR_ERR(tty_dev)); - pr_debug("%s: cleaned up ttyGS* support\n", __func__); + ret = PTR_ERR(tty_dev); + port = ports[port_num].port; + ports[port_num].port = NULL; + gserial_free_port(port); + goto err; + } + *line_num = port_num; +err: + return ret; } +EXPORT_SYMBOL_GPL(gserial_alloc_line); /** * gserial_connect - notify TTY I/O glue that USB link is active @@ -1229,8 +1161,8 @@ void gserial_cleanup(void) * * Caller needs to have set up the endpoints and USB function in @dev * before calling this, as well as the appropriate (speed-specific) - * endpoint descriptors, and also have set up the TTY driver by calling - * @gserial_setup(). + * endpoint descriptors, and also have allocate @port_num by calling + * @gserial_alloc_line(). * * Returns negative errno or zero. * On success, ep->driver_data will be overwritten. @@ -1241,11 +1173,18 @@ int gserial_connect(struct gserial *gser, u8 port_num) unsigned long flags; int status; - if (!gs_tty_driver || port_num >= n_ports) + if (port_num >= MAX_U_SERIAL_PORTS) return -ENXIO; - /* we "know" gserial_cleanup() hasn't been called */ port = ports[port_num].port; + if (!port) { + pr_err("serial line %d not allocated.\n", port_num); + return -EINVAL; + } + if (port->port_usb) { + pr_err("serial line %d is in use.\n", port_num); + return -EBUSY; + } /* activate the endpoints */ status = usb_ep_enable(gser->in); @@ -1292,7 +1231,7 @@ fail_out: gser->in->driver_data = NULL; return status; } - +EXPORT_SYMBOL_GPL(gserial_connect); /** * gserial_disconnect - notify TTY I/O glue that USB link is inactive * @gser: the function, on which gserial_connect() was called @@ -1347,3 +1286,65 @@ void gserial_disconnect(struct gserial *gser) spin_unlock_irqrestore(&port->port_lock, flags); } +EXPORT_SYMBOL_GPL(gserial_disconnect); + +static int userial_init(void) +{ + unsigned i; + int status; + + gs_tty_driver = alloc_tty_driver(MAX_U_SERIAL_PORTS); + if (!gs_tty_driver) + return -ENOMEM; + + gs_tty_driver->driver_name = "g_serial"; + gs_tty_driver->name = PREFIX; + /* uses dynamically assigned dev_t values */ + + gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; + gs_tty_driver->subtype = SERIAL_TYPE_NORMAL; + gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + gs_tty_driver->init_termios = tty_std_termios; + + /* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on + * MS-Windows. Otherwise, most of these flags shouldn't affect + * anything unless we were to actually hook up to a serial line. + */ + gs_tty_driver->init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + gs_tty_driver->init_termios.c_ispeed = 9600; + gs_tty_driver->init_termios.c_ospeed = 9600; + + tty_set_operations(gs_tty_driver, &gs_tty_ops); + for (i = 0; i < MAX_U_SERIAL_PORTS; i++) + mutex_init(&ports[i].lock); + + /* export the driver ... */ + status = tty_register_driver(gs_tty_driver); + if (status) { + pr_err("%s: cannot register, err %d\n", + __func__, status); + goto fail; + } + + pr_debug("%s: registered %d ttyGS* device%s\n", __func__, + MAX_U_SERIAL_PORTS, + (MAX_U_SERIAL_PORTS == 1) ? "" : "s"); + + return status; +fail: + put_tty_driver(gs_tty_driver); + gs_tty_driver = NULL; + return status; +} +module_init(userial_init); + +static void userial_cleanup(void) +{ + tty_unregister_driver(gs_tty_driver); + put_tty_driver(gs_tty_driver); + gs_tty_driver = NULL; +} +module_exit(userial_cleanup); + +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h index 9b0fe6450fb..66ce73a0050 100644 --- a/drivers/usb/gadget/u_serial.h +++ b/drivers/usb/gadget/u_serial.h @@ -15,6 +15,13 @@ #include <linux/usb/composite.h> #include <linux/usb/cdc.h> +#define MAX_U_SERIAL_PORTS 4 + +struct f_serial_opts { + struct usb_function_instance func_inst; + u8 port_num; +}; + /* * One non-multiplexed "serial" I/O port ... there can be several of these * on any given USB peripheral device, if it provides enough endpoints. @@ -49,9 +56,9 @@ struct gserial { struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags); void gs_free_req(struct usb_ep *, struct usb_request *req); -/* port setup/teardown is handled by gadget driver */ -int gserial_setup(struct usb_gadget *g, unsigned n_ports); -void gserial_cleanup(void); +/* management of individual TTY ports */ +int gserial_alloc_line(unsigned char *port_line); +void gserial_free_line(unsigned char port_line); /* connect/disconnect is handled by individual functions */ int gserial_connect(struct gserial *, u8 port_num); diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 4d90a800063..2a9cd369f71 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -102,28 +102,6 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); /* ------------------------------------------------------------------------- */ /** - * usb_gadget_start - tells usb device controller to start up - * @gadget: The gadget we want to get started - * @driver: The driver we want to bind to @gadget - * @bind: The bind function for @driver - * - * This call is issued by the UDC Class driver when it's about - * to register a gadget driver to the device controller, before - * calling gadget driver's bind() method. - * - * It allows the controller to be powered off until strictly - * necessary to have it powered on. - * - * Returns zero on success, else negative errno. - */ -static inline int usb_gadget_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) -{ - return gadget->ops->start(driver, bind); -} - -/** * usb_gadget_udc_start - tells usb device controller to start up * @gadget: The gadget we want to get started * @driver: The driver we want to bind to @gadget @@ -144,24 +122,6 @@ static inline int usb_gadget_udc_start(struct usb_gadget *gadget, } /** - * usb_gadget_stop - tells usb device controller we don't need it anymore - * @gadget: The device we want to stop activity - * @driver: The driver to unbind from @gadget - * - * This call is issued by the UDC Class driver after calling - * gadget driver's unbind() method. - * - * The details are implementation specific, but it can go as - * far as powering off UDC completely and disable its data - * line pullups. - */ -static inline void usb_gadget_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - gadget->ops->stop(driver); -} - -/** * usb_gadget_udc_stop - tells usb device controller we don't need it anymore * @gadget: The device we want to stop activity * @driver: The driver to unbind from @gadget @@ -246,14 +206,6 @@ err1: } EXPORT_SYMBOL_GPL(usb_add_gadget_udc); -static int udc_is_newstyle(struct usb_udc *udc) -{ - if (udc->gadget->ops->udc_start && udc->gadget->ops->udc_stop) - return 1; - return 0; -} - - static void usb_gadget_remove_driver(struct usb_udc *udc) { dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n", @@ -261,14 +213,10 @@ static void usb_gadget_remove_driver(struct usb_udc *udc) kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); - if (udc_is_newstyle(udc)) { - usb_gadget_disconnect(udc->gadget); - udc->driver->disconnect(udc->gadget); - udc->driver->unbind(udc->gadget); - usb_gadget_udc_stop(udc->gadget, udc->driver); - } else { - usb_gadget_stop(udc->gadget, udc->driver); - } + usb_gadget_disconnect(udc->gadget); + udc->driver->disconnect(udc->gadget); + udc->driver->unbind(udc->gadget); + usb_gadget_udc_stop(udc->gadget, udc->driver); udc->driver = NULL; udc->dev.driver = NULL; @@ -311,6 +259,62 @@ EXPORT_SYMBOL_GPL(usb_del_gadget_udc); /* ------------------------------------------------------------------------- */ +static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver) +{ + int ret; + + dev_dbg(&udc->dev, "registering UDC driver [%s]\n", + driver->function); + + udc->driver = driver; + udc->dev.driver = &driver->driver; + + ret = driver->bind(udc->gadget, driver); + if (ret) + goto err1; + ret = usb_gadget_udc_start(udc->gadget, driver); + if (ret) { + driver->unbind(udc->gadget); + goto err1; + } + usb_gadget_connect(udc->gadget); + + kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); + return 0; +err1: + dev_err(&udc->dev, "failed to start %s: %d\n", + udc->driver->function, ret); + udc->driver = NULL; + udc->dev.driver = NULL; + return ret; +} + +int udc_attach_driver(const char *name, struct usb_gadget_driver *driver) +{ + struct usb_udc *udc = NULL; + int ret = -ENODEV; + + mutex_lock(&udc_lock); + list_for_each_entry(udc, &udc_list, list) { + ret = strcmp(name, dev_name(&udc->dev)); + if (!ret) + break; + } + if (ret) { + ret = -ENODEV; + goto out; + } + if (udc->driver) { + ret = -EBUSY; + goto out; + } + ret = udc_bind_to_driver(udc, driver); +out: + mutex_unlock(&udc_lock); + return ret; +} +EXPORT_SYMBOL_GPL(udc_attach_driver); + int usb_gadget_probe_driver(struct usb_gadget_driver *driver) { struct usb_udc *udc = NULL; @@ -329,41 +333,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver) pr_debug("couldn't find an available UDC\n"); mutex_unlock(&udc_lock); return -ENODEV; - found: - dev_dbg(&udc->dev, "registering UDC driver [%s]\n", - driver->function); - - udc->driver = driver; - udc->dev.driver = &driver->driver; - - if (udc_is_newstyle(udc)) { - ret = driver->bind(udc->gadget, driver); - if (ret) - goto err1; - ret = usb_gadget_udc_start(udc->gadget, driver); - if (ret) { - driver->unbind(udc->gadget); - goto err1; - } - usb_gadget_connect(udc->gadget); - } else { - - ret = usb_gadget_start(udc->gadget, driver, driver->bind); - if (ret) - goto err1; - - } - - kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); - mutex_unlock(&udc_lock); - return 0; - -err1: - dev_err(&udc->dev, "failed to start %s: %d\n", - udc->driver->function, ret); - udc->driver = NULL; - udc->dev.driver = NULL; + ret = udc_bind_to_driver(udc, driver); mutex_unlock(&udc_lock); return ret; } @@ -410,13 +381,11 @@ static ssize_t usb_udc_softconn_store(struct device *dev, struct usb_udc *udc = container_of(dev, struct usb_udc, dev); if (sysfs_streq(buf, "connect")) { - if (udc_is_newstyle(udc)) - usb_gadget_udc_start(udc->gadget, udc->driver); + usb_gadget_udc_start(udc->gadget, udc->driver); usb_gadget_connect(udc->gadget); } else if (sysfs_streq(buf, "disconnect")) { usb_gadget_disconnect(udc->gadget); - if (udc_is_newstyle(udc)) - usb_gadget_udc_stop(udc->gadget, udc->driver); + usb_gadget_udc_stop(udc->gadget, udc->driver); } else { dev_err(dev, "unsupported command '%s'\n", buf); return -EINVAL; diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c index 69cf5c2cd33..8cef1e658c2 100644 --- a/drivers/usb/gadget/webcam.c +++ b/drivers/usb/gadget/webcam.c @@ -336,7 +336,7 @@ static struct usb_configuration webcam_config_driver = { .bConfigurationValue = 1, .iConfiguration = 0, /* dynamic */ .bmAttributes = USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, + .MaxPower = CONFIG_USB_GADGET_VBUS_DRAW, }; static int /* __init_or_exit */ diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 6bf4c061136..685fa681cb6 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -10,7 +10,6 @@ * (at your option) any later version. */ - /* * Gadget Zero only needs two bulk endpoints, and is an example of how you * can write a hardware-agnostic gadget driver running inside a USB device. @@ -43,23 +42,11 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/device.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/usb/composite.h> #include "g_zero.h" -#include "gadget_chips.h" - - -/*-------------------------------------------------------------------------*/ - -/* - * Kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module. So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ -#include "f_sourcesink.c" -#include "f_loopback.c" - /*-------------------------------------------------------------------------*/ USB_GADGET_COMPOSITE_OPTIONS(); @@ -67,9 +54,6 @@ USB_GADGET_COMPOSITE_OPTIONS(); static const char longname[] = "Gadget Zero"; -unsigned buflen = 4096; /* only used for bulk endpoints */ -module_param(buflen, uint, 0); - /* * Normally the "loopback" configuration is second (index 1) so * it's not the default. Here's where to change that order, to @@ -79,6 +63,13 @@ module_param(buflen, uint, 0); static bool loopdefault = 0; module_param(loopdefault, bool, S_IRUGO|S_IWUSR); +static struct usb_zero_options gzero_options = { + .isoc_interval = 4, + .isoc_maxpacket = 1024, + .bulk_buflen = 4096, + .qlen = 32, +}; + /*-------------------------------------------------------------------------*/ /* Thanks to NetChip Technologies for donating this product ID. @@ -129,20 +120,27 @@ static struct usb_otg_descriptor otg_descriptor = { .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, }; -const struct usb_descriptor_header *otg_desc[] = { +static const struct usb_descriptor_header *otg_desc[] = { (struct usb_descriptor_header *) &otg_descriptor, NULL, }; +#else +#define otg_desc NULL #endif /* string IDs are assigned dynamically */ /* default serial number takes at least two packets */ static char serial[] = "0123456789.0123456789.0123456789"; +#define USB_GZERO_SS_DESC (USB_GADGET_FIRST_AVAIL_IDX + 0) +#define USB_GZERO_LB_DESC (USB_GADGET_FIRST_AVAIL_IDX + 1) + static struct usb_string strings_dev[] = { [USB_GADGET_MANUFACTURER_IDX].s = "", [USB_GADGET_PRODUCT_IDX].s = longname, [USB_GADGET_SERIAL_IDX].s = serial, + [USB_GZERO_SS_DESC].s = "source and sink data", + [USB_GZERO_LB_DESC].s = "loop input to output", { } /* end of list */ }; @@ -158,58 +156,6 @@ static struct usb_gadget_strings *dev_strings[] = { /*-------------------------------------------------------------------------*/ -struct usb_request *alloc_ep_req(struct usb_ep *ep, int len) -{ - struct usb_request *req; - - req = usb_ep_alloc_request(ep, GFP_ATOMIC); - if (req) { - if (len) - req->length = len; - else - req->length = buflen; - req->buf = kmalloc(req->length, GFP_ATOMIC); - if (!req->buf) { - usb_ep_free_request(ep, req); - req = NULL; - } - } - return req; -} - -void free_ep_req(struct usb_ep *ep, struct usb_request *req) -{ - kfree(req->buf); - usb_ep_free_request(ep, req); -} - -static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep) -{ - int value; - - if (ep->driver_data) { - value = usb_ep_disable(ep); - if (value < 0) - DBG(cdev, "disable %s --> %d\n", - ep->name, value); - ep->driver_data = NULL; - } -} - -void disable_endpoints(struct usb_composite_dev *cdev, - struct usb_ep *in, struct usb_ep *out, - struct usb_ep *iso_in, struct usb_ep *iso_out) -{ - disable_ep(cdev, in); - disable_ep(cdev, out); - if (iso_in) - disable_ep(cdev, iso_in); - if (iso_out) - disable_ep(cdev, iso_out); -} - -/*-------------------------------------------------------------------------*/ - static struct timer_list autoresume_timer; static void zero_autoresume(unsigned long _c) @@ -251,8 +197,65 @@ static void zero_resume(struct usb_composite_dev *cdev) /*-------------------------------------------------------------------------*/ +static struct usb_configuration loopback_driver = { + .label = "loopback", + .bConfigurationValue = 2, + .bmAttributes = USB_CONFIG_ATT_SELFPOWER, + /* .iConfiguration = DYNAMIC */ +}; + +static struct usb_function *func_ss; +static struct usb_function_instance *func_inst_ss; + +static int ss_config_setup(struct usb_configuration *c, + const struct usb_ctrlrequest *ctrl) +{ + switch (ctrl->bRequest) { + case 0x5b: + case 0x5c: + return func_ss->setup(func_ss, ctrl); + default: + return -EOPNOTSUPP; + } +} + +static struct usb_configuration sourcesink_driver = { + .label = "source/sink", + .setup = ss_config_setup, + .bConfigurationValue = 3, + .bmAttributes = USB_CONFIG_ATT_SELFPOWER, + /* .iConfiguration = DYNAMIC */ +}; + +module_param_named(buflen, gzero_options.bulk_buflen, uint, 0); +module_param_named(pattern, gzero_options.pattern, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none"); + +module_param_named(isoc_interval, gzero_options.isoc_interval, uint, + S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(isoc_interval, "1 - 16"); + +module_param_named(isoc_maxpacket, gzero_options.isoc_maxpacket, uint, + S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)"); + +module_param_named(isoc_mult, gzero_options.isoc_mult, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)"); + +module_param_named(isoc_maxburst, gzero_options.isoc_maxburst, uint, + S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)"); + +static struct usb_function *func_lb; +static struct usb_function_instance *func_inst_lb; + +module_param_named(qlen, gzero_options.qlen, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(qlen, "depth of loopback queue"); + static int __init zero_bind(struct usb_composite_dev *cdev) { + struct f_ss_opts *ss_opts; + struct f_lb_opts *lb_opts; int status; /* Allocate string descriptor numbers ... note that string @@ -268,27 +271,105 @@ static int __init zero_bind(struct usb_composite_dev *cdev) setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev); + func_inst_ss = usb_get_function_instance("SourceSink"); + if (IS_ERR(func_inst_ss)) + return PTR_ERR(func_inst_ss); + + ss_opts = container_of(func_inst_ss, struct f_ss_opts, func_inst); + ss_opts->pattern = gzero_options.pattern; + ss_opts->isoc_interval = gzero_options.isoc_interval; + ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket; + ss_opts->isoc_mult = gzero_options.isoc_mult; + ss_opts->isoc_maxburst = gzero_options.isoc_maxpacket; + ss_opts->bulk_buflen = gzero_options.bulk_buflen; + + func_ss = usb_get_function(func_inst_ss); + if (IS_ERR(func_ss)) + goto err_put_func_inst_ss; + + func_inst_lb = usb_get_function_instance("Loopback"); + if (IS_ERR(func_inst_lb)) + goto err_put_func_ss; + + lb_opts = container_of(func_inst_lb, struct f_lb_opts, func_inst); + lb_opts->bulk_buflen = gzero_options.bulk_buflen; + lb_opts->qlen = gzero_options.qlen; + + func_lb = usb_get_function(func_inst_lb); + if (IS_ERR(func_lb)) { + status = PTR_ERR(func_lb); + goto err_put_func_inst_lb; + } + + sourcesink_driver.iConfiguration = strings_dev[USB_GZERO_SS_DESC].id; + loopback_driver.iConfiguration = strings_dev[USB_GZERO_LB_DESC].id; + + /* support autoresume for remote wakeup testing */ + sourcesink_driver.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP; + loopback_driver.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP; + sourcesink_driver.descriptors = NULL; + loopback_driver.descriptors = NULL; + if (autoresume) { + sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + } + + /* support OTG systems */ + if (gadget_is_otg(cdev->gadget)) { + sourcesink_driver.descriptors = otg_desc; + sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + loopback_driver.descriptors = otg_desc; + loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + } + /* Register primary, then secondary configuration. Note that * SH3 only allows one config... */ if (loopdefault) { - loopback_add(cdev, autoresume != 0); - sourcesink_add(cdev, autoresume != 0); + usb_add_config_only(cdev, &loopback_driver); + usb_add_config_only(cdev, &sourcesink_driver); } else { - sourcesink_add(cdev, autoresume != 0); - loopback_add(cdev, autoresume != 0); + usb_add_config_only(cdev, &sourcesink_driver); + usb_add_config_only(cdev, &loopback_driver); } + status = usb_add_function(&sourcesink_driver, func_ss); + if (status) + goto err_conf_flb; + + usb_ep_autoconfig_reset(cdev->gadget); + status = usb_add_function(&loopback_driver, func_lb); + if (status) + goto err_conf_flb; + usb_ep_autoconfig_reset(cdev->gadget); usb_composite_overwrite_options(cdev, &coverwrite); INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname); return 0; + +err_conf_flb: + usb_put_function(func_lb); + func_lb = NULL; +err_put_func_inst_lb: + usb_put_function_instance(func_inst_lb); + func_inst_lb = NULL; +err_put_func_ss: + usb_put_function(func_ss); + func_ss = NULL; +err_put_func_inst_ss: + usb_put_function_instance(func_inst_ss); + func_inst_ss = NULL; + return status; } static int zero_unbind(struct usb_composite_dev *cdev) { del_timer_sync(&autoresume_timer); + if (!IS_ERR_OR_NULL(func_ss)) + usb_put_function(func_ss); + if (!IS_ERR_OR_NULL(func_lb)) + usb_put_function(func_lb); return 0; } |