summaryrefslogtreecommitdiff
path: root/packages/linux
diff options
context:
space:
mode:
authorThomas Kunze <thommycheck@gmx.de>2008-10-20 15:16:07 +0200
committerThomas Kunze <thommycheck@gmx.de>2008-10-20 15:23:43 +0200
commit0eb44cec07715a734c8d5d52fbb433e0287bc5d1 (patch)
tree441066ab0b03ede5843fc38fdca3ffc6645d9ab2 /packages/linux
parent49ff305433b8432a07c14eb05059642ab19767ee (diff)
linux-rp_2.6.26: add patch for collie usb
Diffstat (limited to 'packages/linux')
-rw-r--r--packages/linux/linux-rp-2.6.26/defconfig-collie58
-rw-r--r--packages/linux/linux-rp-2.6.26/usb-gadget27bp.patch26674
-rw-r--r--packages/linux/linux-rp_2.6.26.bb3
3 files changed, 26728 insertions, 7 deletions
diff --git a/packages/linux/linux-rp-2.6.26/defconfig-collie b/packages/linux/linux-rp-2.6.26/defconfig-collie
index e21cc21da2..e80885f332 100644
--- a/packages/linux/linux-rp-2.6.26/defconfig-collie
+++ b/packages/linux/linux-rp-2.6.26/defconfig-collie
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.26
-# Fri Oct 17 18:46:51 2008
+# Mon Oct 20 01:48:37 2008
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -845,7 +845,13 @@ CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
CONFIG_INPUT_UINPUT=m
#
@@ -954,11 +960,11 @@ CONFIG_SSB_POSSIBLE=y
#
# Multimedia Capabilities Port drivers
#
-CONFIG_MCP=m
-CONFIG_MCP_SA11X0=m
-CONFIG_MCP_UCB1200=m
+CONFIG_MCP=y
+CONFIG_MCP_SA11X0=y
+CONFIG_MCP_UCB1200=y
# CONFIG_MCP_UCB1200_TS is not set
-CONFIG_MCP_COLLIE_TS=m
+CONFIG_MCP_COLLIE_TS=y
#
# Multimedia devices
@@ -1044,7 +1050,47 @@ CONFIG_FONT_8x8=y
# CONFIG_SOUND is not set
# CONFIG_HID_SUPPORT is not set
CONFIG_HID=m
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+CONFIG_USB_GADGET_SA1100=y
+CONFIG_USB_SA1100=y
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=m
+# CONFIG_USB_ETH_RNDIS is not set
+# CONFIG_USB_ETH_NO_MDLM is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_USB_G_PRINTER=m
CONFIG_MMC=y
# CONFIG_MMC_DEBUG is not set
CONFIG_MMC_UNSAFE_RESUME=y
diff --git a/packages/linux/linux-rp-2.6.26/usb-gadget27bp.patch b/packages/linux/linux-rp-2.6.26/usb-gadget27bp.patch
new file mode 100644
index 0000000000..3c86f1a474
--- /dev/null
+++ b/packages/linux/linux-rp-2.6.26/usb-gadget27bp.patch
@@ -0,0 +1,26674 @@
+diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
+index 6e784d2..117d0c7 100644
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -118,10 +118,10 @@ config USB_AMD5536UDC
+ config USB_GADGET_ATMEL_USBA
+ boolean "Atmel USBA"
+ select USB_GADGET_DUALSPEED
+- depends on AVR32 || ARCH_AT91CAP9
++ depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL
+ help
+ USBA is the integrated high-speed USB Device controller on
+- the AT32AP700x and AT91CAP9 processors from Atmel.
++ the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
+
+ config USB_ATMEL_USBA
+ tristate
+@@ -172,7 +172,7 @@ config USB_NET2280
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
+-config USB_GADGET_PXA2XX
++config USB_GADGET_PXA25X
+ boolean "PXA 25x or IXP 4xx"
+ depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
+ help
+@@ -184,19 +184,19 @@ config USB_GADGET_PXA2XX
+ zero (for control transfers).
+
+ Say "y" to link the driver statically, or "m" to build a
+- dynamically linked module called "pxa2xx_udc" and force all
++ dynamically linked module called "pxa25x_udc" and force all
+ gadget drivers to also be dynamically linked.
+
+-config USB_PXA2XX
++config USB_PXA25X
+ tristate
+- depends on USB_GADGET_PXA2XX
++ depends on USB_GADGET_PXA25X
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
+ # if there's only one gadget driver, using only two bulk endpoints,
+ # don't waste memory for the other endpoints
+-config USB_PXA2XX_SMALL
+- depends on USB_GADGET_PXA2XX
++config USB_PXA25X_SMALL
++ depends on USB_GADGET_PXA25X
+ bool
+ default n if USB_ETH_RNDIS
+ default y if USB_ZERO
+@@ -284,6 +284,16 @@ config USB_LH7A40X
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
++# built in ../musb along with host support
++config USB_GADGET_MUSB_HDRC
++ boolean "Inventra HDRC USB Peripheral (TI, ...)"
++ depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
++ select USB_GADGET_DUALSPEED
++ select USB_GADGET_SELECTED
++ help
++ This OTG-capable silicon IP is used in dual designs including
++ the TI DaVinci, OMAP 243x, OMAP 343x, and TUSB 6010.
++
+ config USB_GADGET_OMAP
+ boolean "OMAP USB Device Controller"
+ depends on ARCH_OMAP
+@@ -355,6 +365,20 @@ config USB_AT91
+ depends on USB_GADGET_AT91
+ default USB_GADGET
+
++config USB_GADGET_SA1100
++ boolean "SA1100 USB Device Port"
++ depends on ARCH_SA1100
++ help
++ Say "y" to link the driver statically, or "m" to build a
++ dynamically linked module called "sa1100_udc" and force all
++ gadget drivers to also be dynamically linked.
++
++config USB_SA1100
++ tristate
++ depends on USB_GADGET_SA1100
++ default USB_GADGET
++ select USB_GADGET_SELECTED
++
+ config USB_GADGET_DUMMY_HCD
+ boolean "Dummy HCD (DEVELOPMENT)"
+ depends on USB=y || (USB=m && USB_GADGET=m)
+@@ -504,6 +528,20 @@ config USB_ETH_RNDIS
+ XP, you'll need to download drivers from Microsoft's website; a URL
+ is given in comments found in that info file.
+
++config USB_ETH_NO_MDLM
++ bool "Disable MDLM support for CDC_SUBSET"
++ depends on USB_ETH
++ default n
++ help
++ A variation on CDC_SUBSET support is used in newer kernel
++ implementations for use with a proprietary Microsoft Windows driver
++ used for example with the Zaurus linux distribution.
++ However, the MDLM extensions break the older host side drivers making
++ g_ether incompatible with older kernels.
++
++ If you say "y" here, the Ethernet gadget driver will use the older
++ pre-MDLM extensions.
++
+ config USB_GADGETFS
+ tristate "Gadget Filesystem (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+@@ -586,6 +624,20 @@ config USB_G_PRINTER
+ For more information, see Documentation/usb/gadget_printer.txt
+ which includes sample code for accessing the device file.
+
++config USB_CDC_COMPOSITE
++ tristate "CDC Composite Device (Ethernet and ACM)"
++ depends on NET
++ help
++ This driver provides two functions in one configuration:
++ a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link.
++
++ This driver requires four bulk and two interrupt endpoints,
++ plus the ability to handle altsettings. Not all peripheral
++ controllers are that capable.
++
++ Say "y" to link the driver statically, or "m" to build a
++ dynamically linked module.
++
+ # put drivers that need isochronous transfer support (for audio
+ # or video class gadget drivers), or specific hardware, here.
+
+diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
+index 1235725..79a69ae 100644
+--- a/drivers/usb/gadget/Makefile
++++ b/drivers/usb/gadget/Makefile
+@@ -8,7 +8,7 @@ endif
+ obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
+ obj-$(CONFIG_USB_NET2280) += net2280.o
+ obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
+-obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o
++obj-$(CONFIG_USB_PXA25X) += pxa25x_udc.o
+ obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o
+ obj-$(CONFIG_USB_GOKU) += goku_udc.o
+ obj-$(CONFIG_USB_OMAP) += omap_udc.o
+@@ -18,22 +18,27 @@ obj-$(CONFIG_USB_AT91) += at91_udc.o
+ obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
+ obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
+ obj-$(CONFIG_USB_M66592) += m66592-udc.o
++obj-$(CONFIG_USB_SA1100) += sa1100_udc.o
+
+ #
+ # USB gadget drivers
+ #
+-g_zero-objs := zero.o usbstring.o config.o epautoconf.o
+-g_ether-objs := ether.o usbstring.o config.o epautoconf.o
+-g_serial-objs := serial.o usbstring.o config.o epautoconf.o
++C_UTILS = composite.o usbstring.o config.o epautoconf.o
++
++g_zero-objs := zero.o f_sourcesink.o f_loopback.o $(C_UTILS)
++g_ether-objs := ether.o u_ether.o f_subset.o f_ecm.o $(C_UTILS)
++g_serial-objs := serial.o u_serial.o f_acm.o f_serial.o $(C_UTILS)
+ g_midi-objs := gmidi.o usbstring.o config.o epautoconf.o
+ gadgetfs-objs := inode.o
+ g_file_storage-objs := file_storage.o usbstring.o config.o \
+ epautoconf.o
+ g_printer-objs := printer.o usbstring.o config.o \
+ epautoconf.o
++g_cdc-objs := cdc2.o u_ether.o f_ecm.o \
++ u_serial.o f_acm.o $(C_UTILS)
+
+ ifeq ($(CONFIG_USB_ETH_RNDIS),y)
+- g_ether-objs += rndis.o
++ g_ether-objs += f_rndis.o rndis.o
+ endif
+
+ obj-$(CONFIG_USB_ZERO) += g_zero.o
+@@ -43,4 +48,5 @@ obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o
+ obj-$(CONFIG_USB_G_SERIAL) += g_serial.o
+ obj-$(CONFIG_USB_G_PRINTER) += g_printer.o
+ obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o
++obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
+
+diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
+index f261d2a..abf8192 100644
+--- a/drivers/usb/gadget/amd5536udc.c
++++ b/drivers/usb/gadget/amd5536udc.c
+@@ -44,7 +44,6 @@
+ #include <linux/module.h>
+ #include <linux/pci.h>
+ #include <linux/kernel.h>
+-#include <linux/version.h>
+ #include <linux/delay.h>
+ #include <linux/ioport.h>
+ #include <linux/sched.h>
+@@ -3342,7 +3341,7 @@ static int udc_probe(struct udc *dev)
+ spin_lock_init(&dev->lock);
+ dev->gadget.ops = &udc_ops;
+
+- strcpy(dev->gadget.dev.bus_id, "gadget");
++ dev_set_name(&dev->gadget.dev, "gadget");
+ dev->gadget.dev.release = gadget_release;
+ dev->gadget.name = name;
+ dev->gadget.name = name;
+diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
+index 274c60a..a8a1de4 100644
+--- a/drivers/usb/gadget/at91_udc.c
++++ b/drivers/usb/gadget/at91_udc.c
+@@ -40,16 +40,15 @@
+ #include <linux/usb/gadget.h>
+
+ #include <asm/byteorder.h>
+-#include <asm/hardware.h>
++#include <mach/hardware.h>
+ #include <asm/io.h>
+ #include <asm/irq.h>
+ #include <asm/system.h>
+-#include <asm/mach-types.h>
+ #include <asm/gpio.h>
+
+-#include <asm/arch/board.h>
+-#include <asm/arch/cpu.h>
+-#include <asm/arch/at91sam9261_matrix.h>
++#include <mach/board.h>
++#include <mach/cpu.h>
++#include <mach/at91sam9261_matrix.h>
+
+ #include "at91_udc.h"
+
+@@ -888,7 +887,7 @@ static void pullup(struct at91_udc *udc, int is_on)
+ at91_udp_write(udc, AT91_UDP_TXVC, 0);
+ if (cpu_is_at91rm9200())
+ gpio_set_value(udc->board.pullup_pin, active);
+- else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
++ else if (cpu_is_at91sam9260() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
+ u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
+
+ txvc |= AT91_UDP_TXVC_PUON;
+@@ -906,7 +905,7 @@ static void pullup(struct at91_udc *udc, int is_on)
+ at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+ if (cpu_is_at91rm9200())
+ gpio_set_value(udc->board.pullup_pin, !active);
+- else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
++ else if (cpu_is_at91sam9260() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
+ u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
+
+ txvc &= ~AT91_UDP_TXVC_PUON;
+@@ -1687,6 +1686,19 @@ static int __init at91udc_probe(struct platform_device *pdev)
+ udc->board.pullup_active_low);
+ }
+
++ /* newer chips have more FIFO memory than rm9200 */
++ if (cpu_is_at91sam9260()) {
++ udc->ep[0].maxpacket = 64;
++ udc->ep[3].maxpacket = 64;
++ udc->ep[4].maxpacket = 512;
++ udc->ep[5].maxpacket = 512;
++ } else if (cpu_is_at91sam9261()) {
++ udc->ep[3].maxpacket = 64;
++ } else if (cpu_is_at91sam9263()) {
++ udc->ep[0].maxpacket = 64;
++ udc->ep[3].maxpacket = 64;
++ }
++
+ udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1);
+ if (!udc->udp_baseaddr) {
+ retval = -ENOMEM;
+diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
+index a973f2a..c65d622 100644
+--- a/drivers/usb/gadget/at91_udc.h
++++ b/drivers/usb/gadget/at91_udc.h
+@@ -171,7 +171,7 @@ struct at91_request {
+ #endif
+
+ #define ERR(stuff...) pr_err("udc: " stuff)
+-#define WARN(stuff...) pr_warning("udc: " stuff)
++#define WARNING(stuff...) pr_warning("udc: " stuff)
+ #define INFO(stuff...) pr_info("udc: " stuff)
+ #define DBG(stuff...) pr_debug("udc: " stuff)
+
+diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
+index 07e5a0b..ae30ab1 100644
+--- a/drivers/usb/gadget/atmel_usba_udc.c
++++ b/drivers/usb/gadget/atmel_usba_udc.c
+@@ -22,7 +22,7 @@
+ #include <linux/delay.h>
+
+ #include <asm/gpio.h>
+-#include <asm/arch/board.h>
++#include <mach/board.h>
+
+ #include "atmel_usba_udc.h"
+
+@@ -334,7 +334,7 @@ static void toggle_bias(int is_on)
+
+ #elif defined(CONFIG_ARCH_AT91)
+
+-#include <asm/arch/at91_pmc.h>
++#include <mach/at91_pmc.h>
+
+ static void toggle_bias(int is_on)
+ {
+diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c
+new file mode 100644
+index 0000000..a39a4b9
+--- /dev/null
++++ b/drivers/usb/gadget/cdc2.c
+@@ -0,0 +1,246 @@
++/*
++ * cdc2.c -- CDC Composite driver, with ECM and ACM support
++ *
++ * Copyright (C) 2008 David Brownell
++ * Copyright (C) 2008 Nokia Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/kernel.h>
++#include <linux/utsname.h>
++
++#include "u_ether.h"
++#include "u_serial.h"
++
++
++#define DRIVER_DESC "CDC Composite Gadget"
++#define DRIVER_VERSION "King Kamehameha Day 2008"
++
++/*-------------------------------------------------------------------------*/
++
++/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
++ * Instead: allocate your own, using normal USB-IF procedures.
++ */
++
++/* Thanks to NetChip Technologies for donating this product ID.
++ * It's for devices with only this composite CDC configuration.
++ */
++#define CDC_VENDOR_NUM 0x0525 /* NetChip */
++#define CDC_PRODUCT_NUM 0xa4aa /* CDC Composite: ECM + ACM */
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_device_descriptor device_desc = {
++ .bLength = sizeof device_desc,
++ .bDescriptorType = USB_DT_DEVICE,
++
++ .bcdUSB = __constant_cpu_to_le16(0x0200),
++
++ .bDeviceClass = USB_CLASS_COMM,
++ .bDeviceSubClass = 0,
++ .bDeviceProtocol = 0,
++ /* .bMaxPacketSize0 = f(hardware) */
++
++ /* Vendor and product id can be overridden by module parameters. */
++ .idVendor = __constant_cpu_to_le16(CDC_VENDOR_NUM),
++ .idProduct = __constant_cpu_to_le16(CDC_PRODUCT_NUM),
++ /* .bcdDevice = f(hardware) */
++ /* .iManufacturer = DYNAMIC */
++ /* .iProduct = DYNAMIC */
++ /* NO SERIAL NUMBER */
++ .bNumConfigurations = 1,
++};
++
++static struct usb_otg_descriptor otg_descriptor = {
++ .bLength = sizeof otg_descriptor,
++ .bDescriptorType = USB_DT_OTG,
++
++ /* REVISIT SRP-only hardware is possible, although
++ * it would not be called "OTG" ...
++ */
++ .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
++};
++
++static const struct usb_descriptor_header *otg_desc[] = {
++ (struct usb_descriptor_header *) &otg_descriptor,
++ NULL,
++};
++
++
++/* string IDs are assigned dynamically */
++
++#define STRING_MANUFACTURER_IDX 0
++#define STRING_PRODUCT_IDX 1
++
++static char manufacturer[50];
++
++static struct usb_string strings_dev[] = {
++ [STRING_MANUFACTURER_IDX].s = manufacturer,
++ [STRING_PRODUCT_IDX].s = DRIVER_DESC,
++ { } /* end of list */
++};
++
++static struct usb_gadget_strings stringtab_dev = {
++ .language = 0x0409, /* en-us */
++ .strings = strings_dev,
++};
++
++static struct usb_gadget_strings *dev_strings[] = {
++ &stringtab_dev,
++ NULL,
++};
++
++static u8 hostaddr[ETH_ALEN];
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * We _always_ have both CDC ECM and CDC ACM functions.
++ */
++static int __init cdc_do_config(struct usb_configuration *c)
++{
++ int status;
++
++ if (gadget_is_otg(c->cdev->gadget)) {
++ c->descriptors = otg_desc;
++ c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++ }
++
++ status = ecm_bind_config(c, hostaddr);
++ if (status < 0)
++ return status;
++
++ status = acm_bind_config(c, 0);
++ if (status < 0)
++ return status;
++
++ return 0;
++}
++
++static struct usb_configuration cdc_config_driver = {
++ .label = "CDC Composite (ECM + ACM)",
++ .bind = cdc_do_config,
++ .bConfigurationValue = 1,
++ /* .iConfiguration = DYNAMIC */
++ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
++ .bMaxPower = 1, /* 2 mA, minimal */
++};
++
++/*-------------------------------------------------------------------------*/
++
++static int __init cdc_bind(struct usb_composite_dev *cdev)
++{
++ int gcnum;
++ struct usb_gadget *gadget = cdev->gadget;
++ int status;
++
++ if (!can_support_ecm(cdev->gadget)) {
++ ERROR(cdev, "controller '%s' not usable\n", gadget->name);
++ return -EINVAL;
++ }
++
++ /* set up network link layer */
++ status = gether_setup(cdev->gadget, hostaddr);
++ if (status < 0)
++ return status;
++
++ /* set up serial link layer */
++ status = gserial_setup(cdev->gadget, 1);
++ if (status < 0)
++ goto fail0;
++
++ gcnum = usb_gadget_controller_number(gadget);
++ if (gcnum >= 0)
++ device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
++ else {
++ /* We assume that can_support_ecm() tells the truth;
++ * but if the controller isn't recognized at all then
++ * that assumption is a bit more likely to be wrong.
++ */
++ WARNING(cdev, "controller '%s' not recognized; trying %s\n",
++ gadget->name,
++ cdc_config_driver.label);
++ device_desc.bcdDevice =
++ __constant_cpu_to_le16(0x0300 | 0x0099);
++ }
++
++
++ /* Allocate string descriptor numbers ... note that string
++ * contents can be overridden by the composite_dev glue.
++ */
++
++ /* device descriptor strings: manufacturer, product */
++ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
++ init_utsname()->sysname, init_utsname()->release,
++ gadget->name);
++ status = usb_string_id(cdev);
++ if (status < 0)
++ goto fail1;
++ strings_dev[STRING_MANUFACTURER_IDX].id = status;
++ device_desc.iManufacturer = status;
++
++ status = usb_string_id(cdev);
++ if (status < 0)
++ goto fail1;
++ strings_dev[STRING_PRODUCT_IDX].id = status;
++ device_desc.iProduct = status;
++
++ /* register our configuration */
++ status = usb_add_config(cdev, &cdc_config_driver);
++ if (status < 0)
++ goto fail1;
++
++ INFO(cdev, "%s, version: " DRIVER_VERSION "\n", DRIVER_DESC);
++
++ return 0;
++
++fail1:
++ gserial_cleanup();
++fail0:
++ gether_cleanup();
++ return status;
++}
++
++static int __exit cdc_unbind(struct usb_composite_dev *cdev)
++{
++ gserial_cleanup();
++ gether_cleanup();
++ return 0;
++}
++
++static struct usb_composite_driver cdc_driver = {
++ .name = "g_cdc",
++ .dev = &device_desc,
++ .strings = dev_strings,
++ .bind = cdc_bind,
++ .unbind = __exit_p(cdc_unbind),
++};
++
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_AUTHOR("David Brownell");
++MODULE_LICENSE("GPL");
++
++static int __init init(void)
++{
++ return usb_composite_register(&cdc_driver);
++}
++module_init(init);
++
++static void __exit cleanup(void)
++{
++ usb_composite_unregister(&cdc_driver);
++}
++module_exit(cleanup);
+diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
+new file mode 100644
+index 0000000..85c876c
+--- /dev/null
++++ b/drivers/usb/gadget/composite.c
+@@ -0,0 +1,1041 @@
++/*
++ * composite.c - infrastructure for Composite USB Gadgets
++ *
++ * Copyright (C) 2006-2008 David Brownell
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++/* #define VERBOSE_DEBUG */
++
++#include <linux/kallsyms.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/device.h>
++
++#include <linux/usb/composite.h>
++
++
++/*
++ * The code in this file is utility code, used to build a gadget driver
++ * from one or more "function" drivers, one or more "configuration"
++ * objects, and a "usb_composite_driver" by gluing them together along
++ * with the relevant device-wide data.
++ */
++
++/* big enough to hold our biggest descriptor */
++#define USB_BUFSIZ 512
++
++static struct usb_composite_driver *composite;
++
++/* Some systems will need runtime overrides for the product identifers
++ * published in the device descriptor, either numbers or strings or both.
++ * String parameters are in UTF-8 (superset of ASCII's 7 bit characters).
++ */
++
++static ushort idVendor;
++module_param(idVendor, ushort, 0);
++MODULE_PARM_DESC(idVendor, "USB Vendor ID");
++
++static ushort idProduct;
++module_param(idProduct, ushort, 0);
++MODULE_PARM_DESC(idProduct, "USB Product ID");
++
++static ushort bcdDevice;
++module_param(bcdDevice, ushort, 0);
++MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
++
++static char *iManufacturer;
++module_param(iManufacturer, charp, 0);
++MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
++
++static char *iProduct;
++module_param(iProduct, charp, 0);
++MODULE_PARM_DESC(iProduct, "USB Product string");
++
++static char *iSerialNumber;
++module_param(iSerialNumber, charp, 0);
++MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
++
++/*-------------------------------------------------------------------------*/
++
++/**
++ * usb_add_function() - add a function to a configuration
++ * @config: the configuration
++ * @function: the function being added
++ * Context: single threaded during gadget setup
++ *
++ * After initialization, each configuration must have one or more
++ * functions added to it. Adding a function involves calling its @bind()
++ * method to allocate resources such as interface and string identifiers
++ * and endpoints.
++ *
++ * This function returns the value of the function's bind(), which is
++ * zero for success else a negative errno value.
++ */
++int __init usb_add_function(struct usb_configuration *config,
++ struct usb_function *function)
++{
++ int value = -EINVAL;
++
++ DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n",
++ function->name, function,
++ config->label, config);
++
++ if (!function->set_alt || !function->disable)
++ goto done;
++
++ function->config = config;
++ list_add_tail(&function->list, &config->functions);
++
++ /* REVISIT *require* function->bind? */
++ if (function->bind) {
++ value = function->bind(config, function);
++ if (value < 0) {
++ list_del(&function->list);
++ function->config = NULL;
++ }
++ } else
++ value = 0;
++
++ /* We allow configurations that don't work at both speeds.
++ * If we run into a lowspeed Linux system, treat it the same
++ * as full speed ... it's the function drivers that will need
++ * to avoid bulk and ISO transfers.
++ */
++ if (!config->fullspeed && function->descriptors)
++ config->fullspeed = true;
++ if (!config->highspeed && function->hs_descriptors)
++ config->highspeed = true;
++
++done:
++ if (value)
++ DBG(config->cdev, "adding '%s'/%p --> %d\n",
++ function->name, function, value);
++ return value;
++}
++
++/**
++ * usb_interface_id() - allocate an unused interface ID
++ * @config: configuration associated with the interface
++ * @function: function handling the interface
++ * Context: single threaded during gadget setup
++ *
++ * usb_interface_id() is called from usb_function.bind() callbacks to
++ * allocate new interface IDs. The function driver will then store that
++ * ID in interface, association, CDC union, and other descriptors. It
++ * will also handle any control requests targetted at that interface,
++ * particularly changing its altsetting via set_alt(). There may
++ * also be class-specific or vendor-specific requests to handle.
++ *
++ * All interface identifier should be allocated using this routine, to
++ * ensure that for example different functions don't wrongly assign
++ * different meanings to the same identifier. Note that since interface
++ * identifers are configuration-specific, functions used in more than
++ * one configuration (or more than once in a given configuration) need
++ * multiple versions of the relevant descriptors.
++ *
++ * Returns the interface ID which was allocated; or -ENODEV if no
++ * more interface IDs can be allocated.
++ */
++int __init usb_interface_id(struct usb_configuration *config,
++ struct usb_function *function)
++{
++ unsigned id = config->next_interface_id;
++
++ if (id < MAX_CONFIG_INTERFACES) {
++ config->interface[id] = function;
++ config->next_interface_id = id + 1;
++ return id;
++ }
++ return -ENODEV;
++}
++
++static int config_buf(struct usb_configuration *config,
++ enum usb_device_speed speed, void *buf, u8 type)
++{
++ struct usb_config_descriptor *c = buf;
++ void *next = buf + USB_DT_CONFIG_SIZE;
++ int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE;
++ struct usb_function *f;
++ int status;
++
++ /* write the config descriptor */
++ c = buf;
++ c->bLength = USB_DT_CONFIG_SIZE;
++ c->bDescriptorType = type;
++ /* wTotalLength is written later */
++ c->bNumInterfaces = config->next_interface_id;
++ c->bConfigurationValue = config->bConfigurationValue;
++ c->iConfiguration = config->iConfiguration;
++ c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes;
++ c->bMaxPower = config->bMaxPower;
++
++ /* There may be e.g. OTG descriptors */
++ if (config->descriptors) {
++ status = usb_descriptor_fillbuf(next, len,
++ config->descriptors);
++ if (status < 0)
++ return status;
++ len -= status;
++ next += status;
++ }
++
++ /* add each function's descriptors */
++ list_for_each_entry(f, &config->functions, list) {
++ struct usb_descriptor_header **descriptors;
++
++ if (speed == USB_SPEED_HIGH)
++ descriptors = f->hs_descriptors;
++ else
++ descriptors = f->descriptors;
++ if (!descriptors)
++ continue;
++ status = usb_descriptor_fillbuf(next, len,
++ (const struct usb_descriptor_header **) descriptors);
++ if (status < 0)
++ return status;
++ len -= status;
++ next += status;
++ }
++
++ len = next - buf;
++ c->wTotalLength = cpu_to_le16(len);
++ return len;
++}
++
++static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
++{
++ struct usb_gadget *gadget = cdev->gadget;
++ struct usb_configuration *c;
++ u8 type = w_value >> 8;
++ enum usb_device_speed speed = USB_SPEED_UNKNOWN;
++
++ if (gadget_is_dualspeed(gadget)) {
++ int hs = 0;
++
++ if (gadget->speed == USB_SPEED_HIGH)
++ hs = 1;
++ if (type == USB_DT_OTHER_SPEED_CONFIG)
++ hs = !hs;
++ if (hs)
++ speed = USB_SPEED_HIGH;
++
++ }
++
++ /* This is a lookup by config *INDEX* */
++ w_value &= 0xff;
++ list_for_each_entry(c, &cdev->configs, list) {
++ /* ignore configs that won't work at this speed */
++ if (speed == USB_SPEED_HIGH) {
++ if (!c->highspeed)
++ continue;
++ } else {
++ if (!c->fullspeed)
++ continue;
++ }
++ if (w_value == 0)
++ return config_buf(c, speed, cdev->req->buf, type);
++ w_value--;
++ }
++ return -EINVAL;
++}
++
++static int count_configs(struct usb_composite_dev *cdev, unsigned type)
++{
++ struct usb_gadget *gadget = cdev->gadget;
++ struct usb_configuration *c;
++ unsigned count = 0;
++ int hs = 0;
++
++ if (gadget_is_dualspeed(gadget)) {
++ if (gadget->speed == USB_SPEED_HIGH)
++ hs = 1;
++ if (type == USB_DT_DEVICE_QUALIFIER)
++ hs = !hs;
++ }
++ list_for_each_entry(c, &cdev->configs, list) {
++ /* ignore configs that won't work at this speed */
++ if (hs) {
++ if (!c->highspeed)
++ continue;
++ } else {
++ if (!c->fullspeed)
++ continue;
++ }
++ count++;
++ }
++ return count;
++}
++
++static void device_qual(struct usb_composite_dev *cdev)
++{
++ struct usb_qualifier_descriptor *qual = cdev->req->buf;
++
++ qual->bLength = sizeof(*qual);
++ qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
++ /* POLICY: same bcdUSB and device type info at both speeds */
++ qual->bcdUSB = cdev->desc.bcdUSB;
++ qual->bDeviceClass = cdev->desc.bDeviceClass;
++ qual->bDeviceSubClass = cdev->desc.bDeviceSubClass;
++ qual->bDeviceProtocol = cdev->desc.bDeviceProtocol;
++ /* ASSUME same EP0 fifo size at both speeds */
++ qual->bMaxPacketSize0 = cdev->desc.bMaxPacketSize0;
++ qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER);
++ qual->bRESERVED = 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void reset_config(struct usb_composite_dev *cdev)
++{
++ struct usb_function *f;
++
++ DBG(cdev, "reset config\n");
++
++ list_for_each_entry(f, &cdev->config->functions, list) {
++ if (f->disable)
++ f->disable(f);
++ }
++ cdev->config = NULL;
++}
++
++static int set_config(struct usb_composite_dev *cdev,
++ const struct usb_ctrlrequest *ctrl, unsigned number)
++{
++ struct usb_gadget *gadget = cdev->gadget;
++ struct usb_configuration *c = NULL;
++ int result = -EINVAL;
++ unsigned power = gadget_is_otg(gadget) ? 8 : 100;
++ int tmp;
++
++ if (cdev->config)
++ reset_config(cdev);
++
++ if (number) {
++ list_for_each_entry(c, &cdev->configs, list) {
++ if (c->bConfigurationValue == number) {
++ result = 0;
++ break;
++ }
++ }
++ if (result < 0)
++ goto done;
++ } else
++ result = 0;
++
++ INFO(cdev, "%s speed config #%d: %s\n",
++ ({ char *speed;
++ switch (gadget->speed) {
++ case USB_SPEED_LOW: speed = "low"; break;
++ case USB_SPEED_FULL: speed = "full"; break;
++ case USB_SPEED_HIGH: speed = "high"; break;
++ default: speed = "?"; break;
++ } ; speed; }), number, c ? c->label : "unconfigured");
++
++ if (!c)
++ goto done;
++
++ cdev->config = c;
++
++ /* Initialize all interfaces by setting them to altsetting zero. */
++ for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) {
++ struct usb_function *f = c->interface[tmp];
++
++ if (!f)
++ break;
++
++ result = f->set_alt(f, tmp, 0);
++ if (result < 0) {
++ DBG(cdev, "interface %d (%s/%p) alt 0 --> %d\n",
++ tmp, f->name, f, result);
++
++ reset_config(cdev);
++ goto done;
++ }
++ }
++
++ /* when we return, be sure our power usage is valid */
++ power = 2 * c->bMaxPower;
++done:
++ usb_gadget_vbus_draw(gadget, power);
++ return result;
++}
++
++/**
++ * usb_add_config() - add a configuration to a device.
++ * @cdev: wraps the USB gadget
++ * @config: the configuration, with bConfigurationValue assigned
++ * Context: single threaded during gadget setup
++ *
++ * One of the main tasks of a composite driver's bind() routine is to
++ * add each of the configurations it supports, using this routine.
++ *
++ * This function returns the value of the configuration's bind(), which
++ * is zero for success else a negative errno value. Binding configurations
++ * assigns global resources including string IDs, and per-configuration
++ * resources such as interface IDs and endpoints.
++ */
++int __init usb_add_config(struct usb_composite_dev *cdev,
++ struct usb_configuration *config)
++{
++ int status = -EINVAL;
++ struct usb_configuration *c;
++
++ DBG(cdev, "adding config #%u '%s'/%p\n",
++ confi