[PATCH] USB console: fix disconnection issues
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Tue, 25 Apr 2006 05:46:17 +0000 (07:46 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 21 Jun 2006 22:04:09 +0000 (15:04 -0700)
Prevent sending further output to a USB-serial console after the dongle is
disconnected, take care not to leak kref.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/serial/console.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/usb-serial.h

index fc4a0f731d9103ab8436d8a358259ca2317761d3..f3404e10afb4a3abb05bfeecc637883d68a3d3d2 100644 (file)
@@ -202,7 +202,7 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun
        struct usb_serial *serial;
        int retval = -ENODEV;
 
-       if (!port)
+       if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
                return;
        serial = port->serial;
 
@@ -255,6 +255,14 @@ static struct console usbcons = {
        .index =        -1,
 };
 
+void usb_serial_console_disconnect(struct usb_serial *serial)
+{
+       if (serial && serial->port && serial->port[0] && serial->port[0] == usbcons_info.port) {
+               usb_serial_console_exit();
+               usb_serial_put(serial);
+       }
+}
+
 void usb_serial_console_init (int serial_debug, int minor)
 {
        debug = serial_debug;
@@ -280,6 +288,11 @@ void usb_serial_console_init (int serial_debug, int minor)
 
 void usb_serial_console_exit (void)
 {
-       unregister_console(&usbcons);
+       if (usbcons_info.port) {
+               unregister_console(&usbcons);
+               if (usbcons_info.port->open_count)
+                       usbcons_info.port->open_count--;
+               usbcons_info.port = NULL;
+       }
 }
 
index de9111d97a587013e251ddfba396607652bea6ef..92200f05b5310d914f2860f162b8d3146c7d98e8 100644 (file)
@@ -168,6 +168,11 @@ static void destroy_serial(struct kref *kref)
        kfree (serial);
 }
 
+void usb_serial_put(struct usb_serial *serial)
+{
+       kref_put(&serial->kref, destroy_serial);
+}
+
 /*****************************************************************************
  * Driver tty interface functions
  *****************************************************************************/
@@ -232,7 +237,7 @@ bailout_mutex_unlock:
        port->open_count = 0;
        mutex_unlock(&port->mutex);
 bailout_kref_put:
-       kref_put(&serial->kref, destroy_serial);
+       usb_serial_put(serial);
        return retval;
 }
 
@@ -268,7 +273,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
        }
 
        mutex_unlock(&port->mutex);
-       kref_put(&port->serial->kref, destroy_serial);
+       usb_serial_put(port->serial);
 }
 
 static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count)
@@ -276,7 +281,7 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int
        struct usb_serial_port *port = tty->driver_data;
        int retval = -EINVAL;
 
-       if (!port)
+       if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
                goto exit;
 
        dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
@@ -473,7 +478,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int
                        begin += length;
                        length = 0;
                }
-               kref_put(&serial->kref, destroy_serial);
+               usb_serial_put(serial);
        }
        *eof = 1;
 done:
@@ -985,6 +990,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
        struct device *dev = &interface->dev;
        struct usb_serial_port *port;
 
+       usb_serial_console_disconnect(serial);
        dbg ("%s", __FUNCTION__);
 
        usb_set_intfdata (interface, NULL);
@@ -996,7 +1002,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
                }
                /* let the last holder of this object 
                 * cause it to be cleaned up */
-               kref_put(&serial->kref, destroy_serial);
+               usb_serial_put(serial);
        }
        dev_info(dev, "device disconnected\n");
 }
index dc89d87104609524d6b3e07272153a6807459798..c07ece3fef1dffba910245aa66ed50882d5df8be 100644 (file)
@@ -248,13 +248,16 @@ extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
 #ifdef CONFIG_USB_SERIAL_CONSOLE
 extern void usb_serial_console_init (int debug, int minor);
 extern void usb_serial_console_exit (void);
+extern void usb_serial_console_disconnect(struct usb_serial *serial);
 #else
 static inline void usb_serial_console_init (int debug, int minor) { }
 static inline void usb_serial_console_exit (void) { }
+static inline void usb_serial_console_disconnect(struct usb_serial *serial) {}
 #endif
 
 /* Functions needed by other parts of the usbserial core */
 extern struct usb_serial *usb_serial_get_by_index (unsigned int minor);
+extern void usb_serial_put(struct usb_serial *serial);
 extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp);
 extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count);
 extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp);