summaryrefslogtreecommitdiff
path: root/drivers/usb/serial/ch341.c
diff options
context:
space:
mode:
authorLibor Pechacek <lpechacek@suse.cz>2011-01-14 14:30:21 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2011-01-22 18:53:26 -0800
commitd14fc1a74e846d7851f24fc9519fe87dc12a1231 (patch)
tree9d014b0200d4f2ba94c6d5ed1002c46027147fae /drivers/usb/serial/ch341.c
parentca9cfea09fc5802074f79d086547c6363ddc894b (diff)
downloadlinux-3.10-d14fc1a74e846d7851f24fc9519fe87dc12a1231.tar.gz
linux-3.10-d14fc1a74e846d7851f24fc9519fe87dc12a1231.tar.bz2
linux-3.10-d14fc1a74e846d7851f24fc9519fe87dc12a1231.zip
USB: serial: handle Data Carrier Detect changes
Alan's commit 335f8514f200e63d689113d29cb7253a5c282967 introduced .carrier_raised function in several drivers. That also means tty_port_block_til_ready can now suspend the process trying to open the serial port when Carrier Detect is low and put it into tty_port.open_wait queue. We need to wake up the process when Carrier Detect goes high and trigger TTY hangup when CD goes low. Some of the devices do not report modem status line changes, or at least we don't understand the status message, so for those we remove .carrier_raised again. Signed-off-by: Libor Pechacek <lpechacek@suse.cz> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial/ch341.c')
-rw-r--r--drivers/usb/serial/ch341.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index 63f7cc45bca..7b8815ddf36 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -486,12 +486,22 @@ static void ch341_read_int_callback(struct urb *urb)
if (actual_length >= 4) {
struct ch341_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
+ u8 prev_line_status = priv->line_status;
spin_lock_irqsave(&priv->lock, flags);
priv->line_status = (~(data[2])) & CH341_BITS_MODEM_STAT;
if ((data[1] & CH341_MULT_STAT))
priv->multi_status_change = 1;
spin_unlock_irqrestore(&priv->lock, flags);
+
+ if ((priv->line_status ^ prev_line_status) & CH341_BIT_DCD) {
+ struct tty_struct *tty = tty_port_tty_get(&port->port);
+ if (tty)
+ usb_serial_handle_dcd_change(port, tty,
+ priv->line_status & CH341_BIT_DCD);
+ tty_kref_put(tty);
+ }
+
wake_up_interruptible(&priv->delta_msr_wait);
}