diff options
Diffstat (limited to 'drivers/usb/gadget')
78 files changed, 2526 insertions, 6408 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index e0ff51b89529..5a0c541daf89 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -281,6 +281,7 @@ config USB_S3C_HSOTG config USB_IMX tristate "Freescale i.MX1 USB Peripheral Controller" depends on ARCH_MXC + depends on BROKEN help Freescale's i.MX1 includes an integrated full speed USB 1.1 device controller. @@ -319,6 +320,7 @@ config USB_S3C_HSUDC config USB_MV_UDC tristate "Marvell USB2.0 Device Controller" + depends on GENERIC_HARDIRQS help Marvell Socs (including PXA and MMP series) include a high speed USB2.0 OTG controller, which can be configured as high speed or @@ -440,7 +442,7 @@ config USB_GOKU config USB_EG20T tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC" - depends on PCI + depends on PCI && GENERIC_HARDIRQS help This is a USB device driver for EG20T PCH. EG20T PCH is the platform controller hub that is used in Intel's @@ -500,6 +502,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 +535,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 @@ -721,31 +733,6 @@ config USB_FUNCTIONFS_GENERIC Include a configuration with the Function Filesystem alone with no Ethernet interface. -config USB_FILE_STORAGE - tristate "File-backed Storage Gadget (DEPRECATED)" - depends on BLOCK - help - The File-backed Storage Gadget acts as a USB Mass Storage - disk drive. As its storage repository it can use a regular - file or a block device (in much the same way as the "loop" - device driver), specified as a module parameter. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_file_storage". - - NOTE: This driver is deprecated. Its replacement is the - Mass Storage Gadget. - -config USB_FILE_STORAGE_TEST - bool "File-backed Storage Gadget testing version" - depends on USB_FILE_STORAGE - default n - help - Say "y" to generate the larger testing version of the - File-backed Storage Gadget, useful for probing the - behavior of USB Mass Storage hosts. Not needed for - normal operation. - config USB_MASS_STORAGE tristate "Mass Storage Gadget" depends on BLOCK @@ -756,8 +743,8 @@ config USB_MASS_STORAGE device (in much the same way as the "loop" device driver), specified as a module parameter or sysfs option. - This driver is an updated replacement for the deprecated - File-backed Storage Gadget (g_file_storage). + This driver is a replacement for now removed File-backed + Storage Gadget (g_file_storage). Say "y" to link the driver statically, or "m" to build a dynamically linked module called "g_mass_storage". @@ -775,6 +762,9 @@ config USB_GADGET_TARGET config USB_G_SERIAL tristate "Serial Gadget (with CDC ACM and CDC OBEX support)" + depends on TTY + select USB_U_SERIAL + select USB_F_ACM select USB_LIBCOMPOSITE help The Serial Gadget talks to the Linux-USB generic serial driver. @@ -824,10 +814,14 @@ config USB_G_PRINTER For more information, see Documentation/usb/gadget_printer.txt which includes sample code for accessing the device file. +if TTY + 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. @@ -843,6 +837,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. @@ -854,6 +849,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. @@ -866,6 +863,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 @@ -904,6 +903,8 @@ config USB_G_MULTI_CDC If unsure, say "y". +endif # TTY + config USB_G_HID tristate "HID Gadget" select USB_LIBCOMPOSITE @@ -920,6 +921,7 @@ config USB_G_HID # Standalone / single function gadgets config USB_G_DBGP tristate "EHCI Debug Device Gadget" + depends on TTY select USB_LIBCOMPOSITE help This gadget emulates an EHCI Debug device. This is useful when you want @@ -941,6 +943,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 307be5fa824c..82fb22511356 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 @@ -35,6 +35,12 @@ mv_udc-y := mv_udc_core.o obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.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 + # # USB gadget drivers # @@ -44,7 +50,6 @@ g_ether-y := ether.o g_serial-y := serial.o g_midi-y := gmidi.o gadgetfs-y := inode.o -g_file_storage-y := file_storage.o g_mass_storage-y := mass_storage.o g_printer-y := printer.o g_cdc-y := cdc2.o @@ -62,7 +67,6 @@ obj-$(CONFIG_USB_AUDIO) += g_audio.o obj-$(CONFIG_USB_ETH) += g_ether.o obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o obj-$(CONFIG_USB_FUNCTIONFS) += g_ffs.o -obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o obj-$(CONFIG_USB_MASS_STORAGE) += g_mass_storage.o obj-$(CONFIG_USB_G_SERIAL) += g_serial.o obj-$(CONFIG_USB_G_PRINTER) += g_printer.o diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c index 5a7f289805ff..8f2b0e391534 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 fc0ec5e0d58e..75973f33a4c8 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; } @@ -3231,7 +3200,7 @@ static int udc_pci_probe( } if (!pdev->irq) { - dev_err(&dev->pdev->dev, "irq not set\n"); + dev_err(&pdev->dev, "irq not set\n"); kfree(dev); dev = NULL; retval = -ENODEV; @@ -3250,7 +3219,7 @@ static int udc_pci_probe( dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR); if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) { - dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq); + dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq); kfree(dev); dev = NULL; retval = -EBUSY; diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h index 14af87d65caa..f1bf32e6b8d8 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 89d90b5fb787..45dd2929a671 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -31,6 +31,7 @@ #include <linux/usb/gadget.h> #include <linux/of.h> #include <linux/of_gpio.h> +#include <linux/platform_data/atmel.h> #include <asm/byteorder.h> #include <mach/hardware.h> @@ -38,7 +39,6 @@ #include <asm/irq.h> #include <asm/gpio.h> -#include <mach/board.h> #include <mach/cpu.h> #include <mach/at91sam9261_matrix.h> #include <mach/at91_matrix.h> @@ -51,7 +51,7 @@ * full speed USB controllers, including the at91rm9200 (arm920T, with MMU), * at91sam926x (arm926ejs, with MMU), and several no-mmu versions. * - * This driver expects the board has been wired with two GPIOs suppporting + * This driver expects the board has been wired with two GPIOs supporting * a VBUS sensing IRQ, and a D+ pullup. (They may be omitted, but the * testing hasn't covered such cases.) * @@ -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, @@ -1673,7 +1672,7 @@ static void at91udc_shutdown(struct platform_device *dev) spin_unlock_irqrestore(&udc->lock, flags); } -static void __devinit at91udc_of_init(struct at91_udc *udc, +static void at91udc_of_init(struct at91_udc *udc, struct device_node *np) { struct at91_udc_data *board = &udc->board; @@ -1693,7 +1692,7 @@ static void __devinit at91udc_of_init(struct at91_udc *udc, board->pullup_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0; } -static int __devinit at91udc_probe(struct platform_device *pdev) +static int at91udc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct at91_udc *udc; @@ -1739,7 +1738,7 @@ static int __devinit 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; @@ -1982,17 +1981,7 @@ static struct platform_driver at91_udc_driver = { }, }; -static int __init udc_init_module(void) -{ - return platform_driver_probe(&at91_udc_driver, at91udc_probe); -} -module_init(udc_init_module); - -static void __exit udc_exit_module(void) -{ - platform_driver_unregister(&at91_udc_driver); -} -module_exit(udc_exit_module); +module_platform_driver_probe(at91_udc_driver, at91udc_probe); MODULE_DESCRIPTION("AT91 udc driver"); MODULE_AUTHOR("Thomas Rathbone, David Brownell"); diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 9a9bced813ed..b66130c97269 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -21,9 +21,9 @@ #include <linux/usb/gadget.h> #include <linux/usb/atmel_usba_udc.h> #include <linux/delay.h> +#include <linux/platform_data/atmel.h> #include <asm/gpio.h> -#include <mach/board.h> #include "atmel_usba_udc.h" @@ -93,7 +93,7 @@ static ssize_t queue_dbg_read(struct file *file, char __user *buf, if (!access_ok(VERIFY_WRITE, buf, nbytes)) return -EFAULT; - mutex_lock(&file->f_dentry->d_inode->i_mutex); + mutex_lock(&file_inode(file)->i_mutex); list_for_each_entry_safe(req, tmp_req, queue, queue) { len = snprintf(tmpbuf, sizeof(tmpbuf), "%8p %08x %c%c%c %5d %c%c%c\n", @@ -120,7 +120,7 @@ static ssize_t queue_dbg_read(struct file *file, char __user *buf, nbytes -= len; buf += len; } - mutex_unlock(&file->f_dentry->d_inode->i_mutex); + mutex_unlock(&file_inode(file)->i_mutex); return actual; } @@ -168,13 +168,13 @@ out: static ssize_t regs_dbg_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file_inode(file); int ret; mutex_lock(&inode->i_mutex); ret = simple_read_from_buffer(buf, nbytes, ppos, file->private_data, - file->f_dentry->d_inode->i_size); + file_inode(file)->i_size); mutex_unlock(&inode->i_mutex); return ret; @@ -2066,17 +2066,7 @@ static struct platform_driver udc_driver = { }, }; -static int __init udc_init(void) -{ - return platform_driver_probe(&udc_driver, usba_udc_probe); -} -module_init(udc_init); - -static void __exit udc_exit(void) -{ - platform_driver_unregister(&udc_driver); -} -module_exit(udc_exit); +module_platform_driver_probe(udc_driver, usba_udc_probe); MODULE_DESCRIPTION("Atmel USBA UDC driver"); MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c index 9ca792224cd4..8cc8253f1100 100644 --- a/drivers/usb/gadget/bcm63xx_udc.c +++ b/drivers/usb/gadget/bcm63xx_udc.c @@ -2323,7 +2323,7 @@ static void bcm63xx_udc_gadget_release(struct device *dev) * Note that platform data is required, because pd.port_no varies from chip * to chip and is used to switch the correct USB port to device mode. */ -static int __devinit bcm63xx_udc_probe(struct platform_device *pdev) +static int bcm63xx_udc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct bcm63xx_usbd_platform_data *pd = dev->platform_data; @@ -2351,19 +2351,20 @@ static int __devinit bcm63xx_udc_probe(struct platform_device *pdev) dev_err(dev, "error finding USBD resource\n"); return -ENXIO; } - udc->usbd_regs = devm_request_and_ioremap(dev, res); + + udc->usbd_regs = devm_ioremap_resource(dev, res); + if (IS_ERR(udc->usbd_regs)) + return PTR_ERR(udc->usbd_regs); res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!res) { dev_err(dev, "error finding IUDMA resource\n"); return -ENXIO; } - udc->iudma_regs = devm_request_and_ioremap(dev, res); - if (!udc->usbd_regs || !udc->iudma_regs) { - dev_err(dev, "error requesting resources\n"); - return -ENXIO; - } + udc->iudma_regs = devm_ioremap_resource(dev, res); + if (IS_ERR(udc->iudma_regs)) + return PTR_ERR(udc->iudma_regs); spin_lock_init(&udc->lock); INIT_WORK(&udc->ep0_wq, bcm63xx_ep0_process); @@ -2433,7 +2434,7 @@ out_uninit: * bcm63xx_udc_remove - Remove the device from the system. * @pdev: Platform device struct from the bcm63xx BSP code. */ -static int __devexit bcm63xx_udc_remove(struct platform_device *pdev) +static int bcm63xx_udc_remove(struct platform_device *pdev) { struct bcm63xx_udc *udc = platform_get_drvdata(pdev); @@ -2450,7 +2451,7 @@ static int __devexit bcm63xx_udc_remove(struct platform_device *pdev) static struct platform_driver bcm63xx_udc_driver = { .probe = bcm63xx_udc_probe, - .remove = __devexit_p(bcm63xx_udc_remove), + .remove = bcm63xx_udc_remove, .driver = { .name = DRV_MODULE_NAME, .owner = THIS_MODULE, diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c index 1e4bb77f00bb..a7d6f7026757 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 957f973dd96a..c0d62b278610 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 @@ -107,7 +113,7 @@ int config_ep_by_speed(struct usb_gadget *g, } /* else: fall through */ default: - speed_desc = f->descriptors; + speed_desc = f->fs_descriptors; } /* find descriptors */ for_each_ep_desc(speed_desc, d_spd) { @@ -200,7 +206,7 @@ int usb_add_function(struct usb_configuration *config, * as full speed ... it's the function drivers that will need * to avoid bulk and ISO transfers. */ - if (!config->fullspeed && function->descriptors) + if (!config->fullspeed && function->fs_descriptors) config->fullspeed = true; if (!config->highspeed && function->hs_descriptors) config->highspeed = true; @@ -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) { @@ -363,7 +400,7 @@ static int config_buf(struct usb_configuration *config, descriptors = f->hs_descriptors; break; default: - descriptors = f->descriptors; + descriptors = f->fs_descriptors; } if (!descriptors) @@ -620,7 +657,7 @@ static int set_config(struct usb_composite_dev *cdev, descriptors = f->hs_descriptors; break; default: - descriptors = f->descriptors; + descriptors = f->fs_descriptors; } for (; *descriptors; ++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) +int composite_dev_prepare(struct usb_composite_driver *composite, + struct usb_composite_dev *cdev) { - return container_of(gdrv, struct usb_composite_driver, gadget_driver); -} - -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); + 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; @@ -1547,10 +1757,7 @@ static const struct usb_gadget_driver composite_driver_template = { /** * usb_composite_probe() - register a composite driver * @driver: the driver to register - * @bind: the callback used to allocate resources that are shared across the - * whole device, such as string IDs, and add its configurations using - * @usb_add_config(). This may fail by returning a negative errno - * value; it should return zero on successful initialization. + * * Context: single threaded during gadget setup * * This function is used to register drivers using the composite driver diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index e3a98929d346..34e12fc52c23 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -19,7 +19,7 @@ #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> - +#include <linux/usb/composite.h> /** * usb_descriptor_fillbuf - fill buffer with descriptors @@ -158,3 +158,40 @@ usb_copy_descriptors(struct usb_descriptor_header **src) return ret; } EXPORT_SYMBOL_GPL(usb_copy_descriptors); + +int usb_assign_descriptors(struct usb_function *f, + struct usb_descriptor_header **fs, + struct usb_descriptor_header **hs, + struct usb_descriptor_header **ss) +{ + struct usb_gadget *g = f->config->cdev->gadget; + + if (fs) { + f->fs_descriptors = usb_copy_descriptors(fs); + if (!f->fs_descriptors) + goto err; + } + if (hs && gadget_is_dualspeed(g)) { + f->hs_descriptors = usb_copy_descriptors(hs); + if (!f->hs_descriptors) + goto err; + } + if (ss && gadget_is_superspeed(g)) { + f->ss_descriptors = usb_copy_descriptors(ss); + if (!f->ss_descriptors) + goto err; + } + return 0; +err: + usb_free_all_descriptors(f); + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(usb_assign_descriptors); + +void usb_free_all_descriptors(struct usb_function *f) +{ + usb_free_descriptors(f->fs_descriptors); + usb_free_descriptors(f->hs_descriptors); + usb_free_descriptors(f->ss_descriptors); +} +EXPORT_SYMBOL_GPL(usb_free_all_descriptors); diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c index 87d165028162..986fc511a2ed 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/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 0f7541be28f3..8cf0c0f6fa1f 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -63,16 +63,20 @@ MODULE_LICENSE("GPL"); struct dummy_hcd_module_parameters { bool is_super_speed; bool is_high_speed; + unsigned int num; }; static struct dummy_hcd_module_parameters mod_data = { .is_super_speed = false, .is_high_speed = true, + .num = 1, }; module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO); MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection"); module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO); MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection"); +module_param_named(num, mod_data.num, uint, S_IRUGO); +MODULE_PARM_DESC(num, "number of emulated controllers"); /*-------------------------------------------------------------------------*/ /* gadget side driver data structres */ @@ -126,10 +130,7 @@ static const char ep0name[] = "ep0"; static const char *const ep_name[] = { ep0name, /* everyone has ep0 */ - /* act like a net2280: high speed, six configurable endpoints */ - "ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f", - - /* or like pxa250: fifteen fixed function endpoints */ + /* act like a pxa250: fifteen fixed function endpoints */ "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int", "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int", "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso", @@ -137,6 +138,10 @@ static const char *const ep_name[] = { /* or like sa1100: two fixed function endpoints */ "ep1out-bulk", "ep2in-bulk", + + /* and now some generic EPs so we have enough in multi config */ + "ep3out", "ep4in", "ep5out", "ep6out", "ep7in", "ep8out", "ep9in", + "ep10out", "ep11out", "ep12in", "ep13out", "ep14in", "ep15out", }; #define DUMMY_ENDPOINTS ARRAY_SIZE(ep_name) @@ -238,8 +243,6 @@ static inline struct dummy *gadget_dev_to_dummy(struct device *dev) return container_of(dev, struct dummy, gadget.dev); } -static struct dummy the_controller; - /*-------------------------------------------------------------------------*/ /* SLAVE/GADGET SIDE UTILITY ROUTINES */ @@ -973,9 +976,10 @@ static void init_dummy_udc_hw(struct dummy *dum) static int dummy_udc_probe(struct platform_device *pdev) { - struct dummy *dum = &the_controller; + struct dummy *dum; int rc; + dum = *((void **)dev_get_platdata(&pdev->dev)); dum->gadget.name = gadget_name; dum->gadget.ops = &dummy_ops; dum->gadget.max_speed = USB_SPEED_SUPER; @@ -2398,10 +2402,13 @@ static int dummy_h_get_frame(struct usb_hcd *hcd) static int dummy_setup(struct usb_hcd *hcd) { + struct dummy *dum; + + dum = *((void **)dev_get_platdata(hcd->self.controller)); hcd->self.sg_tablesize = ~0; if (usb_hcd_is_primary_hcd(hcd)) { - the_controller.hs_hcd = hcd_to_dummy_hcd(hcd); - the_controller.hs_hcd->dum = &the_controller; + dum->hs_hcd = hcd_to_dummy_hcd(hcd); + dum->hs_hcd->dum = dum; /* * Mark the first roothub as being USB 2.0. * The USB 3.0 roothub will be registered later by @@ -2410,8 +2417,8 @@ static int dummy_setup(struct usb_hcd *hcd) hcd->speed = HCD_USB2; hcd->self.root_hub->speed = USB_SPEED_HIGH; } else { - the_controller.ss_hcd = hcd_to_dummy_hcd(hcd); - the_controller.ss_hcd->dum = &the_controller; + dum->ss_hcd = hcd_to_dummy_hcd(hcd); + dum->ss_hcd->dum = dum; hcd->speed = HCD_USB3; hcd->self.root_hub->speed = USB_SPEED_SUPER; } @@ -2524,11 +2531,13 @@ static struct hc_driver dummy_hcd = { static int dummy_hcd_probe(struct platform_device *pdev) { + struct dummy *dum; struct usb_hcd *hs_hcd; struct usb_hcd *ss_hcd; int retval; dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc); + dum = *((void **)dev_get_platdata(&pdev->dev)); if (!mod_data.is_super_speed) dummy_hcd.flags = HCD_USB2; @@ -2561,7 +2570,7 @@ dealloc_usb2_hcd: usb_remove_hcd(hs_hcd); put_usb2_hcd: usb_put_hcd(hs_hcd); - the_controller.hs_hcd = the_controller.ss_hcd = NULL; + dum->hs_hcd = dum->ss_hcd = NULL; return retval; } @@ -2579,8 +2588,8 @@ static int dummy_hcd_remove(struct platform_device *pdev) usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd)); usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd)); - the_controller.hs_hcd = NULL; - the_controller.ss_hcd = NULL; + dum->hs_hcd = NULL; + dum->ss_hcd = NULL; return 0; } @@ -2627,13 +2636,15 @@ static struct platform_driver dummy_hcd_driver = { }; /*-------------------------------------------------------------------------*/ - -static struct platform_device *the_udc_pdev; -static struct platform_device *the_hcd_pdev; +#define MAX_NUM_UDC 2 +static struct platform_device *the_udc_pdev[MAX_NUM_UDC]; +static struct platform_device *the_hcd_pdev[MAX_NUM_UDC]; static int __init init(void) { int retval = -ENOMEM; + int i; + struct dummy *dum[MAX_NUM_UDC]; if (usb_disabled()) return -ENODEV; @@ -2641,65 +2652,129 @@ static int __init init(void) if (!mod_data.is_high_speed && mod_data.is_super_speed) return -EINVAL; - the_hcd_pdev = platform_device_alloc(driver_name, -1); - if (!the_hcd_pdev) - return retval; - the_udc_pdev = platform_device_alloc(gadget_name, -1); - if (!the_udc_pdev) - goto err_alloc_udc; + if (mod_data.num < 1 || mod_data.num > MAX_NUM_UDC) { + pr_err("Number of emulated UDC must be in range of 1…%d\n", + MAX_NUM_UDC); + return -EINVAL; + } + + for (i = 0; i < mod_data.num; i++) { + the_hcd_pdev[i] = platform_device_alloc(driver_name, i); + if (!the_hcd_pdev[i]) { + i--; + while (i >= 0) + platform_device_put(the_hcd_pdev[i--]); + return retval; + } + } + for (i = 0; i < mod_data.num; i++) { + the_udc_pdev[i] = platform_device_alloc(gadget_name, i); + if (!the_udc_pdev[i]) { + i--; + while (i >= 0) + platform_device_put(the_udc_pdev[i--]); + goto err_alloc_udc; + } + } + for (i = 0; i < mod_data.num; i++) { + dum[i] = kzalloc(sizeof(struct dummy), GFP_KERNEL); + if (!dum[i]) + goto err_add_pdata; + retval = platform_device_add_data(the_hcd_pdev[i], &dum[i], + sizeof(void *)); + if (retval) + goto err_add_pdata; + retval = platform_device_add_data(the_udc_pdev[i], &dum[i], + sizeof(void *)); + if (retval) + goto err_add_pdata; + } retval = platform_driver_register(&dummy_hcd_driver); if (retval < 0) - goto err_register_hcd_driver; + goto err_add_pdata; retval = platform_driver_register(&dummy_udc_driver); if (retval < 0) goto err_register_udc_driver; - retval = platform_device_add(the_hcd_pdev); - if (retval < 0) - goto err_add_hcd; - if (!the_controller.hs_hcd || - (!the_controller.ss_hcd && mod_data.is_super_speed)) { - /* - * The hcd was added successfully but its probe function failed - * for some reason. - */ - retval = -EINVAL; - goto err_add_udc; + for (i = 0; i < mod_data.num; i++) { + retval = platform_device_add(the_hcd_pdev[i]); + if (retval < 0) { + i--; + while (i >= 0) + platform_device_del(the_hcd_pdev[i--]); + goto err_add_hcd; + } } - retval = platform_device_add(the_udc_pdev); - if (retval < 0) - goto err_add_udc; - if (!platform_get_drvdata(the_udc_pdev)) { - /* - * The udc was added successfully but its probe function failed - * for some reason. - */ - retval = -EINVAL; - goto err_probe_udc; + for (i = 0; i < mod_data.num; i++) { + if (!dum[i]->hs_hcd || + (!dum[i]->ss_hcd && mod_data.is_super_speed)) { + /* + * The hcd was added successfully but its probe + * function failed for some reason. + */ + retval = -EINVAL; + goto err_add_udc; + } + } + + for (i = 0; i < mod_data.num; i++) { + retval = platform_device_add(the_udc_pdev[i]); + if (retval < 0) { + i--; + while (i >= 0) + platform_device_del(the_udc_pdev[i]); + goto err_add_udc; + } + } + + for (i = 0; i < mod_data.num; i++) { + if (!platform_get_drvdata(the_udc_pdev[i])) { + /* + * The udc was added successfully but its probe + * function failed for some reason. + */ + retval = -EINVAL; + goto err_probe_udc; + } } return retval; err_probe_udc: - platform_device_del(the_udc_pdev); + for (i = 0; i < mod_data.num; i++) + platform_device_del(the_udc_pdev[i]); err_add_udc: - platform_device_del(the_hcd_pdev); + for (i = 0; i < mod_data.num; i++) + platform_device_del(the_hcd_pdev[i]); err_add_hcd: platform_driver_unregister(&dummy_udc_driver); err_register_udc_driver: platform_driver_unregister(&dummy_hcd_driver); -err_register_hcd_driver: - platform_device_put(the_udc_pdev); +err_add_pdata: + for (i = 0; i < mod_data.num; i++) + kfree(dum[i]); + for (i = 0; i < mod_data.num; i++) + platform_device_put(the_udc_pdev[i]); err_alloc_udc: - platform_device_put(the_hcd_pdev); + for (i = 0; i < mod_data.num; i++) + platform_device_put(the_hcd_pdev[i]); return retval; } module_init(init); static void __exit cleanup(void) { - platform_device_unregister(the_udc_pdev); - platform_device_unregister(the_hcd_pdev); + int i; + + for (i = 0; i < mod_data.num; i++) { + struct dummy *dum; + + dum = *((void **)dev_get_platdata(&the_udc_pdev[i]->dev)); + + platform_device_unregister(the_udc_pdev[i]); + platform_device_unregister(the_hcd_pdev[i]); + kfree(dum); + } platform_driver_unregister(&dummy_udc_driver); platform_driver_unregister(&dummy_hcd_driver); } diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index d672250a61fa..1ae180baa597 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" @@ -87,7 +89,7 @@ static inline struct f_acm *port_to_acm(struct gserial *p) /* notification endpoint uses smallish and infrequent fixed-size messages */ -#define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */ +#define GS_NOTIFY_INTERVAL_MS 32 #define GS_NOTIFY_MAXPACKET 10 /* notification + 2 bytes */ /* interface and class descriptors: */ @@ -167,7 +169,7 @@ static struct usb_endpoint_descriptor acm_fs_notify_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET), - .bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL, + .bInterval = GS_NOTIFY_INTERVAL_MS, }; static struct usb_endpoint_descriptor acm_fs_in_desc = { @@ -199,14 +201,13 @@ static struct usb_descriptor_header *acm_fs_function[] = { }; /* high speed support: */ - static struct usb_endpoint_descriptor acm_hs_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET), - .bInterval = GS_LOG2_NOTIFY_INTERVAL+4, + .bInterval = USB_MS_TO_HS_INTERVAL(GS_NOTIFY_INTERVAL_MS), }; static struct usb_endpoint_descriptor acm_hs_in_desc = { @@ -284,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 = { @@ -606,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) @@ -659,37 +673,22 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) acm->notify_req->complete = acm_cdc_notify_complete; acm->notify_req->context = acm; - /* copy descriptors */ - f->descriptors = usb_copy_descriptors(acm_fs_function); - if (!f->descriptors) - goto fail; - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - acm_hs_in_desc.bEndpointAddress = - acm_fs_in_desc.bEndpointAddress; - acm_hs_out_desc.bEndpointAddress = - acm_fs_out_desc.bEndpointAddress; - acm_hs_notify_desc.bEndpointAddress = - acm_fs_notify_desc.bEndpointAddress; - - /* copy descriptors */ - f->hs_descriptors = usb_copy_descriptors(acm_hs_function); - } - if (gadget_is_superspeed(c->cdev->gadget)) { - acm_ss_in_desc.bEndpointAddress = - acm_fs_in_desc.bEndpointAddress; - acm_ss_out_desc.bEndpointAddress = - acm_fs_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(acm_ss_function); - if (!f->ss_descriptors) - goto fail; - } + acm_hs_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress; + acm_hs_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress; + acm_hs_notify_desc.bEndpointAddress = + acm_fs_notify_desc.bEndpointAddress; + + acm_ss_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress; + acm_ss_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress; + + status = usb_assign_descriptors(f, acm_fs_function, acm_hs_function, + acm_ss_function); + if (status) + goto fail; DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n", acm->port_num, @@ -716,25 +715,40 @@ fail: return status; } -static void -acm_unbind(struct usb_configuration *c, struct usb_function *f) +static struct f_acm *acm_alloc_basic_func(void) { - struct f_acm *acm = func_to_acm(f); + struct f_acm *acm; - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - if (gadget_is_superspeed(c->cdev->gadget)) - usb_free_descriptors(f->ss_descriptors); - usb_free_descriptors(f->descriptors); - gs_free_req(acm->notify, acm->notify_req); - kfree(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; } -/* Some controllers can't support CDC ACM ... */ -static inline bool can_support_cdc(struct usb_configuration *c) +#ifdef USB_FACM_INCLUDED +static void +acm_old_unbind(struct usb_configuration *c, struct usb_function *f) { - /* everything else is *probably* fine ... */ - return true; + struct f_acm *acm = func_to_acm(f); + + usb_free_all_descriptors(f); + if (acm->notify_req) + gs_free_req(acm->notify, acm->notify_req); + kfree(acm); } /** @@ -745,70 +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; + /* allocate and initialize one new instance */ + acm = acm_alloc_basic_func(); + if (!acm) + return -ENOMEM; - /* REVISIT might want instance-specific strings to help - * distinguish instances ... - */ + acm->port_num = port_num; + acm->port.func.unbind = acm_old_unbind; - /* maybe allocate device-global string IDs, and patch descriptors */ - if (acm_string_defs[ACM_CTRL_IDX].id == 0) { - status = usb_string_id(c->cdev); - if (status < 0) - return status; - acm_string_defs[ACM_CTRL_IDX].id = status; + status = usb_add_function(c, &acm->port.func); + if (status) + kfree(acm); + return status; +} - acm_control_interface_desc.iInterface = status; +#else - status = usb_string_id(c->cdev); - if (status < 0) - return status; - acm_string_defs[ACM_DATA_IDX].id = status; +static void acm_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_acm *acm = func_to_acm(f); - acm_data_interface_desc.iInterface = status; + acm_string_defs[0].id = 0; + usb_free_all_descriptors(f); + if (acm->notify_req) + gs_free_req(acm->notify, acm->notify_req); +} - status = usb_string_id(c->cdev); - if (status < 0) - return status; - acm_string_defs[ACM_IAD_IDX].id = status; +static void acm_free_func(struct usb_function *f) +{ + struct f_acm *acm = func_to_acm(f); - acm_iad_descriptor.iFunction = status; - } + kfree(acm); +} - /* allocate and initialize one new instance */ - acm = kzalloc(sizeof *acm, GFP_KERNEL); +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 -ENOMEM; + return ERR_PTR(-ENOMEM); - spin_lock_init(&acm->lock); + 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; - acm->port_num = port_num; + return &acm->port.func; +} - acm->port.connect = acm_connect; - acm->port.disconnect = acm_disconnect; - acm->port.send_break = acm_send_break; +static void acm_free_instance(struct usb_function_instance *fi) +{ + struct f_serial_opts *opts; - 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; + opts = container_of(fi, struct f_serial_opts, func_inst); + kfree(opts); +} - status = usb_add_function(c, &acm->port.func); - if (status) - kfree(acm); - return status; +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_ecm.c b/drivers/usb/gadget/f_ecm.c index 95bc94f8e570..83420a310fb7 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -91,7 +91,7 @@ static inline unsigned ecm_bitrate(struct usb_gadget *g) * encapsulated commands (vendor-specific, using control-OUT). */ -#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ +#define ECM_STATUS_INTERVAL_MS 32 #define ECM_STATUS_BYTECOUNT 16 /* 8 byte header + data */ @@ -192,7 +192,7 @@ static struct usb_endpoint_descriptor fs_ecm_notify_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT), - .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, + .bInterval = ECM_STATUS_INTERVAL_MS, }; static struct usb_endpoint_descriptor fs_ecm_in_desc = { @@ -239,7 +239,7 @@ static struct usb_endpoint_descriptor hs_ecm_notify_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, + .bInterval = USB_MS_TO_HS_INTERVAL(ECM_STATUS_INTERVAL_MS), }; static struct usb_endpoint_descriptor hs_ecm_in_desc = { @@ -288,7 +288,7 @@ static struct usb_endpoint_descriptor ss_ecm_notify_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, + .bInterval = USB_MS_TO_HS_INTERVAL(ECM_STATUS_INTERVAL_MS), }; static struct usb_ss_ep_comp_descriptor ss_ecm_intr_comp_desc = { @@ -330,6 +330,7 @@ static struct usb_ss_ep_comp_descriptor ss_ecm_bulk_comp_desc = { static struct usb_descriptor_header *ecm_ss_function[] = { /* CDC ECM control descriptors */ + (struct usb_descriptor_header *) &ecm_iad_descriptor, (struct usb_descriptor_header *) &ecm_control_intf, (struct usb_descriptor_header *) &ecm_header_desc, (struct usb_descriptor_header *) &ecm_union_desc, @@ -353,7 +354,7 @@ static struct usb_descriptor_header *ecm_ss_function[] = { static struct usb_string ecm_string_defs[] = { [0].s = "CDC Ethernet Control Model (ECM)", - [1].s = NULL /* DYNAMIC */, + [1].s = "", [2].s = "CDC Ethernet Data", [3].s = "CDC ECM", { } /* end of list */ @@ -742,42 +743,24 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) ecm->notify_req->context = ecm; ecm->notify_req->complete = ecm_notify_complete; - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(ecm_fs_function); - if (!f->descriptors) - goto fail; - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_ecm_in_desc.bEndpointAddress = - fs_ecm_in_desc.bEndpointAddress; - hs_ecm_out_desc.bEndpointAddress = - fs_ecm_out_desc.bEndpointAddress; - hs_ecm_notify_desc.bEndpointAddress = - fs_ecm_notify_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(ecm_hs_function); - if (!f->hs_descriptors) - goto fail; - } - - if (gadget_is_superspeed(c->cdev->gadget)) { - ss_ecm_in_desc.bEndpointAddress = - fs_ecm_in_desc.bEndpointAddress; - ss_ecm_out_desc.bEndpointAddress = - fs_ecm_out_desc.bEndpointAddress; - ss_ecm_notify_desc.bEndpointAddress = - fs_ecm_notify_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(ecm_ss_function); - if (!f->ss_descriptors) - goto fail; - } + hs_ecm_in_desc.bEndpointAddress = fs_ecm_in_desc.bEndpointAddress; + hs_ecm_out_desc.bEndpointAddress = fs_ecm_out_desc.bEndpointAddress; + hs_ecm_notify_desc.bEndpointAddress = + fs_ecm_notify_desc.bEndpointAddress; + + ss_ecm_in_desc.bEndpointAddress = fs_ecm_in_desc.bEndpointAddress; + ss_ecm_out_desc.bEndpointAddress = fs_ecm_out_desc.bEndpointAddress; + ss_ecm_notify_desc.bEndpointAddress = + fs_ecm_notify_desc.bEndpointAddress; + + status = usb_assign_descriptors(f, ecm_fs_function, ecm_hs_function, + ecm_ss_function); + if (status) + goto fail; /* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code @@ -795,11 +778,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) return 0; fail: - if (f->descriptors) - usb_free_descriptors(f->descriptors); - if (f->hs_descriptors) - usb_free_descriptors(f->hs_descriptors); - if (ecm->notify_req) { kfree(ecm->notify_req->buf); usb_ep_free_request(ecm->notify, ecm->notify_req); @@ -808,9 +786,9 @@ fail: /* we might as well release our claims on endpoints */ if (ecm->notify) ecm->notify->driver_data = NULL; - if (ecm->port.out_ep->desc) + if (ecm->port.out_ep) ecm->port.out_ep->driver_data = NULL; - if (ecm->port.in_ep->desc) + if (ecm->port.in_ep) ecm->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); @@ -825,16 +803,11 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f) DBG(c->cdev, "ecm unbind\n"); - if (gadget_is_superspeed(c->cdev->gadget)) - usb_free_descriptors(f->ss_descriptors); - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); + ecm_string_defs[0].id = 0; + usb_free_all_descriptors(f); kfree(ecm->notify_req->buf); usb_ep_free_request(ecm->notify, ecm->notify_req); - - ecm_string_defs[1].s = NULL; kfree(ecm); } @@ -859,36 +832,15 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) if (!can_support_ecm(c->cdev->gadget) || !ethaddr) return -EINVAL; - /* maybe allocate device-global string IDs */ if (ecm_string_defs[0].id == 0) { - - /* control interface label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ecm_string_defs[0].id = status; - ecm_control_intf.iInterface = status; - - /* data interface label */ - status = usb_string_id(c->cdev); - if (status < 0) + status = usb_string_ids_tab(c->cdev, ecm_string_defs); + if (status) return status; - ecm_string_defs[2].id = status; - ecm_data_intf.iInterface = status; - /* MAC address */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ecm_string_defs[1].id = status; - ecm_desc.iMACAddress = status; - - /* IAD label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ecm_string_defs[3].id = status; - ecm_iad_descriptor.iFunction = status; + ecm_control_intf.iInterface = ecm_string_defs[0].id; + ecm_data_intf.iInterface = ecm_string_defs[2].id; + ecm_desc.iMACAddress = ecm_string_defs[1].id; + ecm_iad_descriptor.iFunction = ecm_string_defs[3].id; } /* allocate and initialize one new instance */ @@ -913,9 +865,7 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) ecm->port.func.disable = ecm_disable; status = usb_add_function(c, &ecm->port.func); - if (status) { - ecm_string_defs[1].s = NULL; + if (status) kfree(ecm); - } return status; } diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index 1a7b2dd7d408..cf0ebee85563 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -274,38 +274,20 @@ eem_bind(struct usb_configuration *c, struct usb_function *f) status = -ENOMEM; - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(eem_fs_function); - if (!f->descriptors) - goto fail; - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - eem_hs_in_desc.bEndpointAddress = - eem_fs_in_desc.bEndpointAddress; - eem_hs_out_desc.bEndpointAddress = - eem_fs_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(eem_hs_function); - if (!f->hs_descriptors) - goto fail; - } + eem_hs_in_desc.bEndpointAddress = eem_fs_in_desc.bEndpointAddress; + eem_hs_out_desc.bEndpointAddress = eem_fs_out_desc.bEndpointAddress; - if (gadget_is_superspeed(c->cdev->gadget)) { - eem_ss_in_desc.bEndpointAddress = - eem_fs_in_desc.bEndpointAddress; - eem_ss_out_desc.bEndpointAddress = - eem_fs_out_desc.bEndpointAddress; + eem_ss_in_desc.bEndpointAddress = eem_fs_in_desc.bEndpointAddress; + eem_ss_out_desc.bEndpointAddress = eem_fs_out_desc.bEndpointAddress; - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(eem_ss_function); - if (!f->ss_descriptors) - goto fail; - } + status = usb_assign_descriptors(f, eem_fs_function, eem_hs_function, + eem_ss_function); + if (status) + goto fail; DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n", gadget_is_superspeed(c->cdev->gadget) ? "super" : @@ -314,15 +296,10 @@ eem_bind(struct usb_configuration *c, struct usb_function *f) return 0; fail: - if (f->descriptors) - usb_free_descriptors(f->descriptors); - if (f->hs_descriptors) - usb_free_descriptors(f->hs_descriptors); - - /* we might as well release our claims on endpoints */ - if (eem->port.out_ep->desc) + usb_free_all_descriptors(f); + if (eem->port.out_ep) eem->port.out_ep->driver_data = NULL; - if (eem->port.in_ep->desc) + if (eem->port.in_ep) eem->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); @@ -337,11 +314,7 @@ eem_unbind(struct usb_configuration *c, struct usb_function *f) DBG(c->cdev, "eem unbind\n"); - if (gadget_is_superspeed(c->cdev->gadget)) - usb_free_descriptors(f->ss_descriptors); - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); + usb_free_all_descriptors(f); kfree(eem); } diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 64c4ec10d1fc..c377ff84bf2c 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; } @@ -1153,15 +1152,15 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts) pr_err("%s: unmapped value: %lu\n", opts, value); return -EINVAL; } - } - else if (!memcmp(opts, "gid", 3)) + } else if (!memcmp(opts, "gid", 3)) { data->perms.gid = make_kgid(current_user_ns(), value); if (!gid_valid(data->perms.gid)) { pr_err("%s: unmapped value: %lu\n", opts, value); return -EINVAL; } - else + } else { goto invalid; + } break; default: @@ -1236,6 +1235,7 @@ static struct file_system_type ffs_fs_type = { .mount = ffs_fs_mount, .kill_sb = ffs_fs_kill_sb, }; +MODULE_ALIAS_FS("functionfs"); /* Driver's main init/cleanup functions *************************************/ @@ -2097,7 +2097,7 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, if (isHS) func->function.hs_descriptors[(long)valuep] = desc; else - func->function.descriptors[(long)valuep] = desc; + func->function.fs_descriptors[(long)valuep] = desc; if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT) return 0; @@ -2249,7 +2249,7 @@ static int ffs_func_bind(struct usb_configuration *c, * numbers without worrying that it may be described later on. */ if (likely(full)) { - func->function.descriptors = data->fs_descs; + func->function.fs_descriptors = data->fs_descs; ret = ffs_do_descs(ffs->fs_descs_count, data->raw_descs, sizeof data->raw_descs, diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c index 511e527178e2..6e69a8e8d22a 100644 --- a/drivers/usb/gadget/f_hid.c +++ b/drivers/usb/gadget/f_hid.c @@ -573,7 +573,6 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) goto fail; hidg_interface_desc.bInterfaceNumber = status; - /* allocate instance-specific endpoints */ status = -ENODEV; ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_in_ep_desc); @@ -609,20 +608,15 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) hidg_desc.desc[0].wDescriptorLength = cpu_to_le16(hidg->report_desc_length); - /* copy descriptors */ - f->descriptors = usb_copy_descriptors(hidg_fs_descriptors); - if (!f->descriptors) - goto fail; + hidg_hs_in_ep_desc.bEndpointAddress = + hidg_fs_in_ep_desc.bEndpointAddress; + hidg_hs_out_ep_desc.bEndpointAddress = + hidg_fs_out_ep_desc.bEndpointAddress; - if (gadget_is_dualspeed(c->cdev->gadget)) { - hidg_hs_in_ep_desc.bEndpointAddress = - hidg_fs_in_ep_desc.bEndpointAddress; - hidg_hs_out_ep_desc.bEndpointAddress = - hidg_fs_out_ep_desc.bEndpointAddress; - f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors); - if (!f->hs_descriptors) - goto fail; - } + status = usb_assign_descriptors(f, hidg_fs_descriptors, + hidg_hs_descriptors, NULL); + if (status) + goto fail; mutex_init(&hidg->lock); spin_lock_init(&hidg->spinlock); @@ -649,9 +643,7 @@ fail: usb_ep_free_request(hidg->in_ep, hidg->req); } - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); - + usb_free_all_descriptors(f); return status; } @@ -668,9 +660,7 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) kfree(hidg->req->buf); usb_ep_free_request(hidg->in_ep, hidg->req); - /* free descriptors copies */ - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); + usb_free_all_descriptors(f); kfree(hidg->report_desc); kfree(hidg); diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index 7275706caeb0..4a3873a0f2d0 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,12 +171,12 @@ 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); int id; + int ret; /* allocate interface ID(s) */ id = usb_interface_id(c, f); @@ -184,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); @@ -201,22 +207,19 @@ autoconf_fail: loop->out_ep->driver_data = cdev; /* claim */ /* support high speed hardware */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_loop_source_desc.bEndpointAddress = - fs_loop_source_desc.bEndpointAddress; - hs_loop_sink_desc.bEndpointAddress = - fs_loop_sink_desc.bEndpointAddress; - f->hs_descriptors = hs_loopback_descs; - } + hs_loop_source_desc.bEndpointAddress = + fs_loop_source_desc.bEndpointAddress; + hs_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress; /* support super speed hardware */ - if (gadget_is_superspeed(c->cdev->gadget)) { - ss_loop_source_desc.bEndpointAddress = - fs_loop_source_desc.bEndpointAddress; - ss_loop_sink_desc.bEndpointAddress = - fs_loop_sink_desc.bEndpointAddress; - f->ss_descriptors = ss_loopback_descs; - } + ss_loop_source_desc.bEndpointAddress = + fs_loop_source_desc.bEndpointAddress; + ss_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress; + + ret = usb_assign_descriptors(f, fs_loopback_descs, hs_loopback_descs, + ss_loopback_descs); + if (ret) + return ret; DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", (gadget_is_superspeed(c->cdev->gadget) ? "super" : @@ -225,9 +228,9 @@ 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)); } @@ -367,64 +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.descriptors = fs_loopback_descs; 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 3a7668bde3ef..97666e8b1b95 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -228,10 +228,6 @@ static const char fsg_string_interface[] = "Mass Storage"; -#define FSG_NO_DEVICE_STRINGS 1 -#define FSG_NO_OTG 1 -#define FSG_NO_INTR_EP 1 - #include "storage_common.c" @@ -250,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. */ @@ -996,7 +978,7 @@ static int do_synchronize_cache(struct fsg_common *common) static void invalidate_sub(struct fsg_lun *curlun) { struct file *filp = curlun->filp; - struct inode *inode = filp->f_path.dentry->d_inode; + struct inode *inode = file_inode(filp); unsigned long rc; rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); @@ -1378,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) @@ -1722,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; @@ -1788,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 */ @@ -1808,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; } } @@ -2200,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; @@ -2904,9 +2873,7 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) } fsg_common_put(common); - usb_free_descriptors(fsg->function.descriptors); - usb_free_descriptors(fsg->function.hs_descriptors); - usb_free_descriptors(fsg->function.ss_descriptors); + usb_free_all_descriptors(&fsg->function); kfree(fsg); } @@ -2916,6 +2883,8 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) struct usb_gadget *gadget = c->cdev->gadget; int i; struct usb_ep *ep; + unsigned max_burst; + int ret; fsg->gadget = gadget; @@ -2939,45 +2908,27 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) ep->driver_data = fsg->common; /* claim the endpoint */ fsg->bulk_out = ep; - /* Copy descriptors */ - f->descriptors = usb_copy_descriptors(fsg_fs_function); - if (unlikely(!f->descriptors)) - return -ENOMEM; - - if (gadget_is_dualspeed(gadget)) { - /* Assume endpoint addresses are the same for both speeds */ - fsg_hs_bulk_in_desc.bEndpointAddress = - fsg_fs_bulk_in_desc.bEndpointAddress; - fsg_hs_bulk_out_desc.bEndpointAddress = - fsg_fs_bulk_out_desc.bEndpointAddress; - f->hs_descriptors = usb_copy_descriptors(fsg_hs_function); - if (unlikely(!f->hs_descriptors)) { - usb_free_descriptors(f->descriptors); - return -ENOMEM; - } - } - - if (gadget_is_superspeed(gadget)) { - unsigned max_burst; + /* Assume endpoint addresses are the same for both speeds */ + fsg_hs_bulk_in_desc.bEndpointAddress = + fsg_fs_bulk_in_desc.bEndpointAddress; + fsg_hs_bulk_out_desc.bEndpointAddress = + fsg_fs_bulk_out_desc.bEndpointAddress; - /* Calculate bMaxBurst, we know packet size is 1024 */ - max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15); + /* Calculate bMaxBurst, we know packet size is 1024 */ + max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15); - fsg_ss_bulk_in_desc.bEndpointAddress = - fsg_fs_bulk_in_desc.bEndpointAddress; - fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst; + fsg_ss_bulk_in_desc.bEndpointAddress = + fsg_fs_bulk_in_desc.bEndpointAddress; + fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst; - fsg_ss_bulk_out_desc.bEndpointAddress = - fsg_fs_bulk_out_desc.bEndpointAddress; - fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst; + fsg_ss_bulk_out_desc.bEndpointAddress = + fsg_fs_bulk_out_desc.bEndpointAddress; + fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst; - f->ss_descriptors = usb_copy_descriptors(fsg_ss_function); - if (unlikely(!f->ss_descriptors)) { - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); - return -ENOMEM; - } - } + ret = usb_assign_descriptors(f, fsg_fs_function, fsg_hs_function, + fsg_ss_function); + if (ret) + goto autoconf_fail; return 0; @@ -2986,7 +2937,6 @@ autoconf_fail: return -ENOTSUPP; } - /****************************** ADD FUNCTION ******************************/ static struct usb_gadget_strings *fsg_strings_array[] = { diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c index 8ed1259fe80d..263e721c2694 100644 --- a/drivers/usb/gadget/f_midi.c +++ b/drivers/usb/gadget/f_midi.c @@ -414,7 +414,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) kfree(midi->id); midi->id = NULL; - usb_free_descriptors(f->descriptors); + usb_free_all_descriptors(f); kfree(midi); } @@ -881,19 +881,25 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f) * both speeds */ /* copy descriptors, and track endpoint copies */ + f->fs_descriptors = usb_copy_descriptors(midi_function); + if (!f->fs_descriptors) + goto fail_f_midi; + if (gadget_is_dualspeed(c->cdev->gadget)) { - c->highspeed = true; bulk_in_desc.wMaxPacketSize = cpu_to_le16(512); bulk_out_desc.wMaxPacketSize = cpu_to_le16(512); f->hs_descriptors = usb_copy_descriptors(midi_function); - } else { - f->descriptors = usb_copy_descriptors(midi_function); + if (!f->hs_descriptors) + goto fail_f_midi; } kfree(midi_function); return 0; +fail_f_midi: + kfree(midi_function); + usb_free_descriptors(f->hs_descriptors); fail: /* we might as well release our claims on endpoints */ if (midi->out_ep) diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index b651b529c67f..5e7557e23ecc 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 @@ -102,7 +103,7 @@ static inline unsigned ncm_bitrate(struct usb_gadget *g) USB_CDC_NCM_NTB32_SUPPORTED) static struct usb_cdc_ncm_ntb_parameters ntb_parameters = { - .wLength = sizeof ntb_parameters, + .wLength = cpu_to_le16(sizeof(ntb_parameters)), .bmNtbFormatsSupported = cpu_to_le16(FORMATS_SUPPORTED), .dwNtbInMaxSize = cpu_to_le32(NTB_DEFAULT_IN_SIZE), .wNdpInDivisor = cpu_to_le16(4), @@ -121,7 +122,7 @@ static struct usb_cdc_ncm_ntb_parameters ntb_parameters = { * waste less bandwidth. */ -#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ +#define NCM_STATUS_INTERVAL_MS 32 #define NCM_STATUS_BYTECOUNT 16 /* 8 byte header + data */ static struct usb_interface_assoc_descriptor ncm_iad_desc __initdata = { @@ -230,7 +231,7 @@ static struct usb_endpoint_descriptor fs_ncm_notify_desc __initdata = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(NCM_STATUS_BYTECOUNT), - .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, + .bInterval = NCM_STATUS_INTERVAL_MS, }; static struct usb_endpoint_descriptor fs_ncm_in_desc __initdata = { @@ -275,7 +276,7 @@ static struct usb_endpoint_descriptor hs_ncm_notify_desc __initdata = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(NCM_STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, + .bInterval = USB_MS_TO_HS_INTERVAL(NCM_STATUS_INTERVAL_MS), }; static struct usb_endpoint_descriptor hs_ncm_in_desc __initdata = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -321,7 +322,7 @@ static struct usb_descriptor_header *ncm_hs_function[] __initdata = { static struct usb_string ncm_string_defs[] = { [STRING_CTRL_IDX].s = "CDC Network Control Model (NCM)", - [STRING_MAC_IDX].s = NULL /* DYNAMIC */, + [STRING_MAC_IDX].s = "", [STRING_DATA_IDX].s = "CDC Network Data", [STRING_IAD_IDX].s = "CDC NCM", { } /* end of list */ @@ -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; } @@ -869,15 +869,19 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port, struct sk_buff *skb2; int ncb_len = 0; __le16 *tmp; - int div = ntb_parameters.wNdpInDivisor; - int rem = ntb_parameters.wNdpInPayloadRemainder; + int div; + int rem; int pad; - int ndp_align = ntb_parameters.wNdpInAlignment; + 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); + rem = le16_to_cpu(ntb_parameters.wNdpInPayloadRemainder); + ndp_align = le16_to_cpu(ntb_parameters.wNdpInAlignment); + ncb_len += opts->nth_size; ndp_pad = ALIGN(ncb_len, ndp_align) - ncb_len; ncb_len += ndp_pad; @@ -917,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++); @@ -961,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; @@ -998,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; } @@ -1208,30 +1212,18 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f) ncm->notify_req->context = ncm; ncm->notify_req->complete = ncm_notify_complete; - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(ncm_fs_function); - if (!f->descriptors) - goto fail; - /* * support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_ncm_in_desc.bEndpointAddress = - fs_ncm_in_desc.bEndpointAddress; - hs_ncm_out_desc.bEndpointAddress = - fs_ncm_out_desc.bEndpointAddress; - hs_ncm_notify_desc.bEndpointAddress = - fs_ncm_notify_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(ncm_hs_function); - if (!f->hs_descriptors) - goto fail; - } + hs_ncm_in_desc.bEndpointAddress = fs_ncm_in_desc.bEndpointAddress; + hs_ncm_out_desc.bEndpointAddress = fs_ncm_out_desc.bEndpointAddress; + hs_ncm_notify_desc.bEndpointAddress = + fs_ncm_notify_desc.bEndpointAddress; + status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function, + NULL); /* * NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code @@ -1248,9 +1240,7 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f) return 0; fail: - if (f->descriptors) - usb_free_descriptors(f->descriptors); - + usb_free_all_descriptors(f); if (ncm->notify_req) { kfree(ncm->notify_req->buf); usb_ep_free_request(ncm->notify, ncm->notify_req); @@ -1259,9 +1249,9 @@ fail: /* we might as well release our claims on endpoints */ if (ncm->notify) ncm->notify->driver_data = NULL; - if (ncm->port.out_ep->desc) + if (ncm->port.out_ep) ncm->port.out_ep->driver_data = NULL; - if (ncm->port.in_ep->desc) + if (ncm->port.in_ep) ncm->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); @@ -1276,14 +1266,12 @@ ncm_unbind(struct usb_configuration *c, struct usb_function *f) DBG(c->cdev, "ncm unbind\n"); - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); + ncm_string_defs[0].id = 0; + usb_free_all_descriptors(f); kfree(ncm->notify_req->buf); usb_ep_free_request(ncm->notify, ncm->notify_req); - ncm_string_defs[1].s = NULL; kfree(ncm); } @@ -1307,37 +1295,19 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) if (!can_support_ecm(c->cdev->gadget) || !ethaddr) return -EINVAL; - /* maybe allocate device-global string IDs */ if (ncm_string_defs[0].id == 0) { - - /* control interface label */ - status = usb_string_id(c->cdev); + status = usb_string_ids_tab(c->cdev, ncm_string_defs); if (status < 0) return status; - ncm_string_defs[STRING_CTRL_IDX].id = status; - ncm_control_intf.iInterface = status; + ncm_control_intf.iInterface = + ncm_string_defs[STRING_CTRL_IDX].id; - /* data interface label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ncm_string_defs[STRING_DATA_IDX].id = status; + status = ncm_string_defs[STRING_DATA_IDX].id; ncm_data_nop_intf.iInterface = status; ncm_data_intf.iInterface = status; - /* MAC address */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ncm_string_defs[STRING_MAC_IDX].id = status; - ecm_desc.iMACAddress = status; - - /* IAD */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ncm_string_defs[STRING_IAD_IDX].id = status; - ncm_iad_desc.iFunction = status; + ecm_desc.iMACAddress = ncm_string_defs[STRING_MAC_IDX].id; + ncm_iad_desc.iFunction = ncm_string_defs[STRING_IAD_IDX].id; } /* allocate and initialize one new instance */ @@ -1347,7 +1317,7 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) /* export host's Ethernet address in CDC format */ snprintf(ncm->ethaddr, sizeof ncm->ethaddr, "%pm", ethaddr); - ncm_string_defs[1].s = ncm->ethaddr; + ncm_string_defs[STRING_MAC_IDX].s = ncm->ethaddr; spin_lock_init(&ncm->lock); ncm_reset_values(ncm); @@ -1367,9 +1337,7 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) ncm->port.unwrap = ncm_unwrap_ntb; status = usb_add_function(c, &ncm->port.func); - if (status) { - ncm_string_defs[1].s = NULL; + if (status) kfree(ncm); - } return status; } diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c index 5f400f66aa9b..36a004563b82 100644 --- a/drivers/usb/gadget/f_obex.c +++ b/drivers/usb/gadget/f_obex.c @@ -331,23 +331,19 @@ obex_bind(struct usb_configuration *c, struct usb_function *f) obex->port.out = ep; ep->driver_data = cdev; /* claim */ - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(fs_function); - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - obex_hs_ep_in_desc.bEndpointAddress = - obex_fs_ep_in_desc.bEndpointAddress; - obex_hs_ep_out_desc.bEndpointAddress = - obex_fs_ep_out_desc.bEndpointAddress; + obex_hs_ep_in_desc.bEndpointAddress = + obex_fs_ep_in_desc.bEndpointAddress; + obex_hs_ep_out_desc.bEndpointAddress = + obex_fs_ep_out_desc.bEndpointAddress; - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(hs_function); - } + status = usb_assign_descriptors(f, fs_function, hs_function, NULL); + if (status) + goto fail; /* Avoid letting this gadget enumerate until the userspace * OBEX server is active. @@ -368,6 +364,7 @@ obex_bind(struct usb_configuration *c, struct usb_function *f) return 0; fail: + usb_free_all_descriptors(f); /* we might as well release our claims on endpoints */ if (obex->port.out) obex->port.out->driver_data = NULL; @@ -382,9 +379,8 @@ fail: static void obex_unbind(struct usb_configuration *c, struct usb_function *f) { - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); + obex_string_defs[OBEX_CTRL_IDX].id = 0; + usb_free_all_descriptors(f); kfree(func_to_obex(f)); } @@ -410,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) { @@ -423,22 +415,16 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num) if (!can_support_obex(c)) return -EINVAL; - /* maybe allocate device-global string IDs, and patch descriptors */ if (obex_string_defs[OBEX_CTRL_IDX].id == 0) { - status = usb_string_id(c->cdev); - if (status < 0) - return status; - obex_string_defs[OBEX_CTRL_IDX].id = status; - - obex_control_intf.iInterface = status; - - status = usb_string_id(c->cdev); + status = usb_string_ids_tab(c->cdev, obex_string_defs); if (status < 0) return status; - obex_string_defs[OBEX_DATA_IDX].id = status; + obex_control_intf.iInterface = + obex_string_defs[OBEX_CTRL_IDX].id; - obex_data_nop_intf.iInterface = - obex_data_intf.iInterface = status; + status = obex_string_defs[OBEX_DATA_IDX].id; + obex_data_nop_intf.iInterface = status; + obex_data_intf.iInterface = status; } /* allocate and initialize one new instance */ diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 8ee9268fe253..b21ab558b6c0 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -515,14 +515,14 @@ int pn_bind(struct usb_configuration *c, struct usb_function *f) fp->in_ep = ep; ep->driver_data = fp; /* Claim */ - pn_hs_sink_desc.bEndpointAddress = - pn_fs_sink_desc.bEndpointAddress; - pn_hs_source_desc.bEndpointAddress = - pn_fs_source_desc.bEndpointAddress; + pn_hs_sink_desc.bEndpointAddress = pn_fs_sink_desc.bEndpointAddress; + pn_hs_source_desc.bEndpointAddress = pn_fs_source_desc.bEndpointAddress; /* Do not try to bind Phonet twice... */ - fp->function.descriptors = fs_pn_function; - fp->function.hs_descriptors = hs_pn_function; + status = usb_assign_descriptors(f, fs_pn_function, hs_pn_function, + NULL); + if (status) + goto err; /* Incoming USB requests */ status = -ENOMEM; @@ -531,7 +531,7 @@ int pn_bind(struct usb_configuration *c, struct usb_function *f) req = usb_ep_alloc_request(fp->out_ep, GFP_KERNEL); if (!req) - goto err; + goto err_req; req->complete = pn_rx_complete; fp->out_reqv[i] = req; @@ -540,14 +540,18 @@ int pn_bind(struct usb_configuration *c, struct usb_function *f) /* Outgoing USB requests */ fp->in_req = usb_ep_alloc_request(fp->in_ep, GFP_KERNEL); if (!fp->in_req) - goto err; + goto err_req; INFO(cdev, "USB CDC Phonet function\n"); INFO(cdev, "using %s, OUT %s, IN %s\n", cdev->gadget->name, fp->out_ep->name, fp->in_ep->name); return 0; +err_req: + for (i = 0; i < phonet_rxq_size && fp->out_reqv[i]; i++) + usb_ep_free_request(fp->out_ep, fp->out_reqv[i]); err: + usb_free_all_descriptors(f); if (fp->out_ep) fp->out_ep->driver_data = NULL; if (fp->in_ep) @@ -569,6 +573,7 @@ pn_unbind(struct usb_configuration *c, struct usb_function *f) if (fp->out_reqv[i]) usb_ep_free_request(fp->out_ep, fp->out_reqv[i]); + usb_free_all_descriptors(f); kfree(fp); } diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index b1681e45aca7..71beeb833558 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -101,7 +101,7 @@ static unsigned int bitrate(struct usb_gadget *g) /* */ -#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ +#define RNDIS_STATUS_INTERVAL_MS 32 #define STATUS_BYTECOUNT 8 /* 8 bytes data */ @@ -190,7 +190,7 @@ static struct usb_endpoint_descriptor fs_notify_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), - .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, + .bInterval = RNDIS_STATUS_INTERVAL_MS, }; static struct usb_endpoint_descriptor fs_in_desc = { @@ -236,7 +236,7 @@ static struct usb_endpoint_descriptor hs_notify_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, + .bInterval = USB_MS_TO_HS_INTERVAL(RNDIS_STATUS_INTERVAL_MS) }; static struct usb_endpoint_descriptor hs_in_desc = { @@ -284,7 +284,7 @@ static struct usb_endpoint_descriptor ss_notify_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, + .bInterval = USB_MS_TO_HS_INTERVAL(RNDIS_STATUS_INTERVAL_MS) }; static struct usb_ss_ep_comp_descriptor ss_intr_comp_desc = { @@ -722,42 +722,22 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis->notify_req->context = rndis; rndis->notify_req->complete = rndis_response_complete; - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(eth_fs_function); - if (!f->descriptors) - goto fail; - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_in_desc.bEndpointAddress = - fs_in_desc.bEndpointAddress; - hs_out_desc.bEndpointAddress = - fs_out_desc.bEndpointAddress; - hs_notify_desc.bEndpointAddress = - fs_notify_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(eth_hs_function); - if (!f->hs_descriptors) - goto fail; - } + hs_in_desc.bEndpointAddress = fs_in_desc.bEndpointAddress; + hs_out_desc.bEndpointAddress = fs_out_desc.bEndpointAddress; + hs_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress; - if (gadget_is_superspeed(c->cdev->gadget)) { - ss_in_desc.bEndpointAddress = - fs_in_desc.bEndpointAddress; - ss_out_desc.bEndpointAddress = - fs_out_desc.bEndpointAddress; - ss_notify_desc.bEndpointAddress = - fs_notify_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(eth_ss_function); - if (!f->ss_descriptors) - goto fail; - } + ss_in_desc.bEndpointAddress = fs_in_desc.bEndpointAddress; + ss_out_desc.bEndpointAddress = fs_out_desc.bEndpointAddress; + ss_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress; + + status = usb_assign_descriptors(f, eth_fs_function, eth_hs_function, + eth_ss_function); + if (status) + goto fail; rndis->port.open = rndis_open; rndis->port.close = rndis_close; @@ -788,12 +768,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) return 0; fail: - if (gadget_is_superspeed(c->cdev->gadget) && f->ss_descriptors) - usb_free_descriptors(f->ss_descriptors); - if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors) - usb_free_descriptors(f->hs_descriptors); - if (f->descriptors) - usb_free_descriptors(f->descriptors); + usb_free_all_descriptors(f); if (rndis->notify_req) { kfree(rndis->notify_req->buf); @@ -803,9 +778,9 @@ fail: /* we might as well release our claims on endpoints */ if (rndis->notify) rndis->notify->driver_data = NULL; - if (rndis->port.out_ep->desc) + if (rndis->port.out_ep) rndis->port.out_ep->driver_data = NULL; - if (rndis->port.in_ep->desc) + if (rndis->port.in_ep) rndis->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); @@ -820,13 +795,9 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f) rndis_deregister(rndis->config); rndis_exit(); - rndis_string_defs[0].id = 0; - if (gadget_is_superspeed(c->cdev->gadget)) - usb_free_descriptors(f->ss_descriptors); - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); + rndis_string_defs[0].id = 0; + usb_free_all_descriptors(f); kfree(rndis->notify_req->buf); usb_ep_free_request(rndis->notify, rndis->notify_req); @@ -851,34 +822,19 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], if (!can_support_rndis(c) || !ethaddr) return -EINVAL; - /* maybe allocate device-global string IDs */ if (rndis_string_defs[0].id == 0) { - /* ... and setup RNDIS itself */ status = rndis_init(); if (status < 0) return status; - /* control interface label */ - status = usb_string_id(c->cdev); - if (status < 0) + status = usb_string_ids_tab(c->cdev, rndis_string_defs); + if (status) return status; - rndis_string_defs[0].id = status; - rndis_control_intf.iInterface = status; - /* data interface label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - rndis_string_defs[1].id = status; - rndis_data_intf.iInterface = status; - - /* IAD iFunction label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - rndis_string_defs[2].id = status; - rndis_iad_descriptor.iFunction = status; + rndis_control_intf.iInterface = rndis_string_defs[0].id; + rndis_data_intf.iInterface = rndis_string_defs[1].id; + rndis_iad_descriptor.iFunction = rndis_string_defs[2].id; } /* allocate and initialize one new instance */ diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c index 07197d63d9b1..da33cfb3031d 100644 --- a/drivers/usb/gadget/f_serial.c +++ b/drivers/usb/gadget/f_serial.c @@ -213,34 +213,20 @@ gser_bind(struct usb_configuration *c, struct usb_function *f) gser->port.out = ep; ep->driver_data = cdev; /* claim */ - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(gser_fs_function); - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - gser_hs_in_desc.bEndpointAddress = - gser_fs_in_desc.bEndpointAddress; - gser_hs_out_desc.bEndpointAddress = - gser_fs_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(gser_hs_function); - } - if (gadget_is_superspeed(c->cdev->gadget)) { - gser_ss_in_desc.bEndpointAddress = - gser_fs_in_desc.bEndpointAddress; - gser_ss_out_desc.bEndpointAddress = - gser_fs_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(gser_ss_function); - if (!f->ss_descriptors) - goto fail; - } + gser_hs_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress; + gser_hs_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress; + + gser_ss_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress; + gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress; + status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function, + gser_ss_function); + if (status) + goto fail; DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n", gser->port_num, gadget_is_superspeed(c->cdev->gadget) ? "super" : @@ -263,11 +249,7 @@ fail: static void gser_unbind(struct usb_configuration *c, struct usb_function *f) { - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - if (gadget_is_superspeed(c->cdev->gadget)) - usb_free_descriptors(f->ss_descriptors); - usb_free_descriptors(f->descriptors); + usb_free_all_descriptors(f); kfree(func_to_gser(f)); } @@ -278,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 3c126fde6e7e..41adf3ef96c2 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,12 +301,63 @@ 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; struct f_sourcesink *ss = func_to_ss(f); int id; + int ret; /* allocate interface ID(s) */ id = usb_interface_id(c, f); @@ -387,64 +426,57 @@ no_iso: isoc_maxpacket = 1024; /* support high speed hardware */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_source_desc.bEndpointAddress = - fs_source_desc.bEndpointAddress; - hs_sink_desc.bEndpointAddress = - fs_sink_desc.bEndpointAddress; + hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; - /* - * Fill in the HS isoc descriptors from the module parameters. - * We assume that the user knows what they are doing and won't - * give parameters that their UDC doesn't support. - */ - hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket; - hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11; - hs_iso_source_desc.bInterval = isoc_interval; - hs_iso_source_desc.bEndpointAddress = - fs_iso_source_desc.bEndpointAddress; - - hs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket; - hs_iso_sink_desc.wMaxPacketSize |= isoc_mult << 11; - hs_iso_sink_desc.bInterval = isoc_interval; - hs_iso_sink_desc.bEndpointAddress = - fs_iso_sink_desc.bEndpointAddress; - - f->hs_descriptors = hs_source_sink_descs; - } + /* + * Fill in the HS isoc descriptors from the module parameters. + * We assume that the user knows what they are doing and won't + * give parameters that their UDC doesn't support. + */ + hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket; + hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11; + hs_iso_source_desc.bInterval = isoc_interval; + hs_iso_source_desc.bEndpointAddress = + fs_iso_source_desc.bEndpointAddress; + + hs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket; + hs_iso_sink_desc.wMaxPacketSize |= isoc_mult << 11; + hs_iso_sink_desc.bInterval = isoc_interval; + hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress; /* support super speed hardware */ - if (gadget_is_superspeed(c->cdev->gadget)) { - ss_source_desc.bEndpointAddress = - fs_source_desc.bEndpointAddress; - ss_sink_desc.bEndpointAddress = - fs_sink_desc.bEndpointAddress; + ss_source_desc.bEndpointAddress = + fs_source_desc.bEndpointAddress; + ss_sink_desc.bEndpointAddress = + fs_sink_desc.bEndpointAddress; - /* - * Fill in the SS isoc descriptors from the module parameters. - * We assume that the user knows what they are doing and won't - * give parameters that their UDC doesn't support. - */ - ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket; - ss_iso_source_desc.bInterval = isoc_interval; - ss_iso_source_comp_desc.bmAttributes = isoc_mult; - ss_iso_source_comp_desc.bMaxBurst = isoc_maxburst; - ss_iso_source_comp_desc.wBytesPerInterval = - isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); - ss_iso_source_desc.bEndpointAddress = - fs_iso_source_desc.bEndpointAddress; - - ss_iso_sink_desc.wMaxPacketSize = isoc_maxpacket; - ss_iso_sink_desc.bInterval = isoc_interval; - ss_iso_sink_comp_desc.bmAttributes = isoc_mult; - ss_iso_sink_comp_desc.bMaxBurst = isoc_maxburst; - ss_iso_sink_comp_desc.wBytesPerInterval = - isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); - ss_iso_sink_desc.bEndpointAddress = - fs_iso_sink_desc.bEndpointAddress; - - f->ss_descriptors = ss_source_sink_descs; - } + /* + * Fill in the SS isoc descriptors from the module parameters. + * We assume that the user knows what they are doing and won't + * give parameters that their UDC doesn't support. + */ + ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket; + ss_iso_source_desc.bInterval = isoc_interval; + ss_iso_source_comp_desc.bmAttributes = isoc_mult; + ss_iso_source_comp_desc.bMaxBurst = isoc_maxburst; + ss_iso_source_comp_desc.wBytesPerInterval = + isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); + ss_iso_source_desc.bEndpointAddress = + fs_iso_source_desc.bEndpointAddress; + + ss_iso_sink_desc.wMaxPacketSize = isoc_maxpacket; + ss_iso_sink_desc.bInterval = isoc_interval; + ss_iso_sink_comp_desc.bmAttributes = isoc_mult; + ss_iso_sink_comp_desc.bMaxBurst = isoc_maxburst; + ss_iso_sink_comp_desc.wBytesPerInterval = + isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); + ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress; + + ret = usb_assign_descriptors(f, fs_source_sink_descs, + hs_source_sink_descs, ss_source_sink_descs); + if (ret) + return ret; DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n", (gadget_is_superspeed(c->cdev->gadget) ? "super" : @@ -456,8 +488,9 @@ 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)); } @@ -536,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 */ @@ -763,32 +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.descriptors = fs_source_sink_descs; - 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); @@ -857,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 */ -}; - -/** - * 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) +static struct usb_function *source_sink_alloc_func( + struct usb_function_instance *fi) { - int id; + struct f_sourcesink *ss; + 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 = 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; - source_sink_intf_alt0.iInterface = id; - source_sink_intf_alt1.iInterface = id; - sourcesink_driver.iConfiguration = id; + 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; - /* support autoresume for remote wakeup testing */ - if (autoresume) - sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + ss->function.free_func = sourcesink_free_func; - /* support OTG systems */ - if (gadget_is_otg(cdev->gadget)) { - sourcesink_driver.descriptors = otg_desc; - sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; - } + return &ss->function; +} - return usb_add_config(cdev, &sourcesink_driver, sourcesink_bind_config); +static void acm_free_instance(struct usb_function_instance *fi) +{ + struct f_ss_opts *ss_opts; + + ss_opts = container_of(fi, struct f_ss_opts, func_inst); + kfree(ss_opts); } + +static struct usb_function_instance *source_sink_alloc_inst(void) +{ + struct f_ss_opts *ss_opts; + + 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); + +static int __init sslb_modinit(void) +{ + int ret; + + 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_subset.c b/drivers/usb/gadget/f_subset.c index 4060c0bd9785..f172bd152fbb 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -236,7 +236,7 @@ static struct usb_descriptor_header *ss_eth_function[] = { static struct usb_string geth_string_defs[] = { [0].s = "CDC Ethernet Subset/SAFE", - [1].s = NULL /* DYNAMIC */, + [1].s = "", { } /* end of list */ }; @@ -319,38 +319,22 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) geth->port.out_ep = ep; ep->driver_data = cdev; /* claim */ - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(fs_eth_function); - if (!f->descriptors) - goto fail; - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_subset_in_desc.bEndpointAddress = - fs_subset_in_desc.bEndpointAddress; - hs_subset_out_desc.bEndpointAddress = - fs_subset_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(hs_eth_function); - if (!f->hs_descriptors) - goto fail; - } + hs_subset_in_desc.bEndpointAddress = fs_subset_in_desc.bEndpointAddress; + hs_subset_out_desc.bEndpointAddress = + fs_subset_out_desc.bEndpointAddress; - if (gadget_is_superspeed(c->cdev->gadget)) { - ss_subset_in_desc.bEndpointAddress = - fs_subset_in_desc.bEndpointAddress; - ss_subset_out_desc.bEndpointAddress = - fs_subset_out_desc.bEndpointAddress; + ss_subset_in_desc.bEndpointAddress = fs_subset_in_desc.bEndpointAddress; + ss_subset_out_desc.bEndpointAddress = + fs_subset_out_desc.bEndpointAddress; - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(ss_eth_function); - if (!f->ss_descriptors) - goto fail; - } + status = usb_assign_descriptors(f, fs_eth_function, hs_eth_function, + ss_eth_function); + if (status) + goto fail; /* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code @@ -364,15 +348,11 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) return 0; fail: - if (f->descriptors) - usb_free_descriptors(f->descriptors); - if (f->hs_descriptors) - usb_free_descriptors(f->hs_descriptors); - + usb_free_all_descriptors(f); /* we might as well release our claims on endpoints */ - if (geth->port.out_ep->desc) + if (geth->port.out_ep) geth->port.out_ep->driver_data = NULL; - if (geth->port.in_ep->desc) + if (geth->port.in_ep) geth->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); @@ -383,12 +363,8 @@ fail: static void geth_unbind(struct usb_configuration *c, struct usb_function *f) { - if (gadget_is_superspeed(c->cdev->gadget)) - usb_free_descriptors(f->ss_descriptors); - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); - geth_string_defs[1].s = NULL; + geth_string_defs[0].id = 0; + usb_free_all_descriptors(f); kfree(func_to_geth(f)); } @@ -414,20 +390,11 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) /* maybe allocate device-global string IDs */ if (geth_string_defs[0].id == 0) { - - /* interface label */ - status = usb_string_id(c->cdev); + status = usb_string_ids_tab(c->cdev, geth_string_defs); if (status < 0) return status; - geth_string_defs[0].id = status; - subset_data_intf.iInterface = status; - - /* MAC address */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - geth_string_defs[1].id = status; - ether_desc.iMACAddress = status; + subset_data_intf.iInterface = geth_string_defs[0].id; + ether_desc.iMACAddress = geth_string_defs[1].id; } /* allocate and initialize one new instance */ @@ -449,9 +416,7 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) geth->port.func.disable = geth_disable; status = usb_add_function(c, &geth->port.func); - if (status) { - geth_string_defs[1].s = NULL; + if (status) kfree(geth); - } return status; } diff --git a/drivers/usb/gadget/f_uac1.c b/drivers/usb/gadget/f_uac1.c index 1a5dcd5565e3..fa8ea4ea00c1 100644 --- a/drivers/usb/gadget/f_uac1.c +++ b/drivers/usb/gadget/f_uac1.c @@ -418,6 +418,7 @@ static int audio_get_intf_req(struct usb_function *f, req->context = audio; req->complete = f_audio_complete; + len = min_t(size_t, sizeof(value), len); memcpy(req->buf, &value, len); return len; @@ -630,7 +631,7 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f) struct usb_composite_dev *cdev = c->cdev; struct f_audio *audio = func_to_audio(f); int status; - struct usb_ep *ep; + struct usb_ep *ep = NULL; f_audio_build_desc(audio); @@ -659,22 +660,14 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f) status = -ENOMEM; /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(f_audio_desc); - - /* - * support all relevant hardware speeds... we expect that when - * hardware is dual speed, all bulk-capable endpoints work at - * both speeds - */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - c->highspeed = true; - f->hs_descriptors = usb_copy_descriptors(f_audio_desc); - } - + status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL); + if (status) + goto fail; return 0; fail: - + if (ep) + ep->driver_data = NULL; return status; } @@ -683,8 +676,7 @@ f_audio_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_audio *audio = func_to_audio(f); - usb_free_descriptors(f->descriptors); - usb_free_descriptors(f->hs_descriptors); + usb_free_all_descriptors(f); kfree(audio); } diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/f_uac2.c index d3c6cffccb72..c7468b6c07b0 100644 --- a/drivers/usb/gadget/f_uac2.c +++ b/drivers/usb/gadget/f_uac2.c @@ -50,13 +50,6 @@ static int c_ssize = 2; module_param(c_ssize, uint, S_IRUGO); MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)"); -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -#define ALT_SET(x, a) do {(x) &= ~0xff; (x) |= (a); } while (0) -#define ALT_GET(x) ((x) & 0xff) -#define INTF_SET(x, i) do {(x) &= 0xff; (x) |= ((i) << 8); } while (0) -#define INTF_GET(x) ((x >> 8) & 0xff) - /* Keep everyone on toes */ #define USB_XFERS 2 @@ -144,8 +137,9 @@ static struct snd_pcm_hardware uac2_pcm_hardware = { }; struct audio_dev { - /* Currently active {Interface[15:8] | AltSettings[7:0]} */ - __u16 ac_alt, as_out_alt, as_in_alt; + u8 ac_intf, ac_alt; + u8 as_out_intf, as_out_alt; + u8 as_in_intf, as_in_alt; struct usb_ep *in_ep, *out_ep; struct usb_function func; @@ -266,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); @@ -408,7 +397,7 @@ static struct snd_pcm_ops uac2_pcm_ops = { .prepare = uac2_pcm_null, }; -static int __devinit snd_uac2_probe(struct platform_device *pdev) +static int snd_uac2_probe(struct platform_device *pdev) { struct snd_uac2_chip *uac2 = pdev_to_uac2(pdev); struct snd_card *card; @@ -526,32 +515,22 @@ enum { STR_AS_IN_ALT1, }; -static const char ifassoc[] = "Source/Sink"; -static const char ifctrl[] = "Topology Control"; static char clksrc_in[8]; static char clksrc_out[8]; -static const char usb_it[] = "USBH Out"; -static const char io_it[] = "USBD Out"; -static const char usb_ot[] = "USBH In"; -static const char io_ot[] = "USBD In"; -static const char out_alt0[] = "Playback Inactive"; -static const char out_alt1[] = "Playback Active"; -static const char in_alt0[] = "Capture Inactive"; -static const char in_alt1[] = "Capture Active"; static struct usb_string strings_fn[] = { - [STR_ASSOC].s = ifassoc, - [STR_IF_CTRL].s = ifctrl, + [STR_ASSOC].s = "Source/Sink", + [STR_IF_CTRL].s = "Topology Control", [STR_CLKSRC_IN].s = clksrc_in, [STR_CLKSRC_OUT].s = clksrc_out, - [STR_USB_IT].s = usb_it, - [STR_IO_IT].s = io_it, - [STR_USB_OT].s = usb_ot, - [STR_IO_OT].s = io_ot, - [STR_AS_OUT_ALT0].s = out_alt0, - [STR_AS_OUT_ALT1].s = out_alt1, - [STR_AS_IN_ALT0].s = in_alt0, - [STR_AS_IN_ALT1].s = in_alt1, + [STR_USB_IT].s = "USBH Out", + [STR_IO_IT].s = "USBD Out", + [STR_USB_OT].s = "USBH In", + [STR_IO_OT].s = "USBD In", + [STR_AS_OUT_ALT0].s = "Playback Inactive", + [STR_AS_OUT_ALT1].s = "Playback Active", + [STR_AS_IN_ALT0].s = "Capture Inactive", + [STR_AS_IN_ALT1].s = "Capture Active", { }, }; @@ -952,8 +931,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) return ret; } std_ac_if_desc.bInterfaceNumber = ret; - ALT_SET(agdev->ac_alt, 0); - INTF_SET(agdev->ac_alt, ret); + agdev->ac_intf = ret; + agdev->ac_alt = 0; ret = usb_interface_id(cfg, fn); if (ret < 0) { @@ -963,8 +942,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) } std_as_out_if0_desc.bInterfaceNumber = ret; std_as_out_if1_desc.bInterfaceNumber = ret; - ALT_SET(agdev->as_out_alt, 0); - INTF_SET(agdev->as_out_alt, ret); + agdev->as_out_intf = ret; + agdev->as_out_alt = 0; ret = usb_interface_id(cfg, fn); if (ret < 0) { @@ -974,19 +953,23 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) } std_as_in_if0_desc.bInterfaceNumber = ret; std_as_in_if1_desc.bInterfaceNumber = ret; - ALT_SET(agdev->as_in_alt, 0); - INTF_SET(agdev->as_in_alt, ret); + agdev->as_in_intf = ret; + agdev->as_in_alt = 0; agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); - if (!agdev->out_ep) + if (!agdev->out_ep) { dev_err(&uac2->pdev.dev, "%s:%d Error!\n", __func__, __LINE__); + goto err; + } agdev->out_ep->driver_data = agdev; agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc); - if (!agdev->in_ep) + if (!agdev->in_ep) { dev_err(&uac2->pdev.dev, "%s:%d Error!\n", __func__, __LINE__); + goto err; + } agdev->in_ep->driver_data = agdev; hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; @@ -994,9 +977,9 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; hs_epin_desc.wMaxPacketSize = fs_epin_desc.wMaxPacketSize; - fn->descriptors = usb_copy_descriptors(fs_audio_desc); - if (gadget_is_dualspeed(gadget)) - fn->hs_descriptors = usb_copy_descriptors(hs_audio_desc); + ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL); + if (ret) + goto err; prm = &agdev->uac2.c_prm; prm->max_psize = hs_epout_desc.wMaxPacketSize; @@ -1005,6 +988,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) prm->max_psize = 0; dev_err(&uac2->pdev.dev, "%s:%d Error!\n", __func__, __LINE__); + goto err; } prm = &agdev->uac2.p_prm; @@ -1014,17 +998,28 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) prm->max_psize = 0; dev_err(&uac2->pdev.dev, "%s:%d Error!\n", __func__, __LINE__); + goto err; } - return alsa_uac2_init(agdev); + ret = alsa_uac2_init(agdev); + if (ret) + goto err; + return 0; +err: + kfree(agdev->uac2.p_prm.rbuf); + kfree(agdev->uac2.c_prm.rbuf); + usb_free_all_descriptors(fn); + if (agdev->in_ep) + agdev->in_ep->driver_data = NULL; + if (agdev->out_ep) + agdev->out_ep->driver_data = NULL; + return -EINVAL; } static void afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn) { struct audio_dev *agdev = func_to_agdev(fn); - struct usb_composite_dev *cdev = cfg->cdev; - struct usb_gadget *gadget = cdev->gadget; struct uac2_rtd_params *prm; alsa_uac2_exit(agdev); @@ -1034,10 +1029,7 @@ afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn) prm = &agdev->uac2.c_prm; kfree(prm->rbuf); - - if (gadget_is_dualspeed(gadget)) - usb_free_descriptors(fn->hs_descriptors); - usb_free_descriptors(fn->descriptors); + usb_free_all_descriptors(fn); if (agdev->in_ep) agdev->in_ep->driver_data = NULL; @@ -1064,7 +1056,7 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) return -EINVAL; } - if (intf == INTF_GET(agdev->ac_alt)) { + if (intf == agdev->ac_intf) { /* Control I/f has only 1 AltSetting - 0 */ if (alt) { dev_err(&uac2->pdev.dev, @@ -1074,16 +1066,16 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) return 0; } - if (intf == INTF_GET(agdev->as_out_alt)) { + if (intf == agdev->as_out_intf) { ep = agdev->out_ep; prm = &uac2->c_prm; config_ep_by_speed(gadget, fn, ep); - ALT_SET(agdev->as_out_alt, alt); - } else if (intf == INTF_GET(agdev->as_in_alt)) { + agdev->as_out_alt = alt; + } else if (intf == agdev->as_in_intf) { ep = agdev->in_ep; prm = &uac2->p_prm; config_ep_by_speed(gadget, fn, ep); - ALT_SET(agdev->as_in_alt, alt); + agdev->as_in_alt = alt; } else { dev_err(&uac2->pdev.dev, "%s:%d Error!\n", __func__, __LINE__); @@ -1117,7 +1109,6 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) prm->ureq[i].pp = prm; req->zero = 0; - req->dma = DMA_ADDR_INVALID; req->context = &prm->ureq[i]; req->length = prm->max_psize; req->complete = agdev_iso_complete; @@ -1136,12 +1127,12 @@ afunc_get_alt(struct usb_function *fn, unsigned intf) struct audio_dev *agdev = func_to_agdev(fn); struct snd_uac2_chip *uac2 = &agdev->uac2; - if (intf == INTF_GET(agdev->ac_alt)) - return ALT_GET(agdev->ac_alt); - else if (intf == INTF_GET(agdev->as_out_alt)) - return ALT_GET(agdev->as_out_alt); - else if (intf == INTF_GET(agdev->as_in_alt)) - return ALT_GET(agdev->as_in_alt); + if (intf == agdev->ac_intf) + return agdev->ac_alt; + else if (intf == agdev->as_out_intf) + return agdev->as_out_alt; + else if (intf == agdev->as_in_intf) + return agdev->as_in_alt; else dev_err(&uac2->pdev.dev, "%s:%d Invalid Interface %d!\n", @@ -1157,10 +1148,10 @@ afunc_disable(struct usb_function *fn) struct snd_uac2_chip *uac2 = &agdev->uac2; free_ep(&uac2->p_prm, agdev->in_ep); - ALT_SET(agdev->as_in_alt, 0); + agdev->as_in_alt = 0; free_ep(&uac2->c_prm, agdev->out_ep); - ALT_SET(agdev->as_out_alt, 0); + agdev->as_out_alt = 0; } static int @@ -1267,7 +1258,7 @@ setup_rq_inf(struct usb_function *fn, const struct usb_ctrlrequest *cr) u16 w_index = le16_to_cpu(cr->wIndex); u8 intf = w_index & 0xff; - if (intf != INTF_GET(agdev->ac_alt)) { + if (intf != agdev->ac_intf) { dev_err(&uac2->pdev.dev, "%s:%d Error!\n", __func__, __LINE__); return -EOPNOTSUPP; @@ -1316,7 +1307,7 @@ afunc_setup(struct usb_function *fn, const struct usb_ctrlrequest *cr) static int audio_bind_config(struct usb_configuration *cfg) { - int id, res; + int res; agdev_g = kzalloc(sizeof *agdev_g, GFP_KERNEL); if (agdev_g == NULL) { @@ -1324,89 +1315,21 @@ static int audio_bind_config(struct usb_configuration *cfg) return -ENOMEM; } - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_ASSOC].id = id; - iad_desc.iFunction = id, - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_IF_CTRL].id = id; - std_ac_if_desc.iInterface = id, - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_CLKSRC_IN].id = id; - in_clk_src_desc.iClockSource = id, - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_CLKSRC_OUT].id = id; - out_clk_src_desc.iClockSource = id, - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_USB_IT].id = id; - usb_out_it_desc.iTerminal = id, - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_IO_IT].id = id; - io_in_it_desc.iTerminal = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_USB_OT].id = id; - usb_in_ot_desc.iTerminal = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_IO_OT].id = id; - io_out_ot_desc.iTerminal = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_AS_OUT_ALT0].id = id; - std_as_out_if0_desc.iInterface = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_AS_OUT_ALT1].id = id; - std_as_out_if1_desc.iInterface = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_AS_IN_ALT0].id = id; - std_as_in_if0_desc.iInterface = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_AS_IN_ALT1].id = id; - std_as_in_if1_desc.iInterface = id; + res = usb_string_ids_tab(cfg->cdev, strings_fn); + if (res) + return res; + iad_desc.iFunction = strings_fn[STR_ASSOC].id; + std_ac_if_desc.iInterface = strings_fn[STR_IF_CTRL].id; + in_clk_src_desc.iClockSource = strings_fn[STR_CLKSRC_IN].id; + out_clk_src_desc.iClockSource = strings_fn[STR_CLKSRC_OUT].id; + usb_out_it_desc.iTerminal = strings_fn[STR_USB_IT].id; + io_in_it_desc.iTerminal = strings_fn[STR_IO_IT].id; + usb_in_ot_desc.iTerminal = strings_fn[STR_USB_OT].id; + io_out_ot_desc.iTerminal = strings_fn[STR_IO_OT].id; + std_as_out_if0_desc.iInterface = strings_fn[STR_AS_OUT_ALT0].id; + std_as_out_if1_desc.iInterface = strings_fn[STR_AS_OUT_ALT1].id; + std_as_in_if0_desc.iInterface = strings_fn[STR_AS_IN_ALT0].id; + std_as_in_if1_desc.iInterface = strings_fn[STR_AS_IN_ALT1].id; agdev_g->func.name = "uac2_func"; agdev_g->func.strings = fn_strings; diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c index 2a8bf0655c60..92efd6ec48af 100644 --- a/drivers/usb/gadget/f_uvc.c +++ b/drivers/usb/gadget/f_uvc.c @@ -16,6 +16,7 @@ #include <linux/fs.h> #include <linux/list.h> #include <linux/mutex.h> +#include <linux/string.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> #include <linux/usb/video.h> @@ -417,10 +418,9 @@ uvc_register_video(struct uvc_device *uvc) return -ENOMEM; video->parent = &cdev->gadget->dev; - video->minor = -1; video->fops = &uvc_v4l2_fops; video->release = video_device_release; - strncpy(video->name, cdev->gadget->name, sizeof(video->name)); + strlcpy(video->name, cdev->gadget->name, sizeof(video->name)); uvc->vdev = video; video_set_drvdata(video, uvc); @@ -577,27 +577,15 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f) INFO(cdev, "uvc_function_unbind\n"); - if (uvc->vdev) { - if (uvc->vdev->minor == -1) - video_device_release(uvc->vdev); - else - video_unregister_device(uvc->vdev); - uvc->vdev = NULL; - } + video_unregister_device(uvc->vdev); + uvc->control_ep->driver_data = NULL; + uvc->video.ep->driver_data = NULL; - if (uvc->control_ep) - uvc->control_ep->driver_data = NULL; - if (uvc->video.ep) - uvc->video.ep->driver_data = NULL; - - if (uvc->control_req) { - usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); - kfree(uvc->control_buf); - } + uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = 0; + usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); + kfree(uvc->control_buf); - kfree(f->descriptors); - kfree(f->hs_descriptors); - kfree(f->ss_descriptors); + usb_free_all_descriptors(f); kfree(uvc); } @@ -663,49 +651,40 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) /* sanity check the streaming endpoint module parameters */ if (streaming_maxpacket > 1024) streaming_maxpacket = 1024; + /* + * Fill in the HS descriptors from the module parameters for the Video + * Streaming endpoint. + * NOTE: We assume that the user knows what they are doing and won't + * give parameters that their UDC doesn't support. + */ + uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket; + uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11; + uvc_hs_streaming_ep.bInterval = streaming_interval; + uvc_hs_streaming_ep.bEndpointAddress = + uvc_fs_streaming_ep.bEndpointAddress; - /* Copy descriptors for FS. */ - f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); - - /* support high speed hardware */ - if (gadget_is_dualspeed(cdev->gadget)) { - /* - * Fill in the HS descriptors from the module parameters for the - * Video Streaming endpoint. - * NOTE: We assume that the user knows what they are doing and - * won't give parameters that their UDC doesn't support. - */ - uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket; - uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11; - uvc_hs_streaming_ep.bInterval = streaming_interval; - uvc_hs_streaming_ep.bEndpointAddress = - uvc_fs_streaming_ep.bEndpointAddress; - - /* Copy descriptors. */ - f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH); - } + /* + * Fill in the SS descriptors from the module parameters for the Video + * Streaming endpoint. + * NOTE: We assume that the user knows what they are doing and won't + * give parameters that their UDC doesn't support. + */ + uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket; + uvc_ss_streaming_ep.bInterval = streaming_interval; + uvc_ss_streaming_comp.bmAttributes = streaming_mult; + uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst; + uvc_ss_streaming_comp.wBytesPerInterval = + streaming_maxpacket * (streaming_mult + 1) * + (streaming_maxburst + 1); + uvc_ss_streaming_ep.bEndpointAddress = + uvc_fs_streaming_ep.bEndpointAddress; - /* support super speed hardware */ - if (gadget_is_superspeed(c->cdev->gadget)) { - /* - * Fill in the SS descriptors from the module parameters for the - * Video Streaming endpoint. - * NOTE: We assume that the user knows what they are doing and - * won't give parameters that their UDC doesn't support. - */ - uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket; - uvc_ss_streaming_ep.bInterval = streaming_interval; - uvc_ss_streaming_comp.bmAttributes = streaming_mult; - uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst; - uvc_ss_streaming_comp.wBytesPerInterval = - streaming_maxpacket * (streaming_mult + 1) * - (streaming_maxburst + 1); - uvc_ss_streaming_ep.bEndpointAddress = - uvc_fs_streaming_ep.bEndpointAddress; - - /* Copy descriptors. */ + /* Copy descriptors */ + f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); + if (gadget_is_dualspeed(cdev->gadget)) + f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH); + if (gadget_is_superspeed(c->cdev->gadget)) f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER); - } /* Preallocate control endpoint request. */ uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); @@ -740,7 +719,20 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) return 0; error: - uvc_function_unbind(c, f); + if (uvc->vdev) + video_device_release(uvc->vdev); + + if (uvc->control_ep) + uvc->control_ep->driver_data = NULL; + if (uvc->video.ep) + uvc->video.ep->driver_data = NULL; + + if (uvc->control_req) { + usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); + kfree(uvc->control_buf); + } + + usb_free_all_descriptors(f); return ret; } @@ -808,25 +800,16 @@ uvc_bind_config(struct usb_configuration *c, uvc->desc.hs_streaming = hs_streaming; uvc->desc.ss_streaming = ss_streaming; - /* maybe allocate device-global string IDs, and patch descriptors */ + /* Allocate string descriptor numbers. */ if (uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id == 0) { - /* Allocate string descriptor numbers. */ - ret = usb_string_id(c->cdev); - if (ret < 0) - goto error; - uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = ret; - uvc_iad.iFunction = ret; - - ret = usb_string_id(c->cdev); - if (ret < 0) - goto error; - uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = ret; - uvc_control_intf.iInterface = ret; - - ret = usb_string_id(c->cdev); - if (ret < 0) + ret = usb_string_ids_tab(c->cdev, uvc_en_us_strings); + if (ret) goto error; - uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id = ret; + uvc_iad.iFunction = + uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id; + uvc_control_intf.iInterface = + uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id; + ret = uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id; uvc_streaming_intf_alt0.iInterface = ret; uvc_streaming_intf_alt1.iInterface = ret; } diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c deleted file mode 100644 index 3f7d640b6758..000000000000 --- a/drivers/usb/gadget/file_storage.c +++ /dev/null @@ -1,3656 +0,0 @@ -/* - * file_storage.c -- File-backed USB Storage Gadget, for USB development - * - * Copyright (C) 2003-2008 Alan Stern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -/* - * The File-backed Storage Gadget acts as a USB Mass Storage device, - * appearing to the host as a disk drive or as a CD-ROM drive. In addition - * to providing an example of a genuinely useful gadget driver for a USB - * device, it also illustrates a technique of double-buffering for increased - * throughput. Last but not least, it gives an easy way to probe the - * behavior of the Mass Storage drivers in a USB host. - * - * Backing storage is provided by a regular file or a block device, specified - * by the "file" module parameter. Access can be limited to read-only by - * setting the optional "ro" module parameter. (For CD-ROM emulation, - * access is always read-only.) The gadget will indicate that it has - * removable media if the optional "removable" module parameter is set. - * - * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI), - * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected - * by the optional "transport" module parameter. It also supports the - * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03), - * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by - * the optional "protocol" module parameter. In addition, the default - * Vendor ID, Product ID, release number and serial number can be overridden. - * - * There is support for multiple logical units (LUNs), each of which has - * its own backing file. The number of LUNs can be set using the optional - * "luns" module parameter (anywhere from 1 to 8), and the corresponding - * files are specified using comma-separated lists for "file" and "ro". - * The default number of LUNs is taken from the number of "file" elements; - * it is 1 if "file" is not given. If "removable" is not set then a backing - * file must be specified for each LUN. If it is set, then an unspecified - * or empty backing filename means the LUN's medium is not loaded. Ideally - * each LUN would be settable independently as a disk drive or a CD-ROM - * drive, but currently all LUNs have to be the same type. The CD-ROM - * emulation includes a single data track and no audio tracks; hence there - * need be only one backing file per LUN. - * - * Requirements are modest; only a bulk-in and a bulk-out endpoint are - * needed (an interrupt-out endpoint is also needed for CBI). The memory - * requirement amounts to two 16K buffers, size configurable by a parameter. - * Support is included for both full-speed and high-speed operation. - * - * Note that the driver is slightly non-portable in that it assumes a - * single memory/DMA buffer will be useable for bulk-in, bulk-out, and - * interrupt-in endpoints. With most device controllers this isn't an - * issue, but there may be some with hardware restrictions that prevent - * a buffer from being used by more than one endpoint. - * - * Module options: - * - * file=filename[,filename...] - * Required if "removable" is not set, names of - * the files or block devices used for - * backing storage - * serial=HHHH... Required serial number (string of hex chars) - * ro=b[,b...] Default false, booleans for read-only access - * removable Default false, boolean for removable media - * luns=N Default N = number of filenames, number of - * LUNs to support - * nofua=b[,b...] Default false, booleans for ignore FUA flag - * in SCSI WRITE(10,12) commands - * stall Default determined according to the type of - * USB device controller (usually true), - * boolean to permit the driver to halt - * bulk endpoints - * cdrom Default false, boolean for whether to emulate - * a CD-ROM drive - * transport=XXX Default BBB, transport name (CB, CBI, or BBB) - * protocol=YYY Default SCSI, protocol name (RBC, 8020 or - * ATAPI, QIC, UFI, 8070, or SCSI; - * also 1 - 6) - * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID - * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID - * release=0xRRRR Override the USB release number (bcdDevice) - * buflen=N Default N=16384, buffer size used (will be - * rounded down to a multiple of - * PAGE_CACHE_SIZE) - * - * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "serial", "ro", - * "removable", "luns", "nofua", "stall", and "cdrom" options are available; - * default values are used for everything else. - * - * The pathnames of the backing files and the ro settings are available in - * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of - * the gadget's sysfs directory. If the "removable" option is set, writing to - * these files will simulate ejecting/loading the medium (writing an empty - * line means eject) and adjusting a write-enable tab. Changes to the ro - * setting are not allowed when the medium is loaded or if CD-ROM emulation - * is being used. - * - * This gadget driver is heavily based on "Gadget Zero" by David Brownell. - * The driver's SCSI command interface was based on the "Information - * technology - Small Computer System Interface - 2" document from - * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at - * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. The single exception - * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the - * "Universal Serial Bus Mass Storage Class UFI Command Specification" - * document, Revision 1.0, December 14, 1998, available at - * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>. - */ - - -/* - * Driver Design - * - * The FSG driver is fairly straightforward. There is a main kernel - * thread that handles most of the work. Interrupt routines field - * callbacks from the controller driver: bulk- and interrupt-request - * completion notifications, endpoint-0 events, and disconnect events. - * Completion events are passed to the main thread by wakeup calls. Many - * ep0 requests are handled at interrupt time, but SetInterface, - * SetConfiguration, and device reset requests are forwarded to the - * thread in the form of "exceptions" using SIGUSR1 signals (since they - * should interrupt any ongoing file I/O operations). - * - * The thread's main routine implements the standard command/data/status - * parts of a SCSI interaction. It and its subroutines are full of tests - * for pending signals/exceptions -- all this polling is necessary since - * the kernel has no setjmp/longjmp equivalents. (Maybe this is an - * indication that the driver really wants to be running in userspace.) - * An important point is that so long as the thread is alive it keeps an - * open reference to the backing file. This will prevent unmounting - * the backing file's underlying filesystem and could cause problems - * during system shutdown, for example. To prevent such problems, the - * thread catches INT, TERM, and KILL signals and converts them into - * an EXIT exception. - * - * In normal operation the main thread is started during the gadget's - * fsg_bind() callback and stopped during fsg_unbind(). But it can also - * exit when it receives a signal, and there's no point leaving the - * gadget running when the thread is dead. So just before the thread - * exits, it deregisters the gadget driver. This makes things a little - * tricky: The driver is deregistered at two places, and the exiting - * thread can indirectly call fsg_unbind() which in turn can tell the - * thread to exit. The first problem is resolved through the use of the - * REGISTERED atomic bitflag; the driver will only be deregistered once. - * The second problem is resolved by having fsg_unbind() check - * fsg->state; it won't try to stop the thread if the state is already - * FSG_STATE_TERMINATED. - * - * To provide maximum throughput, the driver uses a circular pipeline of - * buffer heads (struct fsg_buffhd). In principle the pipeline can be - * arbitrarily long; in practice the benefits don't justify having more - * than 2 stages (i.e., double buffering). But it helps to think of the - * pipeline as being a long one. Each buffer head contains a bulk-in and - * a bulk-out request pointer (since the buffer can be used for both - * output and input -- directions always are given from the host's - * point of view) as well as a pointer to the buffer and various state - * variables. - * - * Use of the pipeline follows a simple protocol. There is a variable - * (fsg->next_buffhd_to_fill) that points to the next buffer head to use. - * At any time that buffer head may still be in use from an earlier - * request, so each buffer head has a state variable indicating whether - * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the - * buffer head to be EMPTY, filling the buffer either by file I/O or by - * USB I/O (during which the buffer head is BUSY), and marking the buffer - * head FULL when the I/O is complete. Then the buffer will be emptied - * (again possibly by USB I/O, during which it is marked BUSY) and - * finally marked EMPTY again (possibly by a completion routine). - * - * A module parameter tells the driver to avoid stalling the bulk - * endpoints wherever the transport specification allows. This is - * necessary for some UDCs like the SuperH, which cannot reliably clear a - * halt on a bulk endpoint. However, under certain circumstances the - * Bulk-only specification requires a stall. In such cases the driver - * will halt the endpoint and set a flag indicating that it should clear - * the halt in software during the next device reset. Hopefully this - * will permit everything to work correctly. Furthermore, although the - * specification allows the bulk-out endpoint to halt when the host sends - * too much data, implementing this would cause an unavoidable race. - * The driver will always use the "no-stall" approach for OUT transfers. - * - * One subtle point concerns sending status-stage responses for ep0 - * requests. Some of these requests, such as device reset, can involve - * interrupting an ongoing file I/O operation, which might take an - * arbitrarily long time. During that delay the host might give up on - * the original ep0 request and issue a new one. When that happens the - * driver should not notify the host about completion of the original - * request, as the host will no longer be waiting for it. So the driver - * assigns to each ep0 request a unique tag, and it keeps track of the - * tag value of the request associated with a long-running exception - * (device-reset, interface-change, or configuration-change). When the - * exception handler is finished, the status-stage response is submitted - * only if the current ep0 request tag is equal to the exception request - * tag. Thus only the most recently received ep0 request will get a - * status-stage response. - * - * Warning: This driver source file is too long. It ought to be split up - * into a header file plus about 3 separate .c files, to handle the details - * of the Gadget, USB Mass Storage, and SCSI protocols. - */ - - -/* #define VERBOSE_DEBUG */ -/* #define DUMP_MSGS */ - - -#include <linux/blkdev.h> -#include <linux/completion.h> -#include <linux/dcache.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/fcntl.h> -#include <linux/file.h> -#include <linux/fs.h> -#include <linux/kref.h> -#include <linux/kthread.h> -#include <linux/limits.h> -#include <linux/module.h> -#include <linux/rwsem.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <linux/string.h> -#include <linux/freezer.h> -#include <linux/utsname.h> - -#include <linux/usb/composite.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> - -#include "gadget_chips.h" - -#define DRIVER_DESC "File-backed Storage Gadget" -#define DRIVER_NAME "g_file_storage" -#define DRIVER_VERSION "1 September 2010" - -static char fsg_string_manufacturer[64]; -static const char fsg_string_product[] = DRIVER_DESC; -static const char fsg_string_config[] = "Self-powered"; -static const char fsg_string_interface[] = "Mass Storage"; - - -#include "storage_common.c" - - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Alan Stern"); -MODULE_LICENSE("Dual BSD/GPL"); - -/* - * This driver assumes self-powered hardware and has no way for users to - * trigger remote wakeup. It uses autoconfiguration to select endpoints - * and endpoint addresses. - */ - - -/*-------------------------------------------------------------------------*/ - - -/* Encapsulate the module parameter settings */ - -static struct { - char *file[FSG_MAX_LUNS]; - char *serial; - bool ro[FSG_MAX_LUNS]; - bool nofua[FSG_MAX_LUNS]; - unsigned int num_filenames; - unsigned int num_ros; - unsigned int num_nofuas; - unsigned int nluns; - - bool removable; - bool can_stall; - bool cdrom; - - char *transport_parm; - char *protocol_parm; - unsigned short vendor; - unsigned short product; - unsigned short release; - unsigned int buflen; - - int transport_type; - char *transport_name; - int protocol_type; - char *protocol_name; - -} mod_data = { // Default values - .transport_parm = "BBB", - .protocol_parm = "SCSI", - .removable = 0, - .can_stall = 1, - .cdrom = 0, - .vendor = FSG_VENDOR_ID, - .product = FSG_PRODUCT_ID, - .release = 0xffff, // Use controller chip type - .buflen = 16384, - }; - - -module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames, - S_IRUGO); -MODULE_PARM_DESC(file, "names of backing files or devices"); - -module_param_named(serial, mod_data.serial, charp, S_IRUGO); -MODULE_PARM_DESC(serial, "USB serial number"); - -module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO); -MODULE_PARM_DESC(ro, "true to force read-only"); - -module_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas, - S_IRUGO); -MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit"); - -module_param_named(luns, mod_data.nluns, uint, S_IRUGO); -MODULE_PARM_DESC(luns, "number of LUNs"); - -module_param_named(removable, mod_data.removable, bool, S_IRUGO); -MODULE_PARM_DESC(removable, "true to simulate removable media"); - -module_param_named(stall, mod_data.can_stall, bool, S_IRUGO); -MODULE_PARM_DESC(stall, "false to prevent bulk stalls"); - -module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO); -MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk"); - -/* In the non-TEST version, only the module parameters listed above - * are available. */ -#ifdef CONFIG_USB_FILE_STORAGE_TEST - -module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO); -MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)"); - -module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO); -MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, " - "8070, or SCSI)"); - -module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO); -MODULE_PARM_DESC(vendor, "USB Vendor ID"); - -module_param_named(product, mod_data.product, ushort, S_IRUGO); -MODULE_PARM_DESC(product, "USB Product ID"); - -module_param_named(release, mod_data.release, ushort, S_IRUGO); -MODULE_PARM_DESC(release, "USB release number"); - -module_param_named(buflen, mod_data.buflen, uint, S_IRUGO); -MODULE_PARM_DESC(buflen, "I/O buffer size"); - -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ - - -/* - * These definitions will permit the compiler to avoid generating code for - * parts of the driver that aren't used in the non-TEST version. Even gcc - * can recognize when a test of a constant expression yields a dead code - * path. - */ - -#ifdef CONFIG_USB_FILE_STORAGE_TEST - -#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK) -#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI) -#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI) - -#else - -#define transport_is_bbb() 1 -#define transport_is_cbi() 0 -#define protocol_is_scsi() 1 - -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ - - -/*-------------------------------------------------------------------------*/ - - -struct fsg_dev { - /* lock protects: state, all the req_busy's, and cbbuf_cmnd */ - spinlock_t lock; - struct usb_gadget *gadget; - - /* filesem protects: backing files in use */ - struct rw_semaphore filesem; - - /* reference counting: wait until all LUNs are released */ - struct kref ref; - - struct usb_ep *ep0; // Handy copy of gadget->ep0 - struct usb_request *ep0req; // For control responses - unsigned int ep0_req_tag; - const char *ep0req_name; - - struct usb_request *intreq; // For interrupt responses - int intreq_busy; - struct fsg_buffhd *intr_buffhd; - - unsigned int bulk_out_maxpacket; - enum fsg_state state; // For exception handling - unsigned int exception_req_tag; - - u8 config, new_config; - - unsigned int running : 1; - unsigned int bulk_in_enabled : 1; - unsigned int bulk_out_enabled : 1; - unsigned int intr_in_enabled : 1; - unsigned int phase_error : 1; - unsigned int short_packet_received : 1; - unsigned int bad_lun_okay : 1; - - unsigned long atomic_bitflags; -#define REGISTERED 0 -#define IGNORE_BULK_OUT 1 -#define SUSPENDED 2 - - struct usb_ep *bulk_in; - struct usb_ep *bulk_out; - struct usb_ep *intr_in; - - struct fsg_buffhd *next_buffhd_to_fill; - struct fsg_buffhd *next_buffhd_to_drain; - - int thread_wakeup_needed; - struct completion thread_notifier; - struct task_struct *thread_task; - - int cmnd_size; - u8 cmnd[MAX_COMMAND_SIZE]; - enum data_direction data_dir; - u32 data_size; - u32 data_size_from_cmnd; - u32 tag; - unsigned int lun; - u32 residue; - u32 usb_amount_left; - - /* The CB protocol offers no way for a host to know when a command - * has completed. As a result the next command may arrive early, - * and we will still have to handle it. For that reason we need - * a buffer to store new commands when using CB (or CBI, which - * does not oblige a host to wait for command completion either). */ - int cbbuf_cmnd_size; - u8 cbbuf_cmnd[MAX_COMMAND_SIZE]; - - unsigned int nluns; - struct fsg_lun *luns; - struct fsg_lun *curlun; - /* Must be the last entry */ - struct fsg_buffhd buffhds[]; -}; - -typedef void (*fsg_routine_t)(struct fsg_dev *); - -static int exception_in_progress(struct fsg_dev *fsg) -{ - return (fsg->state > FSG_STATE_IDLE); -} - -/* Make bulk-out requests be divisible by the maxpacket size */ -static void set_bulk_out_req_length(struct fsg_dev *fsg, - struct fsg_buffhd *bh, unsigned int length) -{ - unsigned int rem; - - bh->bulk_out_intended_length = length; - rem = length % fsg->bulk_out_maxpacket; - if (rem > 0) - length += fsg->bulk_out_maxpacket - rem; - bh->outreq->length = length; -} - -static struct fsg_dev *the_fsg; -static struct usb_gadget_driver fsg_driver; - - -/*-------------------------------------------------------------------------*/ - -static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) -{ - const char *name; - - if (ep == fsg->bulk_in) - name = "bulk-in"; - else if (ep == fsg->bulk_out) - name = "bulk-out"; - else - name = ep->name; - DBG(fsg, "%s set halt\n", name); - return usb_ep_set_halt(ep); -} - - -/*-------------------------------------------------------------------------*/ - -/* - * DESCRIPTORS ... most are static, but strings and (full) configuration - * descriptors are built on demand. Also the (static) config and interface - * descriptors are adjusted during fsg_bind(). - */ - -/* There is only one configuration. */ -#define CONFIG_VALUE 1 - -static struct usb_device_descriptor -device_desc = { - .bLength = sizeof device_desc, - .bDescriptorType = USB_DT_DEVICE, - - .bcdUSB = cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_PER_INTERFACE, - - /* The next three values can be overridden by module parameters */ - .idVendor = cpu_to_le16(FSG_VENDOR_ID), - .idProduct = cpu_to_le16(FSG_PRODUCT_ID), - .bcdDevice = cpu_to_le16(0xffff), - - .iManufacturer = FSG_STRING_MANUFACTURER, - .iProduct = FSG_STRING_PRODUCT, - .iSerialNumber = FSG_STRING_SERIAL, - .bNumConfigurations = 1, -}; - -static struct usb_config_descriptor -config_desc = { - .bLength = sizeof config_desc, - .bDescriptorType = USB_DT_CONFIG, - - /* wTotalLength computed by usb_gadget_config_buf() */ - .bNumInterfaces = 1, - .bConfigurationValue = CONFIG_VALUE, - .iConfiguration = FSG_STRING_CONFIG, - .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, -}; - - -static struct usb_qualifier_descriptor -dev_qualifier = { - .bLength = sizeof dev_qualifier, - .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - - .bcdUSB = cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_PER_INTERFACE, - - .bNumConfigurations = 1, -}; - -static int populate_bos(struct fsg_dev *fsg, u8 *buf) -{ - memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE); - buf += USB_DT_BOS_SIZE; - - memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE); - buf += USB_DT_USB_EXT_CAP_SIZE; - - memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE); - - return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE - + USB_DT_USB_EXT_CAP_SIZE; -} - -/* - * Config descriptors must agree with the code that sets configurations - * and with code managing interfaces and their altsettings. They must - * also handle different speeds and other-speed requests. - */ -static int populate_config_buf(struct usb_gadget *gadget, - u8 *buf, u8 type, unsigned index) -{ - enum usb_device_speed speed = gadget->speed; - int len; - const struct usb_descriptor_header **function; - - if (index > 0) - return -EINVAL; - - if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG) - speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; - function = gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH - ? (const struct usb_descriptor_header **)fsg_hs_function - : (const struct usb_descriptor_header **)fsg_fs_function; - - /* for now, don't advertise srp-only devices */ - if (!gadget_is_otg(gadget)) - function++; - - len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); - ((struct usb_config_descriptor *) buf)->bDescriptorType = type; - return len; -} - - -/*-------------------------------------------------------------------------*/ - -/* These routines may be called in process context or in_irq */ - -/* Caller must hold fsg->lock */ -static void wakeup_thread(struct fsg_dev *fsg) -{ - /* Tell the main thread that something has happened */ - fsg->thread_wakeup_needed = 1; - if (fsg->thread_task) - wake_up_process(fsg->thread_task); -} - - -static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) -{ - unsigned long flags; - - /* Do nothing if a higher-priority exception is already in progress. - * If a lower-or-equal priority exception is in progress, preempt it - * and notify the main thread by sending it a signal. */ - spin_lock_irqsave(&fsg->lock, flags); - if (fsg->state <= new_state) { - fsg->exception_req_tag = fsg->ep0_req_tag; - fsg->state = new_state; - if (fsg->thread_task) - send_sig_info(SIGUSR1, SEND_SIG_FORCED, - fsg->thread_task); - } - spin_unlock_irqrestore(&fsg->lock, flags); -} - - -/*-------------------------------------------------------------------------*/ - -/* The disconnect callback and ep0 routines. These always run in_irq, - * except that ep0_queue() is called in the main thread to acknowledge - * completion of various requests: set config, set interface, and - * Bulk-only device reset. */ - -static void fsg_disconnect(struct usb_gadget *gadget) -{ - struct fsg_dev *fsg = get_gadget_data(gadget); - - DBG(fsg, "disconnect or port reset\n"); - raise_exception(fsg, FSG_STATE_DISCONNECT); -} - - -static int ep0_queue(struct fsg_dev *fsg) -{ - int rc; - - rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC); - if (rc != 0 && rc != -ESHUTDOWN) { - - /* We can't do much more than wait for a reset */ - WARNING(fsg, "error in submission: %s --> %d\n", - fsg->ep0->name, rc); - } - return rc; -} - -static void ep0_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct fsg_dev *fsg = ep->driver_data; - - if (req->actual > 0) - dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual); - if (req->status || req->actual != req->length) - DBG(fsg, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, req->length); - if (req->status == -ECONNRESET) // Request was cancelled - usb_ep_fifo_flush(ep); - - if (req->status == 0 && req->context) - ((fsg_routine_t) (req->context))(fsg); -} - - -/*-------------------------------------------------------------------------*/ - -/* Bulk and interrupt endpoint completion handlers. - * These always run in_irq. */ - -static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct fsg_dev *fsg = ep->driver_data; - struct fsg_buffhd *bh = req->context; - - if (req->status || req->actual != req->length) - DBG(fsg, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, req->length); - if (req->status == -ECONNRESET) // Request was cancelled - usb_ep_fifo_flush(ep); - - /* Hold the lock while we update the request and buffer states */ - smp_wmb(); - spin_lock(&fsg->lock); - bh->inreq_busy = 0; - bh->state = BUF_STATE_EMPTY; - wakeup_thread(fsg); - spin_unlock(&fsg->lock); -} - -static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct fsg_dev *fsg = ep->driver_data; - struct fsg_buffhd *bh = req->context; - - dump_msg(fsg, "bulk-out", req->buf, req->actual); - if (req->status || req->actual != bh->bulk_out_intended_length) - DBG(fsg, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, - bh->bulk_out_intended_length); - if (req->status == -ECONNRESET) // Request was cancelled - usb_ep_fifo_flush(ep); - - /* Hold the lock while we update the request and buffer states */ - smp_wmb(); - spin_lock(&fsg->lock); - bh->outreq_busy = 0; - bh->state = BUF_STATE_FULL; - wakeup_thread(fsg); - spin_unlock(&fsg->lock); -} - - -#ifdef CONFIG_USB_FILE_STORAGE_TEST -static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct fsg_dev *fsg = ep->driver_data; - struct fsg_buffhd *bh = req->context; - - if (req->status || req->actual != req->length) - DBG(fsg, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, req->length); - if (req->status == -ECONNRESET) // Request was cancelled - usb_ep_fifo_flush(ep); - - /* Hold the lock while we update the request and buffer states */ - smp_wmb(); - spin_lock(&fsg->lock); - fsg->intreq_busy = 0; - bh->state = BUF_STATE_EMPTY; - wakeup_thread(fsg); - spin_unlock(&fsg->lock); -} - -#else -static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) -{} -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ - - -/*-------------------------------------------------------------------------*/ - -/* Ep0 class-specific handlers. These always run in_irq. */ - -#ifdef CONFIG_USB_FILE_STORAGE_TEST -static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct usb_request *req = fsg->ep0req; - static u8 cbi_reset_cmnd[6] = { - SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff}; - - /* Error in command transfer? */ - if (req->status || req->length != req->actual || - req->actual < 6 || req->actual > MAX_COMMAND_SIZE) { - - /* Not all controllers allow a protocol stall after - * receiving control-out data, but we'll try anyway. */ - fsg_set_halt(fsg, fsg->ep0); - return; // Wait for reset - } - - /* Is it the special reset command? */ - if (req->actual >= sizeof cbi_reset_cmnd && - memcmp(req->buf, cbi_reset_cmnd, - sizeof cbi_reset_cmnd) == 0) { - - /* Raise an exception to stop the current operation - * and reinitialize our state. */ - DBG(fsg, "cbi reset request\n"); - raise_exception(fsg, FSG_STATE_RESET); - return; - } - - VDBG(fsg, "CB[I] accept device-specific command\n"); - spin_lock(&fsg->lock); - - /* Save the command for later */ - if (fsg->cbbuf_cmnd_size) - WARNING(fsg, "CB[I] overwriting previous command\n"); - fsg->cbbuf_cmnd_size = req->actual; - memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size); - - wakeup_thread(fsg); - spin_unlock(&fsg->lock); -} - -#else -static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{} -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ - - -static int class_setup_req(struct fsg_dev *fsg, - const struct usb_ctrlrequest *ctrl) -{ - struct usb_request *req = fsg->ep0req; - int value = -EOPNOTSUPP; - u16 w_index = le16_to_cpu(ctrl->wIndex); - u16 w_value = le16_to_cpu(ctrl->wValue); - u16 w_length = le16_to_cpu(ctrl->wLength); - - if (!fsg->config) - return value; - - /* Handle Bulk-only class-specific requests */ - if (transport_is_bbb()) { - switch (ctrl->bRequest) { - - case US_BULK_RESET_REQUEST: - if (ctrl->bRequestType != (USB_DIR_OUT | - USB_TYPE_CLASS | USB_RECIP_INTERFACE)) - break; - if (w_index != 0 || w_value != 0 || w_length != 0) { - value = -EDOM; - break; - } - - /* Raise an exception to stop the current operation - * and reinitialize our state. */ - DBG(fsg, "bulk reset request\n"); - raise_exception(fsg, FSG_STATE_RESET); - value = DELAYED_STATUS; - break; - - case US_BULK_GET_MAX_LUN: - if (ctrl->bRequestType != (USB_DIR_IN | - USB_TYPE_CLASS | USB_RECIP_INTERFACE)) - break; - if (w_index != 0 || w_value != 0 || w_length != 1) { - value = -EDOM; - break; - } - VDBG(fsg, "get max LUN\n"); - *(u8 *) req->buf = fsg->nluns - 1; - value = 1; - break; - } - } - - /* Handle CBI class-specific requests */ - else { - switch (ctrl->bRequest) { - - case USB_CBI_ADSC_REQUEST: - if (ctrl->bRequestType != (USB_DIR_OUT | - USB_TYPE_CLASS | USB_RECIP_INTERFACE)) - break; - if (w_index != 0 || w_value != 0) { - value = -EDOM; - break; - } - if (w_length > MAX_COMMAND_SIZE) { - value = -EOVERFLOW; - break; - } - value = w_length; - fsg->ep0req->context = received_cbi_adsc; - break; - } - } - - if (value == -EOPNOTSUPP) - VDBG(fsg, - "unknown class-specific control req " - "%02x.%02x v%04x i%04x l%u\n", - ctrl->bRequestType, ctrl->bRequest, - le16_to_cpu(ctrl->wValue), w_index, w_length); - return value; -} - - -/*-------------------------------------------------------------------------*/ - -/* Ep0 standard request handlers. These always run in_irq. */ - -static int standard_setup_req(struct fsg_dev *fsg, - const struct usb_ctrlrequest *ctrl) -{ - struct usb_request *req = fsg->ep0req; - int value = -EOPNOTSUPP; - u16 w_index = le16_to_cpu(ctrl->wIndex); - u16 w_value = le16_to_cpu(ctrl->wValue); - - /* Usually this just stores reply data in the pre-allocated ep0 buffer, - * but config change events will also reconfigure hardware. */ - switch (ctrl->bRequest) { - - case USB_REQ_GET_DESCRIPTOR: - if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | - USB_RECIP_DEVICE)) - break; - switch (w_value >> 8) { - - case USB_DT_DEVICE: - VDBG(fsg, "get device descriptor\n"); - device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket; - value = sizeof device_desc; - memcpy(req->buf, &device_desc, value); - break; - case USB_DT_DEVICE_QUALIFIER: - VDBG(fsg, "get device qualifier\n"); - if (!gadget_is_dualspeed(fsg->gadget) || - fsg->gadget->speed == USB_SPEED_SUPER) - break; - /* - * Assume ep0 uses the same maxpacket value for both - * speeds - */ - dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; - value = sizeof dev_qualifier; - memcpy(req->buf, &dev_qualifier, value); - break; - - case USB_DT_OTHER_SPEED_CONFIG: - VDBG(fsg, "get other-speed config descriptor\n"); - if (!gadget_is_dualspeed(fsg->gadget) || - fsg->gadget->speed == USB_SPEED_SUPER) - break; - goto get_config; - case USB_DT_CONFIG: - VDBG(fsg, "get configuration descriptor\n"); -get_config: - value = populate_config_buf(fsg->gadget, - req->buf, - w_value >> 8, - w_value & 0xff); - break; - - case USB_DT_STRING: - VDBG(fsg, "get string descriptor\n"); - - /* wIndex == language code */ - value = usb_gadget_get_string(&fsg_stringtab, - w_value & 0xff, req->buf); - break; - - case USB_DT_BOS: - VDBG(fsg, "get bos descriptor\n"); - - if (gadget_is_superspeed(fsg->gadget)) - value = populate_bos(fsg, req->buf); - break; - } - - break; - - /* One config, two speeds */ - case USB_REQ_SET_CONFIGURATION: - if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | - USB_RECIP_DEVICE)) - break; - VDBG(fsg, "set configuration\n"); - if (w_value == CONFIG_VALUE || w_value == 0) { - fsg->new_config = w_value; - - /* Raise an exception to wipe out previous transaction - * state (queued bufs, etc) and set the new config. */ - raise_exception(fsg, FSG_STATE_CONFIG_CHANGE); - value = DELAYED_STATUS; - } - break; - case USB_REQ_GET_CONFIGURATION: - if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | - USB_RECIP_DEVICE)) - break; - VDBG(fsg, "get configuration\n"); - *(u8 *) req->buf = fsg->config; - value = 1; - break; - - case USB_REQ_SET_INTERFACE: - if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD | - USB_RECIP_INTERFACE)) - break; - if (fsg->config && w_index == 0) { - - /* Raise an exception to wipe out previous transaction - * state (queued bufs, etc) and install the new - * interface altsetting. */ - raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE); - value = DELAYED_STATUS; - } - break; - case USB_REQ_GET_INTERFACE: - if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | - USB_RECIP_INTERFACE)) - break; - if (!fsg->config) - break; - if (w_index != 0) { - value = -EDOM; - break; - } - VDBG(fsg, "get interface\n"); - *(u8 *) req->buf = 0; - value = 1; - break; - - default: - VDBG(fsg, - "unknown control req %02x.%02x v%04x i%04x l%u\n", - ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, le16_to_cpu(ctrl->wLength)); - } - - return value; -} - - -static int fsg_setup(struct usb_gadget *gadget, - const struct usb_ctrlrequest *ctrl) -{ - struct fsg_dev *fsg = get_gadget_data(gadget); - int rc; - int w_length = le16_to_cpu(ctrl->wLength); - - ++fsg->ep0_req_tag; // Record arrival of a new request - fsg->ep0req->context = NULL; - fsg->ep0req->length = 0; - dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl)); - - if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) - rc = class_setup_req(fsg, ctrl); - else - rc = standard_setup_req(fsg, ctrl); - - /* Respond with data/status or defer until later? */ - if (rc >= 0 && rc != DELAYED_STATUS) { - rc = min(rc, w_length); - fsg->ep0req->length = rc; - fsg->ep0req->zero = rc < w_length; - fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? - "ep0-in" : "ep0-out"); - rc = ep0_queue(fsg); - } - - /* Device either stalls (rc < 0) or reports success */ - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -/* All the following routines run in process context */ - - -/* Use this for bulk or interrupt transfers, not ep0 */ -static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep, - struct usb_request *req, int *pbusy, - enum fsg_buffer_state *state) -{ - int rc; - - if (ep == fsg->bulk_in) - dump_msg(fsg, "bulk-in", req->buf, req->length); - else if (ep == fsg->intr_in) - dump_msg(fsg, "intr-in", req->buf, req->length); - - spin_lock_irq(&fsg->lock); - *pbusy = 1; - *state = BUF_STATE_BUSY; - spin_unlock_irq(&fsg->lock); - rc = usb_ep_queue(ep, req, GFP_KERNEL); - if (rc != 0) { - *pbusy = 0; - *state = BUF_STATE_EMPTY; - - /* We can't do much more than wait for a reset */ - - /* Note: currently the net2280 driver fails zero-length - * submissions if DMA is enabled. */ - if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP && - req->length == 0)) - WARNING(fsg, "error in submission: %s --> %d\n", - ep->name, rc); - } -} - - -static int sleep_thread(struct fsg_dev *fsg) -{ - int rc = 0; - - /* Wait until a signal arrives or we are woken up */ - for (;;) { - try_to_freeze(); - set_current_state(TASK_INTERRUPTIBLE); - if (signal_pending(current)) { - rc = -EINTR; - break; - } - if (fsg->thread_wakeup_needed) - break; - schedule(); - } - __set_current_state(TASK_RUNNING); - fsg->thread_wakeup_needed = 0; - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -static int do_read(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - u32 lba; - struct fsg_buffhd *bh; - int rc; - u32 amount_left; - loff_t file_offset, file_offset_tmp; - unsigned int amount; - ssize_t nread; - - /* Get the starting Logical Block Address and check that it's - * not too big */ - if (fsg->cmnd[0] == READ_6) - lba = get_unaligned_be24(&fsg->cmnd[1]); - else { - lba = get_unaligned_be32(&fsg->cmnd[2]); - - /* We allow DPO (Disable Page Out = don't save data in the - * cache) and FUA (Force Unit Access = don't read from the - * cache), but we don't implement them. */ - if ((fsg->cmnd[1] & ~0x18) != 0) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - } - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - file_offset = ((loff_t) lba) << curlun->blkbits; - - /* Carry out the file reads */ - amount_left = fsg->data_size_from_cmnd; - if (unlikely(amount_left == 0)) - return -EIO; // No default reply - - for (;;) { - - /* Figure out how much we need to read: - * Try to read the remaining amount. - * But don't read more than the buffer size. - * And don't try to read past the end of the file. - */ - amount = min((unsigned int) amount_left, mod_data.buflen); - amount = min((loff_t) amount, - curlun->file_length - file_offset); - - /* Wait for the next buffer to become available */ - bh = fsg->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - - /* If we were asked to read past the end of file, - * end with an empty buffer. */ - if (amount == 0) { - curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - bh->inreq->length = 0; - bh->state = BUF_STATE_FULL; - break; - } - - /* Perform the read */ - file_offset_tmp = file_offset; - nread = vfs_read(curlun->filp, - (char __user *) bh->buf, - amount, &file_offset_tmp); - VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nread); - if (signal_pending(current)) - return -EINTR; - - if (nread < 0) { - LDBG(curlun, "error in file read: %d\n", - (int) nread); - nread = 0; - } else if (nread < amount) { - LDBG(curlun, "partial file read: %d/%u\n", - (int) nread, amount); - nread = round_down(nread, curlun->blksize); - } - file_offset += nread; - amount_left -= nread; - fsg->residue -= nread; - - /* Except at the end of the transfer, nread will be - * equal to the buffer size, which is divisible by the - * bulk-in maxpacket size. - */ - bh->inreq->length = nread; - bh->state = BUF_STATE_FULL; - - /* If an error occurred, report it and its position */ - if (nread < amount) { - curlun->sense_data = SS_UNRECOVERED_READ_ERROR; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - - if (amount_left == 0) - break; // No more left to read - - /* Send this buffer and go read some more */ - bh->inreq->zero = 0; - start_transfer(fsg, fsg->bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - } - - return -EIO; // No default reply -} - - -/*-------------------------------------------------------------------------*/ - -static int do_write(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - u32 lba; - struct fsg_buffhd *bh; - int get_some_more; - u32 amount_left_to_req, amount_left_to_write; - loff_t usb_offset, file_offset, file_offset_tmp; - unsigned int amount; - ssize_t nwritten; - int rc; - - if (curlun->ro) { - curlun->sense_data = SS_WRITE_PROTECTED; - return -EINVAL; - } - spin_lock(&curlun->filp->f_lock); - curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait - spin_unlock(&curlun->filp->f_lock); - - /* Get the starting Logical Block Address and check that it's - * not too big */ - if (fsg->cmnd[0] == WRITE_6) - lba = get_unaligned_be24(&fsg->cmnd[1]); - else { - lba = get_unaligned_be32(&fsg->cmnd[2]); - - /* We allow DPO (Disable Page Out = don't save data in the - * cache) and FUA (Force Unit Access = write directly to the - * medium). We don't implement DPO; we implement FUA by - * performing synchronous output. */ - if ((fsg->cmnd[1] & ~0x18) != 0) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - /* FUA */ - if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) { - spin_lock(&curlun->filp->f_lock); - curlun->filp->f_flags |= O_DSYNC; - spin_unlock(&curlun->filp->f_lock); - } - } - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - - /* Carry out the file writes */ - get_some_more = 1; - file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits; - amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd; - - while (amount_left_to_write > 0) { - - /* Queue a request for more data from the host */ - bh = fsg->next_buffhd_to_fill; - if (bh->state == BUF_STATE_EMPTY && get_some_more) { - - /* Figure out how much we want to get: - * Try to get the remaining amount, - * but not more than the buffer size. - */ - amount = min(amount_left_to_req, mod_data.buflen); - - /* Beyond the end of the backing file? */ - if (usb_offset >= curlun->file_length) { - get_some_more = 0; - curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = usb_offset >> curlun->blkbits; - curlun->info_valid = 1; - continue; - } - - /* Get the next buffer */ - usb_offset += amount; - fsg->usb_amount_left -= amount; - amount_left_to_req -= amount; - if (amount_left_to_req == 0) - get_some_more = 0; - - /* Except at the end of the transfer, amount will be - * equal to the buffer size, which is divisible by - * the bulk-out maxpacket size. - */ - set_bulk_out_req_length(fsg, bh, amount); - start_transfer(fsg, fsg->bulk_out, bh->outreq, - &bh->outreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - continue; - } - - /* Write the received data to the backing file */ - bh = fsg->next_buffhd_to_drain; - if (bh->state == BUF_STATE_EMPTY && !get_some_more) - break; // We stopped early - if (bh->state == BUF_STATE_FULL) { - smp_rmb(); - fsg->next_buffhd_to_drain = bh->next; - bh->state = BUF_STATE_EMPTY; - - /* Did something go wrong with the transfer? */ - if (bh->outreq->status != 0) { - curlun->sense_data = SS_COMMUNICATION_FAILURE; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - - amount = bh->outreq->actual; - if (curlun->file_length - file_offset < amount) { - LERROR(curlun, - "write %u @ %llu beyond end %llu\n", - amount, (unsigned long long) file_offset, - (unsigned long long) curlun->file_length); - amount = curlun->file_length - file_offset; - } - - /* Don't accept excess data. The spec doesn't say - * what to do in this case. We'll ignore the error. - */ - amount = min(amount, bh->bulk_out_intended_length); - - /* Don't write a partial block */ - amount = round_down(amount, curlun->blksize); - if (amount == 0) - goto empty_write; - - /* Perform the write */ - file_offset_tmp = file_offset; - nwritten = vfs_write(curlun->filp, - (char __user *) bh->buf, - amount, &file_offset_tmp); - VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nwritten); - if (signal_pending(current)) - return -EINTR; // Interrupted! - - if (nwritten < 0) { - LDBG(curlun, "error in file write: %d\n", - (int) nwritten); - nwritten = 0; - } else if (nwritten < amount) { - LDBG(curlun, "partial file write: %d/%u\n", - (int) nwritten, amount); - nwritten = round_down(nwritten, curlun->blksize); - } - file_offset += nwritten; - amount_left_to_write -= nwritten; - fsg->residue -= nwritten; - - /* If an error occurred, report it and its position */ - if (nwritten < amount) { - curlun->sense_data = SS_WRITE_ERROR; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - - empty_write: - /* Did the host decide to stop early? */ - if (bh->outreq->actual < bh->bulk_out_intended_length) { - fsg->short_packet_received = 1; - break; - } - continue; - } - - /* Wait for something to happen */ - rc = sleep_thread(fsg); - if (rc) - return rc; - } - - return -EIO; // No default reply -} - - -/*-------------------------------------------------------------------------*/ - -static int do_synchronize_cache(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - int rc; - - /* We ignore the requested LBA and write out all file's - * dirty data buffers. */ - rc = fsg_lun_fsync_sub(curlun); - if (rc) - curlun->sense_data = SS_WRITE_ERROR; - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -static void invalidate_sub(struct fsg_lun *curlun) -{ - struct file *filp = curlun->filp; - struct inode *inode = filp->f_path.dentry->d_inode; - unsigned long rc; - - rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); - VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc); -} - -static int do_verify(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - u32 lba; - u32 verification_length; - struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; - loff_t file_offset, file_offset_tmp; - u32 amount_left; - unsigned int amount; - ssize_t nread; - - /* Get the starting Logical Block Address and check that it's - * not too big */ - lba = get_unaligned_be32(&fsg->cmnd[2]); - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - - /* We allow DPO (Disable Page Out = don't save data in the - * cache) but we don't implement it. */ - if ((fsg->cmnd[1] & ~0x10) != 0) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - verification_length = get_unaligned_be16(&fsg->cmnd[7]); - if (unlikely(verification_length == 0)) - return -EIO; // No default reply - - /* Prepare to carry out the file verify */ - amount_left = verification_length << curlun->blkbits; - file_offset = ((loff_t) lba) << curlun->blkbits; - - /* Write out all the dirty buffers before invalidating them */ - fsg_lun_fsync_sub(curlun); - if (signal_pending(current)) - return -EINTR; - - invalidate_sub(curlun); - if (signal_pending(current)) - return -EINTR; - - /* Just try to read the requested blocks */ - while (amount_left > 0) { - - /* Figure out how much we need to read: - * Try to read the remaining amount, but not more than - * the buffer size. - * And don't try to read past the end of the file. - */ - amount = min((unsigned int) amount_left, mod_data.buflen); - amount = min((loff_t) amount, - curlun->file_length - file_offset); - if (amount == 0) { - curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - - /* Perform the read */ - file_offset_tmp = file_offset; - nread = vfs_read(curlun->filp, - (char __user *) bh->buf, - amount, &file_offset_tmp); - VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nread); - if (signal_pending(current)) - return -EINTR; - - if (nread < 0) { - LDBG(curlun, "error in file verify: %d\n", - (int) nread); - nread = 0; - } else if (nread < amount) { - LDBG(curlun, "partial file verify: %d/%u\n", - (int) nread, amount); - nread = round_down(nread, curlun->blksize); - } - if (nread == 0) { - curlun->sense_data = SS_UNRECOVERED_READ_ERROR; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - file_offset += nread; - amount_left -= nread; - } - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - u8 *buf = (u8 *) bh->buf; - - static char vendor_id[] = "Linux "; - static char product_disk_id[] = "File-Stor Gadget"; - static char product_cdrom_id[] = "File-CD Gadget "; - - if (!fsg->curlun) { // Unsupported LUNs are okay - fsg->bad_lun_okay = 1; - memset(buf, 0, 36); - buf[0] = 0x7f; // Unsupported, no device-type - buf[4] = 31; // Additional length - return 36; - } - - memset(buf, 0, 8); - buf[0] = (mod_data.cdrom ? TYPE_ROM : TYPE_DISK); - if (mod_data.removable) - buf[1] = 0x80; - buf[2] = 2; // ANSI SCSI level 2 - buf[3] = 2; // SCSI-2 INQUIRY data format - buf[4] = 31; // Additional length - // No special options - sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, - (mod_data.cdrom ? product_cdrom_id : - product_disk_id), - mod_data.release); - return 36; -} - - -static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - u8 *buf = (u8 *) bh->buf; - u32 sd, sdinfo; - int valid; - - /* - * From the SCSI-2 spec., section 7.9 (Unit attention condition): - * - * If a REQUEST SENSE command is received from an initiator - * with a pending unit attention condition (before the target - * generates the contingent allegiance condition), then the - * target shall either: - * a) report any pending sense data and preserve the unit - * attention condition on the logical unit, or, - * b) report the unit attention condition, may discard any - * pending sense data, and clear the unit attention - * condition on the logical unit for that initiator. - * - * FSG normally uses option a); enable this code to use option b). - */ -#if 0 - if (curlun && curlun->unit_attention_data != SS_NO_SENSE) { - curlun->sense_data = curlun->unit_attention_data; - curlun->unit_attention_data = SS_NO_SENSE; - } -#endif - - if (!curlun) { // Unsupported LUNs are okay - fsg->bad_lun_okay = 1; - sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; - sdinfo = 0; - valid = 0; - } else { - sd = curlun->sense_data; - sdinfo = curlun->sense_data_info; - valid = curlun->info_valid << 7; - curlun->sense_data = SS_NO_SENSE; - curlun->sense_data_info = 0; - curlun->info_valid = 0; - } - - memset(buf, 0, 18); - buf[0] = valid | 0x70; // Valid, current error - buf[2] = SK(sd); - put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */ - buf[7] = 18 - 8; // Additional sense length - buf[12] = ASC(sd); - buf[13] = ASCQ(sd); - return 18; -} - - -static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - u32 lba = get_unaligned_be32(&fsg->cmnd[2]); - int pmi = fsg->cmnd[8]; - u8 *buf = (u8 *) bh->buf; - - /* Check the PMI and LBA fields */ - if (pmi > 1 || (pmi == 0 && lba != 0)) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); - /* Max logical block */ - put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ - return 8; -} - - -static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - int msf = fsg->cmnd[1] & 0x02; - u32 lba = get_unaligned_be32(&fsg->cmnd[2]); - u8 *buf = (u8 *) bh->buf; - - if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */ - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - - memset(buf, 0, 8); - buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */ - store_cdrom_address(&buf[4], msf, lba); - return 8; -} - - -static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - int msf = fsg->cmnd[1] & 0x02; - int start_track = fsg->cmnd[6]; - u8 *buf = (u8 *) bh->buf; - - if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ - start_track > 1) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - memset(buf, 0, 20); - buf[1] = (20-2); /* TOC data length */ - buf[2] = 1; /* First track number */ - buf[3] = 1; /* Last track number */ - buf[5] = 0x16; /* Data track, copying allowed */ - buf[6] = 0x01; /* Only track is number 1 */ - store_cdrom_address(&buf[8], msf, 0); - - buf[13] = 0x16; /* Lead-out track is data */ - buf[14] = 0xAA; /* Lead-out track number */ - store_cdrom_address(&buf[16], msf, curlun->num_sectors); - return 20; -} - - -static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - int mscmnd = fsg->cmnd[0]; - u8 *buf = (u8 *) bh->buf; - u8 *buf0 = buf; - int pc, page_code; - int changeable_values, all_pages; - int valid_page = 0; - int len, limit; - - if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - pc = fsg->cmnd[2] >> 6; - page_code = fsg->cmnd[2] & 0x3f; - if (pc == 3) { - curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; - return -EINVAL; - } - changeable_values = (pc == 1); - all_pages = (page_code == 0x3f); - - /* Write the mode parameter header. Fixed values are: default - * medium type, no cache control (DPOFUA), and no block descriptors. - * The only variable value is the WriteProtect bit. We will fill in - * the mode data length later. */ - memset(buf, 0, 8); - if (mscmnd == MODE_SENSE) { - buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA - buf += 4; - limit = 255; - } else { // MODE_SENSE_10 - buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA - buf += 8; - limit = 65535; // Should really be mod_data.buflen - } - - /* No block descriptors */ - - /* The mode pages, in numerical order. The only page we support - * is the Caching page. */ - if (page_code == 0x08 || all_pages) { - valid_page = 1; - buf[0] = 0x08; // Page code - buf[1] = 10; // Page length - memset(buf+2, 0, 10); // None of the fields are changeable - - if (!changeable_values) { - buf[2] = 0x04; // Write cache enable, - // Read cache not disabled - // No cache retention priorities - put_unaligned_be16(0xffff, &buf[4]); - /* Don't disable prefetch */ - /* Minimum prefetch = 0 */ - put_unaligned_be16(0xffff, &buf[8]); - /* Maximum prefetch */ - put_unaligned_be16(0xffff, &buf[10]); - /* Maximum prefetch ceiling */ - } - buf += 12; - } - - /* Check that a valid page was requested and the mode data length - * isn't too long. */ - len = buf - buf0; - if (!valid_page || len > limit) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - /* Store the mode data length */ - if (mscmnd == MODE_SENSE) - buf0[0] = len - 1; - else - put_unaligned_be16(len - 2, buf0); - return len; -} - - -static int do_start_stop(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - int loej, start; - - if (!mod_data.removable) { - curlun->sense_data = SS_INVALID_COMMAND; - return -EINVAL; - } - - // int immed = fsg->cmnd[1] & 0x01; - loej = fsg->cmnd[4] & 0x02; - start = fsg->cmnd[4] & 0x01; - -#ifdef CONFIG_USB_FILE_STORAGE_TEST - if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed - (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - if (!start) { - - /* Are we allowed to unload the media? */ - if (curlun->prevent_medium_removal) { - LDBG(curlun, "unload attempt prevented\n"); - curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED; - return -EINVAL; - } - if (loej) { // Simulate an unload/eject - up_read(&fsg->filesem); - down_write(&fsg->filesem); - fsg_lun_close(curlun); - up_write(&fsg->filesem); - down_read(&fsg->filesem); - } - } else { - - /* Our emulation doesn't support mounting; the medium is - * available for use as soon as it is loaded. */ - if (!fsg_lun_is_open(curlun)) { - curlun->sense_data = SS_MEDIUM_NOT_PRESENT; - return -EINVAL; - } - } -#endif - return 0; -} - - -static int do_prevent_allow(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - int prevent; - - if (!mod_data.removable) { - curlun->sense_data = SS_INVALID_COMMAND; - return -EINVAL; - } - - prevent = fsg->cmnd[4] & 0x01; - if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - if (curlun->prevent_medium_removal && !prevent) - fsg_lun_fsync_sub(curlun); - curlun->prevent_medium_removal = prevent; - return 0; -} - - -static int do_read_format_capacities(struct fsg_dev *fsg, - struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - u8 *buf = (u8 *) bh->buf; - - buf[0] = buf[1] = buf[2] = 0; - buf[3] = 8; // Only the Current/Maximum Capacity Descriptor - buf += 4; - - put_unaligned_be32(curlun->num_sectors, &buf[0]); - /* Number of blocks */ - put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ - buf[4] = 0x02; /* Current capacity */ - return 12; -} - - -static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - - /* We don't support MODE SELECT */ - curlun->sense_data = SS_INVALID_COMMAND; - return -EINVAL; -} - - -/*-------------------------------------------------------------------------*/ - -static int halt_bulk_in_endpoint(struct fsg_dev *fsg) -{ - int rc; - - rc = fsg_set_halt(fsg, fsg->bulk_in); - if (rc == -EAGAIN) - VDBG(fsg, "delayed bulk-in endpoint halt\n"); - while (rc != 0) { - if (rc != -EAGAIN) { - WARNING(fsg, "usb_ep_set_halt -> %d\n", rc); - rc = 0; - break; - } - - /* Wait for a short time and then try again */ - if (msleep_interruptible(100) != 0) - return -EINTR; - rc = usb_ep_set_halt(fsg->bulk_in); - } - return rc; -} - -static int wedge_bulk_in_endpoint(struct fsg_dev *fsg) -{ - int rc; - - DBG(fsg, "bulk-in set wedge\n"); - rc = usb_ep_set_wedge(fsg->bulk_in); - if (rc == -EAGAIN) - VDBG(fsg, "delayed bulk-in endpoint wedge\n"); - while (rc != 0) { - if (rc != -EAGAIN) { - WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc); - rc = 0; - break; - } - - /* Wait for a short time and then try again */ - if (msleep_interruptible(100) != 0) - return -EINTR; - rc = usb_ep_set_wedge(fsg->bulk_in); - } - return rc; -} - -static int throw_away_data(struct fsg_dev *fsg) -{ - struct fsg_buffhd *bh; - u32 amount; - int rc; - - while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY || - fsg->usb_amount_left > 0) { - - /* Throw away the data in a filled buffer */ - if (bh->state == BUF_STATE_FULL) { - smp_rmb(); - bh->state = BUF_STATE_EMPTY; - fsg->next_buffhd_to_drain = bh->next; - - /* A short packet or an error ends everything */ - if (bh->outreq->actual < bh->bulk_out_intended_length || - bh->outreq->status != 0) { - raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); - return -EINTR; - } - continue; - } - - /* Try to submit another request if we need one */ - bh = fsg->next_buffhd_to_fill; - if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) { - amount = min(fsg->usb_amount_left, - (u32) mod_data.buflen); - - /* Except at the end of the transfer, amount will be - * equal to the buffer size, which is divisible by - * the bulk-out maxpacket size. - */ - set_bulk_out_req_length(fsg, bh, amount); - start_transfer(fsg, fsg->bulk_out, bh->outreq, - &bh->outreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - fsg->usb_amount_left -= amount; - continue; - } - - /* Otherwise wait for something to happen */ - rc = sleep_thread(fsg); - if (rc) - return rc; - } - return 0; -} - - -static int finish_reply(struct fsg_dev *fsg) -{ - struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; - int rc = 0; - - switch (fsg->data_dir) { - case DATA_DIR_NONE: - break; // Nothing to send - - /* If we don't know whether the host wants to read or write, - * this must be CB or CBI with an unknown command. We mustn't - * try to send or receive any data. So stall both bulk pipes - * if we can and wait for a reset. */ - case DATA_DIR_UNKNOWN: - if (mod_data.can_stall) { - fsg_set_halt(fsg, fsg->bulk_out); - rc = halt_bulk_in_endpoint(fsg); - } - break; - - /* All but the last buffer of data must have already been sent */ - case DATA_DIR_TO_HOST: - if (fsg->data_size == 0) - ; // Nothing to send - - /* If there's no residue, simply send the last buffer */ - else if (fsg->residue == 0) { - bh->inreq->zero = 0; - start_transfer(fsg, fsg->bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - } - - /* There is a residue. For CB and CBI, simply mark the end - * of the data with a short packet. However, if we are - * allowed to stall, there was no data at all (residue == - * data_size), and the command failed (invalid LUN or - * sense data is set), then halt the bulk-in endpoint - * instead. */ - else if (!transport_is_bbb()) { - if (mod_data.can_stall && - fsg->residue == fsg->data_size && - (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) { - bh->state = BUF_STATE_EMPTY; - rc = halt_bulk_in_endpoint(fsg); - } else { - bh->inreq->zero = 1; - start_transfer(fsg, fsg->bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - } - } - - /* - * For Bulk-only, mark the end of the data with a short - * packet. If we are allowed to stall, halt the bulk-in - * endpoint. (Note: This violates the Bulk-Only Transport - * specification, which requires us to pad the data if we - * don't halt the endpoint. Presumably nobody will mind.) - */ - else { - bh->inreq->zero = 1; - start_transfer(fsg, fsg->bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - if (mod_data.can_stall) - rc = halt_bulk_in_endpoint(fsg); - } - break; - - /* We have processed all we want from the data the host has sent. - * There may still be outstanding bulk-out requests. */ - case DATA_DIR_FROM_HOST: - if (fsg->residue == 0) - ; // Nothing to receive - - /* Did the host stop sending unexpectedly early? */ - else if (fsg->short_packet_received) { - raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); - rc = -EINTR; - } - - /* We haven't processed all the incoming data. Even though - * we may be allowed to stall, doing so would cause a race. - * The controller may already have ACK'ed all the remaining - * bulk-out packets, in which case the host wouldn't see a - * STALL. Not realizing the endpoint was halted, it wouldn't - * clear the halt -- leading to problems later on. */ -#if 0 - else if (mod_data.can_stall) { - fsg_set_halt(fsg, fsg->bulk_out); - raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); - rc = -EINTR; - } -#endif - - /* We can't stall. Read in the excess data and throw it - * all away. */ - else - rc = throw_away_data(fsg); - break; - } - return rc; -} - - -static int send_status(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - struct fsg_buffhd *bh; - int rc; - u8 status = US_BULK_STAT_OK; - u32 sd, sdinfo = 0; - - /* Wait for the next buffer to become available */ - bh = fsg->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - - if (curlun) { - sd = curlun->sense_data; - sdinfo = curlun->sense_data_info; - } else if (fsg->bad_lun_okay) - sd = SS_NO_SENSE; - else - sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; - - if (fsg->phase_error) { - DBG(fsg, "sending phase-error status\n"); - status = US_BULK_STAT_PHASE; - sd = SS_INVALID_COMMAND; - } else if (sd != SS_NO_SENSE) { - DBG(fsg, "sending command-failure status\n"); - status = US_BULK_STAT_FAIL; - VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;" - " info x%x\n", - SK(sd), ASC(sd), ASCQ(sd), sdinfo); - } - - if (transport_is_bbb()) { - struct bulk_cs_wrap *csw = bh->buf; - - /* Store and send the Bulk-only CSW */ - csw->Signature = cpu_to_le32(US_BULK_CS_SIGN); - csw->Tag = fsg->tag; - csw->Residue = cpu_to_le32(fsg->residue); - csw->Status = status; - - bh->inreq->length = US_BULK_CS_WRAP_LEN; - bh->inreq->zero = 0; - start_transfer(fsg, fsg->bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state); - - } else if (mod_data.transport_type == USB_PR_CB) { - - /* Control-Bulk transport has no status phase! */ - return 0; - - } else { // USB_PR_CBI - struct interrupt_data *buf = bh->buf; - - /* Store and send the Interrupt data. UFI sends the ASC - * and ASCQ bytes. Everything else sends a Type (which - * is always 0) and the status Value. */ - if (mod_data.protocol_type == USB_SC_UFI) { - buf->bType = ASC(sd); - buf->bValue = ASCQ(sd); - } else { - buf->bType = 0; - buf->bValue = status; - } - fsg->intreq->length = CBI_INTERRUPT_DATA_LEN; - - fsg->intr_buffhd = bh; // Point to the right buffhd - fsg->intreq->buf = bh->inreq->buf; - fsg->intreq->context = bh; - start_transfer(fsg, fsg->intr_in, fsg->intreq, - &fsg->intreq_busy, &bh->state); - } - - fsg->next_buffhd_to_fill = bh->next; - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -/* Check whether the command is properly formed and whether its data size - * and direction agree with the values we already have. */ -static int check_command(struct fsg_dev *fsg, int cmnd_size, - enum data_direction data_dir, unsigned int mask, - int needs_medium, const char *name) -{ - int i; - int lun = fsg->cmnd[1] >> 5; - static const char dirletter[4] = {'u', 'o', 'i', 'n'}; - char hdlen[20]; - struct fsg_lun *curlun; - - /* Adjust the expected cmnd_size for protocol encapsulation padding. - * Transparent SCSI doesn't pad. */ - if (protocol_is_scsi()) - ; - - /* There's some disagreement as to whether RBC pads commands or not. - * We'll play it safe and accept either form. */ - else if (mod_data.protocol_type == USB_SC_RBC) { - if (fsg->cmnd_size == 12) - cmnd_size = 12; - - /* All the other protocols pad to 12 bytes */ - } else - cmnd_size = 12; - - hdlen[0] = 0; - if (fsg->data_dir != DATA_DIR_UNKNOWN) - sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir], - fsg->data_size); - VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n", - name, cmnd_size, dirletter[(int) data_dir], - fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen); - - /* We can't reply at all until we know the correct data direction - * and size. */ - if (fsg->data_size_from_cmnd == 0) - data_dir = DATA_DIR_NONE; - if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI - fsg->data_dir = data_dir; - fsg->data_size = fsg->data_size_from_cmnd; - - } else { // Bulk-only - if (fsg->data_size < fsg->data_size_from_cmnd) { - - /* Host data size < Device data size is a phase error. - * Carry out the command, but only transfer as much - * as we are allowed. */ - fsg->data_size_from_cmnd = fsg->data_size; - fsg->phase_error = 1; - } - } - fsg->residue = fsg->usb_amount_left = fsg->data_size; - - /* Conflicting data directions is a phase error */ - if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) { - fsg->phase_error = 1; - return -EINVAL; - } - - /* Verify the length of the command itself */ - if (cmnd_size != fsg->cmnd_size) { - - /* Special case workaround: There are plenty of buggy SCSI - * implementations. Many have issues with cbw->Length - * field passing a wrong command size. For those cases we - * always try to work around the problem by using the length - * sent by the host side provided it is at least as large - * as the correct command length. - * Examples of such cases would be MS-Windows, which issues - * REQUEST SENSE with cbw->Length == 12 where it should - * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and - * REQUEST SENSE with cbw->Length == 10 where it should - * be 6 as well. - */ - if (cmnd_size <= fsg->cmnd_size) { - DBG(fsg, "%s is buggy! Expected length %d " - "but we got %d\n", name, - cmnd_size, fsg->cmnd_size); - cmnd_size = fsg->cmnd_size; - } else { - fsg->phase_error = 1; - return -EINVAL; - } - } - - /* Check that the LUN values are consistent */ - if (transport_is_bbb()) { - if (fsg->lun != lun) - DBG(fsg, "using LUN %d from CBW, " - "not LUN %d from CDB\n", - fsg->lun, lun); - } - - /* Check the LUN */ - curlun = fsg->curlun; - if (curlun) { - if (fsg->cmnd[0] != REQUEST_SENSE) { - curlun->sense_data = SS_NO_SENSE; - curlun->sense_data_info = 0; - curlun->info_valid = 0; - } - } else { - fsg->bad_lun_okay = 0; - - /* INQUIRY and REQUEST SENSE commands are explicitly allowed - * to use unsupported LUNs; all others may not. */ - if (fsg->cmnd[0] != INQUIRY && - fsg->cmnd[0] != REQUEST_SENSE) { - DBG(fsg, "unsupported LUN %d\n", fsg->lun); - return -EINVAL; - } - } - - /* If a unit attention condition exists, only INQUIRY and - * REQUEST SENSE commands are allowed; anything else must fail. */ - if (curlun && curlun->unit_attention_data != SS_NO_SENSE && - fsg->cmnd[0] != INQUIRY && - fsg->cmnd[0] != REQUEST_SENSE) { - curlun->sense_data = curlun->unit_attention_data; - curlun->unit_attention_data = SS_NO_SENSE; - return -EINVAL; - } - - /* Check that only command bytes listed in the mask are non-zero */ - fsg->cmnd[1] &= 0x1f; // Mask away the LUN - for (i = 1; i < cmnd_size; ++i) { - if (fsg->cmnd[i] && !(mask & (1 << i))) { - if (curlun) - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - } - - /* If the medium isn't mounted and the command needs to access - * it, return an error. */ - if (curlun && !fsg_lun_is_open(curlun) && needs_medium) { - curlun->sense_data = SS_MEDIUM_NOT_PRESENT; - return -EINVAL; - } - - return 0; -} - -/* wrapper of check_command for data size in blocks handling */ -static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size, - enum data_direction data_dir, unsigned int mask, - int needs_medium, const char *name) -{ - if (fsg->curlun) - fsg->data_size_from_cmnd <<= fsg->curlun->blkbits; - return check_command(fsg, cmnd_size, data_dir, - mask, needs_medium, name); -} - -static int do_scsi_command(struct fsg_dev *fsg) -{ - struct fsg_buffhd *bh; - int rc; - int reply = -EINVAL; - int i; - static char unknown[16]; - - dump_cdb(fsg); - - /* Wait for the next buffer to become available for data or status */ - bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - fsg->phase_error = 0; - fsg->short_packet_received = 0; - - down_read(&fsg->filesem); // We're using the backing file - switch (fsg->cmnd[0]) { - - case INQUIRY: - fsg->data_size_from_cmnd = fsg->cmnd[4]; - if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, - (1<<4), 0, - "INQUIRY")) == 0) - reply = do_inquiry(fsg, bh); - break; - - case MODE_SELECT: - fsg->data_size_from_cmnd = fsg->cmnd[4]; - if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, - (1<<1) | (1<<4), 0, - "MODE SELECT(6)")) == 0) - reply = do_mode_select(fsg, bh); - break; - - case MODE_SELECT_10: - fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); - if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, - (1<<1) | (3<<7), 0, - "MODE SELECT(10)")) == 0) - reply = do_mode_select(fsg, bh); - break; - - case MODE_SENSE: - fsg->data_size_from_cmnd = fsg->cmnd[4]; - if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, - (1<<1) | (1<<2) | (1<<4), 0, - "MODE SENSE(6)")) == 0) - reply = do_mode_sense(fsg, bh); - break; - - case MODE_SENSE_10: - fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); - if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, - (1<<1) | (1<<2) | (3<<7), 0, - "MODE SENSE(10)")) == 0) - reply = do_mode_sense(fsg, bh); - break; - - case ALLOW_MEDIUM_REMOVAL: - fsg->data_size_from_cmnd = 0; - if ((reply = check_command(fsg, 6, DATA_DIR_NONE, - (1<<4), 0, - "PREVENT-ALLOW MEDIUM REMOVAL")) == 0) - reply = do_prevent_allow(fsg); - break; - - case READ_6: - i = fsg->cmnd[4]; - fsg->data_size_from_cmnd = (i == 0) ? 256 : i; - if ((reply = check_command_size_in_blocks(fsg, 6, - DATA_DIR_TO_HOST, - (7<<1) | (1<<4), 1, - "READ(6)")) == 0) - reply = do_read(fsg); - break; - - case READ_10: - fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); - if ((reply = check_command_size_in_blocks(fsg, 10, - DATA_DIR_TO_HOST, - (1<<1) | (0xf<<2) | (3<<7), 1, - "READ(10)")) == 0) - reply = do_read(fsg); - break; - - case READ_12: - fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]); - if ((reply = check_command_size_in_blocks(fsg, 12, - DATA_DIR_TO_HOST, - (1<<1) | (0xf<<2) | (0xf<<6), 1, - "READ(12)")) == 0) - reply = do_read(fsg); - break; - - case READ_CAPACITY: - fsg->data_size_from_cmnd = 8; - if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, - (0xf<<2) | (1<<8), 1, - "READ CAPACITY")) == 0) - reply = do_read_capacity(fsg, bh); - break; - - case READ_HEADER: - if (!mod_data.cdrom) - goto unknown_cmnd; - fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); - if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, - (3<<7) | (0x1f<<1), 1, - "READ HEADER")) == 0) - reply = do_read_header(fsg, bh); - break; - - case READ_TOC: - if (!mod_data.cdrom) - goto unknown_cmnd; - fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); - if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, - (7<<6) | (1<<1), 1, - "READ TOC")) == 0) - reply = do_read_toc(fsg, bh); - break; - - case READ_FORMAT_CAPACITIES: - fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); - if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, - (3<<7), 1, - "READ FORMAT CAPACITIES")) == 0) - reply = do_read_format_capacities(fsg, bh); - break; - - case REQUEST_SENSE: - fsg->data_size_from_cmnd = fsg->cmnd[4]; - if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, - (1<<4), 0, - "REQUEST SENSE")) == 0) - reply = do_request_sense(fsg, bh); - break; - - case START_STOP: - fsg->data_size_from_cmnd = 0; - if ((reply = check_command(fsg, 6, DATA_DIR_NONE, - (1<<1) | (1<<4), 0, - "START-STOP UNIT")) == 0) - reply = do_start_stop(fsg); - break; - - case SYNCHRONIZE_CACHE: - fsg->data_size_from_cmnd = 0; - if ((reply = check_command(fsg, 10, DATA_DIR_NONE, - (0xf<<2) | (3<<7), 1, - "SYNCHRONIZE CACHE")) == 0) - reply = do_synchronize_cache(fsg); - break; - - case TEST_UNIT_READY: - fsg->data_size_from_cmnd = 0; - reply = check_command(fsg, 6, DATA_DIR_NONE, - 0, 1, - "TEST UNIT READY"); - break; - - /* Although optional, this command is used by MS-Windows. We - * support a minimal version: BytChk must be 0. */ - case VERIFY: - fsg->data_size_from_cmnd = 0; - if ((reply = check_command(fsg, 10, DATA_DIR_NONE, - (1<<1) | (0xf<<2) | (3<<7), 1, - "VERIFY")) == 0) - reply = do_verify(fsg); - break; - - case WRITE_6: - i = fsg->cmnd[4]; - fsg->data_size_from_cmnd = (i == 0) ? 256 : i; - if ((reply = check_command_size_in_blocks(fsg, 6, - DATA_DIR_FROM_HOST, - (7<<1) | (1<<4), 1, - "WRITE(6)")) == 0) - reply = do_write(fsg); - break; - - case WRITE_10: - fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); - if ((reply = check_command_size_in_blocks(fsg, 10, - DATA_DIR_FROM_HOST, - (1<<1) | (0xf<<2) | (3<<7), 1, - "WRITE(10)")) == 0) - reply = do_write(fsg); - break; - - case WRITE_12: - fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]); - if ((reply = check_command_size_in_blocks(fsg, 12, - DATA_DIR_FROM_HOST, - (1<<1) | (0xf<<2) | (0xf<<6), 1, - "WRITE(12)")) == 0) - reply = do_write(fsg); - break; - - /* Some mandatory commands that we recognize but don't implement. - * They don't mean much in this setting. It's left as an exercise - * for anyone interested to implement RESERVE and RELEASE in terms - * of Posix locks. */ - case FORMAT_UNIT: - case RELEASE: - case RESERVE: - case SEND_DIAGNOSTIC: - // Fall through - - default: - unknown_cmnd: - fsg->data_size_from_cmnd = 0; - sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]); - if ((reply = check_command(fsg, fsg->cmnd_size, - DATA_DIR_UNKNOWN, ~0, 0, unknown)) == 0) { - fsg->curlun->sense_data = SS_INVALID_COMMAND; - reply = -EINVAL; - } - break; - } - up_read(&fsg->filesem); - - if (reply == -EINTR || signal_pending(current)) - return -EINTR; - - /* Set up the single reply buffer for finish_reply() */ - if (reply == -EINVAL) - reply = 0; // Error reply length - if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) { - reply = min((u32) reply, fsg->data_size_from_cmnd); - bh->inreq->length = reply; - bh->state = BUF_STATE_FULL; - fsg->residue -= reply; - } // Otherwise it's already set - - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct usb_request *req = bh->outreq; - struct bulk_cb_wrap *cbw = req->buf; - - /* Was this a real packet? Should it be ignored? */ - if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) - return -EINVAL; - - /* Is the CBW valid? */ - if (req->actual != US_BULK_CB_WRAP_LEN || - cbw->Signature != cpu_to_le32( - US_BULK_CB_SIGN)) { - DBG(fsg, "invalid CBW: len %u sig 0x%x\n", - req->actual, - le32_to_cpu(cbw->Signature)); - - /* The Bulk-only spec says we MUST stall the IN endpoint - * (6.6.1), so it's unavoidable. It also says we must - * retain this state until the next reset, but there's - * no way to tell the controller driver it should ignore - * Clear-Feature(HALT) requests. - * - * We aren't required to halt the OUT endpoint; instead - * we can simply accept and discard any data received - * until the next reset. */ - wedge_bulk_in_endpoint(fsg); - set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); - return -EINVAL; - } - - /* Is the CBW meaningful? */ - if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN || - cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { - DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " - "cmdlen %u\n", - cbw->Lun, cbw->Flags, cbw->Length); - - /* We can do anything we want here, so let's stall the - * bulk pipes if we are allowed to. */ - if (mod_data.can_stall) { - fsg_set_halt(fsg, fsg->bulk_out); - halt_bulk_in_endpoint(fsg); - } - return -EINVAL; - } - - /* Save the command for later */ - fsg->cmnd_size = cbw->Length; - memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size); - if (cbw->Flags & US_BULK_FLAG_IN) - fsg->data_dir = DATA_DIR_TO_HOST; - else - fsg->data_dir = DATA_DIR_FROM_HOST; - fsg->data_size = le32_to_cpu(cbw->DataTransferLength); - if (fsg->data_size == 0) - fsg->data_dir = DATA_DIR_NONE; - fsg->lun = cbw->Lun; - fsg->tag = cbw->Tag; - return 0; -} - - -static int get_next_command(struct fsg_dev *fsg) -{ - struct fsg_buffhd *bh; - int rc = 0; - - if (transport_is_bbb()) { - - /* Wait for the next buffer to become available */ - bh = fsg->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - - /* Queue a request to read a Bulk-only CBW */ - set_bulk_out_req_length(fsg, bh, US_BULK_CB_WRAP_LEN); - start_transfer(fsg, fsg->bulk_out, bh->outreq, - &bh->outreq_busy, &bh->state); - - /* We will drain the buffer in software, which means we - * can reuse it for the next filling. No need to advance - * next_buffhd_to_fill. */ - - /* Wait for the CBW to arrive */ - while (bh->state != BUF_STATE_FULL) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - smp_rmb(); - rc = received_cbw(fsg, bh); - bh->state = BUF_STATE_EMPTY; - - } else { // USB_PR_CB or USB_PR_CBI - - /* Wait for the next command to arrive */ - while (fsg->cbbuf_cmnd_size == 0) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - - /* Is the previous status interrupt request still busy? - * The host is allowed to skip reading the status, - * so we must cancel it. */ - if (fsg->intreq_busy) - usb_ep_dequeue(fsg->intr_in, fsg->intreq); - - /* Copy the command and mark the buffer empty */ - fsg->data_dir = DATA_DIR_UNKNOWN; - spin_lock_irq(&fsg->lock); - fsg->cmnd_size = fsg->cbbuf_cmnd_size; - memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size); - fsg->cbbuf_cmnd_size = 0; - spin_unlock_irq(&fsg->lock); - - /* Use LUN from the command */ - fsg->lun = fsg->cmnd[1] >> 5; - } - - /* Update current lun */ - if (fsg->lun >= 0 && fsg->lun < fsg->nluns) - fsg->curlun = &fsg->luns[fsg->lun]; - else - fsg->curlun = NULL; - - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep, - const struct usb_endpoint_descriptor *d) -{ - int rc; - - ep->driver_data = fsg; - ep->desc = d; - rc = usb_ep_enable(ep); - if (rc) - ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc); - return rc; -} - -static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep, - struct usb_request **preq) -{ - *preq = usb_ep_alloc_request(ep, GFP_ATOMIC); - if (*preq) - return 0; - ERROR(fsg, "can't allocate request for %s\n", ep->name); - return -ENOMEM; -} - -/* - * Reset interface setting and re-init endpoint state (toggle etc). - * Call with altsetting < 0 to disable the interface. The only other - * available altsetting is 0, which enables the interface. - */ -static int do_set_interface(struct fsg_dev *fsg, int altsetting) -{ - int rc = 0; - int i; - const struct usb_endpoint_descriptor *d; - - if (fsg->running) - DBG(fsg, "reset interface\n"); - -reset: - /* Deallocate the requests */ - for (i = 0; i < fsg_num_buffers; ++i) { - struct fsg_buffhd *bh = &fsg->buffhds[i]; - - if (bh->inreq) { - usb_ep_free_request(fsg->bulk_in, bh->inreq); - bh->inreq = NULL; - } - if (bh->outreq) { - usb_ep_free_request(fsg->bulk_out, bh->outreq); - bh->outreq = NULL; - } - } - if (fsg->intreq) { - usb_ep_free_request(fsg->intr_in, fsg->intreq); - fsg->intreq = NULL; - } - - /* Disable the endpoints */ - if (fsg->bulk_in_enabled) { - usb_ep_disable(fsg->bulk_in); - fsg->bulk_in_enabled = 0; - } - if (fsg->bulk_out_enabled) { - usb_ep_disable(fsg->bulk_out); - fsg->bulk_out_enabled = 0; - } - if (fsg->intr_in_enabled) { - usb_ep_disable(fsg->intr_in); - fsg->intr_in_enabled = 0; - } - - fsg->running = 0; - if (altsetting < 0 || rc != 0) - return rc; - - DBG(fsg, "set interface %d\n", altsetting); - - /* Enable the endpoints */ - d = fsg_ep_desc(fsg->gadget, - &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc, - &fsg_ss_bulk_in_desc); - if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0) - goto reset; - fsg->bulk_in_enabled = 1; - - d = fsg_ep_desc(fsg->gadget, - &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc, - &fsg_ss_bulk_out_desc); - if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0) - goto reset; - fsg->bulk_out_enabled = 1; - fsg->bulk_out_maxpacket = usb_endpoint_maxp(d); - clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); - - if (transport_is_cbi()) { - d = fsg_ep_desc(fsg->gadget, - &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc, - &fsg_ss_intr_in_desc); - if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0) - goto reset; - fsg->intr_in_enabled = 1; - } - - /* Allocate the requests */ - for (i = 0; i < fsg_num_buffers; ++i) { - struct fsg_buffhd *bh = &fsg->buffhds[i]; - - if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0) - goto reset; - if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0) - goto reset; - bh->inreq->buf = bh->outreq->buf = bh->buf; - bh->inreq->context = bh->outreq->context = bh; - bh->inreq->complete = bulk_in_complete; - bh->outreq->complete = bulk_out_complete; - } - if (transport_is_cbi()) { - if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0) - goto reset; - fsg->intreq->complete = intr_in_complete; - } - - fsg->running = 1; - for (i = 0; i < fsg->nluns; ++i) - fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; - return rc; -} - - -/* - * Change our operational configuration. This code must agree with the code - * that returns config descriptors, and with interface altsetting code. - * - * It's also responsible for power management interactions. Some - * configurations might not work with our current power sources. - * For now we just assume the gadget is always self-powered. - */ -static int do_set_config(struct fsg_dev *fsg, u8 new_config) -{ - int rc = 0; - - /* Disable the single interface */ - if (fsg->config != 0) { - DBG(fsg, "reset config\n"); - fsg->config = 0; - rc = do_set_interface(fsg, -1); - } - - /* Enable the interface */ - if (new_config != 0) { - fsg->config = new_config; - if ((rc = do_set_interface(fsg, 0)) != 0) - fsg->config = 0; // Reset on errors - else - INFO(fsg, "%s config #%d\n", - usb_speed_string(fsg->gadget->speed), - fsg->config); - } - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -static void handle_exception(struct fsg_dev *fsg) -{ - siginfo_t info; - int sig; - int i; - int num_active; - struct fsg_buffhd *bh; - enum fsg_state old_state; - u8 new_config; - struct fsg_lun *curlun; - unsigned int exception_req_tag; - int rc; - - /* Clear the existing signals. Anything but SIGUSR1 is converted - * into a high-priority EXIT exception. */ - for (;;) { - sig = dequeue_signal_lock(current, ¤t->blocked, &info); - if (!sig) - break; - if (sig != SIGUSR1) { - if (fsg->state < FSG_STATE_EXIT) - DBG(fsg, "Main thread exiting on signal\n"); - raise_exception(fsg, FSG_STATE_EXIT); - } - } - - /* Cancel all the pending transfers */ - if (fsg->intreq_busy) - usb_ep_dequeue(fsg->intr_in, fsg->intreq); - for (i = 0; i < fsg_num_buffers; ++i) { - bh = &fsg->buffhds[i]; - if (bh->inreq_busy) - usb_ep_dequeue(fsg->bulk_in, bh->inreq); - if (bh->outreq_busy) - usb_ep_dequeue(fsg->bulk_out, bh->outreq); - } - - /* Wait until everything is idle */ - for (;;) { - num_active = fsg->intreq_busy; - for (i = 0; i < fsg_num_buffers; ++i) { - bh = &fsg->buffhds[i]; - num_active += bh->inreq_busy + bh->outreq_busy; - } - if (num_active == 0) - break; - if (sleep_thread(fsg)) - return; - } - - /* Clear out the controller's fifos */ - if (fsg->bulk_in_enabled) - usb_ep_fifo_flush(fsg->bulk_in); - if (fsg->bulk_out_enabled) - usb_ep_fifo_flush(fsg->bulk_out); - if (fsg->intr_in_enabled) - usb_ep_fifo_flush(fsg->intr_in); - - /* Reset the I/O buffer states and pointers, the SCSI - * state, and the exception. Then invoke the handler. */ - spin_lock_irq(&fsg->lock); - - for (i = 0; i < fsg_num_buffers; ++i) { - bh = &fsg->buffhds[i]; - bh->state = BUF_STATE_EMPTY; - } - fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain = - &fsg->buffhds[0]; - - exception_req_tag = fsg->exception_req_tag; - new_config = fsg->new_config; - old_state = fsg->state; - - if (old_state == FSG_STATE_ABORT_BULK_OUT) - fsg->state = FSG_STATE_STATUS_PHASE; - else { - for (i = 0; i < fsg->nluns; ++i) { - curlun = &fsg->luns[i]; - curlun->prevent_medium_removal = 0; - curlun->sense_data = curlun->unit_attention_data = - SS_NO_SENSE; - curlun->sense_data_info = 0; - curlun->info_valid = 0; - } - fsg->state = FSG_STATE_IDLE; - } - spin_unlock_irq(&fsg->lock); - - /* Carry out any extra actions required for the exception */ - switch (old_state) { - default: - break; - - case FSG_STATE_ABORT_BULK_OUT: - send_status(fsg); - spin_lock_irq(&fsg->lock); - if (fsg->state == FSG_STATE_STATUS_PHASE) - fsg->state = FSG_STATE_IDLE; - spin_unlock_irq(&fsg->lock); - break; - - case FSG_STATE_RESET: - /* In case we were forced against our will to halt a - * bulk endpoint, clear the halt now. (The SuperH UDC - * requires this.) */ - if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) - usb_ep_clear_halt(fsg->bulk_in); - - if (transport_is_bbb()) { - if (fsg->ep0_req_tag == exception_req_tag) - ep0_queue(fsg); // Complete the status stage - - } else if (transport_is_cbi()) - send_status(fsg); // Status by interrupt pipe - - /* Technically this should go here, but it would only be - * a waste of time. Ditto for the INTERFACE_CHANGE and - * CONFIG_CHANGE cases. */ - // for (i = 0; i < fsg->nluns; ++i) - // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; - break; - - case FSG_STATE_INTERFACE_CHANGE: - rc = do_set_interface(fsg, 0); - if (fsg->ep0_req_tag != exception_req_tag) - break; - if (rc != 0) // STALL on errors - fsg_set_halt(fsg, fsg->ep0); - else // Complete the status stage - ep0_queue(fsg); - break; - - case FSG_STATE_CONFIG_CHANGE: - rc = do_set_config(fsg, new_config); - if (fsg->ep0_req_tag != exception_req_tag) - break; - if (rc != 0) // STALL on errors - fsg_set_halt(fsg, fsg->ep0); - else // Complete the status stage - ep0_queue(fsg); - break; - - case FSG_STATE_DISCONNECT: - for (i = 0; i < fsg->nluns; ++i) - fsg_lun_fsync_sub(fsg->luns + i); - do_set_config(fsg, 0); // Unconfigured state - break; - - case FSG_STATE_EXIT: - case FSG_STATE_TERMINATED: - do_set_config(fsg, 0); // Free resources - spin_lock_irq(&fsg->lock); - fsg->state = FSG_STATE_TERMINATED; // Stop the thread - spin_unlock_irq(&fsg->lock); - break; - } -} - - -/*-------------------------------------------------------------------------*/ - -static int fsg_main_thread(void *fsg_) -{ - struct fsg_dev *fsg = fsg_; - - /* Allow the thread to be killed by a signal, but set the signal mask - * to block everything but INT, TERM, KILL, and USR1. */ - allow_signal(SIGINT); - allow_signal(SIGTERM); - allow_signal(SIGKILL); - allow_signal(SIGUSR1); - - /* Allow the thread to be frozen */ - set_freezable(); - - /* Arrange for userspace references to be interpreted as kernel - * pointers. That way we can pass a kernel pointer to a routine - * that expects a __user pointer and it will work okay. */ - set_fs(get_ds()); - - /* The main loop */ - while (fsg->state != FSG_STATE_TERMINATED) { - if (exception_in_progress(fsg) || signal_pending(current)) { - handle_exception(fsg); - continue; - } - - if (!fsg->running) { - sleep_thread(fsg); - continue; - } - - if (get_next_command(fsg)) - continue; - - spin_lock_irq(&fsg->lock); - if (!exception_in_progress(fsg)) - fsg->state = FSG_STATE_DATA_PHASE; - spin_unlock_irq(&fsg->lock); - - if (do_scsi_command(fsg) || finish_reply(fsg)) - continue; - - spin_lock_irq(&fsg->lock); - if (!exception_in_progress(fsg)) - fsg->state = FSG_STATE_STATUS_PHASE; - spin_unlock_irq(&fsg->lock); - - if (send_status(fsg)) - continue; - - spin_lock_irq(&fsg->lock); - if (!exception_in_progress(fsg)) - fsg->state = FSG_STATE_IDLE; - spin_unlock_irq(&fsg->lock); - } - - spin_lock_irq(&fsg->lock); - fsg->thread_task = NULL; - spin_unlock_irq(&fsg->lock); - - /* If we are exiting because of a signal, unregister the - * gadget driver. */ - if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) - usb_gadget_unregister_driver(&fsg_driver); - - /* Let the unbind and cleanup routines know the thread has exited */ - complete_and_exit(&fsg->thread_notifier, 0); -} - - -/*-------------------------------------------------------------------------*/ - - -/* The write permissions and store_xxx pointers are set in fsg_bind() */ -static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL); -static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL); -static DEVICE_ATTR(file, 0444, fsg_show_file, NULL); - - -/*-------------------------------------------------------------------------*/ - -static void fsg_release(struct kref *ref) -{ - struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref); - - kfree(fsg->luns); - kfree(fsg); -} - -static void lun_release(struct device *dev) -{ - struct rw_semaphore *filesem = dev_get_drvdata(dev); - struct fsg_dev *fsg = - container_of(filesem, struct fsg_dev, filesem); - - kref_put(&fsg->ref, fsg_release); -} - -static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) -{ - struct fsg_dev *fsg = get_gadget_data(gadget); - int i; - struct fsg_lun *curlun; - struct usb_request *req = fsg->ep0req; - - DBG(fsg, "unbind\n"); - clear_bit(REGISTERED, &fsg->atomic_bitflags); - - /* If the thread isn't already dead, tell it to exit now */ - if (fsg->state != FSG_STATE_TERMINATED) { - raise_exception(fsg, FSG_STATE_EXIT); - wait_for_completion(&fsg->thread_notifier); - - /* The cleanup routine waits for this completion also */ - complete(&fsg->thread_notifier); - } - - /* Unregister the sysfs attribute files and the LUNs */ - for (i = 0; i < fsg->nluns; ++i) { - curlun = &fsg->luns[i]; - if (curlun->registered) { - device_remove_file(&curlun->dev, &dev_attr_nofua); - device_remove_file(&curlun->dev, &dev_attr_ro); - device_remove_file(&curlun->dev, &dev_attr_file); - fsg_lun_close(curlun); - device_unregister(&curlun->dev); - curlun->registered = 0; - } - } - - /* Free the data buffers */ - for (i = 0; i < fsg_num_buffers; ++i) - kfree(fsg->buffhds[i].buf); - - /* Free the request and buffer for endpoint 0 */ - if (req) { - kfree(req->buf); - usb_ep_free_request(fsg->ep0, req); - } - - set_gadget_data(gadget, NULL); -} - - -static int __init check_parameters(struct fsg_dev *fsg) -{ - int prot; - - /* Store the default values */ - mod_data.transport_type = USB_PR_BULK; - mod_data.transport_name = "Bulk-only"; - mod_data.protocol_type = USB_SC_SCSI; - mod_data.protocol_name = "Transparent SCSI"; - - /* Some peripheral controllers are known not to be able to - * halt bulk endpoints correctly. If one of them is present, - * disable stalls. - */ - if (gadget_is_at91(fsg->gadget)) - mod_data.can_stall = 0; - - if (mod_data.release == 0xffff) - mod_data.release = get_default_bcdDevice(); - - prot = simple_strtol(mod_data.protocol_parm, NULL, 0); - -#ifdef CONFIG_USB_FILE_STORAGE_TEST - if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) { - ; // Use default setting - } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) { - mod_data.transport_type = USB_PR_CB; - mod_data.transport_name = "Control-Bulk"; - } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) { - mod_data.transport_type = USB_PR_CBI; - mod_data.transport_name = "Control-Bulk-Interrupt"; - } else { - ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm); - return -EINVAL; - } - - if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 || - prot == USB_SC_SCSI) { - ; // Use default setting - } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 || - prot == USB_SC_RBC) { - mod_data.protocol_type = USB_SC_RBC; - mod_data.protocol_name = "RBC"; - } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 || - strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 || - prot == USB_SC_8020) { - mod_data.protocol_type = USB_SC_8020; - mod_data.protocol_name = "8020i (ATAPI)"; - } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 || - prot == USB_SC_QIC) { - mod_data.protocol_type = USB_SC_QIC; - mod_data.protocol_name = "QIC-157"; - } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 || - prot == USB_SC_UFI) { - mod_data.protocol_type = USB_SC_UFI; - mod_data.protocol_name = "UFI"; - } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 || - prot == USB_SC_8070) { - mod_data.protocol_type = USB_SC_8070; - mod_data.protocol_name = "8070i"; - } else { - ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm); - return -EINVAL; - } - - mod_data.buflen &= PAGE_CACHE_MASK; - if (mod_data.buflen <= 0) { - ERROR(fsg, "invalid buflen\n"); - return -ETOOSMALL; - } - -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ - - /* Serial string handling. - * On a real device, the serial string would be loaded - * from permanent storage. */ - if (mod_data.serial) { - const char *ch; - unsigned len = 0; - - /* Sanity check : - * The CB[I] specification limits the serial string to - * 12 uppercase hexadecimal characters. - * BBB need at least 12 uppercase hexadecimal characters, - * with a maximum of 126. */ - for (ch = mod_data.serial; *ch; ++ch) { - ++len; - if ((*ch < '0' || *ch > '9') && - (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */ - WARNING(fsg, - "Invalid serial string character: %c\n", - *ch); - goto no_serial; - } - } - if (len > 126 || - (mod_data.transport_type == USB_PR_BULK && len < 12) || - (mod_data.transport_type != USB_PR_BULK && len > 12)) { - WARNING(fsg, "Invalid serial string length!\n"); - goto no_serial; - } - fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial; - } else { - WARNING(fsg, "No serial-number string provided!\n"); - no_serial: - device_desc.iSerialNumber = 0; - } - - return 0; -} - - -static int __init fsg_bind(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - struct fsg_dev *fsg = the_fsg; - int rc; - int i; - struct fsg_lun *curlun; - struct usb_ep *ep; - struct usb_request *req; - char *pathbuf, *p; - - fsg->gadget = gadget; - set_gadget_data(gadget, fsg); - fsg->ep0 = gadget->ep0; - fsg->ep0->driver_data = fsg; - - if ((rc = check_parameters(fsg)) != 0) - goto out; - - if (mod_data.removable) { // Enable the store_xxx attributes - dev_attr_file.attr.mode = 0644; - dev_attr_file.store = fsg_store_file; - if (!mod_data.cdrom) { - dev_attr_ro.attr.mode = 0644; - dev_attr_ro.store = fsg_store_ro; - } - } - - /* Only for removable media? */ - dev_attr_nofua.attr.mode = 0644; - dev_attr_nofua.store = fsg_store_nofua; - - /* Find out how many LUNs there should be */ - i = mod_data.nluns; - if (i == 0) - i = max(mod_data.num_filenames, 1u); - if (i > FSG_MAX_LUNS) { - ERROR(fsg, "invalid number of LUNs: %d\n", i); - rc = -EINVAL; - goto out; - } - - /* Create the LUNs, open their backing files, and register the - * LUN devices in sysfs. */ - fsg->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL); - if (!fsg->luns) { - rc = -ENOMEM; - goto out; - } - fsg->nluns = i; - - for (i = 0; i < fsg->nluns; ++i) { - curlun = &fsg->luns[i]; - curlun->cdrom = !!mod_data.cdrom; - curlun->ro = mod_data.cdrom || mod_data.ro[i]; - curlun->initially_ro = curlun->ro; - curlun->removable = mod_data.removable; - curlun->nofua = mod_data.nofua[i]; - curlun->dev.release = lun_release; - curlun->dev.parent = &gadget->dev; - curlun->dev.driver = &fsg_driver.driver; - dev_set_drvdata(&curlun->dev, &fsg->filesem); - dev_set_name(&curlun->dev,"%s-lun%d", - dev_name(&gadget->dev), i); - - kref_get(&fsg->ref); - rc = device_register(&curlun->dev); - if (rc) { - INFO(fsg, "failed to register LUN%d: %d\n", i, rc); - put_device(&curlun->dev); - goto out; - } - curlun->registered = 1; - - rc = device_create_file(&curlun->dev, &dev_attr_ro); - if (rc) - goto out; - rc = device_create_file(&curlun->dev, &dev_attr_nofua); - if (rc) - goto out; - rc = device_create_file(&curlun->dev, &dev_attr_file); - if (rc) - goto out; - - if (mod_data.file[i] && *mod_data.file[i]) { - rc = fsg_lun_open(curlun, mod_data.file[i]); - if (rc) - goto out; - } else if (!mod_data.removable) { - ERROR(fsg, "no file given for LUN%d\n", i); - rc = -EINVAL; - goto out; - } - } - - /* Find all the endpoints we will use */ - usb_ep_autoconfig_reset(gadget); - ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc); - if (!ep) - goto autoconf_fail; - ep->driver_data = fsg; // claim the endpoint - fsg->bulk_in = ep; - - ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc); - if (!ep) - goto autoconf_fail; - ep->driver_data = fsg; // claim the endpoint - fsg->bulk_out = ep; - - if (transport_is_cbi()) { - ep = usb_ep_autoconfig(gadget, &fsg_fs_intr_in_desc); - if (!ep) - goto autoconf_fail; - ep->driver_data = fsg; // claim the endpoint - fsg->intr_in = ep; - } - - /* Fix up the descriptors */ - device_desc.idVendor = cpu_to_le16(mod_data.vendor); - device_desc.idProduct = cpu_to_le16(mod_data.product); - device_desc.bcdDevice = cpu_to_le16(mod_data.release); - - i = (transport_is_cbi() ? 3 : 2); // Number of endpoints - fsg_intf_desc.bNumEndpoints = i; - fsg_intf_desc.bInterfaceSubClass = mod_data.protocol_type; - fsg_intf_desc.bInterfaceProtocol = mod_data.transport_type; - fsg_fs_function[i + FSG_FS_FUNCTION_PRE_EP_ENTRIES] = NULL; - - if (gadget_is_dualspeed(gadget)) { - fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL; - - /* Assume endpoint addresses are the same for both speeds */ - fsg_hs_bulk_in_desc.bEndpointAddress = - fsg_fs_bulk_in_desc.bEndpointAddress; - fsg_hs_bulk_out_desc.bEndpointAddress = - fsg_fs_bulk_out_desc.bEndpointAddress; - fsg_hs_intr_in_desc.bEndpointAddress = - fsg_fs_intr_in_desc.bEndpointAddress; - } - - if (gadget_is_superspeed(gadget)) { - unsigned max_burst; - - fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL; - - /* Calculate bMaxBurst, we know packet size is 1024 */ - max_burst = min_t(unsigned, mod_data.buflen / 1024, 15); - - /* Assume endpoint addresses are the same for both speeds */ - fsg_ss_bulk_in_desc.bEndpointAddress = - fsg_fs_bulk_in_desc.bEndpointAddress; - fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst; - - fsg_ss_bulk_out_desc.bEndpointAddress = - fsg_fs_bulk_out_desc.bEndpointAddress; - fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst; - } - - if (gadget_is_otg(gadget)) - fsg_otg_desc.bmAttributes |= USB_OTG_HNP; - - rc = -ENOMEM; - - /* Allocate the request and buffer for endpoint 0 */ - fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL); - if (!req) - goto out; - req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL); - if (!req->buf) - goto out; - req->complete = ep0_complete; - - /* Allocate the data buffers */ - for (i = 0; i < fsg_num_buffers; ++i) { - struct fsg_buffhd *bh = &fsg->buffhds[i]; - - /* Allocate for the bulk-in endpoint. We assume that - * the buffer will also work with the bulk-out (and - * interrupt-in) endpoint. */ - bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL); - if (!bh->buf) - goto out; - bh->next = bh + 1; - } - fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0]; - - /* This should reflect the actual gadget power source */ - usb_gadget_set_selfpowered(gadget); - - snprintf(fsg_string_manufacturer, sizeof fsg_string_manufacturer, - "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - - fsg->thread_task = kthread_create(fsg_main_thread, fsg, - "file-storage-gadget"); - if (IS_ERR(fsg->thread_task)) { - rc = PTR_ERR(fsg->thread_task); - goto out; - } - - INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); - INFO(fsg, "NOTE: This driver is deprecated. " - "Consider using g_mass_storage instead.\n"); - INFO(fsg, "Number of LUNs=%d\n", fsg->nluns); - - pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); - for (i = 0; i < fsg->nluns; ++i) { - curlun = &fsg->luns[i]; - if (fsg_lun_is_open(curlun)) { - p = NULL; - if (pathbuf) { - p = d_path(&curlun->filp->f_path, - pathbuf, PATH_MAX); - if (IS_ERR(p)) - p = NULL; - } - LINFO(curlun, "ro=%d, nofua=%d, file: %s\n", - curlun->ro, curlun->nofua, (p ? p : "(error)")); - } - } - kfree(pathbuf); - - DBG(fsg, "transport=%s (x%02x)\n", - mod_data.transport_name, mod_data.transport_type); - DBG(fsg, "protocol=%s (x%02x)\n", - mod_data.protocol_name, mod_data.protocol_type); - DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n", - mod_data.vendor, mod_data.product, mod_data.release); - DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n", - mod_data.removable, mod_data.can_stall, - mod_data.cdrom, mod_data.buflen); - DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task)); - - set_bit(REGISTERED, &fsg->atomic_bitflags); - - /* Tell the thread to start working */ - wake_up_process(fsg->thread_task); - return 0; - -autoconf_fail: - ERROR(fsg, "unable to autoconfigure all endpoints\n"); - rc = -ENOTSUPP; - -out: - fsg->state = FSG_STATE_TERMINATED; // The thread is dead - fsg_unbind(gadget); - complete(&fsg->thread_notifier); - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -static void fsg_suspend(struct usb_gadget *gadget) -{ - struct fsg_dev *fsg = get_gadget_data(gadget); - - DBG(fsg, "suspend\n"); - set_bit(SUSPENDED, &fsg->atomic_bitflags); -} - -static void fsg_resume(struct usb_gadget *gadget) -{ - struct fsg_dev *fsg = get_gadget_data(gadget); - - DBG(fsg, "resume\n"); - clear_bit(SUSPENDED, &fsg->atomic_bitflags); -} - - -/*-------------------------------------------------------------------------*/ - -static __refdata struct usb_gadget_driver fsg_driver = { - .max_speed = USB_SPEED_SUPER, - .function = (char *) fsg_string_product, - .bind = fsg_bind, - .unbind = fsg_unbind, - .disconnect = fsg_disconnect, - .setup = fsg_setup, - .suspend = fsg_suspend, - .resume = fsg_resume, - - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - // .release = ... - // .suspend = ... - // .resume = ... - }, -}; - - -static int __init fsg_alloc(void) -{ - struct fsg_dev *fsg; - - fsg = kzalloc(sizeof *fsg + - fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL); - - if (!fsg) - return -ENOMEM; - spin_lock_init(&fsg->lock); - init_rwsem(&fsg->filesem); - kref_init(&fsg->ref); - init_completion(&fsg->thread_notifier); - - the_fsg = fsg; - return 0; -} - - -static int __init fsg_init(void) -{ - int rc; - struct fsg_dev *fsg; - - rc = fsg_num_buffers_validate(); - if (rc != 0) - return rc; - - if ((rc = fsg_alloc()) != 0) - return rc; - fsg = the_fsg; - rc = usb_gadget_probe_driver(&fsg_driver); - if (rc != 0) - kref_put(&fsg->ref, fsg_release); - return rc; -} -module_init(fsg_init); - - -static void __exit fsg_cleanup(void) -{ - struct fsg_dev *fsg = the_fsg; - - /* Unregister the driver iff the thread hasn't already done so */ - if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) - usb_gadget_unregister_driver(&fsg_driver); - - /* Wait for the thread to finish up */ - wait_for_completion(&fsg->thread_notifier); - - kref_put(&fsg->ref, fsg_release); -} -module_exit(fsg_cleanup); diff --git a/drivers/usb/gadget/fsl_mxc_udc.c b/drivers/usb/gadget/fsl_mxc_udc.c index 1b0f086426bd..d3bd7b095ba3 100644 --- a/drivers/usb/gadget/fsl_mxc_udc.c +++ b/drivers/usb/gadget/fsl_mxc_udc.c @@ -18,14 +18,13 @@ #include <linux/platform_device.h> #include <linux/io.h> -#include <mach/hardware.h> - static struct clk *mxc_ahb_clk; static struct clk *mxc_per_clk; static struct clk *mxc_ipg_clk; /* workaround ENGcm09152 for i.MX35 */ -#define USBPHYCTRL_OTGBASE_OFFSET 0x608 +#define MX35_USBPHYCTRL_OFFSET 0x600 +#define USBPHYCTRL_OTGBASE_OFFSET 0x8 #define USBPHYCTRL_EVDO (1 << 23) int fsl_udc_clk_init(struct platform_device *pdev) @@ -59,7 +58,7 @@ int fsl_udc_clk_init(struct platform_device *pdev) clk_prepare_enable(mxc_per_clk); /* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */ - if (!cpu_is_mx51()) { + if (!strcmp(pdev->id_entry->name, "imx-udc-mx27")) { freq = clk_get_rate(mxc_per_clk); if (pdata->phy_mode != FSL_USB2_PHY_ULPI && (freq < 59999000 || freq > 60001000)) { @@ -79,27 +78,40 @@ eclkrate: return ret; } -void fsl_udc_clk_finalize(struct platform_device *pdev) +int fsl_udc_clk_finalize(struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; - if (cpu_is_mx35()) { - unsigned int v; + int ret = 0; - /* workaround ENGcm09152 for i.MX35 */ - if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) { - v = readl(MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + - USBPHYCTRL_OTGBASE_OFFSET)); - writel(v | USBPHYCTRL_EVDO, - MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + - USBPHYCTRL_OTGBASE_OFFSET)); + /* workaround ENGcm09152 for i.MX35 */ + if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) { + unsigned int v; + struct resource *res = platform_get_resource + (pdev, IORESOURCE_MEM, 0); + void __iomem *phy_regs = ioremap(res->start + + MX35_USBPHYCTRL_OFFSET, 512); + if (!phy_regs) { + dev_err(&pdev->dev, "ioremap for phy address fails\n"); + ret = -EINVAL; + goto ioremap_err; } + + v = readl(phy_regs + USBPHYCTRL_OTGBASE_OFFSET); + writel(v | USBPHYCTRL_EVDO, + phy_regs + USBPHYCTRL_OTGBASE_OFFSET); + + iounmap(phy_regs); } + +ioremap_err: /* ULPI transceivers don't need usbpll */ if (pdata->phy_mode == FSL_USB2_PHY_ULPI) { clk_disable_unprepare(mxc_per_clk); mxc_per_clk = NULL; } + + return ret; } void fsl_udc_clk_release(void) diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index b09452d6f33a..034477ce77c6 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, @@ -2347,7 +2347,7 @@ static int fsl_qe_stop(struct usb_gadget *gadget, } /* udc structure's alloc and setup, include ep-param alloc */ -static struct qe_udc __devinit *qe_udc_config(struct platform_device *ofdev) +static struct qe_udc *qe_udc_config(struct platform_device *ofdev) { struct qe_udc *udc; struct device_node *np = ofdev->dev.of_node; @@ -2402,7 +2402,7 @@ cleanup: } /* USB Controller register init */ -static int __devinit qe_udc_reg_init(struct qe_udc *udc) +static int qe_udc_reg_init(struct qe_udc *udc) { struct usb_ctlr __iomem *qe_usbregs; qe_usbregs = udc->usb_regs; @@ -2420,7 +2420,7 @@ static int __devinit qe_udc_reg_init(struct qe_udc *udc) return 0; } -static int __devinit qe_ep_config(struct qe_udc *udc, unsigned char pipe_num) +static int qe_ep_config(struct qe_udc *udc, unsigned char pipe_num) { struct qe_ep *ep = &udc->eps[pipe_num]; @@ -2473,7 +2473,7 @@ static void qe_udc_release(struct device *dev) /* Driver probe functions */ static const struct of_device_id qe_udc_match[]; -static int __devinit qe_udc_probe(struct platform_device *ofdev) +static int qe_udc_probe(struct platform_device *ofdev) { struct qe_udc *udc; const struct of_device_id *match; @@ -2651,7 +2651,7 @@ static int qe_udc_resume(struct platform_device *dev) } #endif -static int __devexit qe_udc_remove(struct platform_device *ofdev) +static int qe_udc_remove(struct platform_device *ofdev) { struct qe_udc *udc = dev_get_drvdata(&ofdev->dev); struct qe_ep *ep; @@ -2710,7 +2710,7 @@ static int __devexit qe_udc_remove(struct platform_device *ofdev) } /*-------------------------------------------------------------------------*/ -static const struct of_device_id qe_udc_match[] __devinitconst = { +static const struct of_device_id qe_udc_match[] = { { .compatible = "fsl,mpc8323-qe-usb", .data = (void *)PORT_QE, @@ -2735,7 +2735,7 @@ static struct platform_driver udc_driver = { .of_match_table = qe_udc_match, }, .probe = qe_udc_probe, - .remove = __devexit_p(qe_udc_remove), + .remove = qe_udc_remove, #ifdef CONFIG_PM .suspend = qe_udc_suspend, .resume = qe_udc_resume, diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 6ae70cba0c4a..04d5fef1440c 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -41,6 +41,7 @@ #include <linux/fsl_devices.h> #include <linux/dmapool.h> #include <linux/delay.h> +#include <linux/of_device.h> #include <asm/byteorder.h> #include <asm/io.h> @@ -1254,19 +1255,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 +1952,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 +1967,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 +1992,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 +2023,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; } @@ -2126,7 +2091,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count, tmp_reg = fsl_readl(&dr_regs->usbintr); t = scnprintf(next, size, - "USB Intrrupt Enable Reg:\n" + "USB Interrupt Enable Reg:\n" "Sleep Enable: %d SOF Received Enable: %d " "Reset Enable: %d\n" "System Error Enable: %d " @@ -2438,11 +2403,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev) unsigned int i; u32 dccparams; - if (strcmp(pdev->name, driver_name)) { - VDBG("Wrong device"); - return -ENODEV; - } - udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); if (udc_controller == NULL) { ERR("malloc udc failed\n"); @@ -2547,7 +2507,9 @@ static int __init fsl_udc_probe(struct platform_device *pdev) dr_controller_setup(udc_controller); } - fsl_udc_clk_finalize(pdev); + ret = fsl_udc_clk_finalize(pdev); + if (ret) + goto err_free_irq; /* Setup gadget structure */ udc_controller->gadget.ops = &fsl_gadget_ops; @@ -2756,22 +2718,32 @@ static int fsl_udc_otg_resume(struct device *dev) return fsl_udc_resume(NULL); } - /*------------------------------------------------------------------------- Register entry point for the peripheral controller driver --------------------------------------------------------------------------*/ - +static const struct platform_device_id fsl_udc_devtype[] = { + { + .name = "imx-udc-mx27", + }, { + .name = "imx-udc-mx51", + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, fsl_udc_devtype); static struct platform_driver udc_driver = { - .remove = __exit_p(fsl_udc_remove), + .remove = __exit_p(fsl_udc_remove), + /* Just for FSL i.mx SoC currently */ + .id_table = fsl_udc_devtype, /* these suspend and resume are not usb suspend and resume */ - .suspend = fsl_udc_suspend, - .resume = fsl_udc_resume, - .driver = { - .name = (char *)driver_name, - .owner = THIS_MODULE, - /* udc suspend/resume called from OTG driver */ - .suspend = fsl_udc_otg_suspend, - .resume = fsl_udc_otg_resume, + .suspend = fsl_udc_suspend, + .resume = fsl_udc_resume, + .driver = { + .name = (char *)driver_name, + .owner = THIS_MODULE, + /* udc suspend/resume called from OTG driver */ + .suspend = fsl_udc_otg_suspend, + .resume = fsl_udc_otg_resume, }, }; diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index f61a967f7082..c6703bb07b23 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -592,15 +592,16 @@ static inline struct ep_queue_head *get_qh_by_ep(struct fsl_ep *ep) struct platform_device; #ifdef CONFIG_ARCH_MXC int fsl_udc_clk_init(struct platform_device *pdev); -void fsl_udc_clk_finalize(struct platform_device *pdev); +int fsl_udc_clk_finalize(struct platform_device *pdev); void fsl_udc_clk_release(void); #else static inline int fsl_udc_clk_init(struct platform_device *pdev) { return 0; } -static inline void fsl_udc_clk_finalize(struct platform_device *pdev) +static inline int fsl_udc_clk_finalize(struct platform_device *pdev) { + return 0; } static inline void fsl_udc_clk_release(void) { diff --git a/drivers/usb/gadget/functions.c b/drivers/usb/gadget/functions.c new file mode 100644 index 000000000000..b13f839e7368 --- /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 72cd5e6719db..066cb89376de 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); @@ -1547,15 +1518,4 @@ static struct platform_driver fusb300_driver = { }, }; -static int __init fusb300_udc_init(void) -{ - return platform_driver_probe(&fusb300_driver, fusb300_probe); -} - -module_init(fusb300_udc_init); - -static void __exit fusb300_udc_cleanup(void) -{ - platform_driver_unregister(&fusb300_driver); -} -module_exit(fusb300_udc_cleanup); +module_platform_driver_probe(fusb300_driver, fusb300_probe); diff --git a/drivers/usb/gadget/fusb300_udc.h b/drivers/usb/gadget/fusb300_udc.h index 542cd83cc806..6ba444ae8dd5 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 71ca193358b8..ef3e8515272b 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 881aab86ae99..e879e2c9f461 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 51037cb78604..85742d4c67df 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 85cdce0d1901..b4470d2b1d86 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/hid.c b/drivers/usb/gadget/hid.c index 74130f6c12c0..c36260ea8bf2 100644 --- a/drivers/usb/gadget/hid.c +++ b/drivers/usb/gadget/hid.c @@ -203,7 +203,7 @@ static int __init hidg_plat_driver_probe(struct platform_device *pdev) return 0; } -static int __devexit hidg_plat_driver_remove(struct platform_device *pdev) +static int hidg_plat_driver_remove(struct platform_device *pdev) { struct hidg_func_node *e, *n; @@ -229,7 +229,7 @@ static __refdata struct usb_composite_driver hidg_driver = { }; static struct platform_driver hidg_plat_driver = { - .remove = __devexit_p(hidg_plat_driver_remove), + .remove = hidg_plat_driver_remove, .driver = { .owner = THIS_MODULE, .name = "hidg", diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index a0eb85794fd4..5bd930d779b9 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -1334,27 +1334,18 @@ static int imx_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { struct imx_udc_struct *imx_usb; - int retval; imx_usb = container_of(gadget, struct imx_udc_struct, gadget); /* first hook up the driver ... */ imx_usb->driver = driver; imx_usb->gadget.dev.driver = &driver->driver; - retval = device_add(&imx_usb->gadget.dev); - if (retval) - goto fail; - D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n", __func__, driver->driver.name); imx_udc_enable(imx_usb); return 0; -fail: - imx_usb->driver = NULL; - imx_usb->gadget.dev.driver = NULL; - return retval; } static int imx_udc_stop(struct usb_gadget *gadget, @@ -1370,8 +1361,6 @@ static int imx_udc_stop(struct usb_gadget *gadget, imx_usb->gadget.dev.driver = NULL; imx_usb->driver = NULL; - device_del(&imx_usb->gadget.dev); - D_INI(imx_usb->dev, "<%s> unregistered gadget driver '%s'\n", __func__, driver->driver.name); @@ -1477,6 +1466,10 @@ static int __init imx_udc_probe(struct platform_device *pdev) imx_usb->gadget.dev.parent = &pdev->dev; imx_usb->gadget.dev.dma_mask = pdev->dev.dma_mask; + ret = device_add(&imx_usb->gadget.dev); + if (retval) + goto fail4; + platform_set_drvdata(pdev, imx_usb); usb_init_data(imx_usb); @@ -1488,9 +1481,11 @@ static int __init imx_udc_probe(struct platform_device *pdev) ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget); if (ret) - goto fail4; + goto fail5; return 0; +fail5: + device_unregister(&imx_usb->gadget.dev); fail4: for (i = 0; i < IMX_USB_NB_EP + 1; i++) free_irq(imx_usb->usbd_int[i], imx_usb); @@ -1514,6 +1509,7 @@ static int __exit imx_udc_remove(struct platform_device *pdev) int i; usb_del_gadget_udc(&imx_usb->gadget); + device_unregister(&imx_usb->gadget.dev); imx_udc_disable(imx_usb); del_timer(&imx_usb->timer); @@ -1556,17 +1552,7 @@ static struct platform_driver udc_driver = { .resume = imx_udc_resume, }; -static int __init udc_init(void) -{ - return platform_driver_probe(&udc_driver, imx_udc_probe); -} -module_init(udc_init); - -static void __exit udc_exit(void) -{ - platform_driver_unregister(&udc_driver); -} -module_exit(udc_exit); +module_platform_driver_probe(udc_driver, imx_udc_probe); MODULE_DESCRIPTION("IMX USB Device Controller driver"); MODULE_AUTHOR("Darius Augulis <augulis.darius@gmail.com>"); diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 76494cabf4e4..e2b2e9cf254a 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -76,7 +76,6 @@ MODULE_LICENSE ("GPL"); /*----------------------------------------------------------------------*/ #define GADGETFS_MAGIC 0xaee71ee7 -#define DMA_ADDR_INVALID (~(dma_addr_t)0) /* /dev/gadget/$CHIP represents ep0 and the whole device */ enum ep0_state { @@ -918,7 +917,6 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req) if (req->buf != dev->rbuf) { kfree(req->buf); req->buf = dev->rbuf; - req->dma = DMA_ADDR_INVALID; } req->complete = epio_complete; dev->setup_out_ready = 0; @@ -1408,7 +1406,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) dev->setup_abort = 1; req->buf = dev->rbuf; - req->dma = DMA_ADDR_INVALID; req->context = NULL; value = -EOPNOTSUPP; switch (ctrl->bRequest) { @@ -2108,6 +2105,7 @@ static struct file_system_type gadgetfs_type = { .mount = gadgetfs_mount, .kill_sb = gadgetfs_kill_sb, }; +MODULE_ALIAS_FS("gadgetfs"); /*----------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c index 21a9861dabf0..aa04089d6899 100644 --- a/drivers/usb/gadget/lpc32xx_udc.c +++ b/drivers/usb/gadget/lpc32xx_udc.c @@ -2399,7 +2399,7 @@ static void udc_handle_ep0_setup(struct lpc32xx_udc *udc) if (i < 0) { /* setup processing failed, force stall */ - dev_err(udc->dev, + dev_dbg(udc->dev, "req %02x.%02x protocol STALL; stat %d\n", reqtype, req, i); udc->ep0state = WAIT_FOR_SETUP; @@ -3352,7 +3352,7 @@ phy_fail: return retval; } -static int __devexit lpc32xx_udc_remove(struct platform_device *pdev) +static int lpc32xx_udc_remove(struct platform_device *pdev) { struct lpc32xx_udc *udc = platform_get_drvdata(pdev); @@ -3447,7 +3447,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_udc_of_match); #endif static struct platform_driver lpc32xx_udc_driver = { - .remove = __devexit_p(lpc32xx_udc_remove), + .remove = lpc32xx_udc_remove, .shutdown = lpc32xx_udc_shutdown, .suspend = lpc32xx_udc_suspend, .resume = lpc32xx_udc_resume, @@ -3458,17 +3458,7 @@ static struct platform_driver lpc32xx_udc_driver = { }, }; -static int __init udc_init_module(void) -{ - return platform_driver_probe(&lpc32xx_udc_driver, lpc32xx_udc_probe); -} -module_init(udc_init_module); - -static void __exit udc_exit_module(void) -{ - platform_driver_unregister(&lpc32xx_udc_driver); -} -module_exit(udc_exit_module); +module_platform_driver_probe(lpc32xx_udc_driver, lpc32xx_udc_probe); MODULE_DESCRIPTION("LPC32XX udc driver"); MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>"); diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index b6401f1b56ce..c1b8c2dd808d 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: @@ -1753,14 +1721,4 @@ static struct platform_driver m66592_driver = { }, }; -static int __init m66592_udc_init(void) -{ - return platform_driver_probe(&m66592_driver, m66592_probe); -} -module_init(m66592_udc_init); - -static void __exit m66592_udc_cleanup(void) -{ - platform_driver_unregister(&m66592_driver); -} -module_exit(m66592_udc_cleanup); +module_platform_driver_probe(m66592_driver, m66592_probe); diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index 16c7e14678b8..96d49d7bfb6b 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 88472bf7dbb7..20bbbf917fc2 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_u3d_core.c b/drivers/usb/gadget/mv_u3d_core.c index 8cfd5b028dbd..b5cea273c957 100644 --- a/drivers/usb/gadget/mv_u3d_core.c +++ b/drivers/usb/gadget/mv_u3d_core.c @@ -1763,7 +1763,7 @@ static void mv_u3d_gadget_release(struct device *dev) dev_dbg(dev, "%s\n", __func__); } -static __devexit int mv_u3d_remove(struct platform_device *dev) +static int mv_u3d_remove(struct platform_device *dev) { struct mv_u3d *u3d = platform_get_drvdata(dev); diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index ea45224f78c8..c8cf959057fe 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); @@ -1012,7 +1009,7 @@ static void udc_clock_enable(struct mv_udc *udc) unsigned int i; for (i = 0; i < udc->clknum; i++) - clk_enable(udc->clk[i]); + clk_prepare_enable(udc->clk[i]); } static void udc_clock_disable(struct mv_udc *udc) @@ -1020,7 +1017,7 @@ static void udc_clock_disable(struct mv_udc *udc) unsigned int i; for (i = 0; i < udc->clknum; i++) - clk_disable(udc->clk[i]); + clk_disable_unprepare(udc->clk[i]); } static void udc_stop(struct mv_udc *udc) @@ -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 __devexit 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 __devexit 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 __devinit 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 __devinit 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 __devinit 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 __devinit 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 __devinit 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 __devinit 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 __devinit 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 __devinit 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 __devinit 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/net2272.c b/drivers/usb/gadget/net2272.c index c009263a47e3..d226058e3b88 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -2193,7 +2193,7 @@ net2272_gadget_release(struct device *_dev) /*---------------------------------------------------------------------------*/ -static void __devexit +static void net2272_remove(struct net2272 *dev) { usb_del_gadget_udc(&dev->gadget); @@ -2215,8 +2215,7 @@ net2272_remove(struct net2272 *dev) dev_info(dev->dev, "unbind\n"); } -static struct net2272 * __devinit -net2272_probe_init(struct device *dev, unsigned int irq) +static struct net2272 *net2272_probe_init(struct device *dev, unsigned int irq) { struct net2272 *ret; @@ -2246,7 +2245,7 @@ net2272_probe_init(struct device *dev, unsigned int irq) return ret; } -static int __devinit +static int net2272_probe_fin(struct net2272 *dev, unsigned int irqflags) { int ret; @@ -2306,7 +2305,7 @@ err_add_udc: * don't respond over USB until a gadget driver binds to us */ -static int __devinit +static int net2272_rdk1_probe(struct pci_dev *pdev, struct net2272 *dev) { unsigned long resource, len, tmp; @@ -2389,7 +2388,7 @@ net2272_rdk1_probe(struct pci_dev *pdev, struct net2272 *dev) return ret; } -static int __devinit +static int net2272_rdk2_probe(struct pci_dev *pdev, struct net2272 *dev) { unsigned long resource, len; @@ -2447,7 +2446,7 @@ net2272_rdk2_probe(struct pci_dev *pdev, struct net2272 *dev) return ret; } -static int __devinit +static int net2272_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct net2272 *dev; @@ -2489,7 +2488,7 @@ net2272_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) return ret; } -static void __devexit +static void net2272_rdk1_remove(struct pci_dev *pdev, struct net2272 *dev) { int i; @@ -2511,7 +2510,7 @@ net2272_rdk1_remove(struct pci_dev *pdev, struct net2272 *dev) } } -static void __devexit +static void net2272_rdk2_remove(struct pci_dev *pdev, struct net2272 *dev) { int i; @@ -2530,7 +2529,7 @@ net2272_rdk2_remove(struct pci_dev *pdev, struct net2272 *dev) pci_resource_len(pdev, i)); } -static void __devexit +static void net2272_pci_remove(struct pci_dev *pdev) { struct net2272 *dev = pci_get_drvdata(pdev); @@ -2549,7 +2548,7 @@ net2272_pci_remove(struct pci_dev *pdev) } /* Table of matching PCI IDs */ -static struct pci_device_id __devinitdata pci_ids[] = { +static struct pci_device_id pci_ids[] = { { /* RDK 1 card */ .class = ((PCI_CLASS_BRIDGE_OTHER << 8) | 0xfe), .class_mask = 0, @@ -2575,7 +2574,7 @@ static struct pci_driver net2272_pci_driver = { .id_table = pci_ids, .probe = net2272_pci_probe, - .remove = __devexit_p(net2272_pci_remove), + .remove = net2272_pci_remove, }; static int net2272_pci_register(void) @@ -2595,7 +2594,7 @@ static inline void net2272_pci_unregister(void) { } /*---------------------------------------------------------------------------*/ -static int __devinit +static int net2272_plat_probe(struct platform_device *pdev) { struct net2272 *dev; @@ -2661,7 +2660,7 @@ net2272_plat_probe(struct platform_device *pdev) return ret; } -static int __devexit +static int net2272_plat_remove(struct platform_device *pdev) { struct net2272 *dev = platform_get_drvdata(pdev); @@ -2678,7 +2677,7 @@ net2272_plat_remove(struct platform_device *pdev) static struct platform_driver net2272_plat_driver = { .probe = net2272_plat_probe, - .remove = __devexit_p(net2272_plat_remove), + .remove = net2272_plat_remove, .driver = { .name = driver_name, .owner = THIS_MODULE, diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index ac335af154ba..a1b650e11339 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -9,7 +9,7 @@ * CODE STATUS HIGHLIGHTS * * This driver should work well with most "gadget" drivers, including - * the File Storage, Serial, and Ethernet/RNDIS gadget drivers + * the Mass Storage, Serial, and Ethernet/RNDIS gadget drivers * as well as Gadget Zero and Gadgetfs. * * DMA is enabled by default. Drivers using transfer queues might use @@ -116,6 +116,10 @@ static bool enable_suspend = 0; /* "modprobe net2280 enable_suspend=1" etc */ module_param (enable_suspend, bool, S_IRUGO); +/* force full-speed operation */ +static bool full_speed; +module_param(full_speed, bool, 0444); +MODULE_PARM_DESC(full_speed, "force full-speed mode -- for testing only!"); #define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out") @@ -1899,6 +1903,10 @@ static int net2280_start(struct usb_gadget *_gadget, retval = device_create_file (&dev->pdev->dev, &dev_attr_queues); if (retval) goto err_func; + /* Enable force-full-speed testing mode, if desired */ + if (full_speed) + writel(1 << FORCE_FULL_SPEED_MODE, &dev->usb->xcvrdiag); + /* ... then enable host detection and ep0; and we're ready * for set_configuration as well as eventual disconnect. */ @@ -1957,6 +1965,10 @@ static int net2280_stop(struct usb_gadget *_gadget, dev->driver = NULL; net2280_led_active (dev, 0); + + /* Disable full-speed test mode */ + writel(0, &dev->usb->xcvrdiag); + device_remove_file (&dev->pdev->dev, &dev_attr_function); device_remove_file (&dev->pdev->dev, &dev_attr_queues); @@ -2841,6 +2853,9 @@ static void net2280_shutdown (struct pci_dev *pdev) /* disable the pullup so the host will think we're gone */ writel (0, &dev->usb->usbctl); + + /* Disable full-speed test mode */ + writel(0, &dev->usb->xcvrdiag); } diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c index 661600abace8..def37403989a 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 2a4749c3eb3f..f8445653577f 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -44,7 +44,7 @@ #include <asm/unaligned.h> #include <asm/mach-types.h> -#include <plat/dma.h> +#include <linux/omap-dma.h> #include <mach/usb.h> @@ -61,6 +61,9 @@ #define DRIVER_DESC "OMAP UDC driver" #define DRIVER_VERSION "4 October 2004" +#define OMAP_DMA_USB_W2FC_TX0 29 +#define OMAP_DMA_USB_W2FC_RX0 26 + /* * The OMAP UDC needs _very_ early endpoint setup: before enabling the * D+ pullup to allow enumeration. That's too early for the gadget @@ -1307,19 +1310,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, }; /*-------------------------------------------------------------------------*/ @@ -2039,28 +2043,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; @@ -2082,15 +2073,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 */ @@ -2122,19 +2104,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); @@ -2150,13 +2129,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; } @@ -2506,7 +2484,7 @@ static inline void remove_proc_file(void) {} * UDC_SYSCON_1.CFG_LOCK is set can now work. We won't use that * capability yet though. */ -static unsigned __devinit +static unsigned omap_ep_setup(char *name, u8 addr, u8 type, unsigned buf, unsigned maxp, int dbuf) { @@ -2624,7 +2602,7 @@ static void omap_udc_release(struct device *dev) udc = NULL; } -static int __devinit +static int omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv) { unsigned tmp, buf; @@ -2761,7 +2739,7 @@ omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv) return 0; } -static int __devinit omap_udc_probe(struct platform_device *pdev) +static int omap_udc_probe(struct platform_device *pdev) { int status = -ENODEV; int hmc; @@ -2974,7 +2952,7 @@ cleanup0: return status; } -static int __devexit omap_udc_remove(struct platform_device *pdev) +static int omap_udc_remove(struct platform_device *pdev) { DECLARE_COMPLETION_ONSTACK(done); @@ -3060,7 +3038,7 @@ static int omap_udc_resume(struct platform_device *dev) static struct platform_driver udc_driver = { .probe = omap_udc_probe, - .remove = __devexit_p(omap_udc_remove), + .remove = omap_udc_remove, .suspend = omap_udc_suspend, .resume = omap_udc_resume, .driver = { diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 6490c0040e3a..a787a8ef672b 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/printer.c b/drivers/usb/gadget/printer.c index e156e3f26727..bf7a56b6d48a 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -688,7 +688,7 @@ static int printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync) { struct printer_dev *dev = fd->private_data; - struct inode *inode = fd->f_path.dentry->d_inode; + struct inode *inode = file_inode(fd); unsigned long flags; int tx_list_empty; @@ -983,8 +983,10 @@ static int __init printer_func_bind(struct usb_configuration *c, { struct printer_dev *dev = container_of(f, struct printer_dev, function); struct usb_composite_dev *cdev = c->cdev; - struct usb_ep *in_ep, *out_ep; + struct usb_ep *in_ep; + struct usb_ep *out_ep = NULL; int id; + int ret; id = usb_interface_id(c, f); if (id < 0) @@ -1010,6 +1012,11 @@ autoconf_fail: hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; + ret = usb_assign_descriptors(f, fs_printer_function, + hs_printer_function, NULL); + if (ret) + return ret; + dev->in_ep = in_ep; dev->out_ep = out_ep; return 0; @@ -1018,6 +1025,7 @@ autoconf_fail: static void printer_func_unbind(struct usb_configuration *c, struct usb_function *f) { + usb_free_all_descriptors(f); } static int printer_func_set_alt(struct usb_function *f, @@ -1110,8 +1118,6 @@ static int __init printer_bind_config(struct usb_configuration *c) dev = &usb_printer_gadget; dev->function.name = shortname; - dev->function.descriptors = fs_printer_function; - dev->function.hs_descriptors = hs_printer_function; dev->function.bind = printer_func_bind; dev->function.setup = printer_func_setup; dev->function.unbind = printer_func_unbind; diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 8efbf08c3561..d0f37484b6b0 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -29,6 +29,7 @@ #include <linux/list.h> #include <linux/interrupt.h> #include <linux/mm.h> +#include <linux/platform_data/pxa2xx_udc.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/irq.h> @@ -59,9 +60,6 @@ #include <mach/lubbock.h> #endif -#include <asm/mach/udc_pxa2xx.h> - - /* * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x * series processors. The UDC for the IXP 4xx series is very similar. @@ -998,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, @@ -1008,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, }; /*-------------------------------------------------------------------------*/ @@ -1256,58 +1255,26 @@ 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; dev->pullup = 1; - 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); @@ -1344,14 +1311,10 @@ stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver) 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; @@ -1362,14 +1325,11 @@ 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; } @@ -2102,6 +2062,8 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev) int retval, irq; u32 chiprev; + pr_info("%s: version %s\n", driver_name, DRIVER_VERSION); + /* insist on Intel/ARM/XScale */ asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev)); if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) { @@ -2180,6 +2142,13 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev) dev->gadget.dev.parent = &pdev->dev; dev->gadget.dev.dma_mask = pdev->dev.dma_mask; + retval = device_add(&dev->gadget.dev); + if (retval) { + dev->driver = NULL; + dev->gadget.dev.driver = NULL; + goto err_device_add; + } + the_controller = dev; platform_set_drvdata(pdev, dev); @@ -2230,6 +2199,8 @@ lubbock_fail0: free_irq(irq, dev); #endif err_irq1: + device_unregister(&dev->gadget.dev); + err_device_add: if (gpio_is_valid(dev->mach->gpio_pullup)) gpio_free(dev->mach->gpio_pullup); err_gpio_pullup: @@ -2251,10 +2222,11 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev) { struct pxa25x_udc *dev = platform_get_drvdata(pdev); - usb_del_gadget_udc(&dev->gadget); if (dev->driver) return -EBUSY; + usb_del_gadget_udc(&dev->gadget); + device_unregister(&dev->gadget.dev); dev->pullup = 0; pullup(dev); @@ -2348,18 +2320,7 @@ static struct platform_driver udc_driver = { }, }; -static int __init udc_init(void) -{ - pr_info("%s: version %s\n", driver_name, DRIVER_VERSION); - return platform_driver_probe(&udc_driver, pxa25x_udc_probe); -} -module_init(udc_init); - -static void __exit udc_exit(void) -{ - platform_driver_unregister(&udc_driver); -} -module_exit(udc_exit); +module_platform_driver_probe(udc_driver, pxa25x_udc_probe); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell"); diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/pxa25x_udc.h index 2eca1e71fecd..3fe5931dc21a 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 2b3b01d5f403..2fc867652ef5 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,45 +1803,23 @@ 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; dplus_pullup(udc, 1); - retval = device_add(&udc->gadget.dev); - if (retval) { - dev_err(udc->dev, "device_add error %d\n", retval); - goto add_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 +1827,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 +1852,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 +1860,17 @@ 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); @@ -2511,13 +2474,24 @@ static int __init pxa_udc_probe(struct platform_device *pdev) driver_name, udc->irq, retval); goto err_irq; } + + retval = device_add(&udc->gadget.dev); + if (retval) { + dev_err(udc->dev, "device_add error %d\n", retval); + goto err_dev_add; + } + retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); if (retval) goto err_add_udc; pxa_init_debugfs(udc); + return 0; + err_add_udc: + device_unregister(&udc->gadget.dev); +err_dev_add: free_irq(udc->irq, udc); err_irq: iounmap(udc->regs); @@ -2538,6 +2512,7 @@ static int __exit pxa_udc_remove(struct platform_device *_dev) int gpio = udc->mach->gpio_pullup; usb_del_gadget_udc(&udc->gadget); + device_del(&udc->gadget.dev); usb_gadget_unregister_driver(udc->driver); free_irq(udc->irq, udc); pxa_cleanup_debugfs(udc); diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h index a1d268c6f2cc..28f2b53530f5 100644 --- a/drivers/usb/gadget/pxa27x_udc.h +++ b/drivers/usb/gadget/pxa27x_udc.h @@ -418,7 +418,7 @@ struct udc_stats { * @irq: udc irq * @clk: udc clock * @usb_gadget: udc gadget structure - * @driver: bound gadget (zero, g_ether, g_file_storage, ...) + * @driver: bound gadget (zero, g_ether, g_mass_storage, ...) * @dev: device * @mach: machine info, used to activate specific GPIO * @transceiver: external transceiver to handle vbus sense and D+ pullup @@ -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 5a80751accb7..f46a1b77ce3e 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, @@ -2031,21 +2031,10 @@ static struct platform_driver r8a66597_driver = { .name = (char *) udc_name, }, }; -MODULE_ALIAS("platform:r8a66597_udc"); - -static int __init r8a66597_udc_init(void) -{ - return platform_driver_probe(&r8a66597_driver, r8a66597_probe); -} -module_init(r8a66597_udc_init); -static void __exit r8a66597_udc_cleanup(void) -{ - platform_driver_unregister(&r8a66597_driver); -} -module_exit(r8a66597_udc_cleanup); +module_platform_driver_probe(r8a66597_driver, r8a66597_probe); MODULE_DESCRIPTION("R8A66597 USB gadget driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Yoshihiro Shimoda"); - +MODULE_ALIAS("platform:r8a66597_udc"); diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index e4192b887de9..d9297eebbf73 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -1065,7 +1065,7 @@ static int rndis_proc_show(struct seq_file *m, void *v) static ssize_t rndis_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { - rndis_params *p = PDE(file->f_path.dentry->d_inode)->data; + rndis_params *p = PDE(file_inode(file))->data; u32 speed = 0; int i, fl_speed = 0; diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 6f696ee8b817..c26564f29a2c 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -32,6 +32,7 @@ #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> +#include <linux/usb/phy.h> #include <linux/platform_data/s3c-hsotg.h> #include <mach/map.h> @@ -133,7 +134,9 @@ struct s3c_hsotg_ep { * struct s3c_hsotg - driver state. * @dev: The parent device supplied to the probe function * @driver: USB gadget driver - * @plat: The platform specific configuration data. + * @phy: The otg phy transceiver structure for phy control. + * @plat: The platform specific configuration data. This can be removed once + * all SoCs support usb transceiver. * @regs: The memory area mapped for accessing registers. * @irq: The IRQ number we are using * @supplies: Definition of USB power supplies @@ -153,6 +156,7 @@ struct s3c_hsotg_ep { struct s3c_hsotg { struct device *dev; struct usb_gadget_driver *driver; + struct usb_phy *phy; struct s3c_hsotg_plat *plat; spinlock_t lock; @@ -2854,7 +2858,10 @@ static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg) struct platform_device *pdev = to_platform_device(hsotg->dev); dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev); - if (hsotg->plat->phy_init) + + if (hsotg->phy) + usb_phy_init(hsotg->phy); + else if (hsotg->plat->phy_init) hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); } @@ -2869,7 +2876,9 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg) { struct platform_device *pdev = to_platform_device(hsotg->dev); - if (hsotg->plat->phy_exit) + if (hsotg->phy) + usb_phy_shutdown(hsotg->phy); + else if (hsotg->plat->phy_exit) hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); } @@ -3055,7 +3064,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, @@ -3072,7 +3081,7 @@ static struct usb_gadget_ops s3c_hsotg_gadget_ops = { * creation) to give to the gadget driver. Setup the endpoint name, any * direction information and other state that may be required. */ -static void __devinit s3c_hsotg_initep(struct s3c_hsotg *hsotg, +static void s3c_hsotg_initep(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, int epnum) { @@ -3414,7 +3423,7 @@ static const struct file_operations ep_fops = { * with the same name as the device itself, in case we end up * with multiple blocks in future systems. */ -static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg) +static void s3c_hsotg_create_debug(struct s3c_hsotg *hsotg) { struct dentry *root; unsigned epidx; @@ -3460,7 +3469,7 @@ static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg) * * Cleanup (remove) the debugfs files for use on module exit. */ -static void __devexit s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) +static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) { unsigned epidx; @@ -3477,12 +3486,11 @@ static void __devexit s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) /** * s3c_hsotg_release - release callback for hsotg device * @dev: Device to for which release is called + * + * Nothing to do as the resource is allocated using devm_ API. */ static void s3c_hsotg_release(struct device *dev) { - struct s3c_hsotg *hsotg = dev_get_drvdata(dev); - - kfree(hsotg); } /** @@ -3490,9 +3498,10 @@ static void s3c_hsotg_release(struct device *dev) * @pdev: The platform information for the driver */ -static int __devinit s3c_hsotg_probe(struct platform_device *pdev) +static int s3c_hsotg_probe(struct platform_device *pdev) { struct s3c_hsotg_plat *plat = pdev->dev.platform_data; + struct usb_phy *phy; struct device *dev = &pdev->dev; struct s3c_hsotg_ep *eps; struct s3c_hsotg *hsotg; @@ -3501,20 +3510,27 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) int ret; int i; - plat = pdev->dev.platform_data; - if (!plat) { - dev_err(&pdev->dev, "no platform data defined\n"); - return -EINVAL; - } - hsotg = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsotg), GFP_KERNEL); if (!hsotg) { dev_err(dev, "cannot get memory\n"); return -ENOMEM; } + phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); + if (IS_ERR_OR_NULL(phy)) { + /* Fallback for pdata */ + plat = pdev->dev.platform_data; + if (!plat) { + dev_err(&pdev->dev, "no platform data or transceiver defined\n"); + return -EPROBE_DEFER; + } else { + hsotg->plat = plat; + } + } else { + hsotg->phy = phy; + } + hsotg->dev = dev; - hsotg->plat = plat; hsotg->clk = devm_clk_get(&pdev->dev, "otg"); if (IS_ERR(hsotg->clk)) { @@ -3526,10 +3542,9 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hsotg->regs = devm_request_and_ioremap(&pdev->dev, res); - if (!hsotg->regs) { - dev_err(dev, "cannot map registers\n"); - ret = -ENXIO; + hsotg->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hsotg->regs)) { + ret = PTR_ERR(hsotg->regs); goto err_clk; } @@ -3573,7 +3588,7 @@ static int __devinit 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); @@ -3663,8 +3678,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); @@ -3675,7 +3688,7 @@ err_clk: * s3c_hsotg_remove - remove function for hsotg driver * @pdev: The platform information for the driver */ -static int __devexit s3c_hsotg_remove(struct platform_device *pdev) +static int s3c_hsotg_remove(struct platform_device *pdev) { struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); @@ -3689,7 +3702,6 @@ static int __devexit 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); @@ -3708,7 +3720,7 @@ static struct platform_driver s3c_hsotg_driver = { .owner = THIS_MODULE, }, .probe = s3c_hsotg_probe, - .remove = __devexit_p(s3c_hsotg_remove), + .remove = s3c_hsotg_remove, .suspend = s3c_hsotg_suspend, .resume = s3c_hsotg_resume, }; diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index d8e785d4ad59..458965a1b138 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,14 +1254,14 @@ 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, .vbus_draw = s3c_hsudc_vbus_draw, }; -static int __devinit s3c_hsudc_probe(struct platform_device *pdev) +static int s3c_hsudc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res; @@ -1286,7 +1286,7 @@ static int __devinit 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); @@ -1295,10 +1295,9 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hsudc->regs = devm_request_and_ioremap(&pdev->dev, res); - if (!hsudc->regs) { - dev_err(dev, "error mapping device register area\n"); - ret = -EBUSY; + hsudc->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hsudc->regs)) { + ret = PTR_ERR(hsudc->regs); goto err_res; } @@ -1367,7 +1366,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 a2fa6e16d019..08f89652533b 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,84 +1665,28 @@ 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; - int retval; + struct s3c2410_udc *udc = to_s3c2410(g); 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; - /* Bind the driver */ - retval = device_add(&udc->gadget.dev); - if (retval) { - dev_err(&udc->gadget.dev, "Error in device_add() : %d\n", retval); - 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); return 0; - -register_error: - udc->driver = NULL; - udc->gadget.dev.driver = NULL; - 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); + struct s3c2410_udc *udc = to_s3c2410(g); - driver->unbind(&udc->gadget); - - device_del(&udc->gadget.dev); udc->driver = NULL; /* Disable udc */ @@ -1883,6 +1828,13 @@ static int s3c2410_udc_probe(struct platform_device *pdev) udc->gadget.dev.parent = &pdev->dev; udc->gadget.dev.dma_mask = pdev->dev.dma_mask; + /* Bind the driver */ + retval = device_add(&udc->gadget.dev); + if (retval) { + dev_err(&udc->gadget.dev, "Error in device_add() : %d\n", retval); + goto err_device_add; + } + the_controller = udc; platform_set_drvdata(pdev, udc); @@ -1971,6 +1923,8 @@ err_gpio_claim: err_int: free_irq(IRQ_USBD, udc); err_map: + device_unregister(&udc->gadget.dev); +err_device_add: iounmap(base_addr); err_mem: release_mem_region(rsrc_start, rsrc_len); @@ -1988,10 +1942,11 @@ static int s3c2410_udc_remove(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s()\n", __func__); - usb_del_gadget_udc(&udc->gadget); if (udc->driver) return -EBUSY; + usb_del_gadget_udc(&udc->gadget); + device_unregister(&udc->gadget.dev); debugfs_remove(udc->regs_info); if (udc_info && !udc_info->udc_command && diff --git a/drivers/usb/gadget/s3c2410_udc.h b/drivers/usb/gadget/s3c2410_udc.h index 3e80fd5c820f..93bf225f1969 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 44752f531e85..68d7bb06ebcb 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 8d9bcd8207c8..dbce3a9074e6 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -11,30 +11,10 @@ * (at your option) any later version. */ - /* * This file requires the following identifiers used in USB strings to * be defined (each of type pointer to char): - * - fsg_string_manufacturer -- name of the manufacturer - * - fsg_string_product -- name of the product - * - fsg_string_config -- name of the configuration * - fsg_string_interface -- name of the interface - * The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS - * macro is defined prior to including this file. - */ - -/* - * When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and - * fsg_hs_intr_in_desc objects as well as - * FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES - * macros are not defined. - * - * When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER, - * FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not - * defined (as well as corresponding entries in string tables are - * missing) and FSG_STRING_INTERFACE has value of zero. - * - * When FSG_NO_OTG is defined fsg_otg_desc won't be defined. */ /* @@ -78,34 +58,6 @@ #define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args) #define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args) -/* - * Keep those macros in sync with those in - * include/linux/usb/composite.h or else GCC will complain. If they - * are identical (the same names of arguments, white spaces in the - * same places) GCC will allow redefinition otherwise (even if some - * white space is removed or added) warning will be issued. - * - * Those macros are needed here because File Storage Gadget does not - * include the composite.h header. For composite gadgets those macros - * are redundant since composite.h is included any way. - * - * One could check whether those macros are already defined (which - * would indicate composite.h had been included) or not (which would - * indicate we were in FSG) but this is not done because a warning is - * desired if definitions here differ from the ones in composite.h. - * - * We want the definitions to match and be the same in File Storage - * Gadget as well as Mass Storage Function (and so composite gadgets - * using MSF). If someone changes them in composite.h it will produce - * a warning in this file when building MSF. - */ -#define DBG(d, fmt, args...) dev_dbg(&(d)->gadget->dev , fmt , ## args) -#define VDBG(d, fmt, args...) dev_vdbg(&(d)->gadget->dev , fmt , ## args) -#define ERROR(d, fmt, args...) dev_err(&(d)->gadget->dev , fmt , ## args) -#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev , fmt , ## args) -#define INFO(d, fmt, args...) dev_info(&(d)->gadget->dev , fmt , ## args) - - #ifdef DUMP_MSGS @@ -141,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 @@ -203,9 +143,12 @@ struct fsg_lun { struct device dev; }; -#define fsg_lun_is_open(curlun) ((curlun)->filp != NULL) +static inline bool fsg_lun_is_open(struct fsg_lun *curlun) +{ + return curlun->filp != NULL; +} -static struct fsg_lun *fsg_lun_from_dev(struct device *dev) +static inline struct fsg_lun *fsg_lun_from_dev(struct device *dev) { return container_of(dev, struct fsg_lun, dev); } @@ -308,26 +251,10 @@ static inline u32 get_unaligned_be24(u8 *buf) enum { -#ifndef FSG_NO_DEVICE_STRINGS - FSG_STRING_MANUFACTURER = 1, - FSG_STRING_PRODUCT, - FSG_STRING_SERIAL, - FSG_STRING_CONFIG, -#endif FSG_STRING_INTERFACE }; -#ifndef FSG_NO_OTG -static struct usb_otg_descriptor -fsg_otg_desc = { - .bLength = sizeof fsg_otg_desc, - .bDescriptorType = USB_DT_OTG, - - .bmAttributes = USB_OTG_SRP, -}; -#endif - /* There is only one interface. */ static struct usb_interface_descriptor @@ -367,37 +294,10 @@ fsg_fs_bulk_out_desc = { /* wMaxPacketSize set by autoconfiguration */ }; -#ifndef FSG_NO_INTR_EP - -static struct usb_endpoint_descriptor -fsg_fs_intr_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(2), - .bInterval = 32, /* frames -> 32 ms */ -}; - -#ifndef FSG_NO_OTG -# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2 -#else -# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 1 -#endif - -#endif - static struct usb_descriptor_header *fsg_fs_function[] = { -#ifndef FSG_NO_OTG - (struct usb_descriptor_header *) &fsg_otg_desc, -#endif (struct usb_descriptor_header *) &fsg_intf_desc, (struct usb_descriptor_header *) &fsg_fs_bulk_in_desc, (struct usb_descriptor_header *) &fsg_fs_bulk_out_desc, -#ifndef FSG_NO_INTR_EP - (struct usb_descriptor_header *) &fsg_fs_intr_in_desc, -#endif NULL, }; @@ -431,37 +331,11 @@ fsg_hs_bulk_out_desc = { .bInterval = 1, /* NAK every 1 uframe */ }; -#ifndef FSG_NO_INTR_EP - -static struct usb_endpoint_descriptor -fsg_hs_intr_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(2), - .bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */ -}; - -#ifndef FSG_NO_OTG -# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2 -#else -# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 1 -#endif - -#endif static struct usb_descriptor_header *fsg_hs_function[] = { -#ifndef FSG_NO_OTG - (struct usb_descriptor_header *) &fsg_otg_desc, -#endif (struct usb_descriptor_header *) &fsg_intf_desc, (struct usb_descriptor_header *) &fsg_hs_bulk_in_desc, (struct usb_descriptor_header *) &fsg_hs_bulk_out_desc, -#ifndef FSG_NO_INTR_EP - (struct usb_descriptor_header *) &fsg_hs_intr_in_desc, -#endif NULL, }; @@ -499,107 +373,17 @@ static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { /*.bMaxBurst = DYNAMIC, */ }; -#ifndef FSG_NO_INTR_EP - -static struct usb_endpoint_descriptor -fsg_ss_intr_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(2), - .bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */ -}; - -static struct usb_ss_ep_comp_descriptor fsg_ss_intr_in_comp_desc = { - .bLength = sizeof(fsg_ss_bulk_in_comp_desc), - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - - .wBytesPerInterval = cpu_to_le16(2), -}; - -#ifndef FSG_NO_OTG -# define FSG_SS_FUNCTION_PRE_EP_ENTRIES 2 -#else -# define FSG_SS_FUNCTION_PRE_EP_ENTRIES 1 -#endif - -#endif - -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[] = { -#ifndef FSG_NO_OTG - (struct usb_descriptor_header *) &fsg_otg_desc, -#endif (struct usb_descriptor_header *) &fsg_intf_desc, (struct usb_descriptor_header *) &fsg_ss_bulk_in_desc, (struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc, (struct usb_descriptor_header *) &fsg_ss_bulk_out_desc, (struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc, -#ifndef FSG_NO_INTR_EP - (struct usb_descriptor_header *) &fsg_ss_intr_in_desc, - (struct usb_descriptor_header *) &fsg_ss_intr_in_comp_desc, -#endif 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[] = { -#ifndef FSG_NO_DEVICE_STRINGS - {FSG_STRING_MANUFACTURER, fsg_string_manufacturer}, - {FSG_STRING_PRODUCT, fsg_string_product}, - {FSG_STRING_SERIAL, ""}, - {FSG_STRING_CONFIG, fsg_string_config}, -#endif {FSG_STRING_INTERFACE, fsg_string_interface}, {} }; @@ -656,7 +440,7 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) if (!(filp->f_mode & FMODE_WRITE)) ro = 1; - inode = filp->f_path.dentry->d_inode; + inode = file_inode(filp); if ((!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) { LINFO(curlun, "invalid file type: %s\n", filename); goto out; diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index 97e68b38cfdf..7cacd6ae818e 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -1384,7 +1384,7 @@ static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg) nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL); if (!nacl) { - printk(KERN_ERR "Unable to alocate struct usbg_nacl\n"); + printk(KERN_ERR "Unable to allocate struct usbg_nacl\n"); return NULL; } @@ -1794,9 +1794,10 @@ static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg) tpg->tpg_nexus = NULL; kfree(tv_nexus); + ret = 0; out: mutex_unlock(&tpg->tpg_mutex); - return 0; + return ret; } static ssize_t tcm_usbg_tpg_store_nexus( @@ -2139,6 +2140,7 @@ static struct usb_descriptor_header *uasp_fs_function_desc[] = { (struct usb_descriptor_header *) &uasp_status_pipe_desc, (struct usb_descriptor_header *) &uasp_fs_cmd_desc, (struct usb_descriptor_header *) &uasp_cmd_pipe_desc, + NULL, }; static struct usb_descriptor_header *uasp_hs_function_desc[] = { @@ -2239,6 +2241,7 @@ static int usbg_bind(struct usb_configuration *c, struct usb_function *f) struct usb_gadget *gadget = c->cdev->gadget; struct usb_ep *ep; int iface; + int ret; iface = usb_interface_id(c, f); if (iface < 0) @@ -2289,6 +2292,11 @@ static int usbg_bind(struct usb_configuration *c, struct usb_function *f) uasp_ss_status_desc.bEndpointAddress; uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress; + ret = usb_assign_descriptors(f, uasp_fs_function_desc, + uasp_hs_function_desc, uasp_ss_function_desc); + if (ret) + goto ep_fail; + return 0; ep_fail: pr_err("Can't claim all required eps\n"); @@ -2304,6 +2312,7 @@ static void usbg_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_uas *fu = to_f_uas(f); + usb_free_all_descriptors(f); kfree(fu); } @@ -2384,9 +2393,6 @@ static int usbg_cfg_bind(struct usb_configuration *c) if (!fu) return -ENOMEM; fu->function.name = "Target Function"; - fu->function.descriptors = uasp_fs_function_desc; - fu->function.hs_descriptors = uasp_hs_function_desc; - fu->function.ss_descriptors = uasp_ss_function_desc; fu->function.bind = usbg_bind; fu->function.unbind = usbg_unbind; fu->function.set_alt = usbg_set_alt; diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 6458764994ef..a0aa721d8b21 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -20,6 +20,7 @@ #include <linux/ctype.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> +#include <linux/if_vlan.h> #include "u_ether.h" @@ -158,12 +159,12 @@ static int ueth_change_mtu(struct net_device *net, int new_mtu) static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p) { - struct eth_dev *dev = netdev_priv(net); + struct eth_dev *dev = netdev_priv(net); - strlcpy(p->driver, "g_ether", sizeof p->driver); - strlcpy(p->version, UETH__VERSION, sizeof p->version); - strlcpy(p->fw_version, dev->gadget->name, sizeof p->fw_version); - strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof p->bus_info); + strlcpy(p->driver, "g_ether", sizeof(p->driver)); + strlcpy(p->version, UETH__VERSION, sizeof(p->version)); + strlcpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version)); + strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info)); } /* REVISIT can also support: @@ -295,7 +296,7 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req) while (skb2) { if (status < 0 || ETH_HLEN > skb2->len - || skb2->len > ETH_FRAME_LEN) { + || skb2->len > VLAN_ETH_FRAME_LEN) { dev->net->stats.rx_errors++; dev->net->stats.rx_length_errors++; DBG(dev, "rx length %d\n", skb2->len); diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index f1739526820f..c5034d9c946b 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 @@ -495,12 +496,8 @@ static void gs_rx_push(unsigned long _port) req = list_first_entry(queue, struct usb_request, list); - /* discard data if tty was closed */ - if (!tty) - goto recycle; - /* leave data queued if tty was rx throttled */ - if (test_bit(TTY_THROTTLED, &tty->flags)) + if (tty && test_bit(TTY_THROTTLED, &tty->flags)) break; switch (req->status) { @@ -533,7 +530,8 @@ static void gs_rx_push(unsigned long _port) size -= n; } - count = tty_insert_flip_string(tty, packet, size); + count = tty_insert_flip_string(&port->port, packet, + size); if (count) do_push = true; if (count != size) { @@ -546,7 +544,7 @@ static void gs_rx_push(unsigned long _port) } port->n_read = 0; } -recycle: + list_move(&req->list, &port->read_pool); port->read_started--; } @@ -554,8 +552,8 @@ recycle: /* Push from tty to ldisc; without low_latency set this is handled by * a workqueue, so we won't get callbacks and can hold port_lock */ - if (tty && do_push) - tty_flip_buffer_push(tty); + if (do_push) + tty_flip_buffer_push(&port->port); /* We want our data queue to become empty ASAP, keeping data @@ -887,7 +885,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) pr_debug("gs_close: ttyGS%d (%p,%p) done!\n", port->port_num, tty, file); - wake_up_interruptible(&port->port.close_wait); + wake_up(&port->port.close_wait); exit: spin_unlock_irq(&port->port_lock); } @@ -1030,10 +1028,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,107 +1056,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--) - 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) @@ -1162,54 +1071,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; - 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* */ - pr_debug("%s: cleaned up ttyGS* support\n", __func__); + 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)); + + 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 @@ -1226,8 +1158,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. @@ -1238,11 +1170,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); @@ -1289,7 +1228,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 @@ -1344,3 +1283,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 9b0fe6450fbf..66ce73a00509 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/u_uac1.c b/drivers/usb/gadget/u_uac1.c index e0c5e88e03ed..c7d460f43390 100644 --- a/drivers/usb/gadget/u_uac1.c +++ b/drivers/usb/gadget/u_uac1.c @@ -240,8 +240,11 @@ static int gaudio_open_snd_dev(struct gaudio *card) snd = &card->playback; snd->filp = filp_open(fn_play, O_WRONLY, 0); if (IS_ERR(snd->filp)) { + int ret = PTR_ERR(snd->filp); + ERROR(card, "No such PCM playback device: %s\n", fn_play); snd->filp = NULL; + return ret; } pcm_file = snd->filp->private_data; snd->substream = pcm_file->substream; diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index f3cd9690b101..2a9cd369f71c 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; @@ -439,16 +408,6 @@ static DEVICE_ATTR(name, S_IRUSR, usb_udc_##param##_show, NULL) static USB_UDC_SPEED_ATTR(current_speed, speed); static USB_UDC_SPEED_ATTR(maximum_speed, max_speed); -/* TODO: Scheduled for removal in 3.8. */ -static ssize_t usb_udc_is_dualspeed_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - return snprintf(buf, PAGE_SIZE, "%d\n", - gadget_is_dualspeed(udc->gadget)); -} -static DEVICE_ATTR(is_dualspeed, S_IRUSR, usb_udc_is_dualspeed_show, NULL); - #define USB_UDC_ATTR(name) \ ssize_t usb_udc_##name##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \ @@ -472,7 +431,6 @@ static struct attribute *usb_udc_attrs[] = { &dev_attr_current_speed.attr, &dev_attr_maximum_speed.attr, - &dev_attr_is_dualspeed.attr, &dev_attr_is_otg.attr, &dev_attr_is_a_peripheral.attr, &dev_attr_b_hnp_enable.attr, diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c index 69cf5c2cd335..8cef1e658c29 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 6bf4c0611365..685fa681cb65 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; } |