]> git.hungrycats.org Git - linux/commitdiff
tty: cp210x: Fix carrier handling
authorAlan Cox <alan@linux.intel.com>
Wed, 28 Oct 2009 20:12:33 +0000 (21:12 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 8 Dec 2009 18:21:24 +0000 (10:21 -0800)
commit d94c7bd4c1361cab58a21d530078c5673863dcc2 upstream.

Original discussion:
http://thread.gmane.org/gmane.linux.usb.general/23217/focus=23248
or
http://marc.info/?l=linux-usb&m=125553790714133&w=2

9a68e39d4a701fb3be03cae9b462408664ebd205 broke carrier handling so that a
cp210x setup which needed the carrier lines set up (non CLOCAL) which did
not make a call which set the termios bits left the lines down even if
CLOCAL was not asserted.

Fix this not by reverting but by adding the proper dtr_rts and
carrier_raised methods. This both sets the modem lines properly and also
implements the correct blocking semantics for the port as required by
POSIX.

Signed-off-by: Alan Cox <alan@linux.intel.com>
Reported-by: Karl Hiramoto <karl@hiramoto.org>
Tested-by: Karl Hiramoto <karl@hiramoto.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/serial/cp210x.c

index a69457f939085d69df216c1cfd15ac436b318355..2367325e80b0063dd9462f9e571c8cb44c22608b 100644 (file)
@@ -51,6 +51,8 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *,
 static void cp210x_break_ctl(struct tty_struct *, int);
 static int cp210x_startup(struct usb_serial *);
 static void cp210x_disconnect(struct usb_serial *);
+static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
+static int cp210x_carrier_raised(struct usb_serial_port *p);
 
 static int debug;
 
@@ -144,6 +146,8 @@ static struct usb_serial_driver cp210x_device = {
        .tiocmset               = cp210x_tiocmset,
        .attach                 = cp210x_startup,
        .disconnect             = cp210x_disconnect,
+       .dtr_rts                = cp210x_dtr_rts,
+       .carrier_raised         = cp210x_carrier_raised
 };
 
 /* Config request types */
@@ -748,6 +752,14 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *file,
        return cp210x_set_config(port, CP210X_SET_MHS, &control, 2);
 }
 
+static void cp210x_dtr_rts(struct usb_serial_port *p, int on)
+{
+       if (on)
+               cp210x_tiocmset_port(p, NULL,  TIOCM_DTR|TIOCM_RTS, 0);
+       else
+               cp210x_tiocmset_port(p, NULL,  0, TIOCM_DTR|TIOCM_RTS);
+}
+
 static int cp210x_tiocmget (struct tty_struct *tty, struct file *file)
 {
        struct usb_serial_port *port = tty->driver_data;
@@ -770,6 +782,15 @@ static int cp210x_tiocmget (struct tty_struct *tty, struct file *file)
        return result;
 }
 
+static int cp210x_carrier_raised(struct usb_serial_port *p)
+{
+       unsigned int control;
+       cp210x_get_config(p, CP210X_GET_MDMSTS, &control, 1);
+       if (control & CONTROL_DCD)
+               return 1;
+       return 0;
+}
+
 static void cp210x_break_ctl (struct tty_struct *tty, int break_state)
 {
        struct usb_serial_port *port = tty->driver_data;