patch-2.4.27 linux-2.4.27/drivers/usb/gadget/file_storage.c

Next file: linux-2.4.27/drivers/usb/gadget/gadget_chips.h
Previous file: linux-2.4.27/drivers/usb/gadget/ether.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.26/drivers/usb/gadget/file_storage.c linux-2.4.27/drivers/usb/gadget/file_storage.c
@@ -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,

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)