aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-02-21 12:20:00 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-21 12:20:00 -0800
commit74e1a2a39355b2d3ae8c60c78d8add162c6d7183 (patch)
tree1ce09f285c505a774838a95cff7327a750dc85fc /drivers/usb/gadget
parentb5c78e04dd061b776978dad61dd85357081147b0 (diff)
parent6166805c3de539a41cfcae39026c5bc273d7c6aa (diff)
Merge tag 'usb-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB patches from Greg Kroah-Hartman: "Here's the big USB merge for 3.9-rc1 Nothing major, lots of gadget fixes, and of course, xhci stuff. All of this has been in linux-next for a while, with the exception of the last 3 patches, which were reverts of patches in the tree that caused problems, they went in yesterday." * tag 'usb-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (190 commits) Revert "USB: EHCI: make ehci-vt8500 a separate driver" Revert "USB: EHCI: make ehci-orion a separate driver" Revert "USB: update host controller Kconfig entries" USB: update host controller Kconfig entries USB: EHCI: make ehci-orion a separate driver USB: EHCI: make ehci-vt8500 a separate driver USB: usb-storage: unusual_devs update for Super TOP SATA bridge USB: ehci-omap: Fix autoloading of module USB: ehci-omap: Don't free gpios that we didn't request USB: option: add Huawei "ACM" devices using protocol = vendor USB: serial: fix null-pointer dereferences on disconnect USB: option: add Yota / Megafon M100-1 4g modem drivers/usb: add missing GENERIC_HARDIRQS dependencies USB: storage: properly handle the endian issues of idProduct testusb: remove all mentions of 'usbfs' usb: gadget: imx_udc: make it depend on BROKEN usb: omap_control_usb: fix compile warning ARM: OMAP: USB: Add phy binding information ARM: OMAP2: MUSB: Specify omap4 has mailbox ARM: OMAP: devices: create device for usb part of control module ...
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/Kconfig24
-rw-r--r--drivers/usb/gadget/Makefile8
-rw-r--r--drivers/usb/gadget/acm_ms.c42
-rw-r--r--drivers/usb/gadget/amd5536udc.c59
-rw-r--r--drivers/usb/gadget/amd5536udc.h2
-rw-r--r--drivers/usb/gadget/at91_udc.c5
-rw-r--r--drivers/usb/gadget/cdc2.c36
-rw-r--r--drivers/usb/gadget/composite.c326
-rw-r--r--drivers/usb/gadget/dbgp.c14
-rw-r--r--drivers/usb/gadget/f_acm.c153
-rw-r--r--drivers/usb/gadget/f_fs.c5
-rw-r--r--drivers/usb/gadget/f_loopback.c103
-rw-r--r--drivers/usb/gadget/f_mass_storage.c37
-rw-r--r--drivers/usb/gadget/f_ncm.c18
-rw-r--r--drivers/usb/gadget/f_obex.c4
-rw-r--r--drivers/usb/gadget/f_serial.c4
-rw-r--r--drivers/usb/gadget/f_sourcesink.c200
-rw-r--r--drivers/usb/gadget/f_uac2.c9
-rw-r--r--drivers/usb/gadget/f_uvc.c3
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.c2
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c60
-rw-r--r--drivers/usb/gadget/functions.c116
-rw-r--r--drivers/usb/gadget/fusb300_udc.c67
-rw-r--r--drivers/usb/gadget/fusb300_udc.h2
-rw-r--r--drivers/usb/gadget/g_zero.h35
-rw-r--r--drivers/usb/gadget/gmidi.c2
-rw-r--r--drivers/usb/gadget/goku_udc.c70
-rw-r--r--drivers/usb/gadget/goku_udc.h1
-rw-r--r--drivers/usb/gadget/m66592-udc.c72
-rw-r--r--drivers/usb/gadget/m66592-udc.h1
-rw-r--r--drivers/usb/gadget/multi.c71
-rw-r--r--drivers/usb/gadget/mv_udc_core.c246
-rw-r--r--drivers/usb/gadget/net2280.c15
-rw-r--r--drivers/usb/gadget/nokia.c43
-rw-r--r--drivers/usb/gadget/omap_udc.c51
-rw-r--r--drivers/usb/gadget/pch_udc.c67
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c62
-rw-r--r--drivers/usb/gadget/pxa25x_udc.h1
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c61
-rw-r--r--drivers/usb/gadget/pxa27x_udc.h1
-rw-r--r--drivers/usb/gadget/r8a66597-udc.c2
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c44
-rw-r--r--drivers/usb/gadget/s3c-hsudc.c13
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c65
-rw-r--r--drivers/usb/gadget/s3c2410_udc.h1
-rw-r--r--drivers/usb/gadget/serial.c118
-rw-r--r--drivers/usb/gadget/storage_common.c61
-rw-r--r--drivers/usb/gadget/u_serial.c313
-rw-r--r--drivers/usb/gadget/u_serial.h13
-rw-r--r--drivers/usb/gadget/udc-core.c157
-rw-r--r--drivers/usb/gadget/webcam.c2
-rw-r--r--drivers/usb/gadget/zero.c233
52 files changed, 1695 insertions, 1425 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 14625fd2cec..c5c6fa60910 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
@@ -750,6 +762,8 @@ config USB_GADGET_TARGET
config USB_G_SERIAL
tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
+ select USB_U_SERIAL
+ select USB_F_ACM
select USB_LIBCOMPOSITE
help
The Serial Gadget talks to the Linux-USB generic serial driver.
@@ -803,6 +817,8 @@ config USB_CDC_COMPOSITE
tristate "CDC Composite Device (Ethernet and ACM)"
depends on NET
select USB_LIBCOMPOSITE
+ select USB_U_SERIAL
+ select USB_F_ACM
help
This driver provides two functions in one configuration:
a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link.
@@ -818,6 +834,7 @@ config USB_G_NOKIA
tristate "Nokia composite gadget"
depends on PHONET
select USB_LIBCOMPOSITE
+ select USB_U_SERIAL
help
The Nokia composite gadget provides support for acm, obex
and phonet in only one composite gadget driver.
@@ -829,6 +846,8 @@ config USB_G_ACM_MS
tristate "CDC Composite Device (ACM and mass storage)"
depends on BLOCK
select USB_LIBCOMPOSITE
+ select USB_U_SERIAL
+ select USB_F_ACM
help
This driver provides two functions in one configuration:
a mass storage, and a CDC ACM (serial port) link.
@@ -841,6 +860,8 @@ config USB_G_MULTI
depends on BLOCK && NET
select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS
select USB_LIBCOMPOSITE
+ select USB_U_SERIAL
+ select USB_F_ACM
help
The Multifunction Composite Gadget provides Ethernet (RNDIS
and/or CDC Ethernet), mass storage and ACM serial link
@@ -916,6 +937,7 @@ config USB_G_DBGP_PRINTK
config USB_G_DBGP_SERIAL
depends on USB_G_DBGP
+ select USB_U_SERIAL
bool "serial"
help
Userland can interact using /dev/ttyGSxxx.
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 8b4acfd92aa..97a13c349cc 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -6,7 +6,7 @@ ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
obj-$(CONFIG_USB_GADGET) += udc-core.o
obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o
libcomposite-y := usbstring.o config.o epautoconf.o
-libcomposite-y += composite.o
+libcomposite-y += composite.o functions.o
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
obj-$(CONFIG_USB_NET2272) += net2272.o
obj-$(CONFIG_USB_NET2280) += net2280.o
@@ -74,3 +74,9 @@ obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o
obj-$(CONFIG_USB_G_NCM) += g_ncm.o
obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o
obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o
+
+# USB Functions
+obj-$(CONFIG_USB_F_ACM) += f_acm.o
+f_ss_lb-y := f_loopback.o f_sourcesink.o
+obj-$(CONFIG_USB_F_SS_LB) += f_ss_lb.o
+obj-$(CONFIG_USB_U_SERIAL) += u_serial.o
diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c
index 5a7f289805f..8f2b0e39153 100644
--- a/drivers/usb/gadget/acm_ms.c
+++ b/drivers/usb/gadget/acm_ms.c
@@ -40,9 +40,6 @@
* the runtime footprint, and giving us at least some parts of what
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
*/
-
-#include "u_serial.c"
-#include "f_acm.c"
#include "f_mass_storage.c"
/*-------------------------------------------------------------------------*/
@@ -112,12 +109,15 @@ FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
static struct fsg_common fsg_common;
/*-------------------------------------------------------------------------*/
-
+static unsigned char tty_line;
+static struct usb_function *f_acm;
+static struct usb_function_instance *f_acm_inst;
/*
* We _always_ have both ACM and mass storage functions.
*/
static int __init acm_ms_do_config(struct usb_configuration *c)
{
+ struct f_serial_opts *opts;
int status;
if (gadget_is_otg(c->cdev->gadget)) {
@@ -125,16 +125,35 @@ static int __init acm_ms_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
+ f_acm_inst = usb_get_function_instance("acm");
+ if (IS_ERR(f_acm_inst))
+ return PTR_ERR(f_acm_inst);
+
+ opts = container_of(f_acm_inst, struct f_serial_opts, func_inst);
+ opts->port_num = tty_line;
+
+ f_acm = usb_get_function(f_acm_inst);
+ if (IS_ERR(f_acm)) {
+ status = PTR_ERR(f_acm);
+ goto err_func;
+ }
- status = acm_bind_config(c, 0);
+ status = usb_add_function(c, f_acm);
if (status < 0)
- return status;
+ goto err_conf;
status = fsg_bind_config(c->cdev, c, &fsg_common);
if (status < 0)
- return status;
+ goto err_fsg;
return 0;
+err_fsg:
+ usb_remove_function(c, f_acm);
+err_conf:
+ usb_put_function(f_acm);
+err_func:
+ usb_put_function_instance(f_acm_inst);
+ return status;
}
static struct usb_configuration acm_ms_config_driver = {
@@ -153,7 +172,7 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
void *retp;
/* set up serial link layer */
- status = gserial_setup(cdev->gadget, 1);
+ status = gserial_alloc_line(&tty_line);
if (status < 0)
return status;
@@ -189,14 +208,15 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
fail1:
fsg_common_put(&fsg_common);
fail0:
- gserial_cleanup();
+ gserial_free_line(tty_line);
return status;
}
static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
{
- gserial_cleanup();
-
+ usb_put_function(f_acm);
+ usb_put_function_instance(f_acm_inst);
+ gserial_free_line(tty_line);
return 0;
}
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index d9f6b937249..75973f33a4c 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -1400,15 +1400,16 @@ static int udc_wakeup(struct usb_gadget *gadget)
return 0;
}
-static int amd5536_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
-static int amd5536_stop(struct usb_gadget_driver *driver);
+static int amd5536_udc_start(struct usb_gadget *g,
+ struct usb_gadget_driver *driver);
+static int amd5536_udc_stop(struct usb_gadget *g,
+ struct usb_gadget_driver *driver);
/* gadget operations */
static const struct usb_gadget_ops udc_ops = {
.wakeup = udc_wakeup,
.get_frame = udc_get_frame,
- .start = amd5536_start,
- .stop = amd5536_stop,
+ .udc_start = amd5536_udc_start,
+ .udc_stop = amd5536_udc_stop,
};
/* Setups endpoint parameters, adds endpoints to linked list */
@@ -1913,41 +1914,22 @@ static int setup_ep0(struct udc *dev)
}
/* Called by gadget driver to register itself */
-static int amd5536_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
+static int amd5536_udc_start(struct usb_gadget *g,
+ struct usb_gadget_driver *driver)
{
- struct udc *dev = udc;
- int retval;
+ struct udc *dev = to_amd5536_udc(g);
u32 tmp;
- if (!driver || !bind || !driver->setup
- || driver->max_speed < USB_SPEED_HIGH)
- return -EINVAL;
- if (!dev)
- return -ENODEV;
- if (dev->driver)
- return -EBUSY;
-
driver->driver.bus = NULL;
dev->driver = driver;
dev->gadget.dev.driver = &driver->driver;
- retval = bind(&dev->gadget, driver);
-
/* Some gadget drivers use both ep0 directions.
* NOTE: to gadget driver, ep0 is just one endpoint...
*/
dev->ep[UDC_EP0OUT_IX].ep.driver_data =
dev->ep[UDC_EP0IN_IX].ep.driver_data;
- if (retval) {
- DBG(dev, "binding to %s returning %d\n",
- driver->driver.name, retval);
- dev->driver = NULL;
- dev->gadget.dev.driver = NULL;
- return retval;
- }
-
/* get ready for ep0 traffic */
setup_ep0(dev);
@@ -1969,14 +1951,9 @@ __acquires(dev->lock)
{
int tmp;
- if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
- spin_unlock(&dev->lock);
- driver->disconnect(&dev->gadget);
- spin_lock(&dev->lock);
- }
-
/* empty queues and init hardware */
udc_basic_init(dev);
+
for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
empty_req_queue(&dev->ep[tmp]);
@@ -1984,23 +1961,18 @@ __acquires(dev->lock)
}
/* Called by gadget driver to unregister itself */
-static int amd5536_stop(struct usb_gadget_driver *driver)
+static int amd5536_udc_stop(struct usb_gadget *g,
+ struct usb_gadget_driver *driver)
{
- struct udc *dev = udc;
- unsigned long flags;
+ struct udc *dev = to_amd5536_udc(g);
+ unsigned long flags;
u32 tmp;
- if (!dev)
- return -ENODEV;
- if (!driver || driver != dev->driver || !driver->unbind)
- return -EINVAL;
-
spin_lock_irqsave(&dev->lock, flags);
udc_mask_unused_interrupts(dev);
shutdown(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags);
- driver->unbind(&dev->gadget);
dev->gadget.dev.driver = NULL;
dev->driver = NULL;
@@ -2009,9 +1981,6 @@ static int amd5536_stop(struct usb_gadget_driver *driver)
tmp |= AMD_BIT(UDC_DEVCTL_SD);
writel(tmp, &dev->regs->ctl);
-
- DBG(dev, "%s: unregistered\n", driver->driver.name);
-
return 0;
}
diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h
index 14af87d65ca..f1bf32e6b8d 100644
--- a/drivers/usb/gadget/amd5536udc.h
+++ b/drivers/usb/gadget/amd5536udc.h
@@ -563,6 +563,8 @@ struct udc {
u16 cur_alt;
};
+#define to_amd5536_udc(g) (container_of((g), struct udc, gadget))
+
/* setup request data */
union udc_setup_data {
u32 data[2];
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 0143ffa4e40..45dd2929a67 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -1621,8 +1621,7 @@ static void at91_vbus_timer(unsigned long data)
* bus such as i2c or spi which may sleep, so schedule some work
* to read the vbus gpio
*/
- if (!work_pending(&udc->vbus_timer_work))
- schedule_work(&udc->vbus_timer_work);
+ schedule_work(&udc->vbus_timer_work);
}
static int at91_start(struct usb_gadget *gadget,
@@ -1739,7 +1738,7 @@ static int at91udc_probe(struct platform_device *pdev)
/* rm9200 needs manual D+ pullup; off by default */
if (cpu_is_at91rm9200()) {
- if (gpio_is_valid(udc->board.pullup_pin)) {
+ if (!gpio_is_valid(udc->board.pullup_pin)) {
DBG("no D+ pullup?\n");
retval = -ENODEV;
goto fail0;
diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c
index 1e4bb77f00b..a7d6f702675 100644
--- a/drivers/usb/gadget/cdc2.c
+++ b/drivers/usb/gadget/cdc2.c
@@ -42,9 +42,6 @@ USB_GADGET_COMPOSITE_OPTIONS();
* the runtime footprint, and giving us at least some parts of what
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
*/
-
-#include "u_serial.c"
-#include "f_acm.c"
#include "f_ecm.c"
#include "u_ether.c"
@@ -108,12 +105,16 @@ static struct usb_gadget_strings *dev_strings[] = {
static u8 hostaddr[ETH_ALEN];
/*-------------------------------------------------------------------------*/
+static struct usb_function *f_acm;
+static struct usb_function_instance *fi_serial;
+static unsigned char tty_line;
/*
* We _always_ have both CDC ECM and CDC ACM functions.
*/
static int __init cdc_do_config(struct usb_configuration *c)
{
+ struct f_serial_opts *opts;
int status;
if (gadget_is_otg(c->cdev->gadget)) {
@@ -125,11 +126,26 @@ static int __init cdc_do_config(struct usb_configuration *c)
if (status < 0)
return status;
- status = acm_bind_config(c, 0);
- if (status < 0)
- return status;
+ fi_serial = usb_get_function_instance("acm");
+ if (IS_ERR(fi_serial))
+ return PTR_ERR(fi_serial);
+ opts = container_of(fi_serial, struct f_serial_opts, func_inst);
+ opts->port_num = tty_line;
+
+ f_acm = usb_get_function(fi_serial);
+ if (IS_ERR(f_acm))
+ goto err_func_acm;
+
+ status = usb_add_function(c, f_acm);
+ if (status)
+ goto err_conf;
return 0;
+err_conf:
+ usb_put_function(f_acm);
+err_func_acm:
+ usb_put_function_instance(fi_serial);
+ return status;
}
static struct usb_configuration cdc_config_driver = {
@@ -158,7 +174,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
return status;
/* set up serial link layer */
- status = gserial_setup(cdev->gadget, 1);
+ status = gserial_alloc_line(&tty_line);
if (status < 0)
goto fail0;
@@ -184,7 +200,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
return 0;
fail1:
- gserial_cleanup();
+ gserial_free_line(tty_line);
fail0:
gether_cleanup();
return status;
@@ -192,7 +208,9 @@ fail0:
static int __exit cdc_unbind(struct usb_composite_dev *cdev)
{
- gserial_cleanup();
+ usb_put_function(f_acm);
+ usb_put_function_instance(fi_serial);
+ gserial_free_line(tty_line);
gether_cleanup();
return 0;
}
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 2a6bfe759c2..7c821de8ce3 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -28,6 +28,12 @@
* with the relevant device-wide data.
*/
+static struct usb_gadget_strings **get_containers_gs(
+ struct usb_gadget_string_container *uc)
+{
+ return (struct usb_gadget_strings **)uc->stash;
+}
+
/**
* next_ep_desc() - advance to the next EP descriptor
* @t: currect pointer within descriptor array
@@ -215,6 +221,18 @@ done:
}
EXPORT_SYMBOL_GPL(usb_add_function);
+void usb_remove_function(struct usb_configuration *c, struct usb_function *f)
+{
+ if (f->disable)
+ f->disable(f);
+
+ bitmap_zero(f->endpoints, 32);
+ list_del(&f->list);
+ if (f->unbind)
+ f->unbind(c, f);
+}
+EXPORT_SYMBOL_GPL(usb_remove_function);
+
/**
* usb_function_deactivate - prevent function and gadget enumeration
* @function: the function that isn't yet ready to respond
@@ -320,6 +338,25 @@ int usb_interface_id(struct usb_configuration *config,
}
EXPORT_SYMBOL_GPL(usb_interface_id);
+static u8 encode_bMaxPower(enum usb_device_speed speed,
+ struct usb_configuration *c)
+{
+ unsigned val;
+
+ if (c->MaxPower)
+ val = c->MaxPower;
+ else
+ val = CONFIG_USB_GADGET_VBUS_DRAW;
+ if (!val)
+ return 0;
+ switch (speed) {
+ case USB_SPEED_SUPER:
+ return DIV_ROUND_UP(val, 8);
+ default:
+ return DIV_ROUND_UP(val, 2);
+ };
+}
+
static int config_buf(struct usb_configuration *config,
enum usb_device_speed speed, void *buf, u8 type)
{
@@ -339,7 +376,7 @@ static int config_buf(struct usb_configuration *config,
c->bConfigurationValue = config->bConfigurationValue;
c->iConfiguration = config->iConfiguration;
c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes;
- c->bMaxPower = config->bMaxPower ? : (CONFIG_USB_GADGET_VBUS_DRAW / 2);
+ c->bMaxPower = encode_bMaxPower(speed, config);
/* There may be e.g. OTG descriptors */
if (config->descriptors) {
@@ -656,7 +693,7 @@ static int set_config(struct usb_composite_dev *cdev,
}
/* when we return, be sure our power usage is valid */
- power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;
+ power = c->MaxPower ? c->MaxPower : CONFIG_USB_GADGET_VBUS_DRAW;
done:
usb_gadget_vbus_draw(gadget, power);
if (result >= 0 && cdev->delayed_status)
@@ -664,6 +701,31 @@ done:
return result;
}
+int usb_add_config_only(struct usb_composite_dev *cdev,
+ struct usb_configuration *config)
+{
+ struct usb_configuration *c;
+
+ if (!config->bConfigurationValue)
+ return -EINVAL;
+
+ /* Prevent duplicate configuration identifiers */
+ list_for_each_entry(c, &cdev->configs, list) {
+ if (c->bConfigurationValue == config->bConfigurationValue)
+ return -EBUSY;
+ }
+
+ config->cdev = cdev;
+ list_add_tail(&config->list, &cdev->configs);
+
+ INIT_LIST_HEAD(&config->functions);
+ config->next_interface_id = 0;
+ memset(config->interface, 0, sizeof(config->interface));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_add_config_only);
+
/**
* usb_add_config() - add a configuration to a device.
* @cdev: wraps the USB gadget
@@ -684,30 +746,18 @@ int usb_add_config(struct usb_composite_dev *cdev,
int (*bind)(struct usb_configuration *))
{
int status = -EINVAL;
- struct usb_configuration *c;
+
+ if (!bind)
+ goto done;
DBG(cdev, "adding config #%u '%s'/%p\n",
config->bConfigurationValue,
config->label, config);
- if (!config->bConfigurationValue || !bind)
+ status = usb_add_config_only(cdev, config);
+ if (status)
goto done;
- /* Prevent duplicate configuration identifiers */
- list_for_each_entry(c, &cdev->configs, list) {
- if (c->bConfigurationValue == config->bConfigurationValue) {
- status = -EBUSY;
- goto done;
- }
- }
-
- config->cdev = cdev;
- list_add_tail(&config->list, &cdev->configs);
-
- INIT_LIST_HEAD(&config->functions);
- config->next_interface_id = 0;
- memset(config->interface, 0, sizeof(config->interface));
-
status = bind(config);
if (status < 0) {
while (!list_empty(&config->functions)) {
@@ -860,6 +910,7 @@ static int get_string(struct usb_composite_dev *cdev,
void *buf, u16 language, int id)
{
struct usb_composite_driver *composite = cdev->driver;
+ struct usb_gadget_string_container *uc;
struct usb_configuration *c;
struct usb_function *f;
int len;
@@ -892,6 +943,12 @@ static int get_string(struct usb_composite_dev *cdev,
collect_langs(sp, s->wData);
}
}
+ list_for_each_entry(uc, &cdev->gstrings, list) {
+ struct usb_gadget_strings **sp;
+
+ sp = get_containers_gs(uc);
+ collect_langs(sp, s->wData);
+ }
for (len = 0; len <= 126 && s->wData[len]; len++)
continue;
@@ -902,6 +959,15 @@ static int get_string(struct usb_composite_dev *cdev,
return s->bLength;
}
+ list_for_each_entry(uc, &cdev->gstrings, list) {
+ struct usb_gadget_strings **sp;
+
+ sp = get_co