ChangeSet 1.1276.1.53, 2003/08/27 17:31:58-07:00, [EMAIL PROTECTED]
[PATCH] USB: usbnet, cdc ethernet descriptor parsing fixes
This makes the new CDC Ethernet code handle more devices:
- Uses the active config, not just the default one, if it's
coping "descriptors in wrong place" quirk. (bugfix)
- Uses usb_ifnum_to_if() to get interfaces. (bugfix)
- AMBIT USB cable modems have bogus CDC Union descriptors;
workaround by switching master and slave. (add quirk)
- To make it easier the next time we run into firmware
that violates the class spec, add debug messages saying
exactly why it's giving up on a given CDC device.
Net result, this code now handles at least one more
cable modem design.
drivers/usb/net/usbnet.c | 89 +++++++++++++++++++++++++++++++++++------------
1 files changed, 68 insertions(+), 21 deletions(-)
diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
--- a/drivers/usb/net/usbnet.c Tue Sep 2 12:43:15 2003
+++ b/drivers/usb/net/usbnet.c Tue Sep 2 12:43:15 2003
@@ -773,12 +773,15 @@
/* expect strict spec conformance for the descriptors, but
* cope with firmware which stores them in the wrong place
*/
- if (len == 0 && dev->udev->config->extralen) {
- /* Motorola SB4100 (and maybe others) put
- * CDC descriptors here
+ if (len == 0 && dev->udev->actconfig->extralen) {
+ /* Motorola SB4100 (and others: Brad Hards says it's
+ * from a Broadcom design) put CDC descriptors here
*/
- buf = dev->udev->config->extra;
- len = dev->udev->config->extralen;
+ buf = dev->udev->actconfig->extra;
+ len = dev->udev->actconfig->extralen;
+ if (len)
+ dev_dbg (&intf->dev,
+ "CDC descriptors on config\n");
}
memset (info, 0, sizeof *info);
@@ -793,48 +796,92 @@
*/
switch (buf [2]) {
case 0x00: /* Header, mostly useless */
- if (info->header)
+ if (info->header) {
+ dev_dbg (&intf->dev, "extra CDC header\n");
goto bad_desc;
+ }
info->header = (void *) buf;
- if (info->header->bLength != sizeof *info->header)
+ if (info->header->bLength != sizeof *info->header) {
+ dev_dbg (&intf->dev, "CDC header len %u\n",
+ info->header->bLength);
goto bad_desc;
+ }
break;
case 0x06: /* Union (groups interfaces) */
- if (info->u)
+ if (info->u) {
+ dev_dbg (&intf->dev, "extra CDC union\n");
goto bad_desc;
+ }
info->u = (void *) buf;
- if (info->u->bLength != sizeof *info->u)
- goto bad_desc;
- d = &intf->altsetting->desc;
- if (info->u->bMasterInterface0 != d->bInterfaceNumber)
- goto bad_desc;
- info->data = dev->udev->actconfig->interface[0];
- if (intf != (info->data + info->u->bMasterInterface0))
+ if (info->u->bLength != sizeof *info->u) {
+ dev_dbg (&intf->dev, "CDC union len %u\n",
+ info->u->bLength);
goto bad_desc;
+ }
+
+ /* we need a master/control interface (what we're
+ * probed with) and a slave/data interface; union
+ * descriptors sort this all out.
+ */
+ info->control = usb_ifnum_to_if(dev->udev,
+ info->u->bMasterInterface0);
+ info->data = usb_ifnum_to_if(dev->udev,
+ info->u->bSlaveInterface0);
+ if (!info->control || !info->data) {
+ dev_dbg (&intf->dev,
+ "master #%u/%p slave #%u/%p\n",
+ info->u->bMasterInterface0
+ info->control,
+ info->u->bSlaveInterface0,
+ info->data);
+ goto bad_desc;
+ }
+ if (info->control != intf) {
+ dev_dbg (&intf->dev, "bogus CDC Union\n");
+ /* Ambit USB Cable Modem (and maybe others)
+ * interchanges master and slave interface.
+ */
+ if (info->data == intf) {
+ info->data = info->control;
+ info->control = intf;
+ } else
+ goto bad_desc;
+ }
/* a data interface altsetting does the real i/o */
- info->data += info->u->bSlaveInterface0;
d = &info->data->altsetting->desc;
- if (info->u->bSlaveInterface0 != d->bInterfaceNumber
- || d->bInterfaceClass != USB_CLASS_CDC_DATA)
+ if (d->bInterfaceClass != USB_CLASS_CDC_DATA) {
+ dev_dbg (&intf->dev, "slave class %u\n",
+ d->bInterfaceClass);
goto bad_desc;
+ }
if (usb_interface_claimed (info->data))
return -EBUSY;
break;
case 0x0F: /* Ethernet Networking */
- if (info->ether)
+ if (info->ether) {
+ dev_dbg (&intf->dev, "extra CDC ether\n");
goto bad_desc;
+ }
info->ether = (void *) buf;
- if (info->ether->bLength != sizeof *info->ether)
+ if (info->ether->bLength != sizeof *info->ether) {
+ dev_dbg (&intf->dev, "CDC ether len %u\n",
+ info->u->bLength);
goto bad_desc;
+ }
break;
}
next_desc:
len -= buf [0]; /* bLength */
buf += buf [0];
}
- if (!info->header || !info ->u || !info->ether)
+ if (!info->header || !info ->u || !info->ether) {
+ dev_dbg (&intf->dev, "missing cdc %s%s%sdescriptor\n",
+ info->header ? "" : "header ",
+ info->u ? "" : "union ",
+ info->ether ? "" : "ether ");
goto bad_desc;
+ }
#ifdef CONFIG_USB_ZAURUS
/* Zaurus ethernet addresses aren't unique ... */
-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel