USB: fix oops on disconnect in cdc-acm
authorOliver Neukum <oliver@neukum.org>
Tue, 4 Aug 2009 21:52:09 +0000 (23:52 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 7 Aug 2009 23:05:14 +0000 (16:05 -0700)
This patch fixes an oops caused when during an unplug a device's table
of endpoints is zeroed before the driver is notified. A pointer to
the endpoint must be cached.

this fixes a regression caused by commit
5186ffee2320942c3dc9745f7930e0eb15329ca6
Therefore it should go into 2.6.31

Signed-off-by: Oliver Neukum <oliver@neukum.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-acm.h

index e1f89416ef8cdf6235b2cfcebdbda23ab213f7e7..2bfc41ece0e1d2df04ab058f742e76fd7b7749e9 100644 (file)
@@ -387,7 +387,6 @@ static void acm_rx_tasklet(unsigned long _acm)
        struct acm_ru *rcv;
        unsigned long flags;
        unsigned char throttled;
-       struct usb_host_endpoint *ep;
 
        dbg("Entering acm_rx_tasklet");
 
@@ -463,14 +462,12 @@ urbs:
 
                rcv->buffer = buf;
 
-               ep = (usb_pipein(acm->rx_endpoint) ? acm->dev->ep_in : acm->dev->ep_out)
-                               [usb_pipeendpoint(acm->rx_endpoint)];
-               if (usb_endpoint_xfer_int(&ep->desc))
+               if (acm->is_int_ep)
                        usb_fill_int_urb(rcv->urb, acm->dev,
                                         acm->rx_endpoint,
                                         buf->base,
                                         acm->readsize,
-                                        acm_read_bulk, rcv, ep->desc.bInterval);
+                                        acm_read_bulk, rcv, acm->bInterval);
                else
                        usb_fill_bulk_urb(rcv->urb, acm->dev,
                                          acm->rx_endpoint,
@@ -1183,6 +1180,9 @@ made_compressed_probe:
        spin_lock_init(&acm->read_lock);
        mutex_init(&acm->mutex);
        acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
+       acm->is_int_ep = usb_endpoint_xfer_int(epread);
+       if (acm->is_int_ep)
+               acm->bInterval = epread->bInterval;
        tty_port_init(&acm->port);
        acm->port.ops = &acm_port_ops;
 
index 1602324808bafb510e374520b9eb0a264617dc02..c4a0ee8ffccfb3ae4203c8cac4d091d88177b478 100644 (file)
@@ -126,6 +126,8 @@ struct acm {
        unsigned int ctrl_caps;                         /* control capabilities from the class specific header */
        unsigned int susp_count;                        /* number of suspended interfaces */
        int combined_interfaces:1;                      /* control and data collapsed */
+       int is_int_ep:1;                                /* interrupt endpoints contrary to spec used */
+       u8 bInterval;
        struct acm_wb *delayed_wb;                      /* write queued for a device about to be woken */
 };