diff options
| author | Thomas Kunze <thommycheck@gmx.de> | 2008-10-20 15:16:07 +0200 |
|---|---|---|
| committer | Thomas Kunze <thommycheck@gmx.de> | 2008-10-20 15:23:43 +0200 |
| commit | 0eb44cec07715a734c8d5d52fbb433e0287bc5d1 (patch) | |
| tree | 441066ab0b03ede5843fc38fdca3ffc6645d9ab2 /packages/linux | |
| parent | 49ff305433b8432a07c14eb05059642ab19767ee (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-collie | 58 | ||||
| -rw-r--r-- | packages/linux/linux-rp-2.6.26/usb-gadget27bp.patch | 26674 | ||||
| -rw-r--r-- | packages/linux/linux-rp_2.6.26.bb | 3 |
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 |
