USB: stop io performed by mos7720 upon close()
authorOliver Neukum <oliver@neukum.org>
Wed, 16 Jan 2008 16:18:52 +0000 (17:18 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 1 Feb 2008 22:35:03 +0000 (14:35 -0800)
This fixes a problem where the mos7720 driver will make io to a device from
which it has been logically disconnected. It does so by introducing a flag by
which the generic usb serial code can signal the subdrivers their
disconnection and appropriate locking.

Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/serial/mos7720.c
drivers/usb/serial/usb-serial.c
include/linux/usb/serial.h

index 725991fadc26039318d35d190919bc66c68e6dc9..40f3a0188807d95c7e69a7a23001133678dbd9d1 100644 (file)
@@ -564,22 +564,25 @@ static void mos7720_close(struct usb_serial_port *port, struct file *filp)
        }
 
        /* While closing port, shutdown all bulk read, write  *
-        * and interrupt read if they exists                  */
-       if (serial->dev) {
-               dbg("Shutdown bulk write");
-               usb_kill_urb(port->write_urb);
-               dbg("Shutdown bulk read");
-               usb_kill_urb(port->read_urb);
+        * and interrupt read if they exists, otherwise nop   */
+       dbg("Shutdown bulk write");
+       usb_kill_urb(port->write_urb);
+       dbg("Shutdown bulk read");
+       usb_kill_urb(port->read_urb);
+
+       mutex_lock(&serial->disc_mutex);
+       /* these commands must not be issued if the device has
+        * been disconnected */
+       if (!serial->disconnected) {
+               data = 0x00;
+               send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+                            0x04, &data);
+
+               data = 0x00;
+               send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+                            0x01, &data);
        }
-
-       data = 0x00;
-       send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
-                    0x04, &data);
-
-       data = 0x00;
-       send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
-                    0x01, &data);
-
+       mutex_unlock(&serial->disc_mutex);
        mos7720_port->open = 0;
 
        dbg("Leaving %s", __FUNCTION__);
index 28315b05c9cc45312db3f6f03adc7181e1f1e1cd..3ce98e8d7bce6103031af188dc56218693f8ac51 100644 (file)
@@ -634,6 +634,7 @@ static struct usb_serial * create_serial (struct usb_device *dev,
        serial->type = driver;
        serial->interface = interface;
        kref_init(&serial->kref);
+       mutex_init(&serial->disc_mutex);
 
        return serial;
 }
@@ -1089,20 +1090,22 @@ void usb_serial_disconnect(struct usb_interface *interface)
        usb_serial_console_disconnect(serial);
        dbg ("%s", __FUNCTION__);
 
+       mutex_lock(&serial->disc_mutex);
        usb_set_intfdata (interface, NULL);
-       if (serial) {
-               for (i = 0; i < serial->num_ports; ++i) {
-                       port = serial->port[i];
-                       if (port) {
-                               if (port->tty)
-                                       tty_hangup(port->tty);
-                               kill_traffic(port);
-                       }
+       /* must set a flag, to signal subdrivers */
+       serial->disconnected = 1;
+       for (i = 0; i < serial->num_ports; ++i) {
+               port = serial->port[i];
+               if (port) {
+                       if (port->tty)
+                               tty_hangup(port->tty);
+                       kill_traffic(port);
                }
-               /* let the last holder of this object 
-                * cause it to be cleaned up */
-               usb_serial_put(serial);
        }
+       /* let the last holder of this object
+        * cause it to be cleaned up */
+       mutex_unlock(&serial->disc_mutex);
+       usb_serial_put(serial);
        dev_info(dev, "device disconnected\n");
 }
 
@@ -1112,9 +1115,6 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
        struct usb_serial_port *port;
        int i, r = 0;
 
-       if (!serial) /* device has been disconnected */
-               return 0;
-
        for (i = 0; i < serial->num_ports; ++i) {
                port = serial->port[i];
                if (port)
index ef1e430f7bfa130ff05a16e82e17a0bf59280efd..63b29b5332e625dbf171d0663d5cc238f8026314 100644 (file)
@@ -129,6 +129,7 @@ struct usb_serial {
        struct usb_device *             dev;
        struct usb_serial_driver *      type;
        struct usb_interface *          interface;
+       unsigned char                   disconnected;
        unsigned char                   minor;
        unsigned char                   num_ports;
        unsigned char                   num_port_pointers;
@@ -138,6 +139,7 @@ struct usb_serial {
        char                            num_bulk_out;
        struct usb_serial_port *        port[MAX_NUM_PORTS];
        struct kref                     kref;
+       struct mutex                    disc_mutex;
        void *                          private;
 };
 #define to_usb_serial(d) container_of(d, struct usb_serial, kref)