--- /dev/null
+From 2023c610dc54a4f4130b0494309a9bd668ca3df8 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Thu, 30 Jul 2009 15:27:18 -0400
+Subject: Driver core: add new device to bus's list before probing
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit 2023c610dc54a4f4130b0494309a9bd668ca3df8 upstream.
+
+This patch (as1271) affects when new devices get linked into their
+bus's list of devices. Currently this happens after probing, and it
+doesn't happen at all if probing fails. Clearly this is wrong,
+because at that point quite a few symbolic links have already been
+created in sysfs. We are committed to adding the device, so it should
+be linked into the bus's list regardless.
+
+In addition, this needs to happen before the uevent announcing the new
+device gets issued. Otherwise user programs might try to access the
+device before it has been added to the bus.
+
+To fix both these problems, the patch moves the call to
+klist_add_tail() forward from bus_attach_device() to bus_add_device().
+Since bus_attach_device() now does nothing but probe for drivers, it
+has been renamed to bus_probe_device(). And lastly, the kerneldoc is
+updated.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+CC: Kay Sievers <kay.sievers@vrfy.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/base/base.h | 2 +-
+ drivers/base/bus.c | 23 ++++++++++-------------
+ drivers/base/core.c | 2 +-
+ 3 files changed, 12 insertions(+), 15 deletions(-)
+
+--- a/drivers/base/base.h
++++ b/drivers/base/base.h
+@@ -104,7 +104,7 @@ extern int system_bus_init(void);
+ extern int cpu_dev_init(void);
+
+ extern int bus_add_device(struct device *dev);
+-extern void bus_attach_device(struct device *dev);
++extern void bus_probe_device(struct device *dev);
+ extern void bus_remove_device(struct device *dev);
+
+ extern int bus_add_driver(struct device_driver *drv);
+--- a/drivers/base/bus.c
++++ b/drivers/base/bus.c
+@@ -459,8 +459,9 @@ static inline void remove_deprecated_bus
+ * bus_add_device - add device to bus
+ * @dev: device being added
+ *
++ * - Add device's bus attributes.
++ * - Create links to device's bus.
+ * - Add the device to its bus's list of devices.
+- * - Create link to device's bus.
+ */
+ int bus_add_device(struct device *dev)
+ {
+@@ -483,6 +484,7 @@ int bus_add_device(struct device *dev)
+ error = make_deprecated_bus_links(dev);
+ if (error)
+ goto out_deprecated;
++ klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
+ }
+ return 0;
+
+@@ -498,24 +500,19 @@ out_put:
+ }
+
+ /**
+- * bus_attach_device - add device to bus
+- * @dev: device tried to attach to a driver
++ * bus_probe_device - probe drivers for a new device
++ * @dev: device to probe
+ *
+- * - Add device to bus's list of devices.
+- * - Try to attach to driver.
++ * - Automatically probe for a driver if the bus allows it.
+ */
+-void bus_attach_device(struct device *dev)
++void bus_probe_device(struct device *dev)
+ {
+ struct bus_type *bus = dev->bus;
+- int ret = 0;
++ int ret;
+
+- if (bus) {
+- if (bus->p->drivers_autoprobe)
+- ret = device_attach(dev);
++ if (bus && bus->p->drivers_autoprobe) {
++ ret = device_attach(dev);
+ WARN_ON(ret < 0);
+- if (ret >= 0)
+- klist_add_tail(&dev->p->knode_bus,
+- &bus->p->klist_devices);
+ }
+ }
+
+--- a/drivers/base/core.c
++++ b/drivers/base/core.c
+@@ -945,7 +945,7 @@ int device_add(struct device *dev)
+ BUS_NOTIFY_ADD_DEVICE, dev);
+
+ kobject_uevent(&dev->kobj, KOBJ_ADD);
+- bus_attach_device(dev);
++ bus_probe_device(dev);
+ if (parent)
+ klist_add_tail(&dev->p->knode_parent,
+ &parent->p->klist_children);
--- /dev/null
+From 2c2a6172afab7421f6af7e228cd3121f423ea932 Mon Sep 17 00:00:00 2001
+From: Luca Tettamanti <kronos.it@gmail.com>
+Date: Tue, 15 Sep 2009 17:18:10 +0200
+Subject: hwmon: (asus_atk0110) Add maintainer information
+
+From: Luca Tettamanti <kronos.it@gmail.com>
+
+commit 2c2a6172afab7421f6af7e228cd3121f423ea932 upstream.
+
+Add myself as asus_atk0110 maintainer.
+
+Signed-off-by: Luca Tettamanti <kronos.it@gmail.com>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ MAINTAINERS | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -897,6 +897,12 @@ W: http://wireless.kernel.org/en/users/D
+ S: Maintained
+ F: drivers/net/wireless/ath/ar9170/
+
++ATK0110 HWMON DRIVER
++M: Luca Tettamanti <kronos.it@gmail.com>
++L: lm-sensors@lm-sensors.org
++S: Maintained
++F: drivers/hwmon/asus_atk0110.c
++
+ ATI_REMOTE2 DRIVER
+ M: Ville Syrjala <syrjala@sci.fi>
+ S: Maintained
netfilter-ebt_ulog-fix-checkentry-return-value.patch
ath5k-wakeup-fixes.patch
ath5k-do-not-release-irq-across-suspend-resume.patch
+driver-core-add-new-device-to-bus-s-list-before-probing.patch
+tty-add-a-full-port_close-function.patch
+tty-usb-hangup-is-racy.patch
+tty-usb-can-now-use-the-shutdown-method-for-kref-based-freeing-of-ports.patch
+hwmon-add-maintainer-information.patch
+tty-usb-serial-termios-bits.patch
+usb-serial-change-referencing-of-port-and-serial-structures.patch
+usb-serial-put-subroutines-in-logical-order.patch
+usb-serial-change-logic-of-serial-lookups.patch
+usb-serial-acquire-references-when-a-new-tty-is-installed.patch
+usb-serial-fix-termios-initialization-logic.patch
+usb-serial-rename-subroutines.patch
+usb-serial-add-missing-tests-and-debug-lines.patch
+usb-serial-straighten-out-serial_open.patch
+usb-serial-update-the-console-driver.patch
--- /dev/null
+From 7ca0ff9ab3218ec443a7a9ad247e4650373ed41e Mon Sep 17 00:00:00 2001
+From: Alan Cox <alan@linux.intel.com>
+Date: Sat, 19 Sep 2009 13:13:20 -0700
+Subject: tty: Add a full port_close function
+
+From: Alan Cox <alan@linux.intel.com>
+
+commit 7ca0ff9ab3218ec443a7a9ad247e4650373ed41e upstream.
+
+Now we are extracting out methods for shutdown and the like we can add a
+proper tty_port_close method that knows all the innards of the tty closing
+process and hides the lot from the caller.
+
+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>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/tty_port.c | 29 +++++++++++++++++++++++++++--
+ include/linux/tty.h | 8 +++++++-
+ 2 files changed, 34 insertions(+), 3 deletions(-)
+
+--- a/drivers/char/tty_port.c
++++ b/drivers/char/tty_port.c
+@@ -96,6 +96,14 @@ void tty_port_tty_set(struct tty_port *p
+ }
+ EXPORT_SYMBOL(tty_port_tty_set);
+
++static void tty_port_shutdown(struct tty_port *port)
++{
++ if (port->ops->shutdown &&
++ test_and_clear_bit(ASYNC_INITIALIZED, &port->flags))
++ port->ops->shutdown(port);
++
++}
++
+ /**
+ * tty_port_hangup - hangup helper
+ * @port: tty port
+@@ -116,6 +124,7 @@ void tty_port_hangup(struct tty_port *po
+ port->tty = NULL;
+ spin_unlock_irqrestore(&port->lock, flags);
+ wake_up_interruptible(&port->open_wait);
++ tty_port_shutdown(port);
+ }
+ EXPORT_SYMBOL(tty_port_hangup);
+
+@@ -296,15 +305,17 @@ int tty_port_close_start(struct tty_port
+
+ if (port->count) {
+ spin_unlock_irqrestore(&port->lock, flags);
++ if (port->ops->drop)
++ port->ops->drop(port);
+ return 0;
+ }
+- port->flags |= ASYNC_CLOSING;
++ set_bit(ASYNC_CLOSING, &port->flags);
+ tty->closing = 1;
+ spin_unlock_irqrestore(&port->lock, flags);
+ /* Don't block on a stalled port, just pull the chain */
+ if (tty->flow_stopped)
+ tty_driver_flush_buffer(tty);
+- if (port->flags & ASYNC_INITIALIZED &&
++ if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
+ port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, port->closing_wait);
+ if (port->drain_delay) {
+@@ -318,6 +329,9 @@ int tty_port_close_start(struct tty_port
+ timeout = 2 * HZ;
+ schedule_timeout_interruptible(timeout);
+ }
++ /* Don't call port->drop for the last reference. Callers will want
++ to drop the last active reference in ->shutdown() or the tty
++ shutdown path */
+ return 1;
+ }
+ EXPORT_SYMBOL(tty_port_close_start);
+@@ -348,3 +362,14 @@ void tty_port_close_end(struct tty_port
+ spin_unlock_irqrestore(&port->lock, flags);
+ }
+ EXPORT_SYMBOL(tty_port_close_end);
++
++void tty_port_close(struct tty_port *port, struct tty_struct *tty,
++ struct file *filp)
++{
++ if (tty_port_close_start(port, tty, filp) == 0)
++ return;
++ tty_port_shutdown(port);
++ tty_port_close_end(port, tty);
++ tty_port_tty_set(port, NULL);
++}
++EXPORT_SYMBOL(tty_port_close);
+--- a/include/linux/tty.h
++++ b/include/linux/tty.h
+@@ -185,7 +185,12 @@ struct tty_port;
+ struct tty_port_operations {
+ /* Return 1 if the carrier is raised */
+ int (*carrier_raised)(struct tty_port *port);
++ /* Control the DTR line */
+ void (*dtr_rts)(struct tty_port *port, int raise);
++ /* Called when the last close completes or a hangup finishes
++ IFF the port was initialized. Do not use to free resources */
++ void (*shutdown)(struct tty_port *port);
++ void (*drop)(struct tty_port *port);
+ };
+
+ struct tty_port {
+@@ -457,7 +462,8 @@ extern int tty_port_block_til_ready(stru
+ extern int tty_port_close_start(struct tty_port *port,
+ struct tty_struct *tty, struct file *filp);
+ extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty);
+-
++extern void tty_port_close(struct tty_port *port,
++ struct tty_struct *tty, struct file *filp);
+ extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
+ extern int tty_unregister_ldisc(int disc);
+ extern int tty_set_ldisc(struct tty_struct *tty, int ldisc);
--- /dev/null
+From 4455e344959a217ffc28de2ab1af87541322b343 Mon Sep 17 00:00:00 2001
+From: Alan Cox <alan@linux.intel.com>
+Date: Sat, 19 Sep 2009 13:13:24 -0700
+Subject: tty: USB can now use the shutdown method for kref based freeing of ports
+
+From: Alan Cox <alan@linux.intel.com>
+
+commit 4455e344959a217ffc28de2ab1af87541322b343 upstream.
+
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/usb-serial.c | 28 +++++++---------------------
+ 1 file changed, 7 insertions(+), 21 deletions(-)
+
+--- a/drivers/usb/serial/usb-serial.c
++++ b/drivers/usb/serial/usb-serial.c
+@@ -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.
++ *
++ * Called when the last tty kref is dropped.
+ */
+
+-static void serial_do_free(struct usb_serial_port *port)
++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 */
+- if (port->console)
++ if (port == NULL || port->console)
+ return;
+
+ serial = port->serial;
+@@ -350,30 +353,12 @@ static void serial_close(struct tty_stru
+
+ dbg("%s - port %d", __func__, port->number);
+
+- /* FIXME:
+- This leaves a very narrow race. Really we should do the
+- serial_do_free() on tty->shutdown(), but tty->shutdown can
+- be called from IRQ context and serial_do_free can sleep.
+-
+- The right fix is probably to make the tty free (which is rare)
+- and thus tty->shutdown() occur via a work queue and simplify all
+- the drivers that use it.
+- */
+- if (tty_hung_up_p(filp)) {
+- /* serial_hangup already called serial_down at this point.
+- Another user may have already reopened the port but
+- serial_do_free is refcounted */
+- serial_do_free(port);
+- return;
+- }
+-
+ 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(port);
++
+ }
+
+ static void serial_hangup(struct tty_struct *tty)
+@@ -1243,6 +1228,7 @@ static const struct tty_operations seria
+ .chars_in_buffer = serial_chars_in_buffer,
+ .tiocmget = serial_tiocmget,
+ .tiocmset = serial_tiocmset,
++ .shutdown = serial_do_free,
+ .proc_fops = &serial_proc_fops,
+ };
+
--- /dev/null
+From d2b391822a11302add9e46476f3da4e18e6de84c Mon Sep 17 00:00:00 2001
+From: Alan Cox <alan@linux.intel.com>
+Date: Sat, 19 Sep 2009 13:13:23 -0700
+Subject: tty: USB hangup is racy
+
+From: Alan Cox <alan@linux.intel.com>
+
+commit d2b391822a11302add9e46476f3da4e18e6de84c upstream.
+
+The USB layer uses tty_hangup to deal with unplugs of the physical hardware
+(analogous to loss of carrier) and then frees the resources. However the
+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>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/usb-serial.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+--- a/drivers/usb/serial/usb-serial.c
++++ b/drivers/usb/serial/usb-serial.c
+@@ -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) {
+- /* The hangup will occur asynchronously but
+- the object refcounts will sort out all the
+- cleanup */
+- tty_hangup(tty);
++ tty_vhangup(tty);
+ tty_kref_put(tty);
+ }
+ kill_traffic(port);
--- /dev/null
+From fe1ae7fdd2ee603f2d95f04e09a68f7f79045127 Mon Sep 17 00:00:00 2001
+From: Alan Cox <alan@linux.intel.com>
+Date: Sat, 19 Sep 2009 13:13:33 -0700
+Subject: tty: USB serial termios bits
+
+From: Alan Cox <alan@linux.intel.com>
+
+commit fe1ae7fdd2ee603f2d95f04e09a68f7f79045127 upstream.
+
+Various drivers have hacks to mangle termios structures. This stems from
+the fact there is no nice setup hook for configuring the termios settings
+when the port is created
+
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/tty_io.c | 1
+ drivers/usb/serial/ark3116.c | 46 +++++++++------------------------------
+ drivers/usb/serial/cypress_m8.c | 12 ++--------
+ drivers/usb/serial/empeg.c | 12 ++--------
+ drivers/usb/serial/iuu_phoenix.c | 31 +++++++++++---------------
+ drivers/usb/serial/kobil_sct.c | 22 +++++++++---------
+ drivers/usb/serial/oti6858.c | 21 ++++++++---------
+ drivers/usb/serial/spcp8x5.c | 21 ++++++++---------
+ drivers/usb/serial/usb-serial.c | 38 +++++++++++++++++++++++++++++++-
+ drivers/usb/serial/whiteheat.c | 6 ++---
+ include/linux/usb/serial.h | 3 ++
+ 11 files changed, 106 insertions(+), 107 deletions(-)
+
+--- a/drivers/char/tty_io.c
++++ b/drivers/char/tty_io.c
+@@ -1184,6 +1184,7 @@ int tty_init_termios(struct tty_struct *
+ tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+ return 0;
+ }
++EXPORT_SYMBOL_GPL(tty_init_termios);
+
+ /**
+ * tty_driver_install_tty() - install a tty entry in the driver
+--- a/drivers/usb/serial/ark3116.c
++++ b/drivers/usb/serial/ark3116.c
+@@ -35,11 +35,6 @@ static struct usb_device_id id_table []
+ };
+ MODULE_DEVICE_TABLE(usb, id_table);
+
+-struct ark3116_private {
+- spinlock_t lock;
+- u8 termios_initialized;
+-};
+-
+ static inline void ARK3116_SND(struct usb_serial *serial, int seq,
+ __u8 request, __u8 requesttype,
+ __u16 value, __u16 index)
+@@ -82,22 +77,11 @@ static inline void ARK3116_RCV_QUIET(str
+ static int ark3116_attach(struct usb_serial *serial)
+ {
+ char *buf;
+- struct ark3116_private *priv;
+- int i;
+-
+- for (i = 0; i < serial->num_ports; ++i) {
+- priv = kzalloc(sizeof(struct ark3116_private), GFP_KERNEL);
+- if (!priv)
+- goto cleanup;
+- spin_lock_init(&priv->lock);
+-
+- usb_set_serial_port_data(serial->port[i], priv);
+- }
+
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf) {
+ dbg("error kmalloc -> out of mem?");
+- goto cleanup;
++ return -ENOMEM;
+ }
+
+ /* 3 */
+@@ -149,13 +133,16 @@ static int ark3116_attach(struct usb_ser
+
+ kfree(buf);
+ return 0;
++}
+
+-cleanup:
+- for (--i; i >= 0; --i) {
+- kfree(usb_get_serial_port_data(serial->port[i]));
+- usb_set_serial_port_data(serial->port[i], NULL);
+- }
+- return -ENOMEM;
++static void ark3116_init_termios(struct tty_struct *tty)
++{
++ struct ktermios *termios = tty->termios;
++ *termios = tty_std_termios;
++ termios->c_cflag = B9600 | CS8
++ | CREAD | HUPCL | CLOCAL;
++ termios->c_ispeed = 9600;
++ termios->c_ospeed = 9600;
+ }
+
+ static void ark3116_set_termios(struct tty_struct *tty,
+@@ -163,10 +150,8 @@ static void ark3116_set_termios(struct t
+ struct ktermios *old_termios)
+ {
+ struct usb_serial *serial = port->serial;
+- struct ark3116_private *priv = usb_get_serial_port_data(port);
+ struct ktermios *termios = tty->termios;
+ unsigned int cflag = termios->c_cflag;
+- unsigned long flags;
+ int baud;
+ int ark3116_baud;
+ char *buf;
+@@ -176,16 +161,6 @@ static void ark3116_set_termios(struct t
+
+ dbg("%s - port %d", __func__, port->number);
+
+- spin_lock_irqsave(&priv->lock, flags);
+- if (!priv->termios_initialized) {
+- *termios = tty_std_termios;
+- termios->c_cflag = B9600 | CS8
+- | CREAD | HUPCL | CLOCAL;
+- termios->c_ispeed = 9600;
+- termios->c_ospeed = 9600;
+- priv->termios_initialized = 1;
+- }
+- spin_unlock_irqrestore(&priv->lock, flags);
+
+ cflag = termios->c_cflag;
+ termios->c_cflag &= ~(CMSPAR|CRTSCTS);
+@@ -455,6 +430,7 @@ static struct usb_serial_driver ark3116_
+ .num_ports = 1,
+ .attach = ark3116_attach,
+ .set_termios = ark3116_set_termios,
++ .init_termios = ark3116_init_termios,
+ .ioctl = ark3116_ioctl,
+ .tiocmget = ark3116_tiocmget,
+ .open = ark3116_open,
+--- a/drivers/usb/serial/cypress_m8.c
++++ b/drivers/usb/serial/cypress_m8.c
+@@ -659,15 +659,7 @@ static int cypress_open(struct tty_struc
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Set termios */
+- result = cypress_write(tty, port, NULL, 0);
+-
+- if (result) {
+- dev_err(&port->dev,
+- "%s - failed setting the control lines - error %d\n",
+- __func__, result);
+- return result;
+- } else
+- dbg("%s - success setting the control lines", __func__);
++ cypress_send(port);
+
+ if (tty)
+ cypress_set_termios(tty, port, &priv->tmp_termios);
+@@ -1005,6 +997,8 @@ static void cypress_set_termios(struct t
+ dbg("%s - port %d", __func__, port->number);
+
+ spin_lock_irqsave(&priv->lock, flags);
++ /* We can't clean this one up as we don't know the device type
++ early enough */
+ if (!priv->termios_initialized) {
+ if (priv->chiptype == CT_EARTHMATE) {
+ *(tty->termios) = tty_std_termios;
+--- a/drivers/usb/serial/empeg.c
++++ b/drivers/usb/serial/empeg.c
+@@ -90,8 +90,7 @@ static int empeg_chars_in_buffer(struct
+ static void empeg_throttle(struct tty_struct *tty);
+ static void empeg_unthrottle(struct tty_struct *tty);
+ static int empeg_startup(struct usb_serial *serial);
+-static void empeg_set_termios(struct tty_struct *tty,
+- struct usb_serial_port *port, struct ktermios *old_termios);
++static void empeg_init_termios(struct tty_struct *tty);
+ static void empeg_write_bulk_callback(struct urb *urb);
+ static void empeg_read_bulk_callback(struct urb *urb);
+
+@@ -123,7 +122,7 @@ static struct usb_serial_driver empeg_de
+ .throttle = empeg_throttle,
+ .unthrottle = empeg_unthrottle,
+ .attach = empeg_startup,
+- .set_termios = empeg_set_termios,
++ .init_termios = empeg_init_termios,
+ .write = empeg_write,
+ .write_room = empeg_write_room,
+ .chars_in_buffer = empeg_chars_in_buffer,
+@@ -150,9 +149,6 @@ static int empeg_open(struct tty_struct
+
+ dbg("%s - port %d", __func__, port->number);
+
+- /* Force default termio settings */
+- empeg_set_termios(tty, port, NULL) ;
+-
+ bytes_in = 0;
+ bytes_out = 0;
+
+@@ -425,11 +421,9 @@ static int empeg_startup(struct usb_ser
+ }
+
+
+-static void empeg_set_termios(struct tty_struct *tty,
+- struct usb_serial_port *port, struct ktermios *old_termios)
++static void empeg_init_termios(struct tty_struct *tty)
+ {
+ struct ktermios *termios = tty->termios;
+- dbg("%s - port %d", __func__, port->number);
+
+ /*
+ * The empeg-car player wants these particular tty settings.
+--- a/drivers/usb/serial/iuu_phoenix.c
++++ b/drivers/usb/serial/iuu_phoenix.c
+@@ -71,7 +71,6 @@ struct iuu_private {
+ spinlock_t lock; /* store irq state */
+ wait_queue_head_t delta_msr_wait;
+ u8 line_status;
+- u8 termios_initialized;
+ int tiostatus; /* store IUART SIGNAL for tiocmget call */
+ u8 reset; /* if 1 reset is needed */
+ int poll; /* number of poll */
+@@ -1018,6 +1017,18 @@ static void iuu_close(struct usb_serial_
+ }
+ }
+
++static void iuu_init_termios(struct tty_struct *tty)
++{
++ *(tty->termios) = tty_std_termios;
++ tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
++ | TIOCM_CTS | CSTOPB | PARENB;
++ tty->termios->c_ispeed = 9600;
++ tty->termios->c_ospeed = 9600;
++ tty->termios->c_lflag = 0;
++ tty->termios->c_oflag = 0;
++ tty->termios->c_iflag = 0;
++}
++
+ static int iuu_open(struct tty_struct *tty,
+ struct usb_serial_port *port, struct file *filp)
+ {
+@@ -1025,7 +1036,6 @@ static int iuu_open(struct tty_struct *t
+ u8 *buf;
+ int result;
+ u32 actual;
+- unsigned long flags;
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+
+ dbg("%s - port %d", __func__, port->number);
+@@ -1064,21 +1074,7 @@ static int iuu_open(struct tty_struct *t
+ port->bulk_in_buffer, 512,
+ NULL, NULL);
+
+- /* set the termios structure */
+- spin_lock_irqsave(&priv->lock, flags);
+- if (tty && !priv->termios_initialized) {
+- *(tty->termios) = tty_std_termios;
+- tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
+- | TIOCM_CTS | CSTOPB | PARENB;
+- tty->termios->c_ispeed = 9600;
+- tty->termios->c_ospeed = 9600;
+- tty->termios->c_lflag = 0;
+- tty->termios->c_oflag = 0;
+- tty->termios->c_iflag = 0;
+- priv->termios_initialized = 1;
+- priv->poll = 0;
+- }
+- spin_unlock_irqrestore(&priv->lock, flags);
++ priv->poll = 0;
+
+ /* initialize writebuf */
+ #define FISH(a, b, c, d) do { \
+@@ -1201,6 +1197,7 @@ static struct usb_serial_driver iuu_devi
+ .tiocmget = iuu_tiocmget,
+ .tiocmset = iuu_tiocmset,
+ .set_termios = iuu_set_termios,
++ .init_termios = iuu_init_termios,
+ .attach = iuu_startup,
+ .release = iuu_release,
+ };
+--- a/drivers/usb/serial/kobil_sct.c
++++ b/drivers/usb/serial/kobil_sct.c
+@@ -85,7 +85,7 @@ static void kobil_read_int_callback(stru
+ static void kobil_write_callback(struct urb *purb);
+ static void kobil_set_termios(struct tty_struct *tty,
+ struct usb_serial_port *port, struct ktermios *old);
+-
++static void kobil_init_termios(struct tty_struct *tty);
+
+ static struct usb_device_id id_table [] = {
+ { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) },
+@@ -120,6 +120,7 @@ static struct usb_serial_driver kobil_de
+ .release = kobil_release,
+ .ioctl = kobil_ioctl,
+ .set_termios = kobil_set_termios,
++ .init_termios = kobil_init_termios,
+ .tiocmget = kobil_tiocmget,
+ .tiocmset = kobil_tiocmset,
+ .open = kobil_open,
+@@ -210,6 +211,15 @@ static void kobil_release(struct usb_ser
+ kfree(usb_get_serial_port_data(serial->port[i]));
+ }
+
++static void kobil_init_termios(struct tty_struct *tty)
++{
++ /* Default to echo off and other sane device settings */
++ tty->termios->c_lflag = 0;
++ tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
++ tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
++ /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */
++ tty->termios->c_oflag &= ~ONLCR;
++}
+
+ static int kobil_open(struct tty_struct *tty,
+ struct usb_serial_port *port, struct file *filp)
+@@ -226,16 +236,6 @@ static int kobil_open(struct tty_struct
+ /* someone sets the dev to 0 if the close method has been called */
+ port->interrupt_in_urb->dev = port->serial->dev;
+
+- if (tty) {
+-
+- /* Default to echo off and other sane device settings */
+- tty->termios->c_lflag = 0;
+- tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN |
+- XCASE);
+- tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
+- /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */
+- tty->termios->c_oflag &= ~ONLCR;
+- }
+ /* allocate memory for transfer buffer */
+ transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
+ if (!transfer_buffer)
+--- a/drivers/usb/serial/oti6858.c
++++ b/drivers/usb/serial/oti6858.c
+@@ -146,6 +146,7 @@ static int oti6858_open(struct tty_struc
+ static void oti6858_close(struct usb_serial_port *port);
+ static void oti6858_set_termios(struct tty_struct *tty,
+ struct usb_serial_port *port, struct ktermios *old);
++static void oti6858_init_termios(struct tty_struct *tty);
+ static int oti6858_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg);
+ static void oti6858_read_int_callback(struct urb *urb);
+@@ -186,6 +187,7 @@ static struct usb_serial_driver oti6858_
+ .write = oti6858_write,
+ .ioctl = oti6858_ioctl,
+ .set_termios = oti6858_set_termios,
++ .init_termios = oti6858_init_termios,
+ .tiocmget = oti6858_tiocmget,
+ .tiocmset = oti6858_tiocmset,
+ .read_bulk_callback = oti6858_read_bulk_callback,
+@@ -206,7 +208,6 @@ struct oti6858_private {
+ struct {
+ u8 read_urb_in_use;
+ u8 write_urb_in_use;
+- u8 termios_initialized;
+ } flags;
+ struct delayed_work delayed_write_work;
+
+@@ -447,6 +448,14 @@ static int oti6858_chars_in_buffer(struc
+ return chars;
+ }
+
++static void oti6858_init_termios(struct tty_struct *tty)
++{
++ *(tty->termios) = tty_std_termios;
++ tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
++ tty->termios->c_ispeed = 38400;
++ tty->termios->c_ospeed = 38400;
++}
++
+ static void oti6858_set_termios(struct tty_struct *tty,
+ struct usb_serial_port *port, struct ktermios *old_termios)
+ {
+@@ -464,16 +473,6 @@ static void oti6858_set_termios(struct t
+ return;
+ }
+
+- spin_lock_irqsave(&priv->lock, flags);
+- if (!priv->flags.termios_initialized) {
+- *(tty->termios) = tty_std_termios;
+- tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
+- tty->termios->c_ispeed = 38400;
+- tty->termios->c_ospeed = 38400;
+- priv->flags.termios_initialized = 1;
+- }
+- spin_unlock_irqrestore(&priv->lock, flags);
+-
+ cflag = tty->termios->c_cflag;
+
+ spin_lock_irqsave(&priv->lock, flags);
+--- a/drivers/usb/serial/spcp8x5.c
++++ b/drivers/usb/serial/spcp8x5.c
+@@ -299,7 +299,6 @@ struct spcp8x5_private {
+ wait_queue_head_t delta_msr_wait;
+ u8 line_control;
+ u8 line_status;
+- u8 termios_initialized;
+ };
+
+ /* desc : when device plug in,this function would be called.
+@@ -498,6 +497,15 @@ static void spcp8x5_close(struct usb_ser
+ dev_dbg(&port->dev, "usb_unlink_urb(read_urb) = %d\n", result);
+ }
+
++static void spcp8x5_init_termios(struct tty_struct *tty)
++{
++ /* for the 1st time call this function */
++ *(tty->termios) = tty_std_termios;
++ tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
++ tty->termios->c_ispeed = 115200;
++ tty->termios->c_ospeed = 115200;
++}
++
+ /* set the serial param for transfer. we should check if we really need to
+ * transfer. if we set flow control we should do this too. */
+ static void spcp8x5_set_termios(struct tty_struct *tty,
+@@ -514,16 +522,6 @@ static void spcp8x5_set_termios(struct t
+ int i;
+ u8 control;
+
+- /* for the 1st time call this function */
+- spin_lock_irqsave(&priv->lock, flags);
+- if (!priv->termios_initialized) {
+- *(tty->termios) = tty_std_termios;
+- tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
+- tty->termios->c_ispeed = 115200;
+- tty->termios->c_ospeed = 115200;
+- priv->termios_initialized = 1;
+- }
+- spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* check that they really want us to change something */
+ if (!tty_termios_hw_change(tty->termios, old_termios))
+@@ -1011,6 +1009,7 @@ static struct usb_serial_driver spcp8x5_
+ .carrier_raised = spcp8x5_carrier_raised,
+ .write = spcp8x5_write,
+ .set_termios = spcp8x5_set_termios,
++ .init_termios = spcp8x5_init_termios,
+ .ioctl = spcp8x5_ioctl,
+ .tiocmget = spcp8x5_tiocmget,
+ .tiocmset = spcp8x5_tiocmset,
+--- a/drivers/usb/serial/usb-serial.c
++++ b/drivers/usb/serial/usb-serial.c
+@@ -721,6 +721,41 @@ 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)
+ {
+@@ -1228,7 +1263,8 @@ 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_do_free,
++ .install = serial_install,
+ .proc_fops = &serial_proc_fops,
+ };
+
+--- a/drivers/usb/serial/whiteheat.c
++++ b/drivers/usb/serial/whiteheat.c
+@@ -259,7 +259,7 @@ static int firm_send_command(struct usb_
+ __u8 *data, __u8 datasize);
+ static int firm_open(struct usb_serial_port *port);
+ static int firm_close(struct usb_serial_port *port);
+-static int firm_setup_port(struct tty_struct *tty);
++static void firm_setup_port(struct tty_struct *tty);
+ static int firm_set_rts(struct usb_serial_port *port, __u8 onoff);
+ static int firm_set_dtr(struct usb_serial_port *port, __u8 onoff);
+ static int firm_set_break(struct usb_serial_port *port, __u8 onoff);
+@@ -1211,7 +1211,7 @@ static int firm_close(struct usb_serial_
+ }
+
+
+-static int firm_setup_port(struct tty_struct *tty)
++static void firm_setup_port(struct tty_struct *tty)
+ {
+ struct usb_serial_port *port = tty->driver_data;
+ struct whiteheat_port_settings port_settings;
+@@ -1286,7 +1286,7 @@ static int firm_setup_port(struct tty_st
+ port_settings.lloop = 0;
+
+ /* now send the message to the device */
+- return firm_send_command(port, WHITEHEAT_SETUP_PORT,
++ firm_send_command(port, WHITEHEAT_SETUP_PORT,
+ (__u8 *)&port_settings, sizeof(port_settings));
+ }
+
+--- a/include/linux/usb/serial.h
++++ b/include/linux/usb/serial.h
+@@ -261,6 +261,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);
++ /* Called by the usb serial hooks to allow the user to rework the
++ termios state */
++ void (*init_termios)(struct tty_struct *tty);
+ /* USB events */
+ void (*read_int_callback)(struct urb *urb);
+ void (*write_int_callback)(struct urb *urb);
--- /dev/null
+From cc56cd0157753c04a987888a2f793803df661a40 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 1 Sep 2009 11:39:13 -0400
+Subject: usb-serial: acquire references when a new tty is installed
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit cc56cd0157753c04a987888a2f793803df661a40 upstream.
+
+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>
+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, filp);
+ 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;
+
--- /dev/null
+From ff8324df1187b7280e507c976777df76c73a1ef1 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 1 Sep 2009 11:39:51 -0400
+Subject: usb-serial: add missing tests and debug lines
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit ff8324df1187b7280e507c976777df76c73a1ef1 upstream.
+
+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>
+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);
+
--- /dev/null
+From 8bc2c1b2daf95029658868cb1427baea2da87139 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 1 Sep 2009 11:38:59 -0400
+Subject: usb-serial: change logic of serial lookups
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit 8bc2c1b2daf95029658868cb1427baea2da87139 upstream.
+
+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>
+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;
+ }
--- /dev/null
+From 41bd34ddd7aa46dbc03b5bb33896e0fa8100fe7b Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 1 Sep 2009 11:38:34 -0400
+Subject: usb-serial: change referencing of port and serial structures
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit 41bd34ddd7aa46dbc03b5bb33896e0fa8100fe7b upstream.
+
+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>
+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");
+ }
--- /dev/null
+From 7e29bb4b779f4f35385e6f21994758845bf14d23 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 1 Sep 2009 11:39:22 -0400
+Subject: usb-serial: fix termios initialization logic
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit 7e29bb4b779f4f35385e6f21994758845bf14d23 upstream.
+
+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>
+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:
--- /dev/null
+From f5b0953a89fa3407fb293cc54ead7d8feec489e4 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 1 Sep 2009 11:38:44 -0400
+Subject: usb-serial: put subroutines in logical order
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit f5b0953a89fa3407fb293cc54ead7d8feec489e4 upstream.
+
+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>
+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)
+ {
--- /dev/null
+From 74556123e034c8337b69a3ebac2f3a5fc0a97032 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 1 Sep 2009 11:39:40 -0400
+Subject: usb-serial: rename subroutines
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit 74556123e034c8337b69a3ebac2f3a5fc0a97032 upstream.
+
+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>
+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,
+ };
--- /dev/null
+From 320348c8d5c9b591282633ddb8959b42f7fc7a1c Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 1 Sep 2009 11:39:59 -0400
+Subject: usb-serial: straighten out serial_open
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit 320348c8d5c9b591282633ddb8959b42f7fc7a1c upstream.
+
+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>
+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, filp);
+- if (retval)
+- goto bailout_module_put;
++ if (serial->disconnected)
++ retval = -ENODEV;
++ else
++ retval = port->serial->type->open(tty, port, flip);
+ 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;
+ }
+
--- /dev/null
+From 7bd032dc2793afcbaf4a350056768da84cdbd89b Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Fri, 4 Sep 2009 15:29:59 -0400
+Subject: USB serial: update the console driver
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit 7bd032dc2793afcbaf4a350056768da84cdbd89b upstream.
+
+This patch (as1292) modifies the USB serial console driver, to make it
+compatible with the recent changes to the USB serial core. The most
+important change is that serial->disc_mutex now has to be unlocked
+following a successful call to usb_serial_get_by_index().
+
+Other less notable changes include:
+
+ Use the requested port number instead of port 0 always.
+
+ Prevent the serial device from being autosuspended.
+
+ Use the ASYNCB_INITIALIZED flag bit to indicate when the
+ port hardware has been initialized.
+
+In spite of these changes, there's no question that the USB serial
+console code is still a big hack.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/console.c | 28 +++++++++++++++++++---------
+ 1 file changed, 19 insertions(+), 9 deletions(-)
+
+--- a/drivers/usb/serial/console.c
++++ b/drivers/usb/serial/console.c
+@@ -16,6 +16,7 @@
+ #include <linux/slab.h>
+ #include <linux/tty.h>
+ #include <linux/console.h>
++#include <linux/serial.h>
+ #include <linux/usb.h>
+ #include <linux/usb/serial.h>
+
+@@ -63,7 +64,7 @@ static int usb_console_setup(struct cons
+ char *s;
+ struct usb_serial *serial;
+ struct usb_serial_port *port;
+- int retval = 0;
++ int retval;
+ struct tty_struct *tty = NULL;
+ struct ktermios *termios = NULL, dummy;
+
+@@ -116,13 +117,17 @@ static int usb_console_setup(struct cons
+ return -ENODEV;
+ }
+
+- port = serial->port[0];
++ retval = usb_autopm_get_interface(serial->interface);
++ if (retval)
++ goto error_get_interface;
++
++ port = serial->port[co->index - serial->minor];
+ tty_port_tty_set(&port->port, NULL);
+
+ info->port = port;
+
+ ++port->port.count;
+- if (port->port.count == 1) {
++ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
+ if (serial->type->set_termios) {
+ /*
+ * allocate a fake tty so the driver can initialize
+@@ -168,6 +173,7 @@ static int usb_console_setup(struct cons
+ kfree(termios);
+ kfree(tty);
+ }
++ set_bit(ASYNCB_INITIALIZED, &port->port.flags);
+ }
+ /* Now that any required fake tty operations are completed restore
+ * the tty port count */
+@@ -175,18 +181,22 @@ static int usb_console_setup(struct cons
+ /* The console is special in terms of closing the device so
+ * indicate this port is now acting as a system console. */
+ port->console = 1;
+- retval = 0;
+
+-out:
++ mutex_unlock(&serial->disc_mutex);
+ return retval;
+-free_termios:
++
++ free_termios:
+ kfree(termios);
+ tty_port_tty_set(&port->port, NULL);
+-free_tty:
++ free_tty:
+ kfree(tty);
+-reset_open_count:
++ reset_open_count:
+ port->port.count = 0;
+- goto out;
++ usb_autopm_put_interface(serial->interface);
++ error_get_interface:
++ usb_serial_put(serial);
++ mutex_unlock(&serial->disc_mutex);
++ return retval;
+ }
+
+ static void usb_console_write(struct console *co,