Am Donnerstag, 20. Dezember 2007 16:51:59 schrieb Alan Stern:
> On Thu, 20 Dec 2007, Oliver Neukum wrote:
> 
> > @@ -1080,20 +1081,22 @@ void usb_serial_disconnect(struct usb_in
> >     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 use extra flag, as intfdata can be reset */
> > +   serial->disconnected = 1;
> 
> This comment is misleading.  It implies there is a possibility you
> actually could check for disconnects by looking at the value of
> usb_get_intfdata(), but that's completely wrong.  There are about 13 
> places in various serial drivers where this mistake is made; they all 
> need to be fixed.
> 
> Don't you also have to check the disconnect flag in serial_close()  
> before calling usb_autopm_put_interface()?

Where is that?

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 <[EMAIL PROTECTED]>

I'd call this 2.6.25 material.

        Regards
                Oliver

----

--- linux-2.6.24-rc7/include/linux/usb/serial.h 2008-01-16 15:04:38.000000000 
+0100
+++ linux-2.6.24-serial_intfdata/include/linux/usb/serial.h     2008-01-16 
14:55:12.000000000 +0100
@@ -128,6 +128,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;
@@ -137,6 +138,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)
--- linux-2.6.24-rc7/drivers/usb/serial/usb-serial.c    2008-01-16 
15:04:26.000000000 +0100
+++ linux-2.6.24-serial_intfdata/drivers/usb/serial/usb-serial.c        
2008-01-16 14:57:55.000000000 +0100
@@ -625,6 +625,7 @@ static struct usb_serial * create_serial
        serial->type = driver;
        serial->interface = interface;
        kref_init(&serial->kref);
+       mutex_init(&serial->disc_mutex);
 
        return serial;
 }
@@ -1080,20 +1081,22 @@ void usb_serial_disconnect(struct usb_in
        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");
 }
 
@@ -1103,9 +1106,6 @@ int usb_serial_suspend(struct usb_interf
        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)
--- linux-2.6.24-rc7/drivers/usb/serial/mos7720.c       2008-01-16 
15:04:26.000000000 +0100
+++ linux-2.6.24-serial_intfdata/drivers/usb/serial/mos7720.c   2008-01-16 
14:55:12.000000000 +0100
@@ -564,22 +564,25 @@ static void mos7720_close(struct usb_ser
        }
 
        /* 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__);
-
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to