aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/ftdi_sio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/ftdi_sio.c')
-rw-r--r--drivers/usb/serial/ftdi_sio.c36
1 files changed, 20 insertions, 16 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index ff8605b4b4be..02e7f2d32d52 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -75,7 +75,8 @@ struct ftdi_private {
75 unsigned long last_dtr_rts; /* saved modem control outputs */ 75 unsigned long last_dtr_rts; /* saved modem control outputs */
76 struct async_icount icount; 76 struct async_icount icount;
77 wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ 77 wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
78 char prev_status, diff_status; /* Used for TIOCMIWAIT */ 78 char prev_status; /* Used for TIOCMIWAIT */
79 bool dev_gone; /* Used to abort TIOCMIWAIT */
79 char transmit_empty; /* If transmitter is empty or not */ 80 char transmit_empty; /* If transmitter is empty or not */
80 struct usb_serial_port *port; 81 struct usb_serial_port *port;
81 __u16 interface; /* FT2232C, FT2232H or FT4232H port interface 82 __u16 interface; /* FT2232C, FT2232H or FT4232H port interface
@@ -1681,6 +1682,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
1681 init_waitqueue_head(&priv->delta_msr_wait); 1682 init_waitqueue_head(&priv->delta_msr_wait);
1682 1683
1683 priv->flags = ASYNC_LOW_LATENCY; 1684 priv->flags = ASYNC_LOW_LATENCY;
1685 priv->dev_gone = false;
1684 1686
1685 if (quirk && quirk->port_probe) 1687 if (quirk && quirk->port_probe)
1686 quirk->port_probe(priv); 1688 quirk->port_probe(priv);
@@ -1839,6 +1841,9 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
1839 1841
1840 dbg("%s", __func__); 1842 dbg("%s", __func__);
1841 1843
1844 priv->dev_gone = true;
1845 wake_up_interruptible_all(&priv->delta_msr_wait);
1846
1842 remove_sysfs_attrs(port); 1847 remove_sysfs_attrs(port);
1843 1848
1844 kref_put(&priv->kref, ftdi_sio_priv_release); 1849 kref_put(&priv->kref, ftdi_sio_priv_release);
@@ -1982,17 +1987,19 @@ static int ftdi_process_packet(struct tty_struct *tty,
1982 N.B. packet may be processed more than once, but differences 1987 N.B. packet may be processed more than once, but differences
1983 are only processed once. */ 1988 are only processed once. */
1984 status = packet[0] & FTDI_STATUS_B0_MASK; 1989 status = packet[0] & FTDI_STATUS_B0_MASK;
1985 if (status & FTDI_RS0_CTS)
1986 priv->icount.cts++;
1987 if (status & FTDI_RS0_DSR)
1988 priv->icount.dsr++;
1989 if (status & FTDI_RS0_RI)
1990 priv->icount.rng++;
1991 if (status & FTDI_RS0_RLSD)
1992 priv->icount.dcd++;
1993 if (status != priv->prev_status) { 1990 if (status != priv->prev_status) {
1994 priv->diff_status |= status ^ priv->prev_status; 1991 char diff_status = status ^ priv->prev_status;
1995 wake_up_interruptible(&priv->delta_msr_wait); 1992
1993 if (diff_status & FTDI_RS0_CTS)
1994 priv->icount.cts++;
1995 if (diff_status & FTDI_RS0_DSR)
1996 priv->icount.dsr++;
1997 if (diff_status & FTDI_RS0_RI)
1998 priv->icount.rng++;
1999 if (diff_status & FTDI_RS0_RLSD)
2000 priv->icount.dcd++;
2001
2002 wake_up_interruptible_all(&priv->delta_msr_wait);
1996 priv->prev_status = status; 2003 priv->prev_status = status;
1997 } 2004 }
1998 2005
@@ -2395,15 +2402,12 @@ static int ftdi_ioctl(struct tty_struct *tty,
2395 */ 2402 */
2396 case TIOCMIWAIT: 2403 case TIOCMIWAIT:
2397 cprev = priv->icount; 2404 cprev = priv->icount;
2398 while (1) { 2405 while (!priv->dev_gone) {
2399 interruptible_sleep_on(&priv->delta_msr_wait); 2406 interruptible_sleep_on(&priv->delta_msr_wait);
2400 /* see if a signal did it */ 2407 /* see if a signal did it */
2401 if (signal_pending(current)) 2408 if (signal_pending(current))
2402 return -ERESTARTSYS; 2409 return -ERESTARTSYS;
2403 cnow = priv->icount; 2410 cnow = priv->icount;
2404 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
2405 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
2406 return -EIO; /* no change => error */
2407 if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || 2411 if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
2408 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || 2412 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
2409 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || 2413 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
@@ -2412,7 +2416,7 @@ static int ftdi_ioctl(struct tty_struct *tty,
2412 } 2416 }
2413 cprev = cnow; 2417 cprev = cnow;
2414 } 2418 }
2415 /* not reached */ 2419 return -EIO;
2416 break; 2420 break;
2417 case TIOCSERGETLSR: 2421 case TIOCSERGETLSR:
2418 return get_lsr_info(port, (struct serial_struct __user *)arg); 2422 return get_lsr_info(port, (struct serial_struct __user *)arg);