From: Greg Kroah-Hartman Date: Thu, 1 Oct 2009 22:00:58 +0000 (-0700) Subject: .31 tty usb-serial mess X-Git-Tag: v2.6.27.36~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=732a466e4191e33f14aeac269730c2c6248f25c3;p=thirdparty%2Fkernel%2Fstable-queue.git .31 tty usb-serial mess --- diff --git a/queue-2.6.31/driver-core-add-new-device-to-bus-s-list-before-probing.patch b/queue-2.6.31/driver-core-add-new-device-to-bus-s-list-before-probing.patch new file mode 100644 index 00000000000..38b242ac03c --- /dev/null +++ b/queue-2.6.31/driver-core-add-new-device-to-bus-s-list-before-probing.patch @@ -0,0 +1,111 @@ +From 2023c610dc54a4f4130b0494309a9bd668ca3df8 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Thu, 30 Jul 2009 15:27:18 -0400 +Subject: Driver core: add new device to bus's list before probing + +From: Alan Stern + +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 +CC: Kay Sievers +Signed-off-by: Greg Kroah-Hartman + +--- + 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); diff --git a/queue-2.6.31/hwmon-add-maintainer-information.patch b/queue-2.6.31/hwmon-add-maintainer-information.patch new file mode 100644 index 00000000000..54523e618d6 --- /dev/null +++ b/queue-2.6.31/hwmon-add-maintainer-information.patch @@ -0,0 +1,34 @@ +From 2c2a6172afab7421f6af7e228cd3121f423ea932 Mon Sep 17 00:00:00 2001 +From: Luca Tettamanti +Date: Tue, 15 Sep 2009 17:18:10 +0200 +Subject: hwmon: (asus_atk0110) Add maintainer information + +From: Luca Tettamanti + +commit 2c2a6172afab7421f6af7e228cd3121f423ea932 upstream. + +Add myself as asus_atk0110 maintainer. + +Signed-off-by: Luca Tettamanti +Signed-off-by: Jean Delvare +Signed-off-by: Greg Kroah-Hartman + +--- + 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 ++L: lm-sensors@lm-sensors.org ++S: Maintained ++F: drivers/hwmon/asus_atk0110.c ++ + ATI_REMOTE2 DRIVER + M: Ville Syrjala + S: Maintained diff --git a/queue-2.6.31/series b/queue-2.6.31/series index b2eb8de8636..5c42b8de5bf 100644 --- a/queue-2.6.31/series +++ b/queue-2.6.31/series @@ -84,3 +84,18 @@ netfilter-bridge-refcount-fix.patch 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 diff --git a/queue-2.6.31/tty-add-a-full-port_close-function.patch b/queue-2.6.31/tty-add-a-full-port_close-function.patch new file mode 100644 index 00000000000..5a765fb8ac4 --- /dev/null +++ b/queue-2.6.31/tty-add-a-full-port_close-function.patch @@ -0,0 +1,119 @@ +From 7ca0ff9ab3218ec443a7a9ad247e4650373ed41e Mon Sep 17 00:00:00 2001 +From: Alan Cox +Date: Sat, 19 Sep 2009 13:13:20 -0700 +Subject: tty: Add a full port_close function + +From: Alan Cox + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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); diff --git a/queue-2.6.31/tty-usb-can-now-use-the-shutdown-method-for-kref-based-freeing-of-ports.patch b/queue-2.6.31/tty-usb-can-now-use-the-shutdown-method-for-kref-based-freeing-of-ports.patch new file mode 100644 index 00000000000..282261aba4c --- /dev/null +++ b/queue-2.6.31/tty-usb-can-now-use-the-shutdown-method-for-kref-based-freeing-of-ports.patch @@ -0,0 +1,80 @@ +From 4455e344959a217ffc28de2ab1af87541322b343 Mon Sep 17 00:00:00 2001 +From: Alan Cox +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 + +commit 4455e344959a217ffc28de2ab1af87541322b343 upstream. + +Signed-off-by: Alan Cox +Signed-off-by: Greg Kroah-Hartman + +--- + 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, + }; + diff --git a/queue-2.6.31/tty-usb-hangup-is-racy.patch b/queue-2.6.31/tty-usb-hangup-is-racy.patch new file mode 100644 index 00000000000..60d1b1f047b --- /dev/null +++ b/queue-2.6.31/tty-usb-hangup-is-racy.patch @@ -0,0 +1,35 @@ +From d2b391822a11302add9e46476f3da4e18e6de84c Mon Sep 17 00:00:00 2001 +From: Alan Cox +Date: Sat, 19 Sep 2009 13:13:23 -0700 +Subject: tty: USB hangup is racy + +From: Alan Cox + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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); diff --git a/queue-2.6.31/tty-usb-serial-termios-bits.patch b/queue-2.6.31/tty-usb-serial-termios-bits.patch new file mode 100644 index 00000000000..376c975aa74 --- /dev/null +++ b/queue-2.6.31/tty-usb-serial-termios-bits.patch @@ -0,0 +1,533 @@ +From fe1ae7fdd2ee603f2d95f04e09a68f7f79045127 Mon Sep 17 00:00:00 2001 +From: Alan Cox +Date: Sat, 19 Sep 2009 13:13:33 -0700 +Subject: tty: USB serial termios bits + +From: Alan Cox + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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); diff --git a/queue-2.6.31/usb-serial-acquire-references-when-a-new-tty-is-installed.patch b/queue-2.6.31/usb-serial-acquire-references-when-a-new-tty-is-installed.patch new file mode 100644 index 00000000000..b6e30476dc7 --- /dev/null +++ b/queue-2.6.31/usb-serial-acquire-references-when-a-new-tty-is-installed.patch @@ -0,0 +1,223 @@ +From cc56cd0157753c04a987888a2f793803df661a40 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Tue, 1 Sep 2009 11:39:13 -0400 +Subject: usb-serial: acquire references when a new tty is installed + +From: Alan Stern + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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; + diff --git a/queue-2.6.31/usb-serial-add-missing-tests-and-debug-lines.patch b/queue-2.6.31/usb-serial-add-missing-tests-and-debug-lines.patch new file mode 100644 index 00000000000..127da3779bd --- /dev/null +++ b/queue-2.6.31/usb-serial-add-missing-tests-and-debug-lines.patch @@ -0,0 +1,94 @@ +From ff8324df1187b7280e507c976777df76c73a1ef1 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Tue, 1 Sep 2009 11:39:51 -0400 +Subject: usb-serial: add missing tests and debug lines + +From: Alan Stern + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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/queue-2.6.31/usb-serial-change-logic-of-serial-lookups.patch b/queue-2.6.31/usb-serial-change-logic-of-serial-lookups.patch new file mode 100644 index 00000000000..b614a9c226f --- /dev/null +++ b/queue-2.6.31/usb-serial-change-logic-of-serial-lookups.patch @@ -0,0 +1,119 @@ +From 8bc2c1b2daf95029658868cb1427baea2da87139 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Tue, 1 Sep 2009 11:38:59 -0400 +Subject: usb-serial: change logic of serial lookups + +From: Alan Stern + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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/queue-2.6.31/usb-serial-change-referencing-of-port-and-serial-structures.patch b/queue-2.6.31/usb-serial-change-referencing-of-port-and-serial-structures.patch new file mode 100644 index 00000000000..964bef19e9b --- /dev/null +++ b/queue-2.6.31/usb-serial-change-referencing-of-port-and-serial-structures.patch @@ -0,0 +1,235 @@ +From 41bd34ddd7aa46dbc03b5bb33896e0fa8100fe7b Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Tue, 1 Sep 2009 11:38:34 -0400 +Subject: usb-serial: change referencing of port and serial structures + +From: Alan Stern + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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/queue-2.6.31/usb-serial-fix-termios-initialization-logic.patch b/queue-2.6.31/usb-serial-fix-termios-initialization-logic.patch new file mode 100644 index 00000000000..9df954f73fa --- /dev/null +++ b/queue-2.6.31/usb-serial-fix-termios-initialization-logic.patch @@ -0,0 +1,66 @@ +From 7e29bb4b779f4f35385e6f21994758845bf14d23 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Tue, 1 Sep 2009 11:39:22 -0400 +Subject: usb-serial: fix termios initialization logic + +From: Alan Stern + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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/queue-2.6.31/usb-serial-put-subroutines-in-logical-order.patch b/queue-2.6.31/usb-serial-put-subroutines-in-logical-order.patch new file mode 100644 index 00000000000..70afcaf623b --- /dev/null +++ b/queue-2.6.31/usb-serial-put-subroutines-in-logical-order.patch @@ -0,0 +1,230 @@ +From f5b0953a89fa3407fb293cc54ead7d8feec489e4 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Tue, 1 Sep 2009 11:38:44 -0400 +Subject: usb-serial: put subroutines in logical order + +From: Alan Stern + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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/queue-2.6.31/usb-serial-rename-subroutines.patch b/queue-2.6.31/usb-serial-rename-subroutines.patch new file mode 100644 index 00000000000..391132c11f7 --- /dev/null +++ b/queue-2.6.31/usb-serial-rename-subroutines.patch @@ -0,0 +1,100 @@ +From 74556123e034c8337b69a3ebac2f3a5fc0a97032 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Tue, 1 Sep 2009 11:39:40 -0400 +Subject: usb-serial: rename subroutines + +From: Alan Stern + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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/queue-2.6.31/usb-serial-straighten-out-serial_open.patch b/queue-2.6.31/usb-serial-straighten-out-serial_open.patch new file mode 100644 index 00000000000..24921bc11c5 --- /dev/null +++ b/queue-2.6.31/usb-serial-straighten-out-serial_open.patch @@ -0,0 +1,104 @@ +From 320348c8d5c9b591282633ddb8959b42f7fc7a1c Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Tue, 1 Sep 2009 11:39:59 -0400 +Subject: usb-serial: straighten out serial_open + +From: Alan Stern + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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; + } + diff --git a/queue-2.6.31/usb-serial-update-the-console-driver.patch b/queue-2.6.31/usb-serial-update-the-console-driver.patch new file mode 100644 index 00000000000..bd35b11fa9a --- /dev/null +++ b/queue-2.6.31/usb-serial-update-the-console-driver.patch @@ -0,0 +1,109 @@ +From 7bd032dc2793afcbaf4a350056768da84cdbd89b Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Fri, 4 Sep 2009 15:29:59 -0400 +Subject: USB serial: update the console driver + +From: Alan Stern + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 + #include + #include ++#include + #include + #include + +@@ -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,