ChangeSet 1.1929, 2004/04/22 13:32:24-07:00, colin@colino.net [PATCH] USB: fix cdc-acm as it is still (differently) broken drivers/usb/class/cdc-acm.c | 83 ++++++++++++++++++++++++-------------------- 1 files changed, 47 insertions(+), 36 deletions(-) diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c --- a/drivers/usb/class/cdc-acm.c Thu Apr 22 14:41:35 2004 +++ b/drivers/usb/class/cdc-acm.c Thu Apr 22 14:41:35 2004 @@ -581,45 +581,51 @@ dev = interface_to_usbdev (intf); - cfacm = dev->actconfig; - - for (j = 0; j < cfacm->desc.bNumInterfaces - 1; j++) { - - if (usb_interface_claimed(cfacm->interface[j]) || - usb_interface_claimed(cfacm->interface[j + 1])) - continue; + cfacm = dev->actconfig; + + /* We know we're probe()d with the control interface. */ + ifcom = intf->cur_altsetting; - /* We know we're probe()d with the control interface. - * FIXME ACM doesn't guarantee the data interface is + /* ACM doesn't guarantee the data interface is * adjacent to the control interface, or that if one - * is there it's not for call management ... so use - * the cdc union descriptor whenever there is one. + * is there it's not for call management ... so find + * it */ - ifcom = intf->cur_altsetting; - if (intf == cfacm->interface[j]) { - ifdata = cfacm->interface[j + 1]->cur_altsetting; - data = cfacm->interface[j + 1]; - } else if (intf == cfacm->interface[j + 1]) { + for (j = 0; j < cfacm->desc.bNumInterfaces; j++) { ifdata = cfacm->interface[j]->cur_altsetting; data = cfacm->interface[j]; - } else - continue; - if (ifdata->desc.bInterfaceClass != 10 || ifdata->desc.bNumEndpoints < 2) - continue; + if (ifdata->desc.bInterfaceClass == 10 && + ifdata->desc.bNumEndpoints == 2) { + epctrl = &ifcom->endpoint[0].desc; + epread = &ifdata->endpoint[0].desc; + epwrite = &ifdata->endpoint[1].desc; + + if ((epctrl->bEndpointAddress & 0x80) != 0x80 || + (epctrl->bmAttributes & 3) != 3 || + (epread->bmAttributes & 3) != 2 || + (epwrite->bmAttributes & 3) != 2 || + ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80) + goto next_interface; + + if ((epread->bEndpointAddress & 0x80) != 0x80) { + epread = &ifdata->endpoint[1].desc; + epwrite = &ifdata->endpoint[0].desc; + } + dbg("found data interface at %d\n", j); + break; + } else { +next_interface: + ifdata = NULL; + data = NULL; + } + } + + /* there's been a problem */ + if (!ifdata) { + dbg("interface not found (%p)\n", ifdata); + return -ENODEV; - epctrl = &ifcom->endpoint[0].desc; - epread = &ifdata->endpoint[0].desc; - epwrite = &ifdata->endpoint[1].desc; - - if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 || - (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 || - ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80) - continue; - - if ((epread->bEndpointAddress & 0x80) != 0x80) { - epread = &ifdata->endpoint[1].desc; - epwrite = &ifdata->endpoint[0].desc; } for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); @@ -696,16 +702,21 @@ acm->line.databits = 8; acm_set_line(acm, &acm->line); - usb_driver_claim_interface(&acm_driver, data, acm); + if ( (j = usb_driver_claim_interface(&acm_driver, data, acm)) != 0) { + err("claim failed"); + usb_free_urb(acm->ctrlurb); + usb_free_urb(acm->readurb); + usb_free_urb(acm->writeurb); + kfree(acm); + kfree(buf); + return j; + } tty_register_device(acm_tty_driver, minor, &intf->dev); acm_table[minor] = acm; usb_set_intfdata (intf, acm); return 0; - } - - return -EIO; } static void acm_disconnect(struct usb_interface *intf)