diff options
Diffstat (limited to 'tty')
| -rw-r--r-- | tty/tty-kref-put-async | 1 | ||||
| -rw-r--r-- | tty/tty-port-close-fn | 1 | ||||
| -rw-r--r-- | tty/tty-usb-cdc-fix-speed | 1 | ||||
| -rw-r--r-- | tty/tty-usb-clean-dtr-rts | 1 | ||||
| -rw-r--r-- | tty/tty-usb-drop-filp-argp | 22 | ||||
| -rw-r--r-- | tty/tty-usb-serial-termiosbits | 6 | ||||
| -rw-r--r-- | tty/tty-usb-shutdown | 7 | ||||
| -rw-r--r-- | tty/tty-usb-vhangup | 3 | ||||
| -rw-r--r-- | tty/usb-serial-acquire-references-when-a-new-tty-is-installed.patch | 223 | ||||
| -rw-r--r-- | tty/usb-serial-add-missing-tests-and-debug-lines.patch | 94 | ||||
| -rw-r--r-- | tty/usb-serial-change-logic-of-serial-lookups.patch | 119 | ||||
| -rw-r--r-- | tty/usb-serial-change-referencing-of-port-and-serial-structures.patch | 235 | ||||
| -rw-r--r-- | tty/usb-serial-fix-termios-initialization-logic.patch | 66 | ||||
| -rw-r--r-- | tty/usb-serial-put-subroutines-in-logical-order.patch | 230 | ||||
| -rw-r--r-- | tty/usb-serial-rename-subroutines.patch | 100 | ||||
| -rw-r--r-- | tty/usb-serial-straighten-out-serial_open.patch | 104 |
16 files changed, 1195 insertions, 18 deletions
diff --git a/tty/tty-kref-put-async b/tty/tty-kref-put-async index fe32b4fdde67f6..440b9e8c7b5305 100644 --- a/tty/tty-kref-put-async +++ b/tty/tty-kref-put-async @@ -8,6 +8,7 @@ hot path so just pushing it to a work queue doesn't really cause any difficulty. Signed-off-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/char/tty_io.c | 19 ++++++++++++++++--- diff --git a/tty/tty-port-close-fn b/tty/tty-port-close-fn index dca38b2b57e265..7adfad2c0b3eac 100644 --- a/tty/tty-port-close-fn +++ b/tty/tty-port-close-fn @@ -11,6 +11,7 @@ At some point in the future this will be paired with a similar open() helper and the drivers can stick to hardware management. Signed-off-by: Alan Cox <alan@linux.intel.com> +Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- diff --git a/tty/tty-usb-cdc-fix-speed b/tty/tty-usb-cdc-fix-speed index 6023bdc2318caf..1a460922a6c90a 100644 --- a/tty/tty-usb-cdc-fix-speed +++ b/tty/tty-usb-cdc-fix-speed @@ -6,6 +6,7 @@ From: Alan Cox <alan@linux.intel.com> This changed in 2006 so its about time the ACM driver caught up Signed-off-by: Alan Cox <alan@linux.intel.com> +Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- diff --git a/tty/tty-usb-clean-dtr-rts b/tty/tty-usb-clean-dtr-rts index 2fe2e007a4a59b..445941a918b400 100644 --- a/tty/tty-usb-clean-dtr-rts +++ b/tty/tty-usb-clean-dtr-rts @@ -7,6 +7,7 @@ These are handled by the tty_port core code which will raise and lower the carrier correctly in tty_wait_until_ready Signed-off-by: Alan Cox <alan@linux.intel.com> +Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- diff --git a/tty/tty-usb-drop-filp-argp b/tty/tty-usb-drop-filp-argp index 77fb122aa1af38..a3b977a2787716 100644 --- a/tty/tty-usb-drop-filp-argp +++ b/tty/tty-usb-drop-filp-argp @@ -746,15 +746,15 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> /* This HW really does not support a serial break, so one will be --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c -@@ -248,7 +248,7 @@ static int serial_open (struct tty_struc - if (port->console) { - tty_encode_baud_rate(tty, port->console_init_baud, port->console_init_baud); - } else { -- retval = serial->type->open(tty, port, filp); -+ retval = serial->type->open(tty, port); - if (retval) - goto bailout_interface_put; - } +@@ -244,7 +244,7 @@ static int serial_open (struct tty_struc + + /* only call the device specific open if this + * is the first time the port is opened */ +- retval = serial->type->open(tty, port, filp); ++ retval = serial->type->open(tty, port); + if (retval) + goto bailout_interface_put; + mutex_unlock(&serial->disc_mutex); --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -36,8 +36,7 @@ @@ -800,7 +800,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h -@@ -239,9 +239,8 @@ struct usb_serial_driver { +@@ -238,9 +238,8 @@ struct usb_serial_driver { int (*resume)(struct usb_serial *serial); /* serial function calls */ @@ -812,7 +812,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> void (*close)(struct usb_serial_port *port); int (*write)(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); -@@ -301,7 +300,7 @@ static inline void usb_serial_console_di +@@ -300,7 +299,7 @@ static inline void usb_serial_console_di 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 tty_struct *tty, diff --git a/tty/tty-usb-serial-termiosbits b/tty/tty-usb-serial-termiosbits index 503922666cb9d5..a8766ab29a09b2 100644 --- a/tty/tty-usb-serial-termiosbits +++ b/tty/tty-usb-serial-termiosbits @@ -434,7 +434,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> .tiocmset = spcp8x5_tiocmset, --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c -@@ -726,6 +726,41 @@ static const struct tty_port_operations +@@ -721,6 +721,41 @@ static const struct tty_port_operations .dtr_rts = serial_dtr_rts, }; @@ -476,7 +476,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> int usb_serial_probe(struct usb_interface *interface, const struct usb_device_id *id) { -@@ -1233,7 +1268,8 @@ static const struct tty_operations seria +@@ -1228,7 +1263,8 @@ static const struct tty_operations seria .chars_in_buffer = serial_chars_in_buffer, .tiocmget = serial_tiocmget, .tiocmset = serial_tiocmset, @@ -517,7 +517,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h -@@ -261,6 +261,9 @@ struct usb_serial_driver { +@@ -260,6 +260,9 @@ struct usb_serial_driver { be an attached tty at this point */ void (*dtr_rts)(struct usb_serial_port *port, int on); int (*carrier_raised)(struct usb_serial_port *port); diff --git a/tty/tty-usb-shutdown b/tty/tty-usb-shutdown index 3b383524b87585..cfbfd538b0cf07 100644 --- a/tty/tty-usb-shutdown +++ b/tty/tty-usb-shutdown @@ -4,6 +4,7 @@ Subject: tty: USB can now use the shutdown method for kref based freeing of port From: Alan Cox <alan@linux.intel.com> Signed-off-by: Alan Cox <alan@linux.intel.com> +Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- @@ -13,7 +14,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c -@@ -321,16 +321,19 @@ static void serial_do_down(struct usb_se +@@ -316,16 +316,19 @@ static void serial_do_down(struct usb_se * * Do the resource freeing and refcount dropping for the port. We must * be careful about ordering and we must avoid freeing up the console. @@ -35,7 +36,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> return; serial = port->serial; -@@ -355,30 +358,12 @@ static void serial_close(struct tty_stru +@@ -350,30 +353,12 @@ static void serial_close(struct tty_stru dbg("%s - port %d", __func__, port->number); @@ -67,7 +68,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> } static void serial_hangup(struct tty_struct *tty) -@@ -1248,6 +1233,7 @@ static const struct tty_operations seria +@@ -1243,6 +1228,7 @@ static const struct tty_operations seria .chars_in_buffer = serial_chars_in_buffer, .tiocmget = serial_tiocmget, .tiocmset = serial_tiocmset, diff --git a/tty/tty-usb-vhangup b/tty/tty-usb-vhangup index 7853b48d5d2a67..8a594461a6e38e 100644 --- a/tty/tty-usb-vhangup +++ b/tty/tty-usb-vhangup @@ -9,6 +9,7 @@ tty_hangup is asynchronous. As the hangup can sleep we can use tty_vhangup which is the non async version to avoid freeing resources too early. Signed-off-by: Alan Cox <alan@linux.intel.com> +Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- @@ -18,7 +19,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c -@@ -1166,10 +1166,7 @@ void usb_serial_disconnect(struct usb_in +@@ -1161,10 +1161,7 @@ void usb_serial_disconnect(struct usb_in if (port) { struct tty_struct *tty = tty_port_tty_get(&port->port); if (tty) { diff --git a/tty/usb-serial-acquire-references-when-a-new-tty-is-installed.patch b/tty/usb-serial-acquire-references-when-a-new-tty-is-installed.patch new file mode 100644 index 00000000000000..353bafc4594efd --- /dev/null +++ b/tty/usb-serial-acquire-references-when-a-new-tty-is-installed.patch @@ -0,0 +1,223 @@ +From stern@rowland.harvard.edu Tue Sep 15 15:22:00 2009 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Tue, 1 Sep 2009 11:39:13 -0400 (EDT) +Subject: usb-serial: acquire references when a new tty is installed +To: Greg KH <greg@kroah.com> +Message-ID: <Pine.LNX.4.44L0.0909011126470.2648-100000@iolanthe.rowland.org> + + +This patch (as1287) makes serial_install() be reponsible for acquiring +references to the usb_serial structure and the driver module when a +tty is first used. This is more sensible than having serial_open() do +it, because a tty can be opened many times whereas it is installed +only once, when it is created. (Not to mention that these actions are +reversed when the tty is released, not when it is closed.) Finally, +it is at install time that the TTY core takes its own reference to the +usb_serial module, so it is only fitting that we should act the same +way in regard to the lower-level serial driver. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Cc: stable <stable@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/usb-serial.c | 111 ++++++++++++++++------------------------ + 1 file changed, 47 insertions(+), 64 deletions(-) + +--- a/drivers/usb/serial/usb-serial.c ++++ b/drivers/usb/serial/usb-serial.c +@@ -187,100 +187,92 @@ void usb_serial_put(struct usb_serial *s + * Create the termios objects for this tty. We use the default + * USB serial settings but permit them to be overridden by + * serial->type->init_termios. ++ * ++ * 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_do_free(). + */ + static int serial_install(struct tty_driver *driver, struct tty_struct *tty) + { + int idx = tty->index; + struct usb_serial *serial; +- int retval; ++ struct usb_serial_port *port; ++ int retval = -ENODEV; ++ ++ serial = usb_serial_get_by_index(idx); ++ if (!serial) ++ return retval; ++ ++ port = serial->port[idx - serial->minor]; ++ if (!port) ++ goto error_no_port; ++ if (!try_module_get(serial->type->driver.owner)) ++ goto error_module_get; ++ ++ retval = usb_autopm_get_interface(serial->interface); ++ if (retval) ++ goto error_get_interface; + + /* If the termios setup has yet to be done */ + if (tty->driver->termios[idx] == NULL) { + /* perform the standard setup */ + retval = tty_init_termios(tty); + if (retval) +- return retval; ++ goto error_init_termios; + /* allow the driver to update it */ +- serial = usb_serial_get_by_index(tty->index); +- if (serial) { +- if (serial->type->init_termios) +- serial->type->init_termios(tty); +- usb_serial_put(serial); +- mutex_unlock(&serial->disc_mutex); +- } ++ if (serial->type->init_termios) ++ serial->type->init_termios(tty); + } ++ mutex_unlock(&serial->disc_mutex); ++ ++ tty->driver_data = port; ++ + /* Final install (we use the default method) */ + tty_driver_kref_get(driver); + tty->count++; + driver->ttys[idx] = tty; +- return 0; ++ return retval; ++ ++ error_init_termios: ++ usb_autopm_put_interface(serial->interface); ++ error_get_interface: ++ module_put(serial->type->driver.owner); ++ error_module_get: ++ error_no_port: ++ usb_serial_put(serial); ++ mutex_unlock(&serial->disc_mutex); ++ return retval; + } + + static int serial_open (struct tty_struct *tty, struct file *filp) + { + struct usb_serial *serial; + struct usb_serial_port *port; +- unsigned int portNumber; + int retval = 0; + int first = 0; + + dbg("%s", __func__); + +- /* get the serial object associated with this tty pointer */ +- serial = usb_serial_get_by_index(tty->index); +- if (!serial) { +- tty->driver_data = NULL; +- return -ENODEV; +- } +- +- portNumber = tty->index - serial->minor; +- port = serial->port[portNumber]; +- if (!port || serial->disconnected) +- retval = -ENODEV; +- /* +- * Note: Our locking order requirement does not allow port->mutex +- * to be acquired while serial->disc_mutex is held. +- */ +- mutex_unlock(&serial->disc_mutex); +- if (retval) +- goto bailout_serial_put; ++ port = tty->driver_data; ++ serial = port->serial; + +- if (mutex_lock_interruptible(&port->mutex)) { +- retval = -ERESTARTSYS; +- goto bailout_serial_put; +- } ++ if (mutex_lock_interruptible(&port->mutex)) ++ return -ERESTARTSYS; + + ++port->port.count; +- +- /* set up our port structure making the tty driver +- * remember our port object, and us it */ +- tty->driver_data = port; + tty_port_tty_set(&port->port, tty); + + /* If the console is attached, the device is already open */ + if (port->port.count == 1 && !port->console) { + first = 1; +- /* lock this module before we call it +- * this may fail, which means we must bail out, +- * safe because we are called with BKL held */ +- if (!try_module_get(serial->type->driver.owner)) { +- retval = -ENODEV; +- goto bailout_mutex_unlock; +- } +- + mutex_lock(&serial->disc_mutex); +- if (serial->disconnected) +- retval = -ENODEV; +- else +- retval = usb_autopm_get_interface(serial->interface); +- if (retval) +- goto bailout_module_put; + + /* only call the device specific open if this + * is the first time the port is opened */ + retval = serial->type->open(tty, port); + if (retval) +- goto bailout_interface_put; ++ goto bailout_module_put; + mutex_unlock(&serial->disc_mutex); + set_bit(ASYNCB_INITIALIZED, &port->port.flags); + } +@@ -297,18 +289,11 @@ static int serial_open (struct tty_struc + goto bailout_mutex_unlock; + /* Undo the initial port actions */ + mutex_lock(&serial->disc_mutex); +-bailout_interface_put: +- usb_autopm_put_interface(serial->interface); + bailout_module_put: + mutex_unlock(&serial->disc_mutex); +- module_put(serial->type->driver.owner); + bailout_mutex_unlock: + port->port.count = 0; +- tty->driver_data = NULL; +- tty_port_tty_set(&port->port, NULL); + mutex_unlock(&port->mutex); +-bailout_serial_put: +- usb_serial_put(serial); + return retval; + } + +@@ -355,9 +340,6 @@ static void serial_close(struct tty_stru + { + struct usb_serial_port *port = tty->driver_data; + +- if (!port) +- return; +- + dbg("%s - port %d", __func__, port->number); + + if (tty_port_close_start(&port->port, tty, filp) == 0) +@@ -365,7 +347,6 @@ static void serial_close(struct tty_stru + serial_do_down(port); + tty_port_close_end(&port->port, tty); + tty_port_tty_set(&port->port, NULL); +- + } + + /** +@@ -386,9 +367,11 @@ static void serial_do_free(struct tty_st + /* The console is magical. Do not hang up the console hardware + * or there will be tears. + */ +- if (port == NULL || port->console) ++ if (port->console) + return; + ++ tty->driver_data = NULL; ++ + serial = port->serial; + owner = serial->type->driver.owner; + diff --git a/tty/usb-serial-add-missing-tests-and-debug-lines.patch b/tty/usb-serial-add-missing-tests-and-debug-lines.patch new file mode 100644 index 00000000000000..e7b1245043a8e0 --- /dev/null +++ b/tty/usb-serial-add-missing-tests-and-debug-lines.patch @@ -0,0 +1,94 @@ +From stern@rowland.harvard.edu Tue Sep 15 15:22:41 2009 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Tue, 1 Sep 2009 11:39:51 -0400 (EDT) +Subject: usb-serial: add missing tests and debug lines +To: Greg KH <greg@kroah.com> +Message-ID: <Pine.LNX.4.44L0.0909011135090.2648-100000@iolanthe.rowland.org> + + +This patch (as1290) adds some missing tests. serial_down() isn't +supposed to do anything if the hardware hasn't been initialized, and +serial_close() isn't supposed to do anything if the tty has gotten a +hangup (because serial_hangup() takes care of shutting down the +hardware). + +The patch also updates and adds a few debugging lines. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Cc: stable <stable@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/usb-serial.c | 21 +++++++++++++++++---- + 1 file changed, 17 insertions(+), 4 deletions(-) + +--- a/drivers/usb/serial/usb-serial.c ++++ b/drivers/usb/serial/usb-serial.c +@@ -200,6 +200,8 @@ static int serial_install(struct tty_dri + struct usb_serial_port *port; + int retval = -ENODEV; + ++ dbg("%s", __func__); ++ + serial = usb_serial_get_by_index(idx); + if (!serial) + return retval; +@@ -250,11 +252,11 @@ static int serial_open (struct tty_struc + int retval = 0; + int first = 0; + +- dbg("%s", __func__); +- + port = tty->driver_data; + serial = port->serial; + ++ dbg("%s - port %d", __func__, port->number); ++ + if (mutex_lock_interruptible(&port->mutex)) + return -ERESTARTSYS; + +@@ -315,6 +317,12 @@ static void serial_down(struct usb_seria + if (port->console) + return; + ++ /* Don't call the close method if the hardware hasn't been ++ * initialized. ++ */ ++ if (!test_and_clear_bit(ASYNCB_INITIALIZED, &port->port.flags)) ++ return; ++ + mutex_lock(&port->mutex); + serial = port->serial; + owner = serial->type->driver.owner; +@@ -328,10 +336,11 @@ static void serial_down(struct usb_seria + static void serial_hangup(struct tty_struct *tty) + { + struct usb_serial_port *port = tty->driver_data; ++ ++ dbg("%s - port %d", __func__, port->number); ++ + serial_down(port); + tty_port_hangup(&port->port); +- /* We must not free port yet - the USB serial layer depends on it's +- continued existence */ + } + + static void serial_close(struct tty_struct *tty, struct file *filp) +@@ -340,6 +349,8 @@ static void serial_close(struct tty_stru + + dbg("%s - port %d", __func__, port->number); + ++ if (tty_hung_up_p(filp)) ++ return; + if (tty_port_close_start(&port->port, tty, filp) == 0) + return; + serial_down(port); +@@ -368,6 +379,8 @@ static void serial_release(struct tty_st + if (port->console) + return; + ++ dbg("%s - port %d", __func__, port->number); ++ + /* Standard shutdown processing */ + tty_shutdown(tty); + diff --git a/tty/usb-serial-change-logic-of-serial-lookups.patch b/tty/usb-serial-change-logic-of-serial-lookups.patch new file mode 100644 index 00000000000000..166c548a6cba10 --- /dev/null +++ b/tty/usb-serial-change-logic-of-serial-lookups.patch @@ -0,0 +1,119 @@ +From stern@rowland.harvard.edu Tue Sep 15 15:21:44 2009 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Tue, 1 Sep 2009 11:38:59 -0400 (EDT) +Subject: usb-serial: change logic of serial lookups +To: Greg KH <greg@kroah.com> +Message-ID: <Pine.LNX.4.44L0.0909011125270.2648-100000@iolanthe.rowland.org> + + +This patch (as1286) changes usb_serial_get_by_index(). Now the +routine will check whether the serial device has been disconnected; if +it has then the return value will be NULL. If the device hasn't been +disconnected then the routine will return with serial->disc_mutex +held, so that the caller can use the structure without fear of racing +against driver unloads. + +This permits the scope of table_mutex in destroy_serial() to be +reduced. Instead of protecting the entire function, it suffices to +protect the part that actually uses serial_table[], i.e., the call to +return_serial(). There's no longer any danger of the refcount being +incremented after it reaches 0 (which was the reason for having the +large scope previously), because it can't reach 0 until the serial +device has been disconnected. + +Also, the patch makes serial_install() check that serial is non-NULL +before attempting to use it. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Cc: stable <stable@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/usb-serial.c | 31 +++++++++++++++++++++++-------- + 1 file changed, 23 insertions(+), 8 deletions(-) + +--- a/drivers/usb/serial/usb-serial.c ++++ b/drivers/usb/serial/usb-serial.c +@@ -66,6 +66,11 @@ static struct usb_serial *serial_table[S + static DEFINE_MUTEX(table_lock); + static LIST_HEAD(usb_serial_driver_list); + ++/* ++ * Look up the serial structure. If it is found and it hasn't been ++ * disconnected, return with its disc_mutex held and its refcount ++ * incremented. Otherwise return NULL. ++ */ + struct usb_serial *usb_serial_get_by_index(unsigned index) + { + struct usb_serial *serial; +@@ -73,8 +78,15 @@ struct usb_serial *usb_serial_get_by_ind + mutex_lock(&table_lock); + serial = serial_table[index]; + +- if (serial) +- kref_get(&serial->kref); ++ if (serial) { ++ mutex_lock(&serial->disc_mutex); ++ if (serial->disconnected) { ++ mutex_unlock(&serial->disc_mutex); ++ serial = NULL; ++ } else { ++ kref_get(&serial->kref); ++ } ++ } + mutex_unlock(&table_lock); + return serial; + } +@@ -123,8 +135,10 @@ static void return_serial(struct usb_ser + + dbg("%s", __func__); + ++ mutex_lock(&table_lock); + for (i = 0; i < serial->num_ports; ++i) + serial_table[serial->minor + i] = NULL; ++ mutex_unlock(&table_lock); + } + + static void destroy_serial(struct kref *kref) +@@ -158,9 +172,7 @@ static void destroy_serial(struct kref * + + void usb_serial_put(struct usb_serial *serial) + { +- mutex_lock(&table_lock); + kref_put(&serial->kref, destroy_serial); +- mutex_unlock(&table_lock); + } + + /***************************************************************************** +@@ -190,9 +202,12 @@ static int serial_install(struct tty_dri + return retval; + /* allow the driver to update it */ + serial = usb_serial_get_by_index(tty->index); +- if (serial->type->init_termios) +- serial->type->init_termios(tty); +- usb_serial_put(serial); ++ if (serial) { ++ if (serial->type->init_termios) ++ serial->type->init_termios(tty); ++ usb_serial_put(serial); ++ mutex_unlock(&serial->disc_mutex); ++ } + } + /* Final install (we use the default method) */ + tty_driver_kref_get(driver); +@@ -218,7 +233,6 @@ static int serial_open (struct tty_struc + return -ENODEV; + } + +- mutex_lock(&serial->disc_mutex); + portNumber = tty->index - serial->minor; + port = serial->port[portNumber]; + if (!port || serial->disconnected) +@@ -529,6 +543,7 @@ static int serial_proc_show(struct seq_f + + seq_putc(m, '\n'); + usb_serial_put(serial); ++ mutex_unlock(&serial->disc_mutex); + } + return 0; + } diff --git a/tty/usb-serial-change-referencing-of-port-and-serial-structures.patch b/tty/usb-serial-change-referencing-of-port-and-serial-structures.patch new file mode 100644 index 00000000000000..8479f759be7fa2 --- /dev/null +++ b/tty/usb-serial-change-referencing-of-port-and-serial-structures.patch @@ -0,0 +1,235 @@ +From stern@rowland.harvard.edu Tue Sep 15 15:13:05 2009 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Tue, 1 Sep 2009 11:38:34 -0400 (EDT) +Subject: usb-serial: change referencing of port and serial structures +To: Greg KH <greg@kroah.com> +Message-ID: <Pine.LNX.4.44L0.0909011122480.2648-100000@iolanthe.rowland.org> + + +This patch (as1284) changes the referencing of the usb_serial and +usb_serial_port structures in usb-serial.c. It's not feasible to make +the port structures keep a reference to the serial structure, because +the ports need to remain in existence when serial is released -- quite +a few of the drivers expect this. Consequently taking a reference +to the port when the device file is open is insufficient; such a +reference would not pin serial. + +To fix this, we now take a reference to serial when the device file is +opened. The final put_device() for the ports occurs in +destroy_serial(), so that the ports will last as long as they are +needed. + +The patch initializes all the port devices, including those in the +unused "fake" ports. This makes the code more uniform because they +can all be released in the same way. The error handling code in +usb_serial_probe() is much simplified by this approach; instead of +freeing everything by hand we can use a single usb_serial_put() call. + +Also simplified is the port-release mechanism. Instead of being two +separate routines, port_release() and port_free() can be combined into +one. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Cc: stable <stable@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/usb-serial.c | 95 ++++++++-------------------------------- + 1 file changed, 20 insertions(+), 75 deletions(-) + +--- a/drivers/usb/serial/usb-serial.c ++++ b/drivers/usb/serial/usb-serial.c +@@ -43,8 +43,6 @@ + #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/" + #define DRIVER_DESC "USB Serial Driver core" + +-static void port_free(struct usb_serial_port *port); +- + /* Driver structure we register with the USB core */ + static struct usb_driver usb_serial_driver = { + .name = "usbserial", +@@ -145,27 +143,16 @@ static void destroy_serial(struct kref * + + serial->type->release(serial); + +- for (i = 0; i < serial->num_ports; ++i) { ++ /* Now that nothing is using the ports, they can be freed */ ++ for (i = 0; i < serial->num_port_pointers; ++i) { + port = serial->port[i]; +- if (port) ++ if (port) { ++ port->serial = NULL; + put_device(&port->dev); +- } +- +- /* If this is a "fake" port, we have to clean it up here, as it will +- * not get cleaned up in port_release() as it was never registered with +- * the driver core */ +- if (serial->num_ports < serial->num_port_pointers) { +- for (i = serial->num_ports; +- i < serial->num_port_pointers; ++i) { +- port = serial->port[i]; +- if (port) +- port_free(port); + } + } + + usb_put_dev(serial->dev); +- +- /* free up any memory that we allocated */ + kfree(serial); + } + +@@ -201,8 +188,6 @@ static int serial_open (struct tty_struc + port = serial->port[portNumber]; + if (!port || serial->disconnected) + retval = -ENODEV; +- else +- get_device(&port->dev); + /* + * Note: Our locking order requirement does not allow port->mutex + * to be acquired while serial->disc_mutex is held. +@@ -213,7 +198,7 @@ static int serial_open (struct tty_struc + + if (mutex_lock_interruptible(&port->mutex)) { + retval = -ERESTARTSYS; +- goto bailout_port_put; ++ goto bailout_serial_put; + } + + ++port->port.count; +@@ -273,8 +258,6 @@ bailout_mutex_unlock: + tty->driver_data = NULL; + tty_port_tty_set(&port->port, NULL); + mutex_unlock(&port->mutex); +-bailout_port_put: +- put_device(&port->dev); + bailout_serial_put: + usb_serial_put(serial); + return retval; +@@ -333,14 +316,13 @@ static void serial_do_free(struct tty_st + + serial = port->serial; + owner = serial->type->driver.owner; +- put_device(&port->dev); +- /* Mustn't dereference port any more */ ++ + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) + usb_autopm_put_interface(serial->interface); + mutex_unlock(&serial->disc_mutex); ++ + usb_serial_put(serial); +- /* Mustn't dereference serial any more */ + module_put(owner); + } + +@@ -581,14 +563,6 @@ static void usb_serial_port_work(struct + tty_kref_put(tty); + } + +-static void port_release(struct device *dev) +-{ +- struct usb_serial_port *port = to_usb_serial_port(dev); +- +- dbg ("%s - %s", __func__, dev_name(dev)); +- port_free(port); +-} +- + static void kill_traffic(struct usb_serial_port *port) + { + usb_kill_urb(port->read_urb); +@@ -608,8 +582,12 @@ static void kill_traffic(struct usb_seri + usb_kill_urb(port->interrupt_out_urb); + } + +-static void port_free(struct usb_serial_port *port) ++static void port_release(struct device *dev) + { ++ struct usb_serial_port *port = to_usb_serial_port(dev); ++ ++ dbg ("%s - %s", __func__, dev_name(dev)); ++ + /* + * Stop all the traffic before cancelling the work, so that + * nobody will restart it by calling usb_serial_port_softint. +@@ -955,6 +933,11 @@ int usb_serial_probe(struct usb_interfac + mutex_init(&port->mutex); + INIT_WORK(&port->work, usb_serial_port_work); + serial->port[i] = port; ++ port->dev.parent = &interface->dev; ++ port->dev.driver = NULL; ++ port->dev.bus = &usb_serial_bus_type; ++ port->dev.release = &port_release; ++ device_initialize(&port->dev); + } + + /* set up the endpoint information */ +@@ -1097,15 +1080,10 @@ int usb_serial_probe(struct usb_interfac + /* register all of the individual ports with the driver core */ + for (i = 0; i < num_ports; ++i) { + port = serial->port[i]; +- port->dev.parent = &interface->dev; +- port->dev.driver = NULL; +- port->dev.bus = &usb_serial_bus_type; +- port->dev.release = &port_release; +- + dev_set_name(&port->dev, "ttyUSB%d", port->number); + dbg ("%s - registering %s", __func__, dev_name(&port->dev)); + port->dev_state = PORT_REGISTERING; +- retval = device_register(&port->dev); ++ retval = device_add(&port->dev); + if (retval) { + dev_err(&port->dev, "Error registering port device, " + "continuing\n"); +@@ -1123,39 +1101,7 @@ exit: + return 0; + + probe_error: +- for (i = 0; i < num_bulk_in; ++i) { +- port = serial->port[i]; +- if (!port) +- continue; +- usb_free_urb(port->read_urb); +- kfree(port->bulk_in_buffer); +- } +- for (i = 0; i < num_bulk_out; ++i) { +- port = serial->port[i]; +- if (!port) +- continue; +- usb_free_urb(port->write_urb); +- kfree(port->bulk_out_buffer); +- } +- for (i = 0; i < num_interrupt_in; ++i) { +- port = serial->port[i]; +- if (!port) +- continue; +- usb_free_urb(port->interrupt_in_urb); +- kfree(port->interrupt_in_buffer); +- } +- for (i = 0; i < num_interrupt_out; ++i) { +- port = serial->port[i]; +- if (!port) +- continue; +- usb_free_urb(port->interrupt_out_urb); +- kfree(port->interrupt_out_buffer); +- } +- +- /* free up any memory that we allocated */ +- for (i = 0; i < serial->num_port_pointers; ++i) +- kfree(serial->port[i]); +- kfree(serial); ++ usb_serial_put(serial); + return -EIO; + } + EXPORT_SYMBOL_GPL(usb_serial_probe); +@@ -1206,8 +1152,7 @@ void usb_serial_disconnect(struct usb_in + } + serial->type->disconnect(serial); + +- /* let the last holder of this object +- * cause it to be cleaned up */ ++ /* let the last holder of this object cause it to be cleaned up */ + usb_serial_put(serial); + dev_info(dev, "device disconnected\n"); + } diff --git a/tty/usb-serial-fix-termios-initialization-logic.patch b/tty/usb-serial-fix-termios-initialization-logic.patch new file mode 100644 index 00000000000000..fb321e27273826 --- /dev/null +++ b/tty/usb-serial-fix-termios-initialization-logic.patch @@ -0,0 +1,66 @@ +From stern@rowland.harvard.edu Tue Sep 15 15:22:13 2009 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Tue, 1 Sep 2009 11:39:22 -0400 (EDT) +Subject: usb-serial: fix termios initialization logic +To: Greg KH <greg@kroah.com> +Message-ID: <Pine.LNX.4.44L0.0909011127540.2648-100000@iolanthe.rowland.org> + + +This patch (as1288) fixes the initialization logic in +serial_install(). A new tty always needs to have a termios +initialized no matter what, not just in the case where the lower +driver will override the termios settings. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Cc: stable <stable@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/usb-serial.c | 22 ++++++++++------------ + 1 file changed, 10 insertions(+), 12 deletions(-) + +--- a/drivers/usb/serial/usb-serial.c ++++ b/drivers/usb/serial/usb-serial.c +@@ -210,22 +210,21 @@ static int serial_install(struct tty_dri + if (!try_module_get(serial->type->driver.owner)) + goto error_module_get; + ++ /* perform the standard setup */ ++ retval = tty_init_termios(tty); ++ if (retval) ++ goto error_init_termios; ++ + retval = usb_autopm_get_interface(serial->interface); + if (retval) + goto error_get_interface; + +- /* If the termios setup has yet to be done */ +- if (tty->driver->termios[idx] == NULL) { +- /* perform the standard setup */ +- retval = tty_init_termios(tty); +- if (retval) +- goto error_init_termios; +- /* allow the driver to update it */ +- if (serial->type->init_termios) +- serial->type->init_termios(tty); +- } + mutex_unlock(&serial->disc_mutex); + ++ /* allow the driver to update the settings */ ++ if (serial->type->init_termios) ++ serial->type->init_termios(tty); ++ + tty->driver_data = port; + + /* Final install (we use the default method) */ +@@ -234,9 +233,8 @@ static int serial_install(struct tty_dri + driver->ttys[idx] = tty; + return retval; + +- error_init_termios: +- usb_autopm_put_interface(serial->interface); + error_get_interface: ++ error_init_termios: + module_put(serial->type->driver.owner); + error_module_get: + error_no_port: diff --git a/tty/usb-serial-put-subroutines-in-logical-order.patch b/tty/usb-serial-put-subroutines-in-logical-order.patch new file mode 100644 index 00000000000000..d55df59a67ab59 --- /dev/null +++ b/tty/usb-serial-put-subroutines-in-logical-order.patch @@ -0,0 +1,230 @@ +From stern@rowland.harvard.edu Tue Sep 15 15:14:59 2009 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Tue, 1 Sep 2009 11:38:44 -0400 (EDT) +Subject: usb-serial: put subroutines in logical order +To: Greg KH <greg@kroah.com> +Message-ID: <Pine.LNX.4.44L0.0909011124170.2648-100000@iolanthe.rowland.org> + + +This patch (as1285) rearranges the subroutines in usb-serial.c +concerned with tty lifetimes into a more logical order: install, open, +hangup, close, release. It also updates the formatting of the +kerneldoc comments. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Cc: stable <stable@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/usb-serial.c | 154 ++++++++++++++++++++-------------------- + 1 file changed, 77 insertions(+), 77 deletions(-) + +--- a/drivers/usb/serial/usb-serial.c ++++ b/drivers/usb/serial/usb-serial.c +@@ -166,6 +166,41 @@ void usb_serial_put(struct usb_serial *s + /***************************************************************************** + * Driver tty interface functions + *****************************************************************************/ ++ ++/** ++ * serial_install - install tty ++ * @driver: the driver (USB in our case) ++ * @tty: the tty being created ++ * ++ * Create the termios objects for this tty. We use the default ++ * USB serial settings but permit them to be overridden by ++ * serial->type->init_termios. ++ */ ++static int serial_install(struct tty_driver *driver, struct tty_struct *tty) ++{ ++ int idx = tty->index; ++ struct usb_serial *serial; ++ int retval; ++ ++ /* If the termios setup has yet to be done */ ++ if (tty->driver->termios[idx] == NULL) { ++ /* perform the standard setup */ ++ retval = tty_init_termios(tty); ++ if (retval) ++ return retval; ++ /* allow the driver to update it */ ++ serial = usb_serial_get_by_index(tty->index); ++ if (serial->type->init_termios) ++ serial->type->init_termios(tty); ++ usb_serial_put(serial); ++ } ++ /* Final install (we use the default method) */ ++ tty_driver_kref_get(driver); ++ tty->count++; ++ driver->ttys[idx] = tty; ++ return 0; ++} ++ + static int serial_open (struct tty_struct *tty, struct file *filp) + { + struct usb_serial *serial; +@@ -264,13 +299,11 @@ bailout_serial_put: + } + + /** +- * serial_do_down - shut down hardware +- * @port: port to shut down ++ * serial_do_down - shut down hardware ++ * @port: port to shut down + * +- * Shut down a USB port unless it is the console. We never shut down the +- * console hardware as it will always be in use. +- * +- * Don't free any resources at this point ++ * Shut down a USB serial port unless it is the console. We never ++ * shut down the console hardware as it will always be in use. + */ + static void serial_do_down(struct usb_serial_port *port) + { +@@ -278,8 +311,10 @@ static void serial_do_down(struct usb_se + struct usb_serial *serial; + struct module *owner; + +- /* The console is magical, do not hang up the console hardware +- or there will be tears */ ++ /* ++ * The console is magical. Do not hang up the console hardware ++ * or there will be tears. ++ */ + if (port->console) + return; + +@@ -293,24 +328,50 @@ static void serial_do_down(struct usb_se + mutex_unlock(&port->mutex); + } + ++static void serial_hangup(struct tty_struct *tty) ++{ ++ struct usb_serial_port *port = tty->driver_data; ++ serial_do_down(port); ++ tty_port_hangup(&port->port); ++ /* We must not free port yet - the USB serial layer depends on it's ++ continued existence */ ++} ++ ++static void serial_close(struct tty_struct *tty, struct file *filp) ++{ ++ struct usb_serial_port *port = tty->driver_data; ++ ++ if (!port) ++ return; ++ ++ dbg("%s - port %d", __func__, port->number); ++ ++ if (tty_port_close_start(&port->port, tty, filp) == 0) ++ return; ++ serial_do_down(port); ++ tty_port_close_end(&port->port, tty); ++ tty_port_tty_set(&port->port, NULL); ++ ++} ++ + /** +- * serial_do_free - free resources post close/hangup +- * @port: port to free up ++ * serial_do_free - free resources post close/hangup ++ * @port: port to free up + * +- * Do the resource freeing and refcount dropping for the port. We must +- * be careful about ordering and we must avoid freeing up the console. ++ * Do the resource freeing and refcount dropping for the port. ++ * Avoid freeing the console. + * +- * Called when the last tty kref is dropped. ++ * Called when the last tty kref is dropped. + */ +- + static void serial_do_free(struct tty_struct *tty) + { + struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial; + struct module *owner; + +- /* The console is magical, do not hang up the console hardware +- or there will be tears */ ++ /* The console is magical. Do not hang up the console hardware ++ * or there will be tears. ++ */ + if (port == NULL || port->console) + return; + +@@ -326,32 +387,6 @@ static void serial_do_free(struct tty_st + module_put(owner); + } + +-static void serial_close(struct tty_struct *tty, struct file *filp) +-{ +- struct usb_serial_port *port = tty->driver_data; +- +- if (!port) +- return; +- +- dbg("%s - port %d", __func__, port->number); +- +- if (tty_port_close_start(&port->port, tty, filp) == 0) +- return; +- serial_do_down(port); +- tty_port_close_end(&port->port, tty); +- tty_port_tty_set(&port->port, NULL); +- +-} +- +-static void serial_hangup(struct tty_struct *tty) +-{ +- struct usb_serial_port *port = tty->driver_data; +- serial_do_down(port); +- tty_port_hangup(&port->port); +- /* We must not free port yet - the USB serial layer depends on it's +- continued existence */ +-} +- + static int serial_write(struct tty_struct *tty, const unsigned char *buf, + int count) + { +@@ -699,41 +734,6 @@ static const struct tty_port_operations + .dtr_rts = serial_dtr_rts, + }; + +-/** +- * serial_install - install tty +- * @driver: the driver (USB in our case) +- * @tty: the tty being created +- * +- * Create the termios objects for this tty. We use the default USB +- * serial ones but permit them to be overriddenby serial->type->termios. +- * This lets us remove all the ugly hackery +- */ +- +-static int serial_install(struct tty_driver *driver, struct tty_struct *tty) +-{ +- int idx = tty->index; +- struct usb_serial *serial; +- int retval; +- +- /* If the termios setup has yet to be done */ +- if (tty->driver->termios[idx] == NULL) { +- /* perform the standard setup */ +- retval = tty_init_termios(tty); +- if (retval) +- return retval; +- /* allow the driver to update it */ +- serial = usb_serial_get_by_index(tty->index); +- if (serial->type->init_termios) +- serial->type->init_termios(tty); +- usb_serial_put(serial); +- } +- /* Final install (we use the default method) */ +- tty_driver_kref_get(driver); +- tty->count++; +- driver->ttys[idx] = tty; +- return 0; +-} +- + int usb_serial_probe(struct usb_interface *interface, + const struct usb_device_id *id) + { diff --git a/tty/usb-serial-rename-subroutines.patch b/tty/usb-serial-rename-subroutines.patch new file mode 100644 index 00000000000000..d215a181bd2338 --- /dev/null +++ b/tty/usb-serial-rename-subroutines.patch @@ -0,0 +1,100 @@ +From stern@rowland.harvard.edu Tue Sep 15 15:22:28 2009 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Tue, 1 Sep 2009 11:39:40 -0400 (EDT) +Subject: usb-serial: rename subroutines +To: Greg KH <greg@kroah.com> +Message-ID: <Pine.LNX.4.44L0.0909011128490.2648-100000@iolanthe.rowland.org> + + +This patch (as1289) renames serial_do_down() to serial_down() and +serial_do_free() to serial_release(). It also adds a missing call to +tty_shutdown() in serial_release(). + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Cc: stable <stable@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/usb-serial.c | 19 +++++++++++-------- + 1 file changed, 11 insertions(+), 8 deletions(-) + +--- a/drivers/usb/serial/usb-serial.c ++++ b/drivers/usb/serial/usb-serial.c +@@ -191,7 +191,7 @@ void usb_serial_put(struct usb_serial *s + * 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_do_free(). ++ * All these actions are reversed in serial_release(). + */ + static int serial_install(struct tty_driver *driver, struct tty_struct *tty) + { +@@ -296,13 +296,13 @@ bailout_mutex_unlock: + } + + /** +- * serial_do_down - shut down hardware ++ * serial_down - shut down hardware + * @port: port to shut down + * + * Shut down a USB serial port unless it is the console. We never + * shut down the console hardware as it will always be in use. + */ +-static void serial_do_down(struct usb_serial_port *port) ++static void serial_down(struct usb_serial_port *port) + { + struct usb_serial_driver *drv = port->serial->type; + struct usb_serial *serial; +@@ -328,7 +328,7 @@ static void serial_do_down(struct usb_se + static void serial_hangup(struct tty_struct *tty) + { + struct usb_serial_port *port = tty->driver_data; +- serial_do_down(port); ++ serial_down(port); + tty_port_hangup(&port->port); + /* We must not free port yet - the USB serial layer depends on it's + continued existence */ +@@ -342,13 +342,13 @@ static void serial_close(struct tty_stru + + if (tty_port_close_start(&port->port, tty, filp) == 0) + return; +- serial_do_down(port); ++ serial_down(port); + tty_port_close_end(&port->port, tty); + tty_port_tty_set(&port->port, NULL); + } + + /** +- * serial_do_free - free resources post close/hangup ++ * serial_release - free resources post close/hangup + * @port: port to free up + * + * Do the resource freeing and refcount dropping for the port. +@@ -356,7 +356,7 @@ static void serial_close(struct tty_stru + * + * Called when the last tty kref is dropped. + */ +-static void serial_do_free(struct tty_struct *tty) ++static void serial_release(struct tty_struct *tty) + { + struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial; +@@ -368,6 +368,9 @@ static void serial_do_free(struct tty_st + if (port->console) + return; + ++ /* Standard shutdown processing */ ++ tty_shutdown(tty); ++ + tty->driver_data = NULL; + + serial = port->serial; +@@ -1204,7 +1207,7 @@ static const struct tty_operations seria + .chars_in_buffer = serial_chars_in_buffer, + .tiocmget = serial_tiocmget, + .tiocmset = serial_tiocmset, +- .shutdown = serial_do_free, ++ .shutdown = serial_release, + .install = serial_install, + .proc_fops = &serial_proc_fops, + }; diff --git a/tty/usb-serial-straighten-out-serial_open.patch b/tty/usb-serial-straighten-out-serial_open.patch new file mode 100644 index 00000000000000..b5be63198a140e --- /dev/null +++ b/tty/usb-serial-straighten-out-serial_open.patch @@ -0,0 +1,104 @@ +From stern@rowland.harvard.edu Tue Sep 15 15:23:02 2009 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Tue, 1 Sep 2009 11:39:59 -0400 (EDT) +Subject: usb-serial: straighten out serial_open +To: Greg KH <greg@kroah.com> +Message-ID: <Pine.LNX.4.44L0.0909011135470.2648-100000@iolanthe.rowland.org> + + +This patch (as1291) removes a bunch of code from serial_open(), things +that were rendered unnecessary by earlier patches. A missing spinlock +is added to protect port->port.count, which needs to be incremented +even if the open fails but not if the tty has gotten a hangup. The +test for whether the hardware has been initialized, based on the use +count, is replaced by a more transparent test of the +ASYNCB_INITIALIZED bit in the port flags. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Cc: stable <stable@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/usb-serial.c | 59 ++++++++++++++-------------------------- + 1 file changed, 22 insertions(+), 37 deletions(-) + +--- a/drivers/usb/serial/usb-serial.c ++++ b/drivers/usb/serial/usb-serial.c +@@ -245,55 +245,40 @@ static int serial_install(struct tty_dri + return retval; + } + +-static int serial_open (struct tty_struct *tty, struct file *filp) ++static int serial_open(struct tty_struct *tty, struct file *filp) + { +- struct usb_serial *serial; +- struct usb_serial_port *port; +- int retval = 0; +- int first = 0; +- +- port = tty->driver_data; +- serial = port->serial; ++ struct usb_serial_port *port = tty->driver_data; ++ struct usb_serial *serial = port->serial; ++ int retval; + + dbg("%s - port %d", __func__, port->number); + +- if (mutex_lock_interruptible(&port->mutex)) +- return -ERESTARTSYS; +- +- ++port->port.count; ++ spin_lock_irq(&port->port.lock); ++ if (!tty_hung_up_p(filp)) ++ ++port->port.count; ++ spin_unlock_irq(&port->port.lock); + tty_port_tty_set(&port->port, tty); + +- /* If the console is attached, the device is already open */ +- if (port->port.count == 1 && !port->console) { +- first = 1; ++ /* Do the device-specific open only if the hardware isn't ++ * already initialized. ++ */ ++ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) { ++ if (mutex_lock_interruptible(&port->mutex)) ++ return -ERESTARTSYS; + mutex_lock(&serial->disc_mutex); +- +- /* only call the device specific open if this +- * is the first time the port is opened */ +- retval = serial->type->open(tty, port); +- if (retval) +- goto bailout_module_put; ++ if (serial->disconnected) ++ retval = -ENODEV; ++ else ++ retval = port->serial->type->open(tty, port); + mutex_unlock(&serial->disc_mutex); ++ mutex_unlock(&port->mutex); ++ if (retval) ++ return retval; + set_bit(ASYNCB_INITIALIZED, &port->port.flags); + } +- mutex_unlock(&port->mutex); ++ + /* Now do the correct tty layer semantics */ + retval = tty_port_block_til_ready(&port->port, tty, filp); +- if (retval == 0) { +- if (!first) +- usb_serial_put(serial); +- return 0; +- } +- mutex_lock(&port->mutex); +- if (first == 0) +- goto bailout_mutex_unlock; +- /* Undo the initial port actions */ +- mutex_lock(&serial->disc_mutex); +-bailout_module_put: +- mutex_unlock(&serial->disc_mutex); +-bailout_mutex_unlock: +- port->port.count = 0; +- mutex_unlock(&port->mutex); + return retval; + } + |
