Hello.

This patch fixes #260.

The main idea is to provide the same usb device config twice. One with
500mA MaxPower and one with 100mA. This allows charging the battery
faster on a powered hub or host and have it also available on bus
powered hubs for example debug board v2.

Normally g_ether provides one config with cdc_ether only and a second
one if RNDIS is enabled. With this patch it provides 2 or 4 configs.

In cdc_ether only mode all works fine. On host the high power config
is choosen and on debug board the low power config.

Enabling RNDIS makes it a bit more tricky. A special order of the
configs is needed:

rndis_config
eth_config
eth_config_low
rndis_config_low

Anybody know offhand why this is needed?

With this order I'm able to connect to the Neo1973 directly connected
to my host or through the debug board.

On the debug board rejecting of the two 500mA configs works fine:
usb 2-1.3: rejected 2 configurations due to insufficient available bus power

The one remaining problem is that the RNDIS, windows compatible,
support is untested. It seems I have to search such a box to test it.
:(

At the moment this patch applies on top of the current quilt set. I
would suggest to remove g_ether-highpower.patch and let this one base
on the vanilla g_ether driver once we like to apply this one. If you
agree I can take care off it.

regards
Stefan Schmidt
Index: linux-2.6.20.2/drivers/usb/gadget/ether.c
===================================================================
--- linux-2.6.20.2.orig/drivers/usb/gadget/ether.c	2007-03-29 22:40:21.000000000 +0200
+++ linux-2.6.20.2/drivers/usb/gadget/ether.c	2007-03-30 00:06:24.000000000 +0200
@@ -133,7 +133,7 @@
 	u16			cdc_filter;
 	unsigned long		todo;
 #define	WORK_RX_MEMORY		0
-	int			rndis_config;
+	int			rndis_config, rndis_config_low;
 	u8			host_mac [ETH_ALEN];
 };
 
@@ -416,13 +416,13 @@
  *
  * NOTE:  Controllers like superh_udc should probably be able to use
  * an RNDIS-only configuration.
- *
- * FIXME define some higher-powered configurations to make it easier
- * to recharge batteries ...
  */
 
 #define DEV_CONFIG_VALUE	1	/* cdc or subset */
 #define DEV_RNDIS_CONFIG_VALUE	2	/* rndis; optional */
+#define DEV_CONFIG_VALUE_LOW	3	/* cdc or subset; low power */
+#define DEV_RNDIS_CONFIG_VALUE_LOW	4	/* rndis; optional; low power */
+
 
 static struct usb_device_descriptor
 device_desc = {
@@ -439,7 +439,7 @@
 	.idProduct =		__constant_cpu_to_le16 (CDC_PRODUCT_NUM),
 	.iManufacturer =	STRING_MANUFACTURER,
 	.iProduct =		STRING_PRODUCT,
-	.bNumConfigurations =	1,
+	.bNumConfigurations =	2,
 };
 
 static struct usb_otg_descriptor
@@ -459,10 +459,23 @@
 	.bNumInterfaces =	2,
 	.bConfigurationValue =	DEV_CONFIG_VALUE,
 	.iConfiguration =	STRING_CDC,
-	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+	.bmAttributes =		USB_CONFIG_ATT_ONE,
 	.bMaxPower =		250,
 };
 
+static struct usb_config_descriptor
+eth_config_low = {
+	.bLength =		sizeof eth_config_low,
+	.bDescriptorType =	USB_DT_CONFIG,
+
+	/* compute wTotalLength on the fly */
+	.bNumInterfaces =	2,
+	.bConfigurationValue = DEV_CONFIG_VALUE_LOW,
+	.iConfiguration =	STRING_CDC,
+	.bmAttributes =		USB_CONFIG_ATT_ONE,
+	.bMaxPower =		50,
+};
+
 #ifdef	CONFIG_USB_ETH_RNDIS
 static struct usb_config_descriptor
 rndis_config = {
@@ -473,9 +486,22 @@
 	.bNumInterfaces =       2,
 	.bConfigurationValue =  DEV_RNDIS_CONFIG_VALUE,
 	.iConfiguration =       STRING_RNDIS,
-	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+	.bmAttributes =		USB_CONFIG_ATT_ONE,
 	.bMaxPower =            250,
 };
+
+static struct usb_config_descriptor
+rndis_config_low = {
+	.bLength =              sizeof rndis_config_low,
+	.bDescriptorType =      USB_DT_CONFIG,
+
+	/* compute wTotalLength on the fly */
+	.bNumInterfaces =       2,
+	.bConfigurationValue =  DEV_RNDIS_CONFIG_VALUE_LOW,
+	.iConfiguration =       STRING_RNDIS,
+	.bmAttributes =		USB_CONFIG_ATT_ONE,
+	.bMaxPower =            50,
+};
 #endif
 
 /*
@@ -800,7 +826,7 @@
 	.bcdUSB =		__constant_cpu_to_le16 (0x0200),
 	.bDeviceClass =		USB_CLASS_COMM,
 
-	.bNumConfigurations =	1,
+	.bNumConfigurations =	2,
 };
 
 static const struct usb_descriptor_header *hs_eth_function [11] = {
@@ -935,14 +961,23 @@
 	/* list the RNDIS config first, to make Microsoft's drivers
 	 * happy. DOCSIS 1.0 needs this too.
 	 */
-	if (device_desc.bNumConfigurations == 2 && index == 0) {
+	if (device_desc.bNumConfigurations == 4 && index == 0) {
 		config = &rndis_config;
 		function = which_fn (rndis);
-	} else
+	} if (device_desc.bNumConfigurations == 4 && index == 3) {
+		config = &rndis_config_low;
+		function = which_fn (rndis);
+	}
 #endif
-	{
+	/* Index of the cdc_ether configs is important */
+	if ((device_desc.bNumConfigurations == 4 && index == 1) ||
+		(device_desc.bNumConfigurations == 2 && index == 0)) {
 		config = &eth_config;
 		function = which_fn (eth);
+	} if ((device_desc.bNumConfigurations == 4 && index == 2) ||
+		(device_desc.bNumConfigurations == 2 && index == 1)) {
+		config = &eth_config_low;
+		function = which_fn (eth);
 	}
 
 	/* for now, don't advertise srp-only devices */
@@ -1120,10 +1155,12 @@
 
 	switch (number) {
 	case DEV_CONFIG_VALUE:
+	case DEV_CONFIG_VALUE_LOW:
 		result = set_ether_config (dev, gfp_flags);
 		break;
 #ifdef	CONFIG_USB_ETH_RNDIS
 	case DEV_RNDIS_CONFIG_VALUE:
+	case DEV_RNDIS_CONFIG_VALUE_LOW:
 		dev->rndis = 1;
 		result = set_ether_config (dev, gfp_flags);
 		break;
@@ -2151,6 +2188,7 @@
 
 	DEBUG (dev, "unbind\n");
 	rndis_deregister (dev->rndis_config);
+	rndis_deregister (dev->rndis_config_low);
 	rndis_exit ();
 
 	/* we've already been disconnected ... no i/o is active */
@@ -2349,6 +2387,8 @@
 	if (!cdc) {
 		eth_config.bNumInterfaces = 1;
 		eth_config.iConfiguration = STRING_SUBSET;
+		eth_config_low.bNumInterfaces = 1;
+		eth_config_low.iConfiguration = STRING_SUBSET;
 		fs_subset_descriptors();
 		hs_subset_descriptors();
 	}
@@ -2356,13 +2396,13 @@
 	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 	usb_gadget_set_selfpowered (gadget);
 
-	/* For now RNDIS is always a second config */
+	/* For now RNDIS is always a second set of configs */
 	if (rndis)
-		device_desc.bNumConfigurations = 2;
+		device_desc.bNumConfigurations = 4;
 
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
 	if (rndis)
-		dev_qualifier.bNumConfigurations = 2;
+		dev_qualifier.bNumConfigurations = 4;
 	else if (!cdc)
 		dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
 
@@ -2383,9 +2423,13 @@
 		otg_descriptor.bmAttributes |= USB_OTG_HNP,
 		eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		eth_config.bMaxPower = 4;
+		eth_config_low.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+		eth_config_low.bMaxPower = 4;
 #ifdef	CONFIG_USB_ETH_RNDIS
 		rndis_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		rndis_config.bMaxPower = 4;
+		rndis_config_low.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+		rndis_config_low.bMaxPower = 4;
 #endif
 	}
 

Attachment: signature.asc
Description: Digital signature

Reply via email to