Please merge.
- Dave
Brings the file_storage gadget more into sync with the 2.6 code:
- Converts to use the new endpoint autoconfig library code. This makes it a lot simpler to run this on new hardware ... less static config. - Converts to use a table of configuration descriptors (library code) instead of doing that programmatically. - Some bugfixes, including support for big-endian hosts and reporting the correct sense length. All of this is from Alan Stern. --- a/drivers/usb/gadget/file_storage.c Sun Jun 20 21:01:13 2004 +++ b/drivers/usb/gadget/file_storage.c Sun Jun 20 21:01:15 2004 @@ -1,7 +1,7 @@ /* * file_storage.c -- File-backed USB Storage Gadget, for USB development * - * Copyright (C) 2003 Alan Stern + * Copyright (C) 2003, 2004 Alan Stern * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -229,12 +229,14 @@ #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 "14 January 2004" +#define DRIVER_VERSION "05 June 2004" static const char longname[] = DRIVER_DESC; static const char shortname[] = DRIVER_NAME; @@ -251,165 +253,11 @@ #define DRIVER_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget -/*-------------------------------------------------------------------------*/ - -/* - * Hardware-specific configuration, controlled by which device - * controller driver was configured. - * - * CHIP ... hardware identifier - * DRIVER_VERSION_NUM ... alerts the host side driver to differences - * EP_*_NAME ... which endpoints do we use for which purpose? - * EP_*_NUM ... numbers for them (often limited by hardware) - * FS_BULK_IN_MAXPACKET ... maxpacket value for full-speed bulk-in ep - * FS_BULK_OUT_MAXPACKET ... maxpacket value for full-speed bulk-out ep - * HIGHSPEED ... define if ep0 and descriptors need high speed support - * MAX_USB_POWER ... define if we use other than 100 mA bus current - * SELFPOWER ... if we can run on bus power, zero - * NO_BULK_STALL ... bulk endpoint halts don't work well so avoid them - */ - - -/* - * NetChip 2280, PCI based. - * - * This has half a dozen configurable endpoints, four with dedicated - * DMA channels to manage their FIFOs. It supports high speed. - * Those endpoints can be arranged in any desired configuration. - */ -#ifdef CONFIG_USB_GADGET_NET2280 -#define CHIP "net2280" -#define DRIVER_VERSION_NUM 0x0211 -static const char EP_BULK_IN_NAME[] = "ep-a"; -#define EP_BULK_IN_NUM 1 -#define FS_BULK_IN_MAXPACKET 64 -static const char EP_BULK_OUT_NAME[] = "ep-b"; -#define EP_BULK_OUT_NUM 2 -#define FS_BULK_OUT_MAXPACKET 64 -static const char EP_INTR_IN_NAME[] = "ep-e"; -#define EP_INTR_IN_NUM 5 -#define HIGHSPEED -#endif - - -/* - * Dummy_hcd, software-based loopback controller. - * - * This imitates the abilities of the NetChip 2280, so we will use - * the same configuration. - */ -#ifdef CONFIG_USB_GADGET_DUMMY -#define CHIP "dummy" -#define DRIVER_VERSION_NUM 0x0212 -static const char EP_BULK_IN_NAME[] = "ep-a"; -#define EP_BULK_IN_NUM 1 -#define FS_BULK_IN_MAXPACKET 64 -static const char EP_BULK_OUT_NAME[] = "ep-b"; -#define EP_BULK_OUT_NUM 2 -#define FS_BULK_OUT_MAXPACKET 64 -static const char EP_INTR_IN_NAME[] = "ep-e"; -#define EP_INTR_IN_NUM 5 -#define HIGHSPEED -#endif - - -/* - * PXA-2xx UDC: widely used in second gen Linux-capable PDAs. - * - * This has fifteen fixed-function full speed endpoints, and it - * can support all USB transfer types. - * - * These supports three or four configurations, with fixed numbers. - * The hardware interprets SET_INTERFACE, net effect is that you - * can't use altsettings or reset the interfaces independently. - * So stick to a single interface. - */ -#ifdef CONFIG_USB_GADGET_PXA2XX -#define CHIP "pxa2xx" -#define DRIVER_VERSION_NUM 0x0213 -static const char EP_BULK_IN_NAME[] = "ep1in-bulk"; -#define EP_BULK_IN_NUM 1 -#define FS_BULK_IN_MAXPACKET 64 -static const char EP_BULK_OUT_NAME[] = "ep2out-bulk"; -#define EP_BULK_OUT_NUM 2 -#define FS_BULK_OUT_MAXPACKET 64 -static const char EP_INTR_IN_NAME[] = "ep6in-bulk"; -#define EP_INTR_IN_NUM 6 -#endif - - /* - * SuperH UDC: UDC built-in to some Renesas SH processors. - * - * This has three fixed-function full speed bulk/interrupt endpoints. - * - * Only one configuration and interface is supported (SET_CONFIGURATION - * and SET_INTERFACE are handled completely by the hardware). - */ -#ifdef CONFIG_USB_GADGET_SUPERH -#define CHIP "superh" -#define DRIVER_VERSION_NUM 0x0215 -static const char EP_BULK_IN_NAME[] = "ep2in-bulk"; -#define EP_BULK_IN_NUM 2 -#define FS_BULK_IN_MAXPACKET 64 -static const char EP_BULK_OUT_NAME[] = "ep1out-bulk"; -#define EP_BULK_OUT_NUM 1 -#define FS_BULK_OUT_MAXPACKET 64 -static const char EP_INTR_IN_NAME[] = "ep3in-bulk"; -#define EP_INTR_IN_NUM 3 -#define NO_BULK_STALL -#endif - - -/* - * Toshiba TC86C001 ("Goku-S") UDC - * - * This has three semi-configurable full speed bulk/interrupt endpoints. - */ -#ifdef CONFIG_USB_GADGET_GOKU -#define CHIP "goku" -#define DRIVER_VERSION_NUM 0x0216 -static const char EP_BULK_OUT_NAME [] = "ep1-bulk"; -#define EP_BULK_OUT_NUM 1 -#define FS_BULK_IN_MAXPACKET 64 -static const char EP_BULK_IN_NAME [] = "ep2-bulk"; -#define EP_BULK_IN_NUM 2 -#define FS_BULK_OUT_MAXPACKET 64 -static const char EP_INTR_IN_NAME [] = "ep3-bulk"; -#define EP_INTR_IN_NUM 3 -#endif - - -/*-------------------------------------------------------------------------*/ - -#ifndef CHIP -# error Configure some USB peripheral controller driver! -#endif - -/* Power usage is config specific. - * Hardware that supports remote wakeup defaults to disabling it. + * 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. */ -#ifndef SELFPOWER -/* default: say we're self-powered */ -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER -/* else: - * - SELFPOWER value must be zero - * - MAX_USB_POWER may be nonzero. - */ -#endif - -#ifndef MAX_USB_POWER -/* Any hub supports this steady state bus power consumption */ -#define MAX_USB_POWER 100 /* mA */ -#endif - -/* We don't support remote wake-up */ - -#ifdef NO_BULK_STALL -#define CAN_STALL 0 -#else -#define CAN_STALL 1 -#endif /*-------------------------------------------------------------------------*/ @@ -478,14 +326,15 @@ static char *file[MAX_LUNS] = {NULL, }; static int ro[MAX_LUNS] = {0, }; static unsigned int luns = 0; + // Default values static char *transport = "BBB"; static char *protocol = "SCSI"; static int removable = 0; static unsigned short vendor = DRIVER_VENDOR_ID; static unsigned short product = DRIVER_PRODUCT_ID; -static unsigned short release = DRIVER_VERSION_NUM; +static unsigned short release = 0xffff; // Use controller chip type static unsigned int buflen = 16384; -static int stall = CAN_STALL; +static int stall = 1; static struct { unsigned int nluns; @@ -990,7 +839,7 @@ /* The next three values can be overridden by module parameters */ .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_ID), .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_ID), - .bcdDevice = __constant_cpu_to_le16(DRIVER_VERSION_NUM), + .bcdDevice = __constant_cpu_to_le16(0xffff), .iManufacturer = STRING_MANUFACTURER, .iProduct = STRING_PRODUCT, @@ -1003,11 +852,11 @@ .bLength = sizeof config_desc, .bDescriptorType = USB_DT_CONFIG, - /* wTotalLength adjusted during bind() */ + /* wTotalLength computed by usb_gadget_config_buf() */ .bNumInterfaces = 1, .bConfigurationValue = CONFIG_VALUE, - .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER, - .bMaxPower = (MAX_USB_POWER + 1) / 2, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, // self-powered }; /* There is only one interface. */ @@ -1017,47 +866,56 @@ .bLength = sizeof intf_desc, .bDescriptorType = USB_DT_INTERFACE, - .bNumEndpoints = 2, // Adjusted during bind() + .bNumEndpoints = 2, // Adjusted during fsg_bind() .bInterfaceClass = USB_CLASS_MASS_STORAGE, - .bInterfaceSubClass = USB_SC_SCSI, // Adjusted during bind() - .bInterfaceProtocol = USB_PR_BULK, // Adjusted during bind() + .bInterfaceSubClass = USB_SC_SCSI, // Adjusted during fsg_bind() + .bInterfaceProtocol = USB_PR_BULK, // Adjusted during fsg_bind() }; /* Three full-speed endpoint descriptors: bulk-in, bulk-out, * and interrupt-in. */ -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor fs_bulk_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_BULK_IN_NUM | USB_DIR_IN, + .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(FS_BULK_IN_MAXPACKET), + /* wMaxPacketSize set by autoconfiguration */ }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor fs_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_BULK_OUT_NUM, + .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(FS_BULK_OUT_MAXPACKET), + /* wMaxPacketSize set by autoconfiguration */ }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor fs_intr_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_INTR_IN_NUM | USB_DIR_IN, + .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = __constant_cpu_to_le16(2), .bInterval = 32, // frames -> 32 ms }; -#ifdef HIGHSPEED +static const struct usb_descriptor_header *fs_function[] = { + (struct usb_descriptor_header *) &intf_desc, + (struct usb_descriptor_header *) &fs_bulk_in_desc, + (struct usb_descriptor_header *) &fs_bulk_out_desc, + (struct usb_descriptor_header *) &fs_intr_in_desc, + NULL, +}; + + +#ifdef CONFIG_USB_GADGET_DUALSPEED /* * USB 2.0 devices need to expose both high speed and full speed @@ -1067,47 +925,55 @@ * and a "device qualifier" ... plus more construction options * for the config descriptor. */ -static const struct usb_endpoint_descriptor +static struct usb_qualifier_descriptor +dev_qualifier = { + .bLength = sizeof dev_qualifier, + .bDescriptorType = USB_DT_DEVICE_QUALIFIER, + + .bcdUSB = __constant_cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_PER_INTERFACE, + + .bNumConfigurations = 1, +}; + +static struct usb_endpoint_descriptor hs_bulk_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_BULK_IN_NUM | USB_DIR_IN, + /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16(512), }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor hs_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_BULK_OUT_NUM, + /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16(512), .bInterval = 1, // NAK every 1 uframe }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor hs_intr_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_INTR_IN_NUM | USB_DIR_IN, + /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = __constant_cpu_to_le16(2), .bInterval = 9, // 2**(9-1) = 256 uframes -> 32 ms }; -static struct usb_qualifier_descriptor -dev_qualifier = { - .bLength = sizeof dev_qualifier, - .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - - .bcdUSB = __constant_cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_PER_INTERFACE, - - .bNumConfigurations = 1, +static const struct usb_descriptor_header *hs_function[] = { + (struct usb_descriptor_header *) &intf_desc, + (struct usb_descriptor_header *) &hs_bulk_in_desc, + (struct usb_descriptor_header *) &hs_bulk_out_desc, + (struct usb_descriptor_header *) &hs_intr_in_desc, + NULL, }; /* Maxpacket and other transfer characteristics vary by speed. */ @@ -1115,22 +981,23 @@ #else -/* If there's no high speed support, maxpacket doesn't change. */ +/* If there's no high speed support, always use the full-speed descriptor. */ #define ep_desc(g,fs,hs) fs -#endif /* !HIGHSPEED */ +#endif /* !CONFIG_USB_GADGET_DUALSPEED */ /* The CBI specification limits the serial string to 12 uppercase hexadecimal * characters. */ +static char manufacturer[40]; static char serial[13]; -/* Static strings, in ISO 8859/1 */ +/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ static struct usb_string strings[] = { - { STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE " with " CHIP, }, - { STRING_PRODUCT, longname, }, - { STRING_SERIAL, serial, }, - { } // end of list + {STRING_MANUFACTURER, manufacturer}, + {STRING_PRODUCT, longname}, + {STRING_SERIAL, serial}, + {} }; static struct usb_gadget_strings stringtab = { @@ -1140,61 +1007,33 @@ /* - * Config descriptors are handcrafted. They 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. + * 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(enum usb_device_speed speed, - u8 *buf0, u8 type, unsigned index) + u8 *buf, u8 type, unsigned index) { - u8 *buf = buf0; -#ifdef HIGHSPEED - int hs; -#endif + int len; + const struct usb_descriptor_header **function; if (index > 0) return -EINVAL; - if (config_desc.wTotalLength > EP0_BUFSIZE) - return -EDOM; - /* Config (or other speed config) */ - memcpy(buf, &config_desc, USB_DT_CONFIG_SIZE); - buf[1] = type; - buf += USB_DT_CONFIG_SIZE; - - /* Interface */ - memcpy(buf, &intf_desc, USB_DT_INTERFACE_SIZE); - buf += USB_DT_INTERFACE_SIZE; - - /* The endpoints in the interface (at that speed) */ -#ifdef HIGHSPEED - hs = (speed == USB_SPEED_HIGH); +#ifdef CONFIG_USB_GADGET_DUALSPEED if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; - if (hs) { - memcpy(buf, &hs_bulk_in_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy(buf, &hs_bulk_out_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - if (transport_is_cbi()) { - memcpy(buf, &hs_intr_in_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } - } else + speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; + if (speed == USB_SPEED_HIGH) + function = hs_function; + else #endif - { - memcpy(buf, &fs_bulk_in_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy(buf, &fs_bulk_out_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - if (transport_is_cbi()) { - memcpy(buf, &fs_intr_in_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } - } + function = fs_function; - return buf - buf0; + len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); + if (len < 0) + return len; + ((struct usb_config_descriptor *) buf)->bDescriptorType = type; + return len; } @@ -1493,22 +1332,26 @@ value = min(ctrl->wLength, (u16) sizeof device_desc); memcpy(req->buf, &device_desc, value); break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: VDBG(fsg, "get device qualifier\n"); + if (!fsg->gadget->is_dualspeed) + break; value = min(ctrl->wLength, (u16) 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 (!fsg->gadget->is_dualspeed) + break; goto get_config; -#endif /* HIGHSPEED */ +#endif case USB_DT_CONFIG: VDBG(fsg, "get configuration descriptor\n"); -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED get_config: -#endif /* HIGHSPEED */ +#endif value = populate_config_buf(fsg->gadget->speed, req->buf, ctrl->wValue >> 8, @@ -2148,7 +1991,7 @@ buf[4] = 31; // Additional length // No special options sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, product_id, - DRIVER_VERSION_NUM); + mod_data.release); return 36; } @@ -2196,7 +2039,7 @@ buf[0] = 0x80 | 0x70; // Valid, current error buf[2] = SK(sd); put_be32(&buf[3], sdinfo); // Sense information - buf[7] = 18 - 7; // Additional sense length + buf[7] = 18 - 8; // Additional sense length buf[12] = ASC(sd); buf[13] = ASCQ(sd); return 18; @@ -2643,7 +2486,7 @@ /* Store and send the Bulk-only CSW */ csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG); csw->Tag = fsg->tag; - csw->Residue = fsg->residue; + csw->Residue = cpu_to_le32(fsg->residue); csw->Status = status; bh->inreq->length = USB_BULK_CS_WRAP_LEN; @@ -3089,7 +2932,7 @@ fsg->data_dir = DATA_DIR_TO_HOST; else fsg->data_dir = DATA_DIR_FROM_HOST; - fsg->data_size = cbw->DataTransferLength; + fsg->data_size = le32_to_cpu(cbw->DataTransferLength); if (fsg->data_size == 0) fsg->data_dir = DATA_DIR_NONE; fsg->lun = cbw->Lun; @@ -3242,6 +3085,7 @@ if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0) goto reset; fsg->bulk_out_enabled = 1; + fsg->bulk_out_maxpacket = d->wMaxPacketSize; if (transport_is_cbi()) { d = ep_desc(fsg->gadget, &fs_intr_in_desc, &hs_intr_in_desc); @@ -3717,6 +3561,34 @@ mod_data.protocol_type = USB_SC_SCSI; mod_data.protocol_name = "Transparent SCSI"; + if (gadget_is_sh(fsg->gadget)) + mod_data.can_stall = 0; + + if (mod_data.release == 0xffff) { // Parameter wasn't set + if (gadget_is_net2280(fsg->gadget)) + mod_data.release = __constant_cpu_to_le16(0x0221); + else if (gadget_is_dummy(fsg->gadget)) + mod_data.release = __constant_cpu_to_le16(0x0222); + else if (gadget_is_pxa(fsg->gadget)) + mod_data.release = __constant_cpu_to_le16(0x0223); + else if (gadget_is_sh(fsg->gadget)) + mod_data.release = __constant_cpu_to_le16(0x0224); + + /* The sa1100 controller is not supported */ + + else if (gadget_is_goku(fsg->gadget)) + mod_data.release = __constant_cpu_to_le16(0x0226); + else if (gadget_is_mq11xx(fsg->gadget)) + mod_data.release = __constant_cpu_to_le16(0x0227); + else if (gadget_is_omap(fsg->gadget)) + mod_data.release = __constant_cpu_to_le16(0x0228); + else { + WARN(fsg, "controller '%s' not recognized\n", + fsg->gadget->name); + mod_data.release = __constant_cpu_to_le16(0x0299); + } + } + prot = simple_strtol(mod_data.protocol_parm, NULL, 0); #ifdef CONFIG_USB_FILE_STORAGE_TEST @@ -3729,7 +3601,7 @@ mod_data.transport_type = USB_PR_CBI; mod_data.transport_name = "Control-Bulk-Interrupt"; } else { - INFO(fsg, "invalid transport: %s\n", mod_data.transport_parm); + ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm); return -EINVAL; } @@ -3758,13 +3630,13 @@ mod_data.protocol_type = USB_SC_8070; mod_data.protocol_name = "8070i"; } else { - INFO(fsg, "invalid protocol: %s\n", mod_data.protocol_parm); + ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm); return -EINVAL; } mod_data.buflen &= PAGE_CACHE_MASK; if (mod_data.buflen <= 0) { - INFO(fsg, "invalid buflen\n"); + ERROR(fsg, "invalid buflen\n"); return -ETOOSMALL; } #endif /* CONFIG_USB_FILE_STORAGE_TEST */ @@ -3800,7 +3672,7 @@ } } if (i > MAX_LUNS) { - INFO(fsg, "invalid number of LUNs: %d\n", i); + ERROR(fsg, "invalid number of LUNs: %d\n", i); rc = -EINVAL; goto out; } @@ -3827,45 +3699,57 @@ if ((rc = open_backing_file(curlun, file[i])) != 0) goto out; } else if (!mod_data.removable) { - INFO(fsg, "no file given for LUN%d\n", i); + 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, &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, &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, &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.bMaxPacketSize0 = fsg->ep0->maxpacket; -#ifdef HIGHSPEED - dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; // ??? -#endif 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 - config_desc.wTotalLength = USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE - + USB_DT_ENDPOINT_SIZE * i; intf_desc.bNumEndpoints = i; intf_desc.bInterfaceSubClass = mod_data.protocol_type; intf_desc.bInterfaceProtocol = mod_data.transport_type; + fs_function[i+1] = NULL; - /* Find all the endpoints we will use */ - gadget_for_each_ep(ep, gadget) { - if (strcmp(ep->name, EP_BULK_IN_NAME) == 0) - fsg->bulk_in = ep; - else if (strcmp(ep->name, EP_BULK_OUT_NAME) == 0) - fsg->bulk_out = ep; - else if (strcmp(ep->name, EP_INTR_IN_NAME) == 0) - fsg->intr_in = ep; - } - if (!fsg->bulk_in || !fsg->bulk_out || - (transport_is_cbi() && !fsg->intr_in)) { - DBG(fsg, "unable to find all endpoints\n"); - rc = -ENOTSUPP; - goto out; - } - fsg->bulk_out_maxpacket = (gadget->speed == USB_SPEED_HIGH ? 512 : - FS_BULK_OUT_MAXPACKET); +#ifdef CONFIG_USB_GADGET_DUALSPEED + hs_function[i+1] = NULL; + + /* Assume ep0 uses the same maxpacket value for both speeds */ + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; + + /* Assume that all endpoint addresses are the same for both speeds */ + hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress; + hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress; + hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress; +#endif rc = -ENOMEM; @@ -3894,6 +3778,10 @@ /* This should reflect the actual gadget power source */ usb_gadget_set_selfpowered(gadget); + snprintf(manufacturer, sizeof manufacturer, + UTS_SYSNAME " " UTS_RELEASE " with %s", + gadget->name); + /* On a real device, serial[] would be loaded from permanent * storage. We just encode it from the driver version string. */ for (i = 0; i < sizeof(serial) - 2; i += 2) { @@ -3942,6 +3830,10 @@ DBG(fsg, "I/O thread pid: %d\n", fsg->thread_pid); 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); @@ -3953,7 +3845,7 @@ /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver fsg_driver = { -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, #else .speed = USB_SPEED_FULL,