summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2014-01-02 22:49:30 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-03 12:42:24 -0800
commitfd74b0b144d3e392b5269207ae4abba03f0adf59 (patch)
treedace08b0d5e8f0d59e5524db0452c94880f31f36 /drivers/usb
parentb770081f88b75212d61a63a84274e491eb54b25a (diff)
downloadlinux-fd74b0b144d3e392b5269207ae4abba03f0adf59.tar.bz2
USB: ch341: fix ignored TIOCMIWAIT mask
Make sure the TIOCMIWAIT mask is always honoured. The CH341 interrupt status has a multiple-status changed flag which indicates that multiple status changes has occurred since last interrupt event. Unfortunately, if the final status is the same, there appears to be no way to determine which signal(s) has changed (an even number of times). This means that the multiple-status flag should not be used in TIOCMIWAIT as it leads to the signal mask argument being ignored (e.g. TIOCMIWAIT could return if DSR changes twice, even though the user only cares about carrier changes). Signed-off-by: Johan Hovold <jhovold@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/serial/ch341.c12
1 files changed, 4 insertions, 8 deletions
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index 9dd94a7e08b9..025b7857a36c 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -83,7 +83,6 @@ struct ch341_private {
unsigned baud_rate; /* set baud rate */
u8 line_control; /* set line control value RTS/DTR */
u8 line_status; /* active status of modem control inputs */
- u8 multi_status_change; /* status changed multiple since last call */
};
static int ch341_control_out(struct usb_device *dev, u8 request,
@@ -174,7 +173,6 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
r = 0;
spin_lock_irqsave(&priv->lock, flags);
priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
- priv->multi_status_change = 0;
spin_unlock_irqrestore(&priv->lock, flags);
} else
r = -EPROTO;
@@ -457,10 +455,11 @@ static void ch341_update_line_status(struct usb_serial_port *port,
spin_lock_irqsave(&priv->lock, flags);
delta = status ^ priv->line_status;
priv->line_status = status;
- if (data[1] & CH341_MULT_STAT)
- priv->multi_status_change = 1;
spin_unlock_irqrestore(&priv->lock, flags);
+ if (data[1] & CH341_MULT_STAT)
+ dev_dbg(&port->dev, "%s - multiple status change\n", __func__);
+
if (delta & CH341_BIT_DCD) {
tty = tty_port_tty_get(&port->port);
if (tty) {
@@ -516,14 +515,12 @@ static int ch341_tiocmiwait(struct tty_struct *tty, unsigned long arg)
u8 prevstatus;
u8 status;
u8 changed;
- u8 multi_change = 0;
spin_lock_irqsave(&priv->lock, flags);
prevstatus = priv->line_status;
- priv->multi_status_change = 0;
spin_unlock_irqrestore(&priv->lock, flags);
- while (!multi_change) {
+ for (;;) {
interruptible_sleep_on(&port->port.delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
@@ -534,7 +531,6 @@ static int ch341_tiocmiwait(struct tty_struct *tty, unsigned long arg)
spin_lock_irqsave(&priv->lock, flags);
status = priv->line_status;
- multi_change = priv->multi_status_change;
spin_unlock_irqrestore(&priv->lock, flags);
changed = prevstatus ^ status;