USB: make sure usb serial drivers don't flush to logically disconnected devices
authorOliver Neukum <oliver@neukum.org>
Mon, 21 Jan 2008 16:44:10 +0000 (17:44 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 1 Feb 2008 22:35:04 +0000 (14:35 -0800)
If disconnect() is called for a logical disconnect, no more IO must be
done after disconnect() returns, or the old and new drivers may conflict.
This patch avoids this by using the flag and lock introduced by the earlier
patch for the mos7720 driver.

Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/serial/mct_u232.c
drivers/usb/serial/option.c
drivers/usb/serial/sierra.c
drivers/usb/serial/visor.c
drivers/usb/serial/whiteheat.c

index 88b2074867c5d187c5567bd4414fa6264436966e..fc1cea4aba13979ff48ea6fbdd371787fc1cea5e 100644 (file)
@@ -487,21 +487,22 @@ error:
 static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
 {
        unsigned int c_cflag;
-       unsigned long flags;
        unsigned int control_state;
        struct mct_u232_private *priv = usb_get_serial_port_data(port);
        dbg("%s port %d", __FUNCTION__, port->number);
 
        if (port->tty) {
                c_cflag = port->tty->termios->c_cflag;
-               if (c_cflag & HUPCL) {
-                  /* drop DTR and RTS */
-                  spin_lock_irqsave(&priv->lock, flags);
-                  priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
-                  control_state = priv->control_state;
-                  spin_unlock_irqrestore(&priv->lock, flags);
-                  mct_u232_set_modem_ctrl(port->serial, control_state);
+               mutex_lock(&port->serial->disc_mutex);
+               if (c_cflag & HUPCL && !port->serial->disconnected) {
+                       /* drop DTR and RTS */
+                       spin_lock_irq(&priv->lock);
+                       priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+                       control_state = priv->control_state;
+                       spin_unlock_irq(&priv->lock);
+                       mct_u232_set_modem_ctrl(port->serial, control_state);
                }
+               mutex_unlock(&port->serial->disc_mutex);
        }
 
 
index bbbe1b962008296f0251ea41e7453bee207c337b..5e8bf1bc1e50577fb6231e8088b63fdda307994c 100644 (file)
@@ -641,7 +641,10 @@ static void option_close(struct usb_serial_port *port, struct file *filp)
        portdata->dtr_state = 0;
 
        if (serial->dev) {
-               option_send_setup(port);
+               mutex_lock(&serial->disc_mutex);
+               if (!serial->disconnected)
+                       option_send_setup(port);
+               mutex_unlock(&serial->disc_mutex);
 
                /* Stop reading/writing urbs */
                for (i = 0; i < N_IN_URB; i++)
index 953bdf8827d2720d1e155491b3961097f3c4755a..4c925e3e8a6387663447f56cd07bc5532c931ddc 100644 (file)
@@ -597,7 +597,10 @@ static void sierra_close(struct usb_serial_port *port, struct file *filp)
        portdata->dtr_state = 0;
 
        if (serial->dev) {
-               sierra_send_setup(port);
+               mutex_lock(&serial->disc_mutex);
+               if (!serial->disconnected)
+                       sierra_send_setup(port);
+               mutex_unlock(&serial->disc_mutex);
 
                /* Stop reading/writing urbs */
                for (i = 0; i < N_IN_URB; i++)
index 7ee087fed913fbeed34678caebbe15dc8a96567c..c2347995c786e7224e18fb784bd2c4327ad7d610 100644 (file)
@@ -349,16 +349,20 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
        usb_kill_urb(port->read_urb);
        usb_kill_urb(port->interrupt_in_urb);
 
-       /* Try to send shutdown message, if the device is gone, this will just fail. */
-       transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
-       if (transfer_buffer) {
-               usb_control_msg (port->serial->dev,
-                                usb_rcvctrlpipe(port->serial->dev, 0),
-                                VISOR_CLOSE_NOTIFICATION, 0xc2,
-                                0x0000, 0x0000, 
-                                transfer_buffer, 0x12, 300);
-               kfree (transfer_buffer);
+       mutex_lock(&port->serial->disc_mutex);
+       if (!port->serial->disconnected) {
+               /* Try to send shutdown message, unless the device is gone */
+               transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
+               if (transfer_buffer) {
+                       usb_control_msg (port->serial->dev,
+                                        usb_rcvctrlpipe(port->serial->dev, 0),
+                                        VISOR_CLOSE_NOTIFICATION, 0xc2,
+                                        0x0000, 0x0000,
+                                        transfer_buffer, 0x12, 300);
+                       kfree (transfer_buffer);
+               }
        }
+       mutex_lock(&port->serial->disc_mutex);
 
        if (stats)
                dev_info(&port->dev, "Bytes In = %d  Bytes Out = %d\n",
index f5033d482eeec1060fd57fbb85388503ad405e40..38726ef3132b70d83121d8bdaa894b47990f0843 100644 (file)
@@ -658,11 +658,14 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
        struct list_head *tmp2;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
-       
+
+       mutex_lock(&port->serial->disc_mutex);
        /* filp is NULL when called from usb_serial_disconnect */
-       if (filp && (tty_hung_up_p(filp))) {
+       if ((filp && (tty_hung_up_p(filp))) || port->serial->disconnected) {
+               mutex_unlock(&port->serial->disc_mutex);
                return;
        }
+       mutex_unlock(&port->serial->disc_mutex);
 
        port->tty->closing = 1;