]> err.no Git - linux-2.6/commitdiff
Address CH341 comments by Alan Cox
authorTollef Fog Heen <tfheen@err.no>
Sun, 21 Sep 2008 08:26:08 +0000 (10:26 +0200)
committerTollef Fog Heen <tfheen@err.no>
Sun, 21 Sep 2008 08:26:08 +0000 (10:26 +0200)
* 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 <tfheen@err.no>
drivers/usb/serial/ch341.c

index 17b61764af5aae5b3f31923420d0725cc8140ec5..39dee378440b0d181babdc3aa0494a5c82321ac6 100644 (file)
@@ -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;