aboutsummaryrefslogtreecommitdiffstats
path: root/tty
diff options
Diffstat (limited to 'tty')
-rw-r--r--tty/tty-kref-put-async1
-rw-r--r--tty/tty-port-close-fn1
-rw-r--r--tty/tty-usb-cdc-fix-speed1
-rw-r--r--tty/tty-usb-clean-dtr-rts1
-rw-r--r--tty/tty-usb-drop-filp-argp22
-rw-r--r--tty/tty-usb-serial-termiosbits6
-rw-r--r--tty/tty-usb-shutdown7
-rw-r--r--tty/tty-usb-vhangup3
-rw-r--r--tty/usb-serial-acquire-references-when-a-new-tty-is-installed.patch223
-rw-r--r--tty/usb-serial-add-missing-tests-and-debug-lines.patch94
-rw-r--r--tty/usb-serial-change-logic-of-serial-lookups.patch119
-rw-r--r--tty/usb-serial-change-referencing-of-port-and-serial-structures.patch235
-rw-r--r--tty/usb-serial-fix-termios-initialization-logic.patch66
-rw-r--r--tty/usb-serial-put-subroutines-in-logical-order.patch230
-rw-r--r--tty/usb-serial-rename-subroutines.patch100
-rw-r--r--tty/usb-serial-straighten-out-serial_open.patch104
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;
+ }
+