aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorSimon Arlott <simon@fire.lp0.eu>2012-03-26 16:19:40 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-04-09 18:41:16 -0400
commitfca5430d48d53eaf103498c33fd0d1984b9f448b (patch)
tree3cfa374927c3cab25186369f7a4a0d0af7ee89ec /drivers/usb
parentcd4376e23a59a2adf3084cb5f4a523e6d5fd4e49 (diff)
USB: ftdi_sio: fix status line change handling for TIOCMIWAIT and TIOCGICOUNT
Handling of TIOCMIWAIT was changed by commit 1d749f9afa657f6ee9336b2bc1fcd750a647d157 USB: ftdi_sio.c: Use ftdi async_icount structure for TIOCMIWAIT, as in other drivers FTDI_STATUS_B0_MASK does not indicate the changed modem status lines, it indicates the value of the current modem status lines. An xor is still required to determine which lines have changed. The count was only being incremented if the line was high. The only reason TIOCMIWAIT still worked was because the status packet is repeated every 1ms, so the count was always changing. The wakeup itself still ran based on the status lines changing. This change fixes handling of updates to the modem status lines and allows multiple processes to use TIOCMIWAIT concurrently. Tested with two processes waiting on different status lines being toggled independently. Signed-off-by: Simon Arlott <simon@fire.lp0.eu> Cc: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/serial/ftdi_sio.c24
1 files changed, 13 insertions, 11 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index ff8605b4b4be..c02e4602d90a 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -75,7 +75,7 @@ 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 char transmit_empty; /* If transmitter is empty or not */ 79 char transmit_empty; /* If transmitter is empty or not */
80 struct usb_serial_port *port; 80 struct usb_serial_port *port;
81 __u16 interface; /* FT2232C, FT2232H or FT4232H port interface 81 __u16 interface; /* FT2232C, FT2232H or FT4232H port interface
@@ -1982,17 +1982,19 @@ static int ftdi_process_packet(struct tty_struct *tty,
1982 N.B. packet may be processed more than once, but differences 1982 N.B. packet may be processed more than once, but differences
1983 are only processed once. */ 1983 are only processed once. */
1984 status = packet[0] & FTDI_STATUS_B0_MASK; 1984 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) { 1985 if (status != priv->prev_status) {
1994 priv->diff_status |= status ^ priv->prev_status; 1986 char diff_status = status ^ priv->prev_status;
1995 wake_up_interruptible(&priv->delta_msr_wait); 1987
1988 if (diff_status & FTDI_RS0_CTS)
1989 priv->icount.cts++;
1990 if (diff_status & FTDI_RS0_DSR)
1991 priv->icount.dsr++;
1992 if (diff_status & FTDI_RS0_RI)
1993 priv->icount.rng++;
1994 if (diff_status & FTDI_RS0_RLSD)
1995 priv->icount.dcd++;
1996
1997 wake_up_interruptible_all(&priv->delta_msr_wait);
1996 priv->prev_status = status; 1998 priv->prev_status = status;
1997 } 1999 }
1998 2000