]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/usb/serial/usb-serial.c
Merge commit 'v2.6.32-rc5' into perf/probes
[karo-tx-linux.git] / drivers / usb / serial / usb-serial.c
index ff75a3589e7e9f809a6839053c20fb2442784d50..bd3fa7ff15b12166bf0cf2ad86f3214144f914c0 100644 (file)
@@ -156,7 +156,8 @@ static void destroy_serial(struct kref *kref)
        if (serial->minor != SERIAL_TTY_NO_MINOR)
                return_serial(serial);
 
-       serial->type->release(serial);
+       if (serial->attached)
+               serial->type->release(serial);
 
        /* Now that nothing is using the ports, they can be freed */
        for (i = 0; i < serial->num_port_pointers; ++i) {
@@ -192,7 +193,7 @@ void usb_serial_put(struct usb_serial *serial)
  * This is the first place a new tty gets used.  Hence this is where we
  * acquire references to the usb_serial structure and the driver module,
  * where we store a pointer to the port, and where we do an autoresume.
- * All these actions are reversed in serial_release().
+ * All these actions are reversed in serial_cleanup().
  */
 static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
 {
@@ -339,15 +340,16 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
 }
 
 /**
- * serial_release - free resources post close/hangup
+ * serial_cleanup - free resources post close/hangup
  * @port: port to free up
  *
  * Do the resource freeing and refcount dropping for the port.
  * Avoid freeing the console.
  *
- * Called when the last tty kref is dropped.
+ * Called asynchronously after the last tty kref is dropped,
+ * and the tty layer has already done the tty_shutdown(tty);
  */
-static void serial_release(struct tty_struct *tty)
+static void serial_cleanup(struct tty_struct *tty)
 {
        struct usb_serial_port *port = tty->driver_data;
        struct usb_serial *serial;
@@ -361,9 +363,6 @@ static void serial_release(struct tty_struct *tty)
 
        dbg("%s - port %d", __func__, port->number);
 
-       /* Standard shutdown processing */
-       tty_shutdown(tty);
-
        tty->driver_data = NULL;
 
        serial = port->serial;
@@ -1061,12 +1060,15 @@ int usb_serial_probe(struct usb_interface *interface,
                module_put(type->driver.owner);
                if (retval < 0)
                        goto probe_error;
+               serial->attached = 1;
                if (retval > 0) {
                        /* quietly accept this device, but don't bind to a
                           serial port as it's about to disappear */
                        serial->num_ports = 0;
                        goto exit;
                }
+       } else {
+               serial->attached = 1;
        }
 
        if (get_free_serial(serial, num_ports, &minor) == NULL) {
@@ -1166,8 +1168,10 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
 
        if (serial->type->suspend) {
                r = serial->type->suspend(serial, message);
-               if (r < 0)
+               if (r < 0) {
+                       serial->suspending = 0;
                        goto err_out;
+               }
        }
 
        for (i = 0; i < serial->num_ports; ++i) {
@@ -1210,7 +1214,7 @@ static const struct tty_operations serial_ops = {
        .chars_in_buffer =      serial_chars_in_buffer,
        .tiocmget =             serial_tiocmget,
        .tiocmset =             serial_tiocmset,
-       .shutdown =             serial_release,
+       .cleanup =              serial_cleanup,
        .install =              serial_install,
        .proc_fops =            &serial_proc_fops,
 };