ChangeSet 1.1337.38.4, 2003/10/23 17:12:01-07:00, [EMAIL PROTECTED]

[PATCH] USB: ACM USB modem fixes

Please merge this patch.  I've had two success reports from it.
Putback comment can be:

  Fixes some long-standing cdc-acm bugs including:
  - Oopsing
  - Probe messages not so excessive
  - Makes /proc/bus/usb/devices show both interface claims
  - Now cdc_acm won't hotplug for Ethernet devices (or RNDIS)


 drivers/usb/class/cdc-acm.c |   82 +++++++++++++++++++++++---------------------
 1 files changed, 43 insertions(+), 39 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 Oct 23 23:04:31 2003
+++ b/drivers/usb/class/cdc-acm.c       Thu Oct 23 23:04:31 2003
@@ -1,5 +1,5 @@
 /*
- * acm.c  Version 0.21
+ * acm.c  Version 0.22
  *
  * Copyright (c) 1999 Armin Fuerst     <[EMAIL PROTECTED]>
  * Copyright (c) 1999 Pavel Machek     <[EMAIL PROTECTED]>
@@ -24,6 +24,8 @@
  *     v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan)
  *     v0.20 - switched to probing on interface (rather than device) class
  *     v0.21 - revert to probing on device for devices with multiple configs
+ *     v0.22 - probe only the control interface. if usbcore doesn't choose the
+ *             config we want, sysadmin changes bConfigurationValue in sysfs.
  */
 
 /*
@@ -139,7 +141,8 @@
 
 struct acm {
        struct usb_device *dev;                         /* the corresponding usb 
device */
-       struct usb_interface *iface;                    /* the interfaces - +0 control 
+1 data */
+       struct usb_interface *control;                  /* control interface */
+       struct usb_interface *data;                     /* data interface */
        struct tty_struct *tty;                         /* the corresponding tty */
        struct urb *ctrlurb, *readurb, *writeurb;       /* urbs */
        struct acm_line line;                           /* line coding (bits, stop, 
parity) */
@@ -167,12 +170,15 @@
 {
        int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
                request, USB_RT_ACM, value,
-               acm->iface[0].altsetting[0].desc.bInterfaceNumber,
+               acm->control->altsetting[0].desc.bInterfaceNumber,
                buf, len, HZ * 5);
        dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, 
value, len, retval);
        return retval < 0 ? retval : 0;
 }
 
+/* devices aren't required to support these requests.
+ * the cdc acm descriptor tells whether they do...
+ */
 #define acm_set_control(acm, control)  acm_ctrl_msg(acm, ACM_REQ_SET_CONTROL, 
control, NULL, 0)
 #define acm_set_line(acm, line)                acm_ctrl_msg(acm, ACM_REQ_SET_LINE, 0, 
line, sizeof(struct acm_line))
 #define acm_send_break(acm, ms)                acm_ctrl_msg(acm, ACM_REQ_SEND_BREAK, 
ms, NULL, 0)
@@ -211,7 +217,7 @@
 
                case ACM_IRQ_NETWORK:
 
-                       dbg("%s network", data[0] ? "connected to" : "disconnected 
from");
+                       dbg("%s network", dr->wValue ? "connected to" : "disconnected 
from");
                        break;
 
                case ACM_IRQ_LINE_STATE:
@@ -546,17 +552,15 @@
        struct usb_device *dev;
        struct acm *acm;
        struct usb_host_config *cfacm;
+       struct usb_interface *data;
        struct usb_host_interface *ifcom, *ifdata;
        struct usb_endpoint_descriptor *epctrl, *epread, *epwrite;
-       int readsize, ctrlsize, minor, i, j;
+       int readsize, ctrlsize, minor, j;
        unsigned char *buf;
 
        dev = interface_to_usbdev (intf);
-       for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
-
-               cfacm = dev->config + i;
 
-               dbg("probing config %d", cfacm->desc.bConfigurationValue);
+               cfacm = dev->actconfig;
 
                for (j = 0; j < cfacm->desc.bNumInterfaces - 1; j++) {
                    
@@ -564,19 +568,23 @@
                            usb_interface_claimed(cfacm->interface[j + 1]))
                        continue;
 
-                       ifcom = cfacm->interface[j]->altsetting + 0;
-                       ifdata = cfacm->interface[j + 1]->altsetting + 0;
-
-                       if (ifdata->desc.bInterfaceClass != 10 || 
ifdata->desc.bNumEndpoints < 2) {
-                               ifcom = cfacm->interface[j + 1]->altsetting + 0;
+                       /* We know we're probe()d with the control interface.
+                        * FIXME 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.
+                        */
+                       ifcom = intf->altsetting + 0;
+                       if (intf == cfacm->interface[j]) {
+                               ifdata = cfacm->interface[j + 1]->altsetting + 0;
+                               data = cfacm->interface[j + 1];
+                       } else if (intf == cfacm->interface[j + 1]) {
                                ifdata = cfacm->interface[j]->altsetting + 0;
-                               if (ifdata->desc.bInterfaceClass != 10 || 
ifdata->desc.bNumEndpoints < 2)
-                                       continue;
-                       }
+                               data = cfacm->interface[j];
+                       } else
+                               continue;
 
-                       if (ifcom->desc.bInterfaceClass != 2 || 
ifcom->desc.bInterfaceSubClass != 2 ||
-                           ifcom->desc.bInterfaceProtocol < 1 || 
ifcom->desc.bInterfaceProtocol > 6 ||
-                           ifcom->desc.bNumEndpoints < 1)
+                       if (ifdata->desc.bInterfaceClass != 10 || 
ifdata->desc.bNumEndpoints < 2)
                                continue;
 
                        epctrl = &ifcom->endpoint[0].desc;
@@ -593,15 +601,6 @@
                                epwrite = &ifdata->endpoint[0].desc;
                        }
 
-                       /* FIXME don't scan every config. it's either correct
-                        * when we probe(), or some other task must fix this.
-                        */
-                       if (dev->actconfig != cfacm) {
-                               err("need inactive config #%d",
-                                       cfacm->desc.bConfigurationValue);
-                               return -ENODEV;
-                       }
-
                        for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; 
minor++);
                        if (acm_table[minor]) {
                                err("no more free acm devices");
@@ -617,7 +616,8 @@
                        ctrlsize = epctrl->wMaxPacketSize;
                        readsize = epread->wMaxPacketSize;
                        acm->writesize = epwrite->wMaxPacketSize;
-                       acm->iface = cfacm->interface[j];
+                       acm->control = intf;
+                       acm->data = data;
                        acm->minor = minor;
                        acm->dev = dev;
 
@@ -665,7 +665,7 @@
                                buf += readsize, acm->writesize, acm_write_bulk, acm);
                        acm->writeurb->transfer_flags |= URB_NO_FSBR;
 
-                       info("ttyACM%d: USB ACM device", minor);
+                       dev_info(&intf->dev, "ttyACM%d: USB ACM device", minor);
 
                        acm_set_control(acm, acm->ctrlout);
 
@@ -673,8 +673,7 @@
                        acm->line.databits = 8;
                        acm_set_line(acm, &acm->line);
 
-                       usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
-                       usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
+                       usb_driver_claim_interface(&acm_driver, data, acm);
 
                        tty_register_device(acm_tty_driver, minor, &intf->dev);
 
@@ -682,7 +681,6 @@
                        usb_set_intfdata (intf, acm);
                        return 0;
                }
-       }
 
        return -EIO;
 }
@@ -705,8 +703,7 @@
 
        kfree(acm->ctrlurb->transfer_buffer);
 
-       usb_driver_release_interface(&acm_driver, acm->iface + 0);
-       usb_driver_release_interface(&acm_driver, acm->iface + 1);
+       usb_driver_release_interface(&acm_driver, acm->data);
 
        if (!acm->used) {
                tty_unregister_device(acm_tty_driver, acm->minor);
@@ -727,8 +724,15 @@
  */
 
 static struct usb_device_id acm_ids[] = {
-       { USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) },
-       { USB_DEVICE_INFO(USB_CLASS_COMM, 2, 0) },
+       /* control interfaces with various AT-command sets */
+       { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 1) },
+       { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 2) },
+       { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 3) },
+       { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 4) },
+       { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 5) },
+       { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 6) },
+
+       /* NOTE:  COMM/2/0xff is likely MSFT RNDIS ... NOT a modem!! */
        { }
 };
 
@@ -736,7 +740,7 @@
 
 static struct usb_driver acm_driver = {
        .owner =        THIS_MODULE,
-       .name =         "acm",
+       .name =         "cdc_acm",
        .probe =        acm_probe,
        .disconnect =   acm_disconnect,
        .id_table =     acm_ids,



-------------------------------------------------------
This SF.net email is sponsored by: The SF.net Donation Program.
Do you like what SourceForge.net is doing for the Open
Source Community?  Make a contribution, and help us add new
features and functionality. Click here: http://sourceforge.net/donate/
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to