]> git.hungrycats.org Git - linux/commitdiff
tty: USB serial termios bits
authorAlan Cox <alan@linux.intel.com>
Sat, 19 Sep 2009 20:13:33 +0000 (13:13 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 5 Oct 2009 16:32:37 +0000 (09:32 -0700)
commit fe1ae7fdd2ee603f2d95f04e09a68f7f79045127 upstream.

Various drivers have hacks to mangle termios structures. This stems from
the fact there is no nice setup hook for configuring the termios settings
when the port is created

Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/char/tty_io.c
drivers/usb/serial/ark3116.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/empeg.c
drivers/usb/serial/iuu_phoenix.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/spcp8x5.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/whiteheat.c
include/linux/usb/serial.h

index a3afa0c387cdeb79c9dc9a406eb70935ceaf50d4..9fc95178a7a998a383aa0fd2e186ac7c109b6665 100644 (file)
@@ -1184,6 +1184,7 @@ int tty_init_termios(struct tty_struct *tty)
        tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
        return 0;
 }
+EXPORT_SYMBOL_GPL(tty_init_termios);
 
 /**
  *     tty_driver_install_tty() - install a tty entry in the driver
index aec61880f36c0485be60ad6774447937ecc14d42..1a50beb3202910964524bc5d5f44044101663a9e 100644 (file)
@@ -35,11 +35,6 @@ static struct usb_device_id id_table [] = {
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-struct ark3116_private {
-       spinlock_t lock;
-       u8 termios_initialized;
-};
-
 static inline void ARK3116_SND(struct usb_serial *serial, int seq,
                               __u8 request, __u8 requesttype,
                               __u16 value, __u16 index)
@@ -82,22 +77,11 @@ static inline void ARK3116_RCV_QUIET(struct usb_serial *serial,
 static int ark3116_attach(struct usb_serial *serial)
 {
        char *buf;
-       struct ark3116_private *priv;
-       int i;
-
-       for (i = 0; i < serial->num_ports; ++i) {
-               priv = kzalloc(sizeof(struct ark3116_private), GFP_KERNEL);
-               if (!priv)
-                       goto cleanup;
-               spin_lock_init(&priv->lock);
-
-               usb_set_serial_port_data(serial->port[i], priv);
-       }
 
        buf = kmalloc(1, GFP_KERNEL);
        if (!buf) {
                dbg("error kmalloc -> out of mem?");
-               goto cleanup;
+               return -ENOMEM;
        }
 
        /* 3 */
@@ -149,13 +133,16 @@ static int ark3116_attach(struct usb_serial *serial)
 
        kfree(buf);
        return 0;
+}
 
-cleanup:
-       for (--i; i >= 0; --i) {
-               kfree(usb_get_serial_port_data(serial->port[i]));
-               usb_set_serial_port_data(serial->port[i], NULL);
-       }
-       return -ENOMEM;
+static void ark3116_init_termios(struct tty_struct *tty)
+{
+       struct ktermios *termios = tty->termios;
+       *termios = tty_std_termios;
+       termios->c_cflag = B9600 | CS8
+                                     | CREAD | HUPCL | CLOCAL;
+       termios->c_ispeed = 9600;
+       termios->c_ospeed = 9600;
 }
 
 static void ark3116_set_termios(struct tty_struct *tty,
@@ -163,10 +150,8 @@ static void ark3116_set_termios(struct tty_struct *tty,
                                struct ktermios *old_termios)
 {
        struct usb_serial *serial = port->serial;
-       struct ark3116_private *priv = usb_get_serial_port_data(port);
        struct ktermios *termios = tty->termios;
        unsigned int cflag = termios->c_cflag;
-       unsigned long flags;
        int baud;
        int ark3116_baud;
        char *buf;
@@ -176,16 +161,6 @@ static void ark3116_set_termios(struct tty_struct *tty,
 
        dbg("%s - port %d", __func__, port->number);
 
-       spin_lock_irqsave(&priv->lock, flags);
-       if (!priv->termios_initialized) {
-               *termios = tty_std_termios;
-               termios->c_cflag = B9600 | CS8
-                                             | CREAD | HUPCL | CLOCAL;
-               termios->c_ispeed = 9600;
-               termios->c_ospeed = 9600;
-               priv->termios_initialized = 1;
-       }
-       spin_unlock_irqrestore(&priv->lock, flags);
 
        cflag = termios->c_cflag;
        termios->c_cflag &= ~(CMSPAR|CRTSCTS);
@@ -455,6 +430,7 @@ static struct usb_serial_driver ark3116_device = {
        .num_ports =            1,
        .attach =               ark3116_attach,
        .set_termios =          ark3116_set_termios,
+       .init_termios =         ark3116_init_termios,
        .ioctl =                ark3116_ioctl,
        .tiocmget =             ark3116_tiocmget,
        .open =                 ark3116_open,
index 59adfe123110b5e3c631f2ffa111d5b3c56680a7..27b5a271fe4a8b21ce19868aa9729ea448ce136d 100644 (file)
@@ -659,15 +659,7 @@ static int cypress_open(struct tty_struct *tty,
        spin_unlock_irqrestore(&priv->lock, flags);
 
        /* Set termios */
-       result = cypress_write(tty, port, NULL, 0);
-
-       if (result) {
-               dev_err(&port->dev,
-                       "%s - failed setting the control lines - error %d\n",
-                                                       __func__, result);
-               return result;
-       } else
-               dbg("%s - success setting the control lines", __func__);
+       cypress_send(port);
 
        if (tty)
                cypress_set_termios(tty, port, &priv->tmp_termios);
@@ -1005,6 +997,8 @@ static void cypress_set_termios(struct tty_struct *tty,
        dbg("%s - port %d", __func__, port->number);
 
        spin_lock_irqsave(&priv->lock, flags);
+       /* We can't clean this one up as we don't know the device type
+          early enough */
        if (!priv->termios_initialized) {
                if (priv->chiptype == CT_EARTHMATE) {
                        *(tty->termios) = tty_std_termios;
index 80cb3471adbe0fe64cae662184aef149180a942b..3433f9db4418bbd06f3b33c65864e30ce880b338 100644 (file)
@@ -90,8 +90,7 @@ static int  empeg_chars_in_buffer(struct tty_struct *tty);
 static void empeg_throttle(struct tty_struct *tty);
 static void empeg_unthrottle(struct tty_struct *tty);
 static int  empeg_startup(struct usb_serial *serial);
-static void empeg_set_termios(struct tty_struct *tty,
-               struct usb_serial_port *port, struct ktermios *old_termios);
+static void empeg_init_termios(struct tty_struct *tty);
 static void empeg_write_bulk_callback(struct urb *urb);
 static void empeg_read_bulk_callback(struct urb *urb);
 
@@ -123,7 +122,7 @@ static struct usb_serial_driver empeg_device = {
        .throttle =             empeg_throttle,
        .unthrottle =           empeg_unthrottle,
        .attach =               empeg_startup,
-       .set_termios =          empeg_set_termios,
+       .init_termios =         empeg_init_termios,
        .write =                empeg_write,
        .write_room =           empeg_write_room,
        .chars_in_buffer =      empeg_chars_in_buffer,
@@ -150,9 +149,6 @@ static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port,
 
        dbg("%s - port %d", __func__, port->number);
 
-       /* Force default termio settings */
-       empeg_set_termios(tty, port, NULL) ;
-
        bytes_in = 0;
        bytes_out = 0;
 
@@ -425,11 +421,9 @@ static int  empeg_startup(struct usb_serial *serial)
 }
 
 
-static void empeg_set_termios(struct tty_struct *tty,
-               struct usb_serial_port *port, struct ktermios *old_termios)
+static void empeg_init_termios(struct tty_struct *tty)
 {
        struct ktermios *termios = tty->termios;
-       dbg("%s - port %d", __func__, port->number);
 
        /*
         * The empeg-car player wants these particular tty settings.
index 96873a7a32b082ecd370e4329852a65e6b3d356b..af6df6c788b9808422e2139cd65662ca0e2a66b4 100644 (file)
@@ -71,7 +71,6 @@ struct iuu_private {
        spinlock_t lock;        /* store irq state */
        wait_queue_head_t delta_msr_wait;
        u8 line_status;
-       u8 termios_initialized;
        int tiostatus;          /* store IUART SIGNAL for tiocmget call */
        u8 reset;               /* if 1 reset is needed */
        int poll;               /* number of poll */
@@ -1018,6 +1017,18 @@ static void iuu_close(struct usb_serial_port *port)
        }
 }
 
+static void iuu_init_termios(struct tty_struct *tty)
+{
+       *(tty->termios) = tty_std_termios;
+       tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
+                               | TIOCM_CTS | CSTOPB | PARENB;
+       tty->termios->c_ispeed = 9600;
+       tty->termios->c_ospeed = 9600;
+       tty->termios->c_lflag = 0;
+       tty->termios->c_oflag = 0;
+       tty->termios->c_iflag = 0;
+}
+
 static int iuu_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp)
 {
@@ -1025,7 +1036,6 @@ static int iuu_open(struct tty_struct *tty,
        u8 *buf;
        int result;
        u32 actual;
-       unsigned long flags;
        struct iuu_private *priv = usb_get_serial_port_data(port);
 
        dbg("%s -  port %d", __func__, port->number);
@@ -1064,21 +1074,7 @@ static int iuu_open(struct tty_struct *tty,
                          port->bulk_in_buffer, 512,
                          NULL, NULL);
 
-       /* set the termios structure */
-       spin_lock_irqsave(&priv->lock, flags);
-       if (tty && !priv->termios_initialized) {
-               *(tty->termios) = tty_std_termios;
-               tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
-                                       | TIOCM_CTS | CSTOPB | PARENB;
-               tty->termios->c_ispeed = 9600;
-               tty->termios->c_ospeed = 9600;
-               tty->termios->c_lflag = 0;
-               tty->termios->c_oflag = 0;
-               tty->termios->c_iflag = 0;
-               priv->termios_initialized = 1;
-               priv->poll = 0;
-        }
-       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->poll = 0;
 
        /* initialize writebuf */
 #define FISH(a, b, c, d) do { \
@@ -1201,6 +1197,7 @@ static struct usb_serial_driver iuu_device = {
        .tiocmget = iuu_tiocmget,
        .tiocmset = iuu_tiocmset,
        .set_termios = iuu_set_termios,
+       .init_termios = iuu_init_termios,
        .attach = iuu_startup,
        .release = iuu_release,
 };
index 6db0e561f6805c25a032797ffd1e25bf57c5fa18..46d47d1463c943ef4f209e754bbb700d458f09d3 100644 (file)
@@ -85,7 +85,7 @@ static void kobil_read_int_callback(struct urb *urb);
 static void kobil_write_callback(struct urb *purb);
 static void kobil_set_termios(struct tty_struct *tty,
                        struct usb_serial_port *port, struct ktermios *old);
-
+static void kobil_init_termios(struct tty_struct *tty);
 
 static struct usb_device_id id_table [] = {
        { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) },
@@ -120,6 +120,7 @@ static struct usb_serial_driver kobil_device = {
        .release =              kobil_release,
        .ioctl =                kobil_ioctl,
        .set_termios =          kobil_set_termios,
+       .init_termios =         kobil_init_termios,
        .tiocmget =             kobil_tiocmget,
        .tiocmset =             kobil_tiocmset,
        .open =                 kobil_open,
@@ -210,6 +211,15 @@ static void kobil_release(struct usb_serial *serial)
                kfree(usb_get_serial_port_data(serial->port[i]));
 }
 
+static void kobil_init_termios(struct tty_struct *tty)
+{
+       /* Default to echo off and other sane device settings */
+       tty->termios->c_lflag = 0;
+       tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
+       tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
+       /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */
+       tty->termios->c_oflag &= ~ONLCR;
+}
 
 static int kobil_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp)
@@ -226,16 +236,6 @@ static int kobil_open(struct tty_struct *tty,
        /* someone sets the dev to 0 if the close method has been called */
        port->interrupt_in_urb->dev = port->serial->dev;
 
-       if (tty) {
-
-               /* Default to echo off and other sane device settings */
-               tty->termios->c_lflag = 0;
-               tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN |
-                                                                XCASE);
-               tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
-               /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */
-               tty->termios->c_oflag &= ~ONLCR;
-       }
        /* allocate memory for transfer buffer */
        transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
        if (!transfer_buffer)
index 3cece27325e71d90c7042aabfd812d70b2d158d4..ef34cffabdf8008d820b43795688023c37652a13 100644 (file)
@@ -146,6 +146,7 @@ static int oti6858_open(struct tty_struct *tty,
 static void oti6858_close(struct usb_serial_port *port);
 static void oti6858_set_termios(struct tty_struct *tty,
                        struct usb_serial_port *port, struct ktermios *old);
+static void oti6858_init_termios(struct tty_struct *tty);
 static int oti6858_ioctl(struct tty_struct *tty, struct file *file,
                        unsigned int cmd, unsigned long arg);
 static void oti6858_read_int_callback(struct urb *urb);
@@ -186,6 +187,7 @@ static struct usb_serial_driver oti6858_device = {
        .write =                oti6858_write,
        .ioctl =                oti6858_ioctl,
        .set_termios =          oti6858_set_termios,
+       .init_termios =         oti6858_init_termios,
        .tiocmget =             oti6858_tiocmget,
        .tiocmset =             oti6858_tiocmset,
        .read_bulk_callback =   oti6858_read_bulk_callback,
@@ -206,7 +208,6 @@ struct oti6858_private {
        struct {
                u8 read_urb_in_use;
                u8 write_urb_in_use;
-               u8 termios_initialized;
        } flags;
        struct delayed_work delayed_write_work;
 
@@ -447,6 +448,14 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty)
        return chars;
 }
 
+static void oti6858_init_termios(struct tty_struct *tty)
+{
+       *(tty->termios) = tty_std_termios;
+       tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
+       tty->termios->c_ispeed = 38400;
+       tty->termios->c_ospeed = 38400;
+}
+
 static void oti6858_set_termios(struct tty_struct *tty,
                struct usb_serial_port *port, struct ktermios *old_termios)
 {
@@ -464,16 +473,6 @@ static void oti6858_set_termios(struct tty_struct *tty,
                return;
        }
 
-       spin_lock_irqsave(&priv->lock, flags);
-       if (!priv->flags.termios_initialized) {
-               *(tty->termios) = tty_std_termios;
-               tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
-               tty->termios->c_ispeed = 38400;
-               tty->termios->c_ospeed = 38400;
-               priv->flags.termios_initialized = 1;
-       }
-       spin_unlock_irqrestore(&priv->lock, flags);
-
        cflag = tty->termios->c_cflag;
 
        spin_lock_irqsave(&priv->lock, flags);
index 3c249d8e8b8eb356fef7aaee52ef2e0157994a01..993a6d5a1b7ad8783ef55ccdd6b716700012b199 100644 (file)
@@ -299,7 +299,6 @@ struct spcp8x5_private {
        wait_queue_head_t       delta_msr_wait;
        u8                      line_control;
        u8                      line_status;
-       u8                      termios_initialized;
 };
 
 /* desc : when device plug in,this function would be called.
@@ -498,6 +497,15 @@ static void spcp8x5_close(struct usb_serial_port *port)
                dev_dbg(&port->dev, "usb_unlink_urb(read_urb) = %d\n", result);
 }
 
+static void spcp8x5_init_termios(struct tty_struct *tty)
+{
+       /* for the 1st time call this function */
+       *(tty->termios) = tty_std_termios;
+       tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
+       tty->termios->c_ispeed = 115200;
+       tty->termios->c_ospeed = 115200;
+}
+
 /* set the serial param for transfer. we should check if we really need to
  * transfer. if we set flow control we should do this too. */
 static void spcp8x5_set_termios(struct tty_struct *tty,
@@ -514,16 +522,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
        int i;
        u8 control;
 
-       /* for the 1st time call this function */
-       spin_lock_irqsave(&priv->lock, flags);
-       if (!priv->termios_initialized) {
-               *(tty->termios) = tty_std_termios;
-               tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
-               tty->termios->c_ispeed = 115200;
-               tty->termios->c_ospeed = 115200;
-               priv->termios_initialized = 1;
-       }
-       spin_unlock_irqrestore(&priv->lock, flags);
 
        /* check that they really want us to change something */
        if (!tty_termios_hw_change(tty->termios, old_termios))
@@ -1011,6 +1009,7 @@ static struct usb_serial_driver spcp8x5_device = {
        .carrier_raised         = spcp8x5_carrier_raised,
        .write                  = spcp8x5_write,
        .set_termios            = spcp8x5_set_termios,
+       .init_termios           = spcp8x5_init_termios,
        .ioctl                  = spcp8x5_ioctl,
        .tiocmget               = spcp8x5_tiocmget,
        .tiocmset               = spcp8x5_tiocmset,
index 31c7a0939b986079397671bff061e86d451cea66..ce6997f346f45d09397de7171e7c797e1ae39195 100644 (file)
@@ -721,6 +721,41 @@ static const struct tty_port_operations serial_port_ops = {
        .dtr_rts = serial_dtr_rts,
 };
 
+/**
+ *     serial_install          -       install tty
+ *     @driver: the driver (USB in our case)
+ *     @tty: the tty being created
+ *
+ *     Create the termios objects for this tty. We use the default USB
+ *     serial ones but permit them to be overriddenby serial->type->termios.
+ *     This lets us remove all the ugly hackery
+ */
+
+static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+       int idx = tty->index;
+       struct usb_serial *serial;
+       int retval;
+
+       /* If the termios setup has yet to be done */
+       if (tty->driver->termios[idx] == NULL) {
+               /* perform the standard setup */
+               retval = tty_init_termios(tty);
+               if (retval)
+                       return retval;
+               /* allow the driver to update it */
+               serial = usb_serial_get_by_index(tty->index);
+               if (serial->type->init_termios)
+                       serial->type->init_termios(tty);
+               usb_serial_put(serial);
+       }
+       /* Final install (we use the default method) */
+       tty_driver_kref_get(driver);
+       tty->count++;
+       driver->ttys[idx] = tty;
+       return 0;
+}
+
 int usb_serial_probe(struct usb_interface *interface,
                               const struct usb_device_id *id)
 {
@@ -1228,7 +1263,8 @@ static const struct tty_operations serial_ops = {
        .chars_in_buffer =      serial_chars_in_buffer,
        .tiocmget =             serial_tiocmget,
        .tiocmset =             serial_tiocmset,
-       .shutdown =             serial_do_free,
+       .shutdown =             serial_do_free,
+       .install =              serial_install,
        .proc_fops =            &serial_proc_fops,
 };
 
index 8d126dd7a02e4ebf423b54bf4064599721fb98b2..f7232b1bce5127cefbbc62a89fefc7c6883b574d 100644 (file)
@@ -259,7 +259,7 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command,
                                                __u8 *data, __u8 datasize);
 static int firm_open(struct usb_serial_port *port);
 static int firm_close(struct usb_serial_port *port);
-static int firm_setup_port(struct tty_struct *tty);
+static void firm_setup_port(struct tty_struct *tty);
 static int firm_set_rts(struct usb_serial_port *port, __u8 onoff);
 static int firm_set_dtr(struct usb_serial_port *port, __u8 onoff);
 static int firm_set_break(struct usb_serial_port *port, __u8 onoff);
@@ -1211,7 +1211,7 @@ static int firm_close(struct usb_serial_port *port)
 }
 
 
-static int firm_setup_port(struct tty_struct *tty)
+static void firm_setup_port(struct tty_struct *tty)
 {
        struct usb_serial_port *port = tty->driver_data;
        struct whiteheat_port_settings port_settings;
@@ -1286,7 +1286,7 @@ static int firm_setup_port(struct tty_struct *tty)
        port_settings.lloop = 0;
 
        /* now send the message to the device */
-       return firm_send_command(port, WHITEHEAT_SETUP_PORT,
+       firm_send_command(port, WHITEHEAT_SETUP_PORT,
                        (__u8 *)&port_settings, sizeof(port_settings));
 }
 
index 0ec50ba62139e5bde97db61a10b8585c2882c916..73f121ef4de0309418b075e30745fcd17ac3cbfd 100644 (file)
@@ -261,6 +261,9 @@ struct usb_serial_driver {
           be an attached tty at this point */
        void (*dtr_rts)(struct usb_serial_port *port, int on);
        int  (*carrier_raised)(struct usb_serial_port *port);
+       /* Called by the usb serial hooks to allow the user to rework the
+          termios state */
+       void (*init_termios)(struct tty_struct *tty);
        /* USB events */
        void (*read_int_callback)(struct urb *urb);
        void (*write_int_callback)(struct urb *urb);