Hi,

I am looking for testers with a CDC ACM device willing to test this patch
which makes device detection follow the standard.

        TIA
                Oliver

diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
--- a/drivers/usb/class/cdc-acm.c       Fri May 28 10:48:56 2004
+++ b/drivers/usb/class/cdc-acm.c       Fri May 28 10:48:56 2004
@@ -60,6 +60,8 @@
 #include <linux/usb.h>
 #include <asm/byteorder.h>
 
+#include "cdc.h"
+
 /*
  * Version Information
  */
@@ -572,70 +574,84 @@
 static int acm_probe (struct usb_interface *intf,
                      const struct usb_device_id *id)
 {
-       struct usb_device *dev;
+       struct union_desc *union_header = NULL;
+       u8 *buffer = intf->altsetting->extra;
+       int buflen = intf->altsetting->extralen;
+       struct usb_interface *control_interface;
+       struct usb_interface *data_interface;
+       struct usb_host_interface *ifcom = intf->cur_altsetting;
+       struct usb_host_interface *ifdata = NULL;
+       struct usb_device *usb_dev;
+
        struct acm *acm;
-       struct usb_host_config *cfacm;
-       struct usb_interface *data = NULL;
-       struct usb_host_interface *ifcom, *ifdata = NULL;
+
        struct usb_endpoint_descriptor *epctrl = NULL;
        struct usb_endpoint_descriptor *epread = NULL;
        struct usb_endpoint_descriptor *epwrite = NULL;
-       int readsize, ctrlsize, minor, j;
+
+       int minor;
+       int ctrlsize,readsize,j;
        unsigned char *buf;
 
-       dev = interface_to_usbdev (intf);
+       usb_dev = interface_to_usbdev(intf);
 
-       cfacm = dev->actconfig;
+       if (!buffer) {
+               err("Wierd descriptor references");
+               return -EINVAL;
+       }
 
-       /* We know we're probe()d with the control interface. */
-       ifcom = intf->cur_altsetting;
+       while (buflen > 0) {
+               if (buffer [1] != USB_DT_CS_INTERFACE) {
+                       err("skipping garbage");
+                       goto next_desc;
+               }
+               switch (buffer [2]) {
+                       case CDC_UNION_TYPE: /* we've found it */
+                               if (union_header) {
+                                       err("More than one union descriptor, skipping 
...");
+                                       goto next_desc;
+                               }
+                               union_header = (struct union_desc *)buffer;
+                               break;
+                       default:
+                               err("Ignoring extra header");
+                               break;
+                       }
+next_desc:
+               buflen -= buffer[0];
+               buffer += buffer[0];
+       }
+
+       if (!union_header) {
+               err("No union descriptor, giving up");
+               return -ENODEV;
+       }
 
-       /* 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 find
-        * it
-        */
-       for (j = 0; j < cfacm->desc.bNumInterfaces; j++) {
-               ifdata = cfacm->interface[j]->cur_altsetting;
-               data = cfacm->interface[j];
+       control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
+       data_interface = usb_ifnum_to_if(usb_dev, union_header->bSlaveInterface0);
+       if (!control_interface || !data_interface) {
+               err("No interfaces");
+               return -ENODEV;
+       }
 
-               if (ifdata->desc.bInterfaceClass == USB_CLASS_CDC_DATA
-                   && ifdata->desc.bNumEndpoints == 2) {
+       /* workaround for buggy devices */
+       if (data_interface->cur_altsetting->desc.bInterfaceClass != 
CDC_DATA_INTERFACE_TYPE) {
+               if (control_interface->cur_altsetting->desc.bInterfaceClass == 
CDC_DATA_INTERFACE_TYPE) {
+                       struct usb_interface *t;
                        
-                       epctrl = &ifcom->endpoint[0].desc;
-                       epread = &ifdata->endpoint[0].desc;
-                       epwrite = &ifdata->endpoint[1].desc;
-
-                       if ((epctrl->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN
-                           || !CHECK_XFERTYPE(epctrl,  USB_ENDPOINT_XFER_INT)
-                           || !CHECK_XFERTYPE(epread,  USB_ENDPOINT_XFER_BULK)
-                           || !CHECK_XFERTYPE(epwrite, USB_ENDPOINT_XFER_BULK)
-                           || ((epread->bEndpointAddress & USB_DIR_IN)
-                               ^ (epwrite->bEndpointAddress & USB_DIR_IN)) != 
USB_DIR_IN) {
-                               /* not suitable */
-                               goto next_interface;
-                       }
-                       
-                       if ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) {
-                               /* descriptors are swapped */
-                               epread = &ifdata->endpoint[1].desc;
-                               epwrite = &ifdata->endpoint[0].desc;
-                       }
-                       dev_dbg(&intf->dev, "found data interface at %d\n", j);
-                       break;
-               } else {
-next_interface:
-                       ifdata = NULL;
-                       data = NULL;
+                       dev_dbg(&intf->dev, "Unswitching descriptors.");
+                       t = control_interface;
+                       control_interface = data_interface;
+                       data_interface = t;
                }
        }
+       
+       ifdata = data_interface->cur_altsetting;
 
-       /* there's been a problem */
-       if (!ifdata) {
-               dev_dbg(&intf->dev, "data interface not found\n");
-               return -ENODEV;
+       epctrl = &ifcom->endpoint[0].desc;
+       epread = &ifcom->endpoint[0].desc;
+       epwrite = &ifdata->endpoint[1].desc;
 
-       }
 
        for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
        if (acm_table[minor]) {
@@ -653,10 +669,10 @@
        ctrlsize = epctrl->wMaxPacketSize;
        readsize = epread->wMaxPacketSize;
        acm->writesize = epwrite->wMaxPacketSize;
-       acm->control = intf;
-       acm->data = data;
+       acm->control = control_interface;
+       acm->data = data_interface;
        acm->minor = minor;
-       acm->dev = dev;
+       acm->dev = usb_dev;
 
        acm->bh.func = acm_rx_tasklet;
        acm->bh.data = (unsigned long) acm;
@@ -693,18 +709,18 @@
                return -ENOMEM;
        }
 
-       usb_fill_int_urb(acm->ctrlurb, dev, usb_rcvintpipe(dev, 
epctrl->bEndpointAddress),
+       usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, 
epctrl->bEndpointAddress),
                buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
 
-       usb_fill_bulk_urb(acm->readurb, dev, usb_rcvbulkpipe(dev, 
epread->bEndpointAddress),
+       usb_fill_bulk_urb(acm->readurb, usb_dev, usb_rcvbulkpipe(usb_dev, 
epread->bEndpointAddress),
                buf += ctrlsize, readsize, acm_read_bulk, acm);
        acm->readurb->transfer_flags |= URB_NO_FSBR;
 
-       usb_fill_bulk_urb(acm->writeurb, dev, usb_sndbulkpipe(dev, 
epwrite->bEndpointAddress),
+       usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, 
epwrite->bEndpointAddress),
                buf += readsize, acm->writesize, acm_write_bulk, acm);
        acm->writeurb->transfer_flags |= URB_NO_FSBR;
 
-       if ( (j = usb_driver_claim_interface(&acm_driver, data, acm)) != 0) {
+       if ( (j = usb_driver_claim_interface(&acm_driver, data_interface, acm)) != 0) {
                err("claim failed");
                usb_free_urb(acm->ctrlurb);
                usb_free_urb(acm->readurb);
diff -Nru a/drivers/usb/class/cdc.h b/drivers/usb/class/cdc.h
--- /dev/null   Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/class/cdc.h   Fri May 28 10:48:56 2004
@@ -0,0 +1,13 @@
+/* "Union Functional Descriptor" from CDC spec 5.2.3.X */
+struct union_desc {
+       u8      bLength;
+       u8      bDescriptorType;
+       u8      bDescriptorSubType;
+
+       u8      bMasterInterface0;
+       u8      bSlaveInterface0;
+       /* ... and there could be other slave interfaces */
+} __attribute__ ((packed));
+
+#define CDC_UNION_TYPE                 0x06
+#define CDC_DATA_INTERFACE_TYPE                0x0a


-------------------------------------------------------
This SF.Net email is sponsored by: Oracle 10g
Get certified on the hottest thing ever to hit the market... Oracle 10g. 
Take an Oracle 10g class now, and we'll give you the exam FREE.
http://ads.osdn.com/?ad_id=3149&alloc_id=8166&op=click
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to