aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2014-01-02 16:49:30 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-03 15:42:24 -0500
commitfd74b0b144d3e392b5269207ae4abba03f0adf59 (patch)
treedace08b0d5e8f0d59e5524db0452c94880f31f36
parentb770081f88b75212d61a63a84274e491eb54b25a (diff)
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>
-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 {
83 unsigned baud_rate; /* set baud rate */ 83 unsigned baud_rate; /* set baud rate */
84 u8 line_control; /* set line control value RTS/DTR */ 84 u8 line_control; /* set line control value RTS/DTR */
85 u8 line_status; /* active status of modem control inputs */ 85 u8 line_status; /* active status of modem control inputs */
86 u8 multi_status_change; /* status changed multiple since last call */
87}; 86};
88 87
89static int ch341_control_out(struct usb_device *dev, u8 request, 88static 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)
174 r = 0; 173 r = 0;
175 spin_lock_irqsave(&priv->lock, flags); 174 spin_lock_irqsave(&priv->lock, flags);
176 priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT; 175 priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
177 priv->multi_status_change = 0;
178 spin_unlock_irqrestore(&priv->lock, flags); 176 spin_unlock_irqrestore(&priv->lock, flags);
179 } else 177 } else
180 r = -EPROTO; 178 r = -EPROTO;
@@ -457,10 +455,11 @@ static void ch341_update_line_status(struct usb_serial_port *port,
457 spin_lock_irqsave(&priv->lock, flags); 455 spin_lock_irqsave(&priv->lock, flags);
458 delta = status ^ priv->line_status; 456 delta = status ^ priv->line_status;
459 priv->line_status = status; 457 priv->line_status = status;
460 if (data[1] & CH341_MULT_STAT)
461 priv->multi_status_change = 1;
462 spin_unlock_irqrestore(&priv->lock, flags); 458 spin_unlock_irqrestore(&priv->lock, flags);
463 459
460 if (data[1] & CH341_MULT_STAT)
461 dev_dbg(&port->dev, "%s - multiple status change\n", __func__);
462
464 if (delta & CH341_BIT_DCD) { 463 if (delta & CH341_BIT_DCD) {
465 tty = tty_port_tty_get(&port->port); 464 tty = tty_port_tty_get(&port->port);
466 if (tty) { 465 if (tty) {
@@ -516,14 +515,12 @@ static int ch341_tiocmiwait(struct tty_struct *tty, unsigned long arg)
516 u8 prevstatus; 515 u8 prevstatus;
517 u8 status; 516 u8 status;
518 u8 changed; 517 u8 changed;
519 u8 multi_change = 0;
520 518
521 spin_lock_irqsave(&priv->lock, flags); 519 spin_lock_irqsave(&priv->lock, flags);
522 prevstatus = priv->line_status; 520 prevstatus = priv->line_status;
523 priv->multi_status_change = 0;
524 spin_unlock_irqrestore(&priv->lock, flags); 521 spin_unlock_irqrestore(&priv->lock, flags);
525 522
526 while (!multi_change) { 523 for (;;) {
527 interruptible_sleep_on(&port->port.delta_msr_wait); 524 interruptible_sleep_on(&port->port.delta_msr_wait);
528 /* see if a signal did it */ 525 /* see if a signal did it */
529 if (signal_pending(current)) 526 if (signal_pending(current))
@@ -534,7 +531,6 @@ static int ch341_tiocmiwait(struct tty_struct *tty, unsigned long arg)
534 531
535 spin_lock_irqsave(&priv->lock, flags); 532 spin_lock_irqsave(&priv->lock, flags);
536 status = priv->line_status; 533 status = priv->line_status;
537 multi_change = priv->multi_status_change;
538 spin_unlock_irqrestore(&priv->lock, flags); 534 spin_unlock_irqrestore(&priv->lock, flags);
539 535
540 changed = prevstatus ^ status; 536 changed = prevstatus ^ status;