revert-alsa-hda-shut-up-pins-at-power-saving-mode-with-conexnat-codecs.patch
alsa-hda-always-turn-on-pins-for-hdmi-dp.patch
alsa-hda-fix-internal-mic-for-lenovo-ideapad-u300s.patch
+usb-serial-add-modem-status-change-wait-queue.patch
+usb-ark3116-fix-use-after-free-in-tiocmiwait.patch
+usb-ch341-fix-use-after-free-in-tiocmiwait.patch
+usb-cypress_m8-fix-use-after-free-in-tiocmiwait.patch
+usb-ftdi_sio-fix-use-after-free-in-tiocmiwait.patch
+usb-io_edgeport-fix-use-after-free-in-tiocmiwait.patch
+usb-io_ti-fix-use-after-free-in-tiocmiwait.patch
+usb-mct_u232-fix-use-after-free-in-tiocmiwait.patch
+usb-mos7840-fix-broken-tiocmiwait.patch
+usb-mos7840-fix-use-after-free-in-tiocmiwait.patch
+usb-oti6858-fix-use-after-free-in-tiocmiwait.patch
+usb-pl2303-fix-use-after-free-in-tiocmiwait.patch
+usb-spcp8x5-fix-use-after-free-in-tiocmiwait.patch
+usb-ssu100-fix-use-after-free-in-tiocmiwait.patch
+usb-ti_usb_3410_5052-fix-use-after-free-in-tiocmiwait.patch
+usb-serial-fix-hang-when-opening-port.patch
--- /dev/null
+From 923ab36b14cb557482a079b0d67ef80f90bbc410 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Tue, 19 Mar 2013 09:21:11 +0100
+Subject: USB: ark3116: fix use-after-free in TIOCMIWAIT
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 5018860321dc7a9e50a75d5f319bc981298fb5b7 upstream.
+
+Use the port wait queue and make sure to check the serial disconnected
+flag before accessing private port data after waking up.
+
+This is is needed as the private port data (including the wait queue
+itself) can be gone when waking up after a disconnect.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/ark3116.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/serial/ark3116.c
++++ b/drivers/usb/serial/ark3116.c
+@@ -68,7 +68,6 @@ static int is_irda(struct usb_serial *se
+ }
+
+ struct ark3116_private {
+- wait_queue_head_t delta_msr_wait;
+ struct async_icount icount;
+ int irda; /* 1 for irda device */
+
+@@ -148,7 +147,6 @@ static int ark3116_attach(struct usb_ser
+ if (!priv)
+ return -ENOMEM;
+
+- init_waitqueue_head(&priv->delta_msr_wait);
+ mutex_init(&priv->hw_lock);
+ spin_lock_init(&priv->status_lock);
+
+@@ -460,10 +458,14 @@ static int ark3116_ioctl(struct tty_stru
+ case TIOCMIWAIT:
+ for (;;) {
+ struct async_icount prev = priv->icount;
+- interruptible_sleep_on(&priv->delta_msr_wait);
++ interruptible_sleep_on(&port->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
++
++ if (port->serial->disconnected)
++ return -EIO;
++
+ if ((prev.rng == priv->icount.rng) &&
+ (prev.dsr == priv->icount.dsr) &&
+ (prev.dcd == priv->icount.dcd) &&
+@@ -584,7 +586,7 @@ static void ark3116_update_msr(struct us
+ priv->icount.dcd++;
+ if (msr & UART_MSR_TERI)
+ priv->icount.rng++;
+- wake_up_interruptible(&priv->delta_msr_wait);
++ wake_up_interruptible(&port->delta_msr_wait);
+ }
+ }
+
--- /dev/null
+From d14eeaffa77b092812af5868f9bfed2c6502d786 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Tue, 19 Mar 2013 09:21:12 +0100
+Subject: USB: ch341: fix use-after-free in TIOCMIWAIT
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit fa1e11d5231c001c80a479160b5832933c5d35fb upstream.
+
+Use the port wait queue and make sure to check the serial disconnected
+flag before accessing private port data after waking up.
+
+This is is needed as the private port data (including the wait queue
+itself) can be gone when waking up after a disconnect.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/ch341.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/serial/ch341.c
++++ b/drivers/usb/serial/ch341.c
+@@ -82,7 +82,6 @@ MODULE_DEVICE_TABLE(usb, id_table);
+
+ struct ch341_private {
+ spinlock_t lock; /* access lock */
+- wait_queue_head_t delta_msr_wait; /* wait queue for modem status */
+ unsigned baud_rate; /* set baud rate */
+ u8 line_control; /* set line control value RTS/DTR */
+ u8 line_status; /* active status of modem control inputs */
+@@ -262,7 +261,6 @@ static int ch341_attach(struct usb_seria
+ return -ENOMEM;
+
+ spin_lock_init(&priv->lock);
+- init_waitqueue_head(&priv->delta_msr_wait);
+ priv->baud_rate = DEFAULT_BAUD_RATE;
+ priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
+
+@@ -299,7 +297,7 @@ static void ch341_dtr_rts(struct usb_ser
+ priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ ch341_set_handshake(port->serial->dev, priv->line_control);
+- wake_up_interruptible(&priv->delta_msr_wait);
++ wake_up_interruptible(&port->delta_msr_wait);
+ }
+
+ static void ch341_close(struct usb_serial_port *port)
+@@ -502,7 +500,7 @@ static void ch341_read_int_callback(stru
+ tty_kref_put(tty);
+ }
+
+- wake_up_interruptible(&priv->delta_msr_wait);
++ wake_up_interruptible(&port->delta_msr_wait);
+ }
+
+ exit:
+@@ -528,11 +526,14 @@ static int wait_modem_info(struct usb_se
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ while (!multi_change) {
+- interruptible_sleep_on(&priv->delta_msr_wait);
++ interruptible_sleep_on(&port->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
++ if (port->serial->disconnected)
++ return -EIO;
++
+ spin_lock_irqsave(&priv->lock, flags);
+ status = priv->line_status;
+ multi_change = priv->multi_status_change;
--- /dev/null
+From 2d5a267e36781e0d81e4546d2e4ffc9f63474fdf Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Tue, 19 Mar 2013 09:21:13 +0100
+Subject: USB: cypress_m8: fix use-after-free in TIOCMIWAIT
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 356050d8b1e526db093e9d2c78daf49d6bf418e3 upstream.
+
+Use the port wait queue and make sure to check the serial disconnected
+flag before accessing private port data after waking up.
+
+This is is needed as the private port data (including the wait queue
+itself) can be gone when waking up after a disconnect.
+
+Also remove bogus test for private data pointer being NULL as it is
+never assigned in the loop.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/cypress_m8.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/serial/cypress_m8.c
++++ b/drivers/usb/serial/cypress_m8.c
+@@ -125,7 +125,6 @@ struct cypress_private {
+ int baud_rate; /* stores current baud rate in
+ integer form */
+ int isthrottled; /* if throttled, discard reads */
+- wait_queue_head_t delta_msr_wait; /* used for TIOCMIWAIT */
+ char prev_status, diff_status; /* used for TIOCMIWAIT */
+ /* we pass a pointer to this as the argument sent to
+ cypress_set_termios old_termios */
+@@ -475,7 +474,6 @@ static int generic_startup(struct usb_se
+ kfree(priv);
+ return -ENOMEM;
+ }
+- init_waitqueue_head(&priv->delta_msr_wait);
+
+ /* Skip reset for FRWD device. It is a workaound:
+ device hangs if it receives SET_CONFIGURE in Configured
+@@ -919,12 +917,16 @@ static int cypress_ioctl(struct tty_stru
+ switch (cmd) {
+ /* This code comes from drivers/char/serial.c and ftdi_sio.c */
+ case TIOCMIWAIT:
+- while (priv != NULL) {
+- interruptible_sleep_on(&priv->delta_msr_wait);
++ for (;;) {
++ interruptible_sleep_on(&port->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+- else {
++
++ if (port->serial->disconnected)
++ return -EIO;
++
++ {
+ char diff = priv->diff_status;
+ if (diff == 0)
+ return -EIO; /* no change => error */
+@@ -1250,7 +1252,7 @@ static void cypress_read_int_callback(st
+ if (priv->current_status != priv->prev_status) {
+ priv->diff_status |= priv->current_status ^
+ priv->prev_status;
+- wake_up_interruptible(&priv->delta_msr_wait);
++ wake_up_interruptible(&port->delta_msr_wait);
+ priv->prev_status = priv->current_status;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
--- /dev/null
+From 31b9905f62ed5c361a37bb6f59cbf414873da65b Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Tue, 19 Mar 2013 09:21:15 +0100
+Subject: USB: ftdi_sio: fix use-after-free in TIOCMIWAIT
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 71ccb9b01981fabae27d3c98260ea4613207618e upstream.
+
+Use the port wait queue and make sure to check the serial disconnected
+flag before accessing private port data after waking up.
+
+This is is needed as the private port data (including the wait queue
+itself) can be gone when waking up after a disconnect.
+
+When switching to tty ports, some lifetime assumptions were changed.
+Specifically, close can now be called before the final tty reference is
+dropped as part of hangup at device disconnect. Even with the ftdi
+private-data refcounting this means that the port private data can be
+freed while a process is sleeping on modem-status changes and thus
+cannot be relied on to detect disconnects when woken up.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/ftdi_sio.c | 19 ++++++++-----------
+ 1 file changed, 8 insertions(+), 11 deletions(-)
+
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -74,9 +74,7 @@ struct ftdi_private {
+ int flags; /* some ASYNC_xxxx flags are supported */
+ unsigned long last_dtr_rts; /* saved modem control outputs */
+ struct async_icount icount;
+- wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
+ char prev_status; /* Used for TIOCMIWAIT */
+- bool dev_gone; /* Used to abort TIOCMIWAIT */
+ char transmit_empty; /* If transmitter is empty or not */
+ struct usb_serial_port *port;
+ __u16 interface; /* FT2232C, FT2232H or FT4232H port interface
+@@ -1746,10 +1744,8 @@ static int ftdi_sio_port_probe(struct us
+ kref_init(&priv->kref);
+ mutex_init(&priv->cfg_lock);
+ memset(&priv->icount, 0x00, sizeof(priv->icount));
+- init_waitqueue_head(&priv->delta_msr_wait);
+
+ priv->flags = ASYNC_LOW_LATENCY;
+- priv->dev_gone = false;
+
+ if (quirk && quirk->port_probe)
+ quirk->port_probe(priv);
+@@ -1908,8 +1904,7 @@ static int ftdi_sio_port_remove(struct u
+
+ dbg("%s", __func__);
+
+- priv->dev_gone = true;
+- wake_up_interruptible_all(&priv->delta_msr_wait);
++ wake_up_interruptible(&port->delta_msr_wait);
+
+ remove_sysfs_attrs(port);
+
+@@ -2064,7 +2059,7 @@ static int ftdi_process_packet(struct tt
+ if (diff_status & FTDI_RS0_RLSD)
+ priv->icount.dcd++;
+
+- wake_up_interruptible_all(&priv->delta_msr_wait);
++ wake_up_interruptible(&port->delta_msr_wait);
+ priv->prev_status = status;
+ }
+
+@@ -2467,11 +2462,15 @@ static int ftdi_ioctl(struct tty_struct
+ */
+ case TIOCMIWAIT:
+ cprev = priv->icount;
+- while (!priv->dev_gone) {
+- interruptible_sleep_on(&priv->delta_msr_wait);
++ for (;;) {
++ interruptible_sleep_on(&port->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
++
++ if (port->serial->disconnected)
++ return -EIO;
++
+ cnow = priv->icount;
+ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+@@ -2481,8 +2480,6 @@ static int ftdi_ioctl(struct tty_struct
+ }
+ cprev = cnow;
+ }
+- return -EIO;
+- break;
+ case TIOCSERGETLSR:
+ return get_lsr_info(port, (struct serial_struct __user *)arg);
+ break;
--- /dev/null
+From 0c384c6e92e05ecb3466060fffe7fb5e759de724 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Tue, 19 Mar 2013 09:21:16 +0100
+Subject: USB: io_edgeport: fix use-after-free in TIOCMIWAIT
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 333576255d4cfc53efd056aad438568184b36af6 upstream.
+
+Use the port wait queue and make sure to check the serial disconnected
+flag before accessing private port data after waking up.
+
+This is is needed as the private port data (including the wait queue
+itself) can be gone when waking up after a disconnect.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/io_edgeport.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/serial/io_edgeport.c
++++ b/drivers/usb/serial/io_edgeport.c
+@@ -114,7 +114,6 @@ struct edgeport_port {
+ wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
+ wait_queue_head_t wait_open; /* for handling sleeping while waiting for open to finish */
+ wait_queue_head_t wait_command; /* for handling sleeping while waiting for command to finish */
+- wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */
+
+ struct async_icount icount;
+ struct usb_serial_port *port; /* loop back to the owner of this object */
+@@ -884,7 +883,6 @@ static int edge_open(struct tty_struct *
+ /* initialize our wait queues */
+ init_waitqueue_head(&edge_port->wait_open);
+ init_waitqueue_head(&edge_port->wait_chase);
+- init_waitqueue_head(&edge_port->delta_msr_wait);
+ init_waitqueue_head(&edge_port->wait_command);
+
+ /* initialize our icount structure */
+@@ -1701,13 +1699,17 @@ static int edge_ioctl(struct tty_struct
+ dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
+ cprev = edge_port->icount;
+ while (1) {
+- prepare_to_wait(&edge_port->delta_msr_wait,
++ prepare_to_wait(&port->delta_msr_wait,
+ &wait, TASK_INTERRUPTIBLE);
+ schedule();
+- finish_wait(&edge_port->delta_msr_wait, &wait);
++ finish_wait(&port->delta_msr_wait, &wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
++
++ if (port->serial->disconnected)
++ return -EIO;
++
+ cnow = edge_port->icount;
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+@@ -2088,7 +2090,7 @@ static void handle_new_msr(struct edgepo
+ icount->dcd++;
+ if (newMsr & EDGEPORT_MSR_DELTA_RI)
+ icount->rng++;
+- wake_up_interruptible(&edge_port->delta_msr_wait);
++ wake_up_interruptible(&edge_port->port->delta_msr_wait);
+ }
+
+ /* Save the new modem status */
--- /dev/null
+From 24d369d8ad2aea254f5685f6565bf31175a1c617 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Tue, 19 Mar 2013 09:21:17 +0100
+Subject: USB: io_ti: fix use-after-free in TIOCMIWAIT
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 7b2459690584f239650a365f3411ba2ec1c6d1e0 upstream.
+
+Use the port wait queue and make sure to check the serial disconnected
+flag before accessing private port data after waking up.
+
+This is is needed as the private port data (including the wait queue
+itself) can be gone when waking up after a disconnect.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/io_ti.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/serial/io_ti.c
++++ b/drivers/usb/serial/io_ti.c
+@@ -91,9 +91,6 @@ struct edgeport_port {
+ int close_pending;
+ int lsr_event;
+ struct async_icount icount;
+- wait_queue_head_t delta_msr_wait; /* for handling sleeping while
+- waiting for msr change to
+- happen */
+ struct edgeport_serial *edge_serial;
+ struct usb_serial_port *port;
+ __u8 bUartMode; /* Port type, 0: RS232, etc. */
+@@ -1549,7 +1546,7 @@ static void handle_new_msr(struct edgepo
+ icount->dcd++;
+ if (msr & EDGEPORT_MSR_DELTA_RI)
+ icount->rng++;
+- wake_up_interruptible(&edge_port->delta_msr_wait);
++ wake_up_interruptible(&edge_port->port->delta_msr_wait);
+ }
+
+ /* Save the new modem status */
+@@ -1867,7 +1864,6 @@ static int edge_open(struct tty_struct *
+ dev = port->serial->dev;
+
+ memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount));
+- init_waitqueue_head(&edge_port->delta_msr_wait);
+
+ /* turn off loopback */
+ status = ti_do_config(edge_port, UMPC_SET_CLR_LOOPBACK, 0);
+@@ -2553,10 +2549,14 @@ static int edge_ioctl(struct tty_struct
+ dbg("%s - (%d) TIOCMIWAIT", __func__, port->number);
+ cprev = edge_port->icount;
+ while (1) {
+- interruptible_sleep_on(&edge_port->delta_msr_wait);
++ interruptible_sleep_on(&port->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
++
++ if (port->serial->disconnected)
++ return -EIO;
++
+ cnow = edge_port->icount;
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
--- /dev/null
+From 4f8adbff06abdb87614b8cfae32d207683400c26 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Tue, 19 Mar 2013 09:21:18 +0100
+Subject: USB: mct_u232: fix use-after-free in TIOCMIWAIT
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit cf1d24443677a0758cfa88ca40f24858b89261c0 upstream.
+
+Use the port wait queue and make sure to check the serial disconnected
+flag before accessing private port data after waking up.
+
+This is is needed as the private port data (including the wait queue
+itself) can be gone when waking up after a disconnect.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+[bwh: Backported to 3.2: adjust context]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/mct_u232.c | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/serial/mct_u232.c
++++ b/drivers/usb/serial/mct_u232.c
+@@ -126,8 +126,6 @@ struct mct_u232_private {
+ unsigned char last_msr; /* Modem Status Register */
+ unsigned int rx_flags; /* Throttling flags */
+ struct async_icount icount;
+- wait_queue_head_t msr_wait; /* for handling sleeping while waiting
+- for msr change to happen */
+ };
+
+ #define THROTTLED 0x01
+@@ -407,7 +405,6 @@ static int mct_u232_startup(struct usb_s
+ if (!priv)
+ return -ENOMEM;
+ spin_lock_init(&priv->lock);
+- init_waitqueue_head(&priv->msr_wait);
+ usb_set_serial_port_data(serial->port[0], priv);
+
+ init_waitqueue_head(&serial->port[0]->write_wait);
+@@ -631,7 +628,7 @@ static void mct_u232_read_int_callback(s
+ tty_kref_put(tty);
+ }
+ #endif
+- wake_up_interruptible(&priv->msr_wait);
++ wake_up_interruptible(&port->delta_msr_wait);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ exit:
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+@@ -852,13 +849,17 @@ static int mct_u232_ioctl(struct tty_st
+ cprev = mct_u232_port->icount;
+ spin_unlock_irqrestore(&mct_u232_port->lock, flags);
+ for ( ; ; ) {
+- prepare_to_wait(&mct_u232_port->msr_wait,
++ prepare_to_wait(&port->delta_msr_wait,
+ &wait, TASK_INTERRUPTIBLE);
+ schedule();
+- finish_wait(&mct_u232_port->msr_wait, &wait);
++ finish_wait(&port->delta_msr_wait, &wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
++
++ if (port->serial->disconnected)
++ return -EIO;
++
+ spin_lock_irqsave(&mct_u232_port->lock, flags);
+ cnow = mct_u232_port->icount;
+ spin_unlock_irqrestore(&mct_u232_port->lock, flags);
--- /dev/null
+From 928ab2854c082067496ca91c0495a60b17d7bf9e Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Tue, 19 Mar 2013 09:21:19 +0100
+Subject: USB: mos7840: fix broken TIOCMIWAIT
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit e670c6af12517d08a403487b1122eecf506021cf upstream.
+
+Make sure waiting processes are woken on modem-status changes.
+
+Currently processes are only woken on termios changes regardless of
+whether the modem status has changed.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+[bwh: Backported to 3.2: adjust context]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/mos7840.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/serial/mos7840.c
++++ b/drivers/usb/serial/mos7840.c
+@@ -453,6 +453,9 @@ static void mos7840_handle_new_msr(struc
+ icount->rng++;
+ smp_wmb();
+ }
++
++ mos7840_port->delta_msr_cond = 1;
++ wake_up_interruptible(&mos7840_port->delta_msr_wait);
+ }
+ }
+
+@@ -2074,8 +2077,6 @@ static void mos7840_change_port_settings
+ mos7840_port->read_urb_busy = false;
+ }
+ }
+- wake_up(&mos7840_port->delta_msr_wait);
+- mos7840_port->delta_msr_cond = 1;
+ dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x",
+ mos7840_port->shadowLCR);
+ }
--- /dev/null
+From 82159cdc841eaf66435eadf6e084f0f2c5791cbe Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Tue, 19 Mar 2013 09:21:20 +0100
+Subject: USB: mos7840: fix use-after-free in TIOCMIWAIT
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit a14430db686b8e459e1cf070a6ecf391515c9ab9 upstream.
+
+Use the port wait queue and make sure to check the serial disconnected
+flag before accessing private port data after waking up.
+
+This is is needed as the private port data (including the wait queue
+itself) can be gone when waking up after a disconnect.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/mos7840.c | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/serial/mos7840.c
++++ b/drivers/usb/serial/mos7840.c
+@@ -240,7 +240,6 @@ struct moschip_port {
+ char open;
+ char open_ports;
+ wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
+- wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */
+ int delta_msr_cond;
+ struct async_icount icount;
+ struct usb_serial_port *port; /* loop back to the owner of this object */
+@@ -455,7 +454,7 @@ static void mos7840_handle_new_msr(struc
+ }
+
+ mos7840_port->delta_msr_cond = 1;
+- wake_up_interruptible(&mos7840_port->delta_msr_wait);
++ wake_up_interruptible(&port->port->delta_msr_wait);
+ }
+ }
+
+@@ -1116,7 +1115,6 @@ static int mos7840_open(struct tty_struc
+
+ /* initialize our wait queues */
+ init_waitqueue_head(&mos7840_port->wait_chase);
+- init_waitqueue_head(&mos7840_port->delta_msr_wait);
+
+ /* initialize our icount structure */
+ memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount));
+@@ -2285,13 +2283,18 @@ static int mos7840_ioctl(struct tty_stru
+ while (1) {
+ /* interruptible_sleep_on(&mos7840_port->delta_msr_wait); */
+ mos7840_port->delta_msr_cond = 0;
+- wait_event_interruptible(mos7840_port->delta_msr_wait,
+- (mos7840_port->
++ wait_event_interruptible(port->delta_msr_wait,
++ (port->serial->disconnected ||
++ mos7840_port->
+ delta_msr_cond == 1));
+
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
++
++ if (port->serial->disconnected)
++ return -EIO;
++
+ cnow = mos7840_port->icount;
+ smp_rmb();
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
--- /dev/null
+From 5db2cb168b894409ec5e2dcc5672578538bdedee Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Tue, 19 Mar 2013 09:21:21 +0100
+Subject: USB: oti6858: fix use-after-free in TIOCMIWAIT
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 8edfdab37157d2683e51b8be5d3d5697f66a9f7b upstream.
+
+Use the port wait queue and make sure to check the serial disconnected
+flag before accessing private port data after waking up.
+
+This is is needed as the private port data (including the wait queue
+itself) can be gone when waking up after a disconnect.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+[bwh: Backported to 3.2: adjust context, indentation]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/oti6858.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/serial/oti6858.c
++++ b/drivers/usb/serial/oti6858.c
+@@ -198,7 +198,6 @@ struct oti6858_private {
+ u8 setup_done;
+ struct delayed_work delayed_setup_work;
+
+- wait_queue_head_t intr_wait;
+ struct usb_serial_port *port; /* USB port with which associated */
+ };
+
+@@ -356,7 +355,6 @@ static int oti6858_startup(struct usb_se
+ break;
+
+ spin_lock_init(&priv->lock);
+- init_waitqueue_head(&priv->intr_wait);
+ /* INIT_WORK(&priv->setup_work, setup_line, serial->port[i]); */
+ /* INIT_WORK(&priv->write_work, send_data, serial->port[i]); */
+ priv->port = port;
+@@ -703,11 +701,15 @@ static int wait_modem_info(struct usb_se
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ while (1) {
+- wait_event_interruptible(priv->intr_wait,
++ wait_event_interruptible(port->delta_msr_wait,
++ port->serial->disconnected ||
+ priv->status.pin_state != prev);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
++ if (port->serial->disconnected)
++ return -EIO;
++
+ spin_lock_irqsave(&priv->lock, flags);
+ status = priv->status.pin_state & PIN_MASK;
+ spin_unlock_irqrestore(&priv->lock, flags);
+@@ -819,7 +821,7 @@ static void oti6858_read_int_callback(st
+
+ if (!priv->transient) {
+ if (xs->pin_state != priv->status.pin_state)
+- wake_up_interruptible(&priv->intr_wait);
++ wake_up_interruptible(&port->delta_msr_wait);
+ memcpy(&priv->status, xs, OTI6858_CTRL_PKT_SIZE);
+ }
+
--- /dev/null
+From 664e1221e7828164acc8431968fb933ed998bbb2 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Tue, 19 Mar 2013 09:21:22 +0100
+Subject: USB: pl2303: fix use-after-free in TIOCMIWAIT
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 40509ca982c00c4b70fc00be887509feca0bff15 upstream.
+
+Use the port wait queue and make sure to check the serial disconnected
+flag before accessing private port data after waking up.
+
+This is is needed as the private port data (including the wait queue
+itself) can be gone when waking up after a disconnect.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/pl2303.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/serial/pl2303.c
++++ b/drivers/usb/serial/pl2303.c
+@@ -149,7 +149,6 @@ enum pl2303_type {
+
+ struct pl2303_private {
+ spinlock_t lock;
+- wait_queue_head_t delta_msr_wait;
+ u8 line_control;
+ u8 line_status;
+ enum pl2303_type type;
+@@ -203,7 +202,6 @@ static int pl2303_startup(struct usb_ser
+ if (!priv)
+ goto cleanup;
+ spin_lock_init(&priv->lock);
+- init_waitqueue_head(&priv->delta_msr_wait);
+ priv->type = type;
+ usb_set_serial_port_data(serial->port[i], priv);
+ }
+@@ -595,11 +593,14 @@ static int wait_modem_info(struct usb_se
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ while (1) {
+- interruptible_sleep_on(&priv->delta_msr_wait);
++ interruptible_sleep_on(&port->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
++ if (port->serial->disconnected)
++ return -EIO;
++
+ spin_lock_irqsave(&priv->lock, flags);
+ status = priv->line_status;
+ spin_unlock_irqrestore(&priv->lock, flags);
+@@ -721,7 +722,7 @@ static void pl2303_update_line_status(st
+ spin_unlock_irqrestore(&priv->lock, flags);
+ if (priv->line_status & UART_BREAK_ERROR)
+ usb_serial_handle_break(port);
+- wake_up_interruptible(&priv->delta_msr_wait);
++ wake_up_interruptible(&port->delta_msr_wait);
+
+ tty = tty_port_tty_get(&port->port);
+ if (!tty)
+@@ -788,7 +789,7 @@ static void pl2303_process_read_urb(stru
+ line_status = priv->line_status;
+ priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
+ spin_unlock_irqrestore(&priv->lock, flags);
+- wake_up_interruptible(&priv->delta_msr_wait);
++ wake_up_interruptible(&port->delta_msr_wait);
+
+ if (!urb->actual_length)
+ return;
--- /dev/null
+From da07f4596510e8141e105c9502a25b568caba860 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Tue, 19 Mar 2013 09:21:10 +0100
+Subject: USB: serial: add modem-status-change wait queue
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit e5b33dc9d16053c2ae4c2c669cf008829530364b upstream.
+
+Add modem-status-change wait queue to struct usb_serial_port that
+subdrivers can use to implement TIOCMIWAIT.
+
+Currently subdrivers use a private wait queue which may have been
+released when waking up after device disconnected.
+
+Note that we're adding a new wait queue rather than reusing the tty-port
+one as we do not want to get woken up at hangup (yet).
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/linux/usb/serial.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/include/linux/usb/serial.h
++++ b/include/linux/usb/serial.h
+@@ -66,6 +66,7 @@
+ * port.
+ * @flags: usb serial port flags
+ * @write_wait: a wait_queue_head_t used by the port.
++ * @delta_msr_wait: modem-status-change wait queue
+ * @work: work queue entry for the line discipline waking up.
+ * @throttled: nonzero if the read urb is inactive to throttle the device
+ * @throttle_req: nonzero if the tty wants to throttle us
+@@ -112,6 +113,7 @@ struct usb_serial_port {
+
+ unsigned long flags;
+ wait_queue_head_t write_wait;
++ wait_queue_head_t delta_msr_wait;
+ struct work_struct work;
+ char throttled;
+ char throttle_req;
--- /dev/null
+From a796ce4827fcbbb269f9e105f6b852b0dec85217 Mon Sep 17 00:00:00 2001
+From: Ming Lei <tom.leiming@gmail.com>
+Date: Tue, 26 Mar 2013 10:49:55 +0800
+Subject: USB: serial: fix hang when opening port
+
+From: Ming Lei <tom.leiming@gmail.com>
+
+commit eba0e3c3a0ba7b96f01cbe997680f6a4401a0bfc upstream.
+
+Johan's 'fix use-after-free in TIOCMIWAIT' patchset[1] introduces
+one bug which can cause kernel hang when opening port.
+
+This patch initialized the 'port->delta_msr_wait' waitqueue head
+to fix the bug which is introduced in 3.9-rc4.
+
+[1], http://marc.info/?l=linux-usb&m=136368139627876&w=2
+
+Signed-off-by: Ming Lei <tom.leiming@gmail.com>
+Acked-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/usb-serial.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/usb/serial/usb-serial.c
++++ b/drivers/usb/serial/usb-serial.c
+@@ -908,6 +908,7 @@ int usb_serial_probe(struct usb_interfac
+ port->port.ops = &serial_port_ops;
+ port->serial = serial;
+ spin_lock_init(&port->lock);
++ init_waitqueue_head(&port->delta_msr_wait);
+ /* Keep this for private driver use for the moment but
+ should probably go away */
+ INIT_WORK(&port->work, usb_serial_port_work);
--- /dev/null
+From d1baabc8006fd238ad8da4d734dc815a8de02362 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Tue, 19 Mar 2013 09:21:24 +0100
+Subject: USB: spcp8x5: fix use-after-free in TIOCMIWAIT
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit d1baabc8006fd238ad8da4d734dc815a8de02362 upstream.
+
+commit dbcea7615d8d7d58f6ff49d2c5568113f70effe9 upstream.
+
+Use the port wait queue and make sure to check the serial disconnected
+flag before accessing private port data after waking up.
+
+This is is needed as the private port data (including the wait queue
+itself) can be gone when waking up after a disconnect.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+[bwh: Backported to 3.2: adjust context, indentation]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/spcp8x5.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/serial/spcp8x5.c
++++ b/drivers/usb/serial/spcp8x5.c
+@@ -162,7 +162,6 @@ static struct usb_driver spcp8x5_driver
+ struct spcp8x5_private {
+ spinlock_t lock;
+ enum spcp8x5_type type;
+- wait_queue_head_t delta_msr_wait;
+ u8 line_control;
+ u8 line_status;
+ };
+@@ -196,7 +195,6 @@ static int spcp8x5_startup(struct usb_se
+ goto cleanup;
+
+ spin_lock_init(&priv->lock);
+- init_waitqueue_head(&priv->delta_msr_wait);
+ priv->type = type;
+ usb_set_serial_port_data(serial->port[i] , priv);
+ }
+@@ -499,7 +497,7 @@ static void spcp8x5_process_read_urb(str
+ priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ /* wake up the wait for termios */
+- wake_up_interruptible(&priv->delta_msr_wait);
++ wake_up_interruptible(&port->delta_msr_wait);
+
+ if (!urb->actual_length)
+ return;
+@@ -549,12 +547,15 @@ static int spcp8x5_wait_modem_info(struc
+
+ while (1) {
+ /* wake up in bulk read */
+- interruptible_sleep_on(&priv->delta_msr_wait);
++ interruptible_sleep_on(&port->delta_msr_wait);
+
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
++ if (port->serial->disconnected)
++ return -EIO;
++
+ spin_lock_irqsave(&priv->lock, flags);
+ status = priv->line_status;
+ spin_unlock_irqrestore(&priv->lock, flags);
--- /dev/null
+From a8d6465295472939d209947962e7319b555dc55c Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Tue, 19 Mar 2013 09:21:25 +0100
+Subject: USB: ssu100: fix use-after-free in TIOCMIWAIT
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 43a66b4c417ad15f6d2f632ce67ad195bdf999e8 upstream.
+
+Use the port wait queue and make sure to check the serial disconnected
+flag before accessing private port data after waking up.
+
+This is is needed as the private port data (including the wait queue
+itself) can be gone when waking up after a disconnect.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+[bwh: Backported to 3.2: adjust context]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/ssu100.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/serial/ssu100.c
++++ b/drivers/usb/serial/ssu100.c
+@@ -77,7 +77,6 @@ struct ssu100_port_private {
+ spinlock_t status_lock;
+ u8 shadowLSR;
+ u8 shadowMSR;
+- wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
+ struct async_icount icount;
+ };
+
+@@ -386,8 +385,9 @@ static int wait_modem_info(struct usb_se
+ spin_unlock_irqrestore(&priv->status_lock, flags);
+
+ while (1) {
+- wait_event_interruptible(priv->delta_msr_wait,
+- ((priv->icount.rng != prev.rng) ||
++ wait_event_interruptible(port->delta_msr_wait,
++ (port->serial->disconnected ||
++ (priv->icount.rng != prev.rng) ||
+ (priv->icount.dsr != prev.dsr) ||
+ (priv->icount.dcd != prev.dcd) ||
+ (priv->icount.cts != prev.cts)));
+@@ -395,6 +395,9 @@ static int wait_modem_info(struct usb_se
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
++ if (port->serial->disconnected)
++ return -EIO;
++
+ spin_lock_irqsave(&priv->status_lock, flags);
+ cur = priv->icount;
+ spin_unlock_irqrestore(&priv->status_lock, flags);
+@@ -477,7 +480,6 @@ static int ssu100_attach(struct usb_seri
+ }
+
+ spin_lock_init(&priv->status_lock);
+- init_waitqueue_head(&priv->delta_msr_wait);
+ usb_set_serial_port_data(port, priv);
+
+ return ssu100_initdevice(serial->dev);
+@@ -563,7 +565,7 @@ static void ssu100_update_msr(struct usb
+ priv->icount.dcd++;
+ if (msr & UART_MSR_TERI)
+ priv->icount.rng++;
+- wake_up_interruptible(&priv->delta_msr_wait);
++ wake_up_interruptible(&port->delta_msr_wait);
+ }
+ }
+
--- /dev/null
+From 3668b9c17765cacf411effc4fc6e44099ac30800 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Tue, 19 Mar 2013 09:21:26 +0100
+Subject: USB: ti_usb_3410_5052: fix use-after-free in TIOCMIWAIT
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 3668b9c17765cacf411effc4fc6e44099ac30800 upstream.
+
+commit fc98ab873aa3dbe783ce56a2ffdbbe7c7609521a upstream.
+
+Use the port wait queue and make sure to check the serial disconnected
+flag before accessing private port data after waking up.
+
+This is is needed as the private port data (including the wait queue
+itself) can be gone when waking up after a disconnect.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+[bwh: Backported to 3.2: adjust context]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/ti_usb_3410_5052.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/serial/ti_usb_3410_5052.c
++++ b/drivers/usb/serial/ti_usb_3410_5052.c
+@@ -75,7 +75,6 @@ struct ti_port {
+ int tp_flags;
+ int tp_closing_wait;/* in .01 secs */
+ struct async_icount tp_icount;
+- wait_queue_head_t tp_msr_wait; /* wait for msr change */
+ wait_queue_head_t tp_write_wait;
+ struct ti_device *tp_tdev;
+ struct usb_serial_port *tp_port;
+@@ -430,7 +429,6 @@ static int ti_startup(struct usb_serial
+ tport->tp_uart_base_addr = (i == 0 ?
+ TI_UART1_BASE_ADDR : TI_UART2_BASE_ADDR);
+ tport->tp_closing_wait = closing_wait;
+- init_waitqueue_head(&tport->tp_msr_wait);
+ init_waitqueue_head(&tport->tp_write_wait);
+ if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE,
+ GFP_KERNEL)) {
+@@ -827,9 +825,13 @@ static int ti_ioctl(struct tty_struct *t
+ dbg("%s - (%d) TIOCMIWAIT", __func__, port->number);
+ cprev = tport->tp_icount;
+ while (1) {
+- interruptible_sleep_on(&tport->tp_msr_wait);
++ interruptible_sleep_on(&port->delta_msr_wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
++
++ if (port->serial->disconnected)
++ return -EIO;
++
+ cnow = tport->tp_icount;
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+@@ -1458,7 +1460,7 @@ static void ti_handle_new_msr(struct ti_
+ icount->dcd++;
+ if (msr & TI_MSR_DELTA_RI)
+ icount->rng++;
+- wake_up_interruptible(&tport->tp_msr_wait);
++ wake_up_interruptible(&tport->tp_port->delta_msr_wait);
+ spin_unlock_irqrestore(&tport->tp_lock, flags);
+ }
+