---
 drivers/usb/gadget/epautoconf.c   |    9 +++++-
 drivers/usb/gadget/ether.c        |   51 +++++++++++++++++++++++++++++++++++---
 drivers/usb/gadget/file_storage.c |   11 +++++---
 drivers/usb/gadget/serial.c       |   18 +++++++++++--
 drivers/usb/gadget/zero.c         |   13 ++++++++-
 include/linux/usb/gadget.h        |   23 ++++++++++++++++-
 6 files changed, 110 insertions(+), 15 deletions(-)

Index: linux-2.6.23/drivers/usb/gadget/epautoconf.c
===================================================================
--- linux-2.6.23.orig/drivers/usb/gadget/epautoconf.c	2007-10-16 11:05:56.000000000 +0100
+++ linux-2.6.23/drivers/usb/gadget/epautoconf.c	2007-10-16 11:06:02.000000000 +0100
@@ -228,14 +228,19 @@ find_ep (struct usb_gadget *gadget, cons
  *
  * On failure, this returns a null endpoint descriptor.
  */
-struct usb_ep * __devinit usb_ep_autoconfig (
+struct usb_ep * usb_ep_autoconfig (
 	struct usb_gadget		*gadget,
-	struct usb_endpoint_descriptor	*desc
+	struct usb_endpoint_descriptor	*desc,
+	struct usb_endpoint_config *epconfig, int numconfigs
 )
 {
 	struct usb_ep	*ep;
 	u8		type;
 
+	/* Use device specific ep allocation code if provided */
+	if (gadget->ops->ep_alloc)
+		return gadget->ops->ep_alloc(gadget, desc, epconfig, numconfigs);
+
 	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
 
 	/* First, apply chip-specific "best usage" knowledge.
Index: linux-2.6.23/drivers/usb/gadget/ether.c
===================================================================
--- linux-2.6.23.orig/drivers/usb/gadget/ether.c	2007-10-16 11:05:56.000000000 +0100
+++ linux-2.6.23/drivers/usb/gadget/ether.c	2007-10-16 11:06:02.000000000 +0100
@@ -2265,7 +2265,8 @@ eth_bind (struct usb_gadget *gadget)
 	struct eth_dev		*dev;
 	struct net_device	*net;
 	u8			cdc = 1, zlp = 1, rndis = 1;
-	struct usb_ep		*in_ep, *out_ep, *status_ep = NULL;
+	struct usb_ep		*in_ep = NULL , *out_ep = NULL, *status_ep = NULL;
+	struct usb_endpoint_config ep_config[2];
 	int			status = -ENOMEM;
 	int			gcnum;
 
@@ -2364,7 +2365,26 @@ eth_bind (struct usb_gadget *gadget)
 
 	/* all we really need is bulk IN/OUT */
 	usb_ep_autoconfig_reset (gadget);
-	in_ep = usb_ep_autoconfig (gadget, &fs_source_desc);
+
+	ep_config[0].config = DEV_CONFIG_VALUE;
+#if 	defined(DEV_CONFIG_CDC)
+	ep_config[0].interface = data_intf.bInterfaceNumber;
+	ep_config[0].altinterface = data_intf.bAlternateSetting;
+#else 	/* DEV_CONFIG_SUBSET */
+	ep_config[0].interface = subset_data_intf.bInterfaceNumber;
+	ep_config[0].altinterface = subset_data_intf.bAlternateSetting;
+#endif
+
+#ifdef	CONFIG_USB_ETH_RNDIS
+	ep_config[1].config = DEV_RNDIS_CONFIG_VALUE;
+	ep_config[1].interface = rndis_data_intf.bInterfaceNumber;
+	ep_config[1].altinterface = rndis_data_intf.bAlternateSetting;
+
+	in_ep = usb_ep_autoconfig(gadget, &fs_source_desc, &ep_config[0], 2);
+#else
+	in_ep = usb_ep_autoconfig(gadget, &fs_source_desc, &ep_config[0], 1);
+#endif
+
 	if (!in_ep) {
 autoconf_fail:
 		dev_err (&gadget->dev,
@@ -2374,7 +2394,12 @@ autoconf_fail:
 	}
 	in_ep->driver_data = in_ep;	/* claim */
 
-	out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
+#ifdef CONFIG_USB_ETH_RNDIS
+	out_ep = usb_ep_autoconfig(gadget, &fs_sink_desc, &ep_config[0], 2);
+#else
+	out_ep = usb_ep_autoconfig(gadget, &fs_sink_desc, &ep_config[0], 1);
+#endif
+
 	if (!out_ep)
 		goto autoconf_fail;
 	out_ep->driver_data = out_ep;	/* claim */
@@ -2384,7 +2409,25 @@ autoconf_fail:
 	 * Since some hosts expect one, try to allocate one anyway.
 	 */
 	if (cdc || rndis) {
-		status_ep = usb_ep_autoconfig (gadget, &fs_status_desc);
+#ifdef DEV_CONFIG_CDC
+		ep_config[0].config = DEV_CONFIG_VALUE;
+		ep_config[0].interface = control_intf.bInterfaceNumber;
+		ep_config[0].altinterface = control_intf.bAlternateSetting;
+#endif
+#ifdef CONFIG_USB_ETH_RNDIS
+		ep_config[1].config = DEV_RNDIS_CONFIG_VALUE;
+		ep_config[1].interface = rndis_control_intf.bInterfaceNumber;
+		ep_config[1].altinterface = rndis_control_intf.bAlternateSetting;
+#endif
+
+#if defined(DEV_CONFIG_CDC) && defined(CONFIG_USB_ETH_RNDIS)
+		status_ep = usb_ep_autoconfig(gadget, &fs_status_desc, &ep_config[0], 2);
+#elif defined(CONFIG_USB_ETH_RNDIS)
+		status_ep = usb_ep_autoconfig(gadget, &fs_status_desc, &ep_config[1], 1);
+#else
+		status_ep = usb_ep_autoconfig(gadget, &fs_status_desc, &ep_config[0], 1);
+#endif
+
 		if (status_ep) {
 			status_ep->driver_data = status_ep;	/* claim */
 		} else if (rndis) {
Index: linux-2.6.23/drivers/usb/gadget/file_storage.c
===================================================================
--- linux-2.6.23.orig/drivers/usb/gadget/file_storage.c	2007-10-16 11:05:56.000000000 +0100
+++ linux-2.6.23/drivers/usb/gadget/file_storage.c	2007-10-16 11:06:02.000000000 +0100
@@ -3806,6 +3806,7 @@ static int __init fsg_bind(struct usb_ga
 	struct usb_ep		*ep;
 	struct usb_request	*req;
 	char			*pathbuf, *p;
+	struct usb_endpoint_config ep_config;
 
 	fsg->gadget = gadget;
 	set_gadget_data(gadget, fsg);
@@ -3876,21 +3877,25 @@ static int __init fsg_bind(struct usb_ga
 	}
 
 	/* Find all the endpoints we will use */
+	ep_config.config = CONFIG_VALUE;
+	ep_config.interface = intf_desc.bInterfaceNumber;
+	ep_config.altinterface = intf_desc.bAlternateSetting;
+
 	usb_ep_autoconfig_reset(gadget);
-	ep = usb_ep_autoconfig(gadget, &fs_bulk_in_desc);
+	ep = usb_ep_autoconfig(gadget, &fs_bulk_in_desc, &ep_config, 1);
 	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);
+	ep = usb_ep_autoconfig(gadget, &fs_bulk_out_desc, &ep_config, 1);
 	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);
+		ep = usb_ep_autoconfig(gadget, &fs_intr_in_desc, &ep_config, 1);
 		if (!ep)
 			goto autoconf_fail;
 		ep->driver_data = fsg;		// claim the endpoint
Index: linux-2.6.23/drivers/usb/gadget/serial.c
===================================================================
--- linux-2.6.23.orig/drivers/usb/gadget/serial.c	2007-10-16 11:05:56.000000000 +0100
+++ linux-2.6.23/drivers/usb/gadget/serial.c	2007-10-16 11:06:02.000000000 +0100
@@ -1338,6 +1338,7 @@ static int __init gs_bind(struct usb_gad
 	struct usb_ep *ep;
 	struct gs_dev *dev;
 	int gcnum;
+	struct usb_endpoint_config ep_config[2];
 
 	/* Some controllers can't support CDC ACM:
 	 * - sh doesn't support multiple interfaces or configs;
@@ -1358,22 +1359,33 @@ static int __init gs_bind(struct usb_gad
 			__constant_cpu_to_le16(GS_VERSION_NUM|0x0099);
 	}
 
+	ep_config[0].config = GS_BULK_CONFIG_ID;
+	ep_config[0].interface = gs_bulk_interface_desc.bInterfaceNumber;
+	ep_config[0].altinterface = gs_bulk_interface_desc.bAlternateSetting;
+	ep_config[1].config = GS_ACM_CONFIG_ID;
+	ep_config[1].interface = gs_data_interface_desc.bInterfaceNumber;
+	ep_config[1].altinterface = gs_data_interface_desc.bAlternateSetting;
+
 	usb_ep_autoconfig_reset(gadget);
 
-	ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc);
+	ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc, &ep_config[0], 2);
 	if (!ep)
 		goto autoconf_fail;
 	EP_IN_NAME = ep->name;
 	ep->driver_data = ep;	/* claim the endpoint */
 
-	ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc);
+	ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc, &ep_config[0], 2);
 	if (!ep)
 		goto autoconf_fail;
 	EP_OUT_NAME = ep->name;
 	ep->driver_data = ep;	/* claim the endpoint */
 
 	if (use_acm) {
-		ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc);
+		ep_config[0].config = GS_ACM_CONFIG_ID;
+		ep_config[0].interface = gs_control_interface_desc.bInterfaceNumber;
+		ep_config[0].altinterface = gs_control_interface_desc.bAlternateSetting;
+
+		ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc, &ep_config[0], 1);
 		if (!ep) {
 			printk(KERN_ERR "gs_bind: cannot run ACM on %s\n", gadget->name);
 			goto autoconf_fail;
Index: linux-2.6.23/drivers/usb/gadget/zero.c
===================================================================
--- linux-2.6.23.orig/drivers/usb/gadget/zero.c	2007-10-16 11:05:56.000000000 +0100
+++ linux-2.6.23/drivers/usb/gadget/zero.c	2007-10-16 11:08:41.000000000 +0100
@@ -1100,6 +1100,7 @@ zero_bind (struct usb_gadget *gadget)
 	struct zero_dev		*dev;
 	struct usb_ep		*ep;
 	int			gcnum;
+	struct usb_endpoint_config ep_config[2];
 
 	/* FIXME this can't yet work right with SH ... it has only
 	 * one configuration, numbered one.
@@ -1112,7 +1113,15 @@ zero_bind (struct usb_gadget *gadget)
 	 * but there may also be important quirks to address.
 	 */
 	usb_ep_autoconfig_reset (gadget);
-	ep = usb_ep_autoconfig (gadget, &fs_source_desc);
+
+	ep_config[0].config = CONFIG_SOURCE_SINK;
+	ep_config[0].interface = source_sink_intf.bInterfaceNumber;
+	ep_config[0].altinterface = source_sink_intf.bAlternateSetting;
+	ep_config[1].config = CONFIG_LOOPBACK;
+	ep_config[1].interface = loopback_intf.bInterfaceNumber;
+	ep_config[1].altinterface = loopback_intf.bAlternateSetting;
+
+	ep = usb_ep_autoconfig(gadget, &fs_source_desc, &ep_config[0], 2);
 	if (!ep) {
 autoconf_fail:
 		printk (KERN_ERR "%s: can't autoconfigure on %s\n",
@@ -1122,7 +1131,7 @@ autoconf_fail:
 	EP_IN_NAME = ep->name;
 	ep->driver_data = ep;	/* claim */
 
-	ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
+	ep = usb_ep_autoconfig(gadget, &fs_sink_desc, &ep_config[0], 2);
 	if (!ep)
 		goto autoconf_fail;
 	EP_OUT_NAME = ep->name;
Index: linux-2.6.23/include/linux/usb/gadget.h
===================================================================
--- linux-2.6.23.orig/include/linux/usb/gadget.h	2007-10-16 11:10:30.000000000 +0100
+++ linux-2.6.23/include/linux/usb/gadget.h	2007-10-16 11:11:48.000000000 +0100
@@ -397,10 +397,28 @@ usb_ep_fifo_flush (struct usb_ep *ep)
 
 struct usb_gadget;
 
+/**
+ * struct usb_endpoint_config - possible configurations of a given endpoint
+ * @config: the configuration number
+ * @interface: the interface number
+ * @altinterface: the altinterface number
+ *
+ * Used as an array to pass information about the possible configurations
+ * of a given endpoint to the bus controller.
+ */
+struct usb_endpoint_config {
+	u8	config;
+	u8	interface;
+	u8	altinterface;
+};
+
 /* the rest of the api to the controller hardware: device operations,
  * which don't involve endpoints (or i/o).
  */
 struct usb_gadget_ops {
+	struct usb_ep* (*ep_alloc)(struct usb_gadget *,
+				struct usb_endpoint_descriptor *,
+				struct usb_endpoint_config *, int);
 	int	(*get_frame)(struct usb_gadget *);
 	int	(*wakeup)(struct usb_gadget *);
 	int	(*set_selfpowered) (struct usb_gadget *, int is_selfpowered);
@@ -857,7 +875,10 @@ int usb_gadget_config_buf(const struct u
 /* utility wrapping a simple endpoint selection policy */
 
 extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *,
-			struct usb_endpoint_descriptor *) __devinit;
+			struct usb_endpoint_descriptor *,
+			struct usb_endpoint_config *,
+			int numconfigs
+) __devinit;
 
 extern void usb_ep_autoconfig_reset (struct usb_gadget *) __devinit;
 
