From 09ed51af78b6100b246db39edf0a498f12b2a531 Mon Sep 17 00:00:00 2001 From: Tollef Fog Heen Date: Sun, 21 Sep 2008 10:26:08 +0200 Subject: [PATCH] Address CH341 comments by Alan Cox * Mask off bits we don't support * Write back into the termios what the baud rate ended up being * Don't raise RTS/DTR unless CLOCAL is set * In set_termios, tty->termios can't be null * Use wait_event_interruptible rather than interruptible_sleep_on Signed-off-by: Tollef Fog Heen --- drivers/usb/serial/ch341.c | 60 ++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 17b61764af..39dee37844 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -68,11 +68,12 @@ MODULE_DEVICE_TABLE(usb, id_table); struct ch341_private { spinlock_t lock; /* access lock */ wait_queue_head_t delta_msr_wait; /* wait queue for modem status */ + int delta_msr_cond; 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 */ - struct usb_device *dev; + struct usb_serial *serial; }; static int ch341_control_out(struct usb_device *dev, u8 request, @@ -104,17 +105,21 @@ static int ch341_control_in(struct usb_device *dev, } static int ch341_set_baudrate(struct usb_device *dev, + struct tty_struct *tty, struct ch341_private *priv) { short a, b; int r; unsigned long factor; short divisor; + unsigned baud; + unsigned t1, t2; dbg("ch341_set_baudrate(%d)", priv->baud_rate); - if (!priv->baud_rate) - return -EINVAL; + if (priv->baud_rate > CH341_BAUDBASE_FACTOR) + priv->baud_rate = CH341_BAUDBASE_FACTOR; + factor = (CH341_BAUDBASE_FACTOR / priv->baud_rate); divisor = CH341_BAUDBASE_DIVMAX; @@ -123,8 +128,19 @@ static int ch341_set_baudrate(struct usb_device *dev, divisor--; } - if (factor > 0xfff0) - return -EINVAL; + if (factor > 0xfff0) { /* Clamp */ + factor = 0xfff0; + divisor = 0; + } + + t1 = factor; + for (t2 = divisor; t2 <= CH341_BAUDBASE_DIVMAX; t2++) { + t1 >>= 3; + } + baud = CH341_BAUDBASE_FACTOR / t1; + + if (baud && tty) + tty_encode_baud_rate(tty, baud, baud); factor = 0x10000 - factor; a = (factor & 0xff00) | divisor; @@ -197,7 +213,7 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) if (r < 0) goto out; - r = ch341_set_baudrate(dev, priv); + r = ch341_set_baudrate(dev, NULL, priv); if (r < 0) goto out; @@ -219,7 +235,7 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) if (r < 0) goto out; - r = ch341_set_baudrate(dev, priv); + r = ch341_set_baudrate(dev, NULL, priv); if (r < 0) goto out; @@ -252,8 +268,7 @@ static int ch341_attach(struct usb_serial *serial) priv->baud_rate = DEFAULT_BAUD_RATE; priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR; - priv->dev = serial->dev; - priv->adapter.owner = THIS_MODULE; + priv->serial = serial; r = ch341_configure(serial->dev, priv); if (r < 0) @@ -261,8 +276,6 @@ static int ch341_attach(struct usb_serial *serial) usb_set_serial_port_data(serial->port[0], priv); - dev_info(&priv->adapter.dev, "connected ch341 device\n"); - return 0; error: kfree(priv); @@ -274,7 +287,6 @@ static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port, { struct ch341_private *priv = usb_get_serial_port_data(port); unsigned long flags; - unsigned int c_cflag; dbg("%s - port %d", __func__, port->number); @@ -285,8 +297,7 @@ static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port, usb_kill_urb(port->interrupt_in_urb); if (tty) { - c_cflag = tty->termios->c_cflag; - if (c_cflag & HUPCL) { + if (C_HUPCL(tty)) { /* drop DTR and RTS */ spin_lock_irqsave(&priv->lock, flags); priv->line_control = 0; @@ -295,6 +306,7 @@ static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port, } } wake_up_interruptible(&priv->delta_msr_wait); + priv->delta_msr_cond = 1; } @@ -309,7 +321,12 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port, dbg("ch341_open()"); priv->baud_rate = DEFAULT_BAUD_RATE; - priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR; + + if (C_CLOCAL(tty)) { + priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR; + } else { + priv->line_control = 0; + } r = ch341_configure(serial->dev, priv); if (r) @@ -319,7 +336,7 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port, if (r) goto out; - r = ch341_set_baudrate(serial->dev, priv); + r = ch341_set_baudrate(serial->dev, tty, priv); if (r) goto out; @@ -350,7 +367,7 @@ static void ch341_set_termios(struct tty_struct *tty, dbg("ch341_set_termios()"); - if (!tty || !tty->termios) + if (!tty) return; baud_rate = tty_get_baud_rate(tty); @@ -361,7 +378,7 @@ static void ch341_set_termios(struct tty_struct *tty, spin_lock_irqsave(&priv->lock, flags); priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS); spin_unlock_irqrestore(&priv->lock, flags); - ch341_set_baudrate(port->serial->dev, priv); + ch341_set_baudrate(port->serial->dev, tty, priv); } else { spin_lock_irqsave(&priv->lock, flags); priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS); @@ -375,6 +392,8 @@ static void ch341_set_termios(struct tty_struct *tty, * (cflag & PARENB) : parity {NONE, EVEN, ODD} * (cflag & CSTOPB) : stop bits [1, 2] */ + tty->termios->c_cflag &= ~(CSIZE | PARENB | CSTOPB); + } static int ch341_tiocmset(struct tty_struct *tty, struct file *file, @@ -439,6 +458,7 @@ static void ch341_read_int_callback(struct urb *urb) priv->multi_status_change = 1; spin_unlock_irqrestore(&priv->lock, flags); wake_up_interruptible(&priv->delta_msr_wait); + priv->delta_msr_cond = 1; } exit: @@ -464,7 +484,9 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) spin_unlock_irqrestore(&priv->lock, flags); while (!multi_change) { - interruptible_sleep_on(&priv->delta_msr_wait); + priv->delta_msr_cond = 0; + wait_event_interruptible(priv->delta_msr_wait, + (priv->delta_msr_cond == 1)); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; -- 2.39.5