]> oss.titaniummirror.com Git - cp210x.git/commitdiff
Reorganize code in cp2101.c
authorsmckown <smckown@986fd584-583e-0410-b54d-b9fe63dff8e5>
Wed, 15 Apr 2009 16:40:39 +0000 (16:40 +0000)
committersmckown <smckown@986fd584-583e-0410-b54d-b9fe63dff8e5>
Wed, 15 Apr 2009 16:40:39 +0000 (16:40 +0000)
Now cp2101.c looks like it would if the minimal patch were applied to cp2101.c
from the plain vanilla linux 2.6.24 code.  We did also add some newer usb
device id's from 2.6.30's cp2101.c.

src/cp2101.c

index f9433a17af41e7c98fe1b8c5af94180389d2ec67..7ad61dacfb60afe1a6138956da624e5747592d85 100644 (file)
  * thanks to Karl Hiramoto karl@hiramoto.org. RTSCTS hardware flow
  * control thanks to Munir Nassar nassarmu@real-time.com
  *
+ * Silicon Labs RJM: updated to 0.11 for 2.6.15 and later kernels
+ *
  * Port configuration, usb descriptor and gpio management by R. Steve McKown
- * (smckown@titaniummirror.com).
+ * rsmckown@gmail.com.
  *
  * Outstanding Issues:
  *  Buffers are not flushed when the port is opened.
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/usb.h>
-#include <linux/version.h>
 #include <asm/uaccess.h>
-#include <linux/byteorder/generic.h>
-
-#ifndef KERNEL_VERSION
-#define KERNEL_VERSION(a,b,c) ((a)*65536 + (b)*256 + (c))
-#endif
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
-#ifdef LINUX26
-#undef LINUX26
-#endif
-#define LINUX26
-#endif
-
-#ifdef LINUX26
-
-#include <linux/moduleparam.h>
 #include <linux/usb/serial.h>
-#define DEV_ERR(dev,format,arg...) dev_err(dev,format, ## arg)
-#define USB_KILL_URB usb_kill_urb
-
-#else /* !LINUX26 */
-
-#include <linux/config.h>
-#include "usb-serial.h"
-
-#ifdef CONFIG_USB_SERIAL_DEBUG
-       static int debug = 1;
-#else
-       static int debug;
-#endif
-
-#define DEV_ERR(dev,format,arg...)  err(format, ## arg)
-#define USB_KILL_URB  usb_unlink_urb
-
-#endif /* LINUX26 */
 
 /*
  * Version Information
- * RJM: updated to 0.11 for 2.6.15 and later kernels
  */
 #define DRIVER_VERSION "v0.11rsm"
 #define DRIVER_DESC "Silicon Labs CP2101/CP2102/CP2103 RS232 serial adaptor driver"
 /*
  * Function Prototypes
  */
-static int     cp2101_open(struct usb_serial_port*, struct file*);
+static int cp2101_open(struct usb_serial_port*, struct file*);
 static void cp2101_cleanup(struct usb_serial_port*);
 static void cp2101_close(struct usb_serial_port*, struct file*);
 static void cp2101_get_termios(struct usb_serial_port*);
-static void cp2101_set_termios(struct usb_serial_port*, struct termios*);
+static void cp2101_set_termios(struct usb_serial_port*, struct ktermios*);
+static int cp2101_tiocmget (struct usb_serial_port *, struct file *);
+static int cp2101_tiocmset (struct usb_serial_port *, struct file *,
+               unsigned int, unsigned int);
 static void cp2101_break_ctl(struct usb_serial_port*, int);
-static int     cp2101_startup (struct usb_serial *);
+static int cp2101_startup (struct usb_serial *);
 static void cp2101_shutdown(struct usb_serial*);
-static int  cp2101_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg);
-static int     cp2101_tiocmget (struct usb_serial_port *, struct file *);
-static int     cp2101_tiocmset (struct usb_serial_port *, struct file *, unsigned int, unsigned int);
+static int cp2101_ioctl(struct usb_serial_port *, struct file *,
+               unsigned int, unsigned long);
 
 static int debug;
 
 static struct usb_device_id id_table [] = {
+       { USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */
+       { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
+       { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
        { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
+       { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */
+       { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */
        { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
        { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
        { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
+       { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */
        { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
+       { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
+       { USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */
        { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */
        { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */
        { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
+       { USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */
        { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
+       { USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */
        { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
        { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */
        { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */
        { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
+       { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */
+       { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */
+       { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */
        { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
        { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
+       { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
        { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
+       { USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */
+       { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demostration module */
+       { USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */
+       { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
+       { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */
+       { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
        { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
+       { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
+       { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */
+       { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */
+       { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */
+       { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */
        { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
+       { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
        { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
+       { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
        { } /* Terminating Entry */
 };
 
 MODULE_DEVICE_TABLE (usb, id_table);
 
-#ifdef LINUX26
 static struct usb_driver cp2101_driver = {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
-       .owner          = THIS_MODULE,
-#endif
-       .name           = "CP2101",
+       .name           = "cp2101",
        .probe          = usb_serial_probe,
        .disconnect     = usb_serial_disconnect,
        .id_table       = id_table,
+       .no_dynamic_id  =       1,
 };
-#define USB_SUBMIT_URB_ATOMIC(_x_) usb_submit_urb(_x_ , GFP_ATOMIC)
-#define USB_SUBMIT_URB_KERNEL(_x_) usb_submit_urb(_x_ , GFP_KERNEL)
-
-#else  /* LINUX26 */
-
-#define USB_SUBMIT_URB_ATOMIC(_x_) usb_submit_urb(_x_)
-#define USB_SUBMIT_URB_KERNEL(_x_) usb_submit_urb(_x_)
-#endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
 static struct usb_serial_driver cp2101_device = {
        .driver = {
                .owner =        THIS_MODULE,
                .name =         "cp2101",
        },
-#else
-static struct usb_serial_device_type cp2101_device = {
-       .owner                          = THIS_MODULE,
-       .name                           = "CP2101/CP2102/CP2103 USB to UART Bridge",
-#endif
-       .id_table                       = id_table,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+       .usb_driver             = &cp2101_driver,
+       .id_table               = id_table,
        .num_interrupt_in       = 0,
-       .num_bulk_in            = 0,
-       .num_bulk_out           = 0,
-#else
-       .num_interrupt_in       = NUM_DONT_CARE,
        .num_bulk_in            = NUM_DONT_CARE,
        .num_bulk_out           = NUM_DONT_CARE,
-#endif
-       .num_ports                      = 1,
-       .open                           = cp2101_open,
-       .close                          = cp2101_close,
-       .ioctl                          = cp2101_ioctl,     /* GLA, Added backport */
-       .break_ctl                      = cp2101_break_ctl,
-       .set_termios                    = cp2101_set_termios,
-#ifdef LINUX26
-       .tiocmget                       = cp2101_tiocmget,
-       .tiocmset                       = cp2101_tiocmset,
-       .attach                         = cp2101_startup,
-#else
-       .startup                        = cp2101_startup,
-#endif
-       .shutdown                       = cp2101_shutdown
+       .num_ports              = 1,
+       .open                   = cp2101_open,
+       .close                  = cp2101_close,
+       .ioctl                  = cp2101_ioctl,
+       .break_ctl              = cp2101_break_ctl,
+       .set_termios            = cp2101_set_termios,
+       .tiocmget               = cp2101_tiocmget,
+       .tiocmset               = cp2101_tiocmset,
+       .attach                 = cp2101_startup,
+       .shutdown               = cp2101_shutdown,
 };
 
 /* Config request types */
@@ -176,54 +146,54 @@ static struct usb_serial_device_type cp2101_device = {
 #define REQTYPE_DEVICE_TO_HOST 0xc1
 
 /* Config SET requests. To GET, add 1 to the request number */
-#define CP2101_UART                    0x00    /* Enable / Disable */
-#define CP2101_BAUDRATE                        0x01    /* (BAUD_RATE_GEN_FREQ / baudrate) */
-#define CP2101_BITS                            0x03    /* 0x(0)(databits)(parity)(stopbits) */
-#define CP2101_BREAK                   0x05    /* On / Off */
-#define CP2101_CONTROL                 0x07    /* Flow control line states */
-#define CP2101_MODEMCTL                        0x13    /* Modem controls */
-#define CP2101_CONFIG_6                        0x19    /* 6 bytes of config data ??? */
+#define CP2101_UART            0x00    /* Enable / Disable */
+#define CP2101_BAUDRATE                0x01    /* (BAUD_RATE_GEN_FREQ / baudrate) */
+#define CP2101_BITS            0x03    /* 0x(0)(databits)(parity)(stopbits) */
+#define CP2101_BREAK           0x05    /* On / Off */
+#define CP2101_CONTROL         0x07    /* Flow control line states */
+#define CP2101_MODEMCTL                0x13    /* Modem controls */
+#define CP2101_CONFIG_6                0x19    /* 6 bytes of config data ??? */
 
 /* CP2101_UART */
-#define UART_ENABLE                            0x0001
-#define UART_DISABLE                   0x0000
+#define UART_ENABLE            0x0001
+#define UART_DISABLE           0x0000
 
 /* CP2101_BAUDRATE */
-#define BAUD_RATE_GEN_FREQ             0x384000
+#define BAUD_RATE_GEN_FREQ     0x384000
 
 /* CP2101_BITS */
-#define BITS_DATA_MASK                 0x0f00
-#define BITS_DATA_5                            0x0500
-#define BITS_DATA_6                            0x0600
-#define BITS_DATA_7                            0x0700
-#define BITS_DATA_8                            0x0800
-#define BITS_DATA_9                            0x0900
-
-#define BITS_PARITY_MASK               0x00f0
-#define BITS_PARITY_NONE               0x0000
-#define BITS_PARITY_ODD                        0x0010
-#define BITS_PARITY_EVEN               0x0020
-#define BITS_PARITY_MARK               0x0030
-#define BITS_PARITY_SPACE              0x0040
-
-#define BITS_STOP_MASK             0x000f
-#define BITS_STOP_1                    0x0000
-#define BITS_STOP_1_5              0x0001
-#define BITS_STOP_2                    0x0002
+#define BITS_DATA_MASK         0X0f00
+#define BITS_DATA_5            0X0500
+#define BITS_DATA_6            0X0600
+#define BITS_DATA_7            0X0700
+#define BITS_DATA_8            0X0800
+#define BITS_DATA_9            0X0900
+
+#define BITS_PARITY_MASK       0x00f0
+#define BITS_PARITY_NONE       0x0000
+#define BITS_PARITY_ODD                0x0010
+#define BITS_PARITY_EVEN       0x0020
+#define BITS_PARITY_MARK       0x0030
+#define BITS_PARITY_SPACE      0x0040
+
+#define BITS_STOP_MASK         0x000f
+#define BITS_STOP_1            0x0000
+#define BITS_STOP_1_5          0x0001
+#define BITS_STOP_2            0x0002
 
 /* CP2101_BREAK */
-#define BREAK_ON                       0x0000
-#define BREAK_OFF                      0x0001
+#define BREAK_ON               0x0000
+#define BREAK_OFF              0x0001
 
 /* CP2101_CONTROL */
-#define CONTROL_DTR                    0x0001
-#define CONTROL_RTS                    0x0002
-#define CONTROL_CTS                    0x0010
-#define CONTROL_DSR                    0x0020
-#define CONTROL_RING               0x0040
-#define CONTROL_DCD                    0x0080
-#define CONTROL_WRITE_DTR          0x0100
-#define CONTROL_WRITE_RTS          0x0200
+#define CONTROL_DTR            0x0001
+#define CONTROL_RTS            0x0002
+#define CONTROL_CTS            0x0010
+#define CONTROL_DSR            0x0020
+#define CONTROL_RING           0x0040
+#define CONTROL_DCD            0x0080
+#define CONTROL_WRITE_DTR      0x0100
+#define CONTROL_WRITE_RTS      0x0200
 
 /* CP2103 ioctls */
 #define IOCTL_GPIOGET          0x8000  /* Get gpio bits */
@@ -244,34 +214,34 @@ static struct usb_serial_device_type cp2101_device = {
 /* FIXME: where is IOCTL_SETMFG? */
 
 /* CP2103 GPIO */
-#define GPIO_0         0x01
-#define GPIO_1         0x02
-#define GPIO_2         0x04
-#define GPIO_3         0x08
-#define GPIO_MASK      (GPIO_0|GPIO_1|GPIO_2|GPIO_3)
+#define GPIO_0                 0x01
+#define GPIO_1                 0x02
+#define GPIO_2                 0x04
+#define GPIO_3                 0x08
+#define GPIO_MASK              (GPIO_0|GPIO_1|GPIO_2|GPIO_3)
 
 /* GetDeviceVersion() return codes */
-#define                CP210x_CP2101_VERSION                           0x01
-#define                CP210x_CP2102_VERSION                           0x02
-#define                CP210x_CP2103_VERSION                           0x03
-                                                                                       
+#define CP210x_CP2101_VERSION  0x01
+#define        CP210x_CP2102_VERSION   0x02
+#define        CP210x_CP2103_VERSION   0x03
+
 /* Return codes */
-#define                CP210x_SUCCESS                                          0x00
-#define                CP210x_DEVICE_NOT_FOUND                         0xFF
-#define                CP210x_INVALID_HANDLE                           0x01
-#define                CP210x_INVALID_PARAMETER                        0x02
-#define                CP210x_DEVICE_IO_FAILED                         0x03
-#define                CP210x_FUNCTION_NOT_SUPPORTED           0x04
-#define                CP210x_GLOBAL_DATA_ERROR                        0x05
-#define                CP210x_FILE_ERROR                                       0x06
-#define                CP210x_COMMAND_FAILED                           0x08
-#define                CP210x_INVALID_ACCESS_TYPE                      0x09
+#define        CP210x_SUCCESS                  0x00
+#define        CP210x_DEVICE_NOT_FOUND         0xFF
+#define        CP210x_INVALID_HANDLE           0x01
+#define        CP210x_INVALID_PARAMETER        0x02
+#define        CP210x_DEVICE_IO_FAILED         0x03
+#define        CP210x_FUNCTION_NOT_SUPPORTED   0x04
+#define        CP210x_GLOBAL_DATA_ERROR        0x05
+#define        CP210x_FILE_ERROR               0x06
+#define        CP210x_COMMAND_FAILED           0x08
+#define        CP210x_INVALID_ACCESS_TYPE      0x09
 
 /* USB descriptor sizes */
-#define                CP210x_MAX_DEVICE_STRLEN                        256
-#define                CP210x_MAX_PRODUCT_STRLEN                       126
-#define                CP210x_MAX_SERIAL_STRLEN                        63
-#define                CP210x_MAX_MAXPOWER                                     250
+#define        CP210x_MAX_DEVICE_STRLEN        256
+#define        CP210x_MAX_PRODUCT_STRLEN       126
+#define        CP210x_MAX_SERIAL_STRLEN        63
+#define        CP210x_MAX_MAXPOWER             250
 
 /* Used to pass variable sized buffers between user and kernel space (ioctls) */
 typedef struct {
@@ -281,31 +251,30 @@ typedef struct {
 
 /* Port config definitions */
 typedef struct {
-    uint16_t mode;             /* Push-pull = 1, Open-drain = 0 */
-    uint16_t lowPower;
-    uint16_t latch;            /* Logic high = 1, Logic low = 0 */
+       uint16_t mode;          /* Push-pull = 1, Open-drain = 0 */
+       uint16_t lowPower;
+       uint16_t latch;         /* Logic high = 1, Logic low = 0 */
 } cp2101_port_state_t;
 
 typedef struct {
-    cp2101_port_state_t reset;
-    cp2101_port_state_t suspend;
-    uint8_t enhancedFxn;
+       cp2101_port_state_t reset;
+       cp2101_port_state_t suspend;
+       uint8_t enhancedFxn;
 } cp2101_port_config_t;
 
 #define PORT_CONFIG_LEN        13      /* Because sizeof() will pad to full words */
 
-
 /*
  * cp2101_buf_from_user
  * Copy a buffer from user space, returning the number of bytes copied
  * from ubuf.buf into kbuf.  klen is the size of the buffer at kbuf.
  */
-size_t copy_buf_from_user(charkbuf, unsigned long ubuf, size_t klen)
+size_t copy_buf_from_user(char *kbuf, unsigned long ubuf, size_t klen)
 {
-    cp2101_buffer_t t;
+       cp2101_buffer_t t;
 
-       if (!kbuf || !ubuf || !klen || copy_from_user(&t, (cp2101_buffer_t *)ubuf,
-                       sizeof(t)))
+       if (!kbuf || !ubuf || !klen ||
+                       copy_from_user(&t, (cp2101_buffer_t *)ubuf, sizeof(t)))
                return 0;
        if (t.len < klen)
                klen = t.len;
@@ -314,145 +283,6 @@ size_t copy_buf_from_user(char* kbuf, unsigned long ubuf, size_t klen)
        return klen;
 }
 
-/*
- * cp2101_get_config
- * Reads from the CP2101 configuration registers
- * 'size' is specified in bytes.
- * 'data' is a pointer to a pre-allocated array of integers large
- * enough to hold 'size' bytes (with 4 bytes to each integer)
- */
-static int cp2101_get_config(struct usb_serial_port* port, u8 request,
-               unsigned int *data, int size)
-{
-       struct usb_serial *serial = port->serial;
-       u32 *buf;
-       int result, i, length;
-
-       /* Number of integers required to contain the array */
-       length = (((size - 1) | 3) + 1)/4;
-
-       buf = kmalloc (length * sizeof(u32), GFP_KERNEL);
-       memset(buf, 0, length * sizeof(u32));
-
-       if (!buf) {
-               DEV_ERR(&port->dev,"%s - out of memory.\n", __FUNCTION__);
-               return -ENOMEM;
-       }
-
-       /* For get requests, the request number must be incremented */
-       request++;
-
-       /* Issue the request, attempting to read 'size' bytes */
-       result = usb_control_msg (
-                    serial->dev,
-                    usb_rcvctrlpipe (serial->dev, 0),
-                                   request, 
-                    REQTYPE_DEVICE_TO_HOST, 
-                    0x0000,
-                                   0, 
-                    buf, 
-                    size, 
-                    300);
-
-       /* Convert data into an array of integers */
-       for (i=0; i<length; i++) data[i] = le32_to_cpu(buf[i]);
-
-       kfree(buf);
-
-       if (result != size) {
-               DEV_ERR(&port->dev,"%s - Unable to send config request, "
-                               "request=0x%x size=%d result=%d\n",
-                               __FUNCTION__, request, size, result);
-               return -EPROTO;
-       }
-
-       return 0;
-}
-
-/*
- * cp2101_set_config
- * Writes to the CP2101 configuration registers
- * Values less than 16 bits wide are sent directly
- * 'size' is specified in bytes.
- */
-static int cp2101_set_config(struct usb_serial_port* port, u8 request,
-               unsigned int *data, int size)
-{
-       struct usb_serial *serial = port->serial;
-       u32 *buf;
-       int result, i, length;
-
-       /* Number of integers required to contain the array */
-       length = (((size - 1) | 3) + 1)/4;
-
-       buf = kmalloc(length * sizeof(u32), GFP_KERNEL);
-       if (!buf) {
-               DEV_ERR(&port->dev,"%s - out of memory.\n",
-                               __FUNCTION__);
-               return -ENOMEM;
-       }
-
-       /* Array of integers into bytes */
-       for (i = 0; i < length; i++) buf[i] = cpu_to_le32(data[i]);
-
-       if (size > 2) {
-               result = usb_control_msg (
-                    serial->dev,
-                                   usb_sndctrlpipe(serial->dev, 0),
-                                   request, 
-                    REQTYPE_HOST_TO_DEVICE, 
-                    0x0000,
-                                   0, 
-                    buf, 
-                    size, 
-                    300);
-       } else {
-               result = usb_control_msg (
-                    serial->dev,
-                                   usb_sndctrlpipe(serial->dev, 0),
-                                   request, 
-                    REQTYPE_HOST_TO_DEVICE, 
-                    data[0],
-                                   0, 
-                    NULL, 
-                    0, 
-                    300);
-       }
-
-       kfree(buf);
-
-       if ((size > 2 && result != size) || result < 0) {
-               DEV_ERR(&port->dev,"%s - Unable to send request, "
-                               "request=0x%x size=%d result=%d\n",
-                               __FUNCTION__, request, size, result);
-               return -EPROTO;
-       }
-
-       /* Single data value */
-       result = usb_control_msg (
-                serial->dev,
-                           usb_sndctrlpipe(serial->dev, 0),
-                           request,
-                REQTYPE_HOST_TO_DEVICE, 
-                data[0],
-                           0, 
-                NULL, 
-                0, 
-                300);
-       return 0;
-}
-
-/*
- * cp2101_set_config_single
- * Convenience function for calling cp2101_set_config on single data values
- * without requiring an integer pointer
- */
-static inline int cp2101_set_config_single(struct usb_serial_port* port,
-               u8 request, unsigned int data)
-{
-       return cp2101_set_config(port, request, &data, 2);
-}
-
 /*
  * cp2101_ctlmsg
  * A generic usb control message interface.
@@ -494,8 +324,8 @@ static int cp2101_reset(struct usb_serial_port *port)
 #if 1
     /* Is this better than usb_device_reset?  It may be.  Once a client issues
         * the reset ioctl, it must disconnect and reconnect, since the USB
-        * connections are torn down.  We also ignore the error return, since the
-        * part resets and doesn't send one...
+        * connections are torn down.  We also ignore the error return, since
+        * the part resets and doesn't send one...
         */
        cp2101_ctlmsg(port, 0xff, 0x40, 0x0008, 0x00, 0, 0);
 #else
@@ -509,15 +339,18 @@ static int cp2101_get_partnum(struct usb_serial_port *port)
        static u8 _partnum = 0;
        int ret = CP210x_SUCCESS;
        if (!_partnum) {
-               u8 addr = port->serial->dev->actconfig->interface[0]->cur_altsetting->
-                       endpoint[0].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+               u8 addr = port->serial->dev->actconfig->interface[0]->
+                       cur_altsetting->endpoint[0].desc.bEndpointAddress &
+                       USB_ENDPOINT_NUMBER_MASK;
 
                if (addr == 0x03 || addr == 0x02) /* The part is a cp2101 */
                        _partnum = 0x01;
-               else if (addr == 0x01) /* Must query part to determine part number */
-                       ret = (cp2101_ctlmsg(port, 0xff, 0xc0, 0x370b, 0x00, &_partnum, 1)
-                                       == 1) ? CP210x_SUCCESS : CP210x_DEVICE_IO_FAILED;
-               else
+               else if (addr == 0x01) {
+                       /* Must query part to determine part number */
+                       if (cp2101_ctlmsg(port, 0xff, 0xc0, 0x370b, 0x00,
+                                       &_partnum, 1) != 1)
+                               ret = CP210x_DEVICE_IO_FAILED;
+               } else
                        ret = CP210x_DEVICE_IO_FAILED;
        }
        dbg("%s - partnum %u err %d", __FUNCTION__, _partnum, ret);
@@ -547,7 +380,7 @@ static int make_usb_string(char* usbstr, size_t usblen, char* src,
        if (usbstr && usblen >= 2 && src && *src && srclen) {
                char* p;
 
-               /* The usb string format uses a single byte to represent length */
+               /* The usb string format uses first byte as length */
                if (usblen > 256)
                        usblen = 256;
 
@@ -574,12 +407,241 @@ static int make_usb_string(char* usbstr, size_t usblen, char* src,
 inline int cp2101_setstr(struct usb_serial_port *port, int cmd, char *usbstr)
 {
        unsigned len = usbstr[0];
-       int ret = cp2101_ctlmsg(port, 0xff, 0x40, 0x3700 | (cmd & 0xff), 0, usbstr,
-                       len);
+       int ret = cp2101_ctlmsg(port, 0xff, 0x40, 0x3700 | (cmd & 0xff), 0,
+                       usbstr, len);
        dbg("%s - cmd 0x%02x len %d ret %d", __FUNCTION__, cmd, len, ret);
        return ret;
 }
 
+/* Set all gpio simultaneously */
+static int cp2101_gpioset(struct usb_serial_port *port, u8 gpio)
+{
+       dbg("%s - port %d, gpio = 0x%.2x", __FUNCTION__, port->number, gpio);
+
+       return cp2101_ctlmsg(port, 0xff, 0x40, 0x37e1,
+                       ((uint16_t)gpio << 8) | GPIO_MASK, 0, 0);
+}
+
+/* Set select gpio bits */
+static int cp2101_gpiosetb(struct usb_serial_port *port, u8 set, u8 clear)
+{
+       u16 gpio = 0;
+
+       /* The bitmask is in the LSB, the values in the MSB */
+       if (set & GPIO_0)
+               gpio |= (GPIO_0 << 8)|GPIO_0;
+       if (set & GPIO_1)
+               gpio |= (GPIO_1 << 8)|GPIO_1;
+       if (set & GPIO_2)
+               gpio |= (GPIO_2 << 8)|GPIO_2;
+       if (set & GPIO_3)
+               gpio |= (GPIO_3 << 8)|GPIO_3;
+       if (clear & GPIO_0)
+               gpio = (gpio & ~(GPIO_0 << 8))|GPIO_0;
+       if (clear & GPIO_1)
+               gpio = (gpio & ~(GPIO_1 << 8))|GPIO_1;
+       if (clear & GPIO_2)
+               gpio = (gpio & ~(GPIO_2 << 8))|GPIO_2;
+       if (clear & GPIO_3)
+               gpio = (gpio & ~(GPIO_3 << 8))|GPIO_3;
+
+       dbg("%s - port %d, gpiob = 0x%.4x", __FUNCTION__, port->number, gpio);
+
+       /* FIXME: how about REQTYPE_HOST_TO_DEVICE instead of 0x40? */
+       return cp2101_ctlmsg(port, 0xff, 0x40, 0x37e1, gpio, 0, 0);
+}
+
+static int cp2101_gpioget(struct usb_serial_port *port, u8* gpio)
+{
+       int ret;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       /* FIXME: how about REQTYPE_DEVICE_TO_HOST instead of 0xc0? */
+       ret = cp2101_ctlmsg(port, 0xff, 0xc0, 0x00c2, 0, gpio, 1);
+
+       dbg("%s - gpio = 0x%.2x (%d)", __FUNCTION__, *gpio, ret);
+
+       return (ret == 1) ? 0 : -1;
+}
+
+static int cp2101_portconfset(struct usb_serial_port *port,
+               cp2101_port_config_t* config)
+{
+       cp2101_port_config_t lconfig;
+       int ret;
+
+       dbg("%s", __FUNCTION__);
+
+       memcpy(&lconfig, config, sizeof(lconfig));
+
+       /* apparently not implemented yet */
+       lconfig.suspend.lowPower = 0;
+       lconfig.reset.lowPower = 0;
+
+       /* Words from cp2103 are MSB */
+       lconfig.reset.mode = cpu_to_be16(config->reset.mode);
+       /* lconfig.reset.lowPower = cpu_to_be16(config->reset.lowPower); */
+       lconfig.reset.latch = cpu_to_be16(config->reset.latch);
+       lconfig.suspend.mode = cpu_to_be16(config->suspend.mode);
+       /* lconfig.suspend.lowPower = cpu_to_be16(config->suspend.lowPower); */
+       lconfig.suspend.latch = cpu_to_be16(config->suspend.latch);
+
+       ret = cp2101_ctlmsg(port, 0xff, 0x40, 0x370c, 0, &lconfig,
+                       PORT_CONFIG_LEN);
+       if (ret == PORT_CONFIG_LEN)
+               return 0;
+       else if (ret >= 0)
+               return -1;
+       else
+               return ret;
+}
+
+static int cp2101_portconfget(struct usb_serial_port *port,
+               cp2101_port_config_t* config)
+{
+       int ret;
+
+       dbg("%s", __FUNCTION__);
+
+       ret = cp2101_ctlmsg(port, 0xff, 0xc0, 0x370c, 0, config,
+                       PORT_CONFIG_LEN);
+       if (ret == PORT_CONFIG_LEN) {
+               /* Words from cp2103 are MSB */
+               config->reset.mode = be16_to_cpu(config->reset.mode);
+               config->reset.lowPower = be16_to_cpu(config->reset.lowPower);
+               config->reset.latch = be16_to_cpu(config->reset.latch);
+               config->suspend.mode = be16_to_cpu(config->suspend.mode);
+               config->suspend.lowPower =
+                               be16_to_cpu(config->suspend.lowPower);
+               config->suspend.latch = be16_to_cpu(config->suspend.latch);
+
+               /* apparently not implemented yet */
+               config->reset.lowPower = 0;
+               config->suspend.lowPower = 0;
+
+               return 0;
+       } else if (ret >= 0)
+               return -1;
+       else
+               return ret;
+
+}
+
+/*
+ * cp2101_get_config
+ * Reads from the CP2101 configuration registers
+ * 'size' is specified in bytes.
+ * 'data' is a pointer to a pre-allocated array of integers large
+ * enough to hold 'size' bytes (with 4 bytes to each integer)
+ */
+static int cp2101_get_config(struct usb_serial_port* port, u8 request,
+               unsigned int *data, int size)
+{
+       struct usb_serial *serial = port->serial;
+       __le32 *buf;
+       int result, i, length;
+
+       /* Number of integers required to contain the array */
+       length = (((size - 1) | 3) + 1)/4;
+
+       buf = kcalloc(length, sizeof(__le32), GFP_KERNEL);
+       if (!buf) {
+               dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
+               return -ENOMEM;
+       }
+
+       /* For get requests, the request number must be incremented */
+       request++;
+
+       /* Issue the request, attempting to read 'size' bytes */
+       result = usb_control_msg (serial->dev,usb_rcvctrlpipe (serial->dev, 0),
+                               request, REQTYPE_DEVICE_TO_HOST, 0x0000,
+                               0, buf, size, 300);
+
+       /* Convert data into an array of integers */
+       for (i=0; i<length; i++)
+               data[i] = le32_to_cpu(buf[i]);
+
+       kfree(buf);
+
+       if (result != size) {
+               dev_err(&port->dev, "%s - Unable to send config request, "
+                               "request=0x%x size=%d result=%d\n",
+                               __FUNCTION__, request, size, result);
+               return -EPROTO;
+       }
+
+       return 0;
+}
+
+/*
+ * cp2101_set_config
+ * Writes to the CP2101 configuration registers
+ * Values less than 16 bits wide are sent directly
+ * 'size' is specified in bytes.
+ */
+static int cp2101_set_config(struct usb_serial_port* port, u8 request,
+               unsigned int *data, int size)
+{
+       struct usb_serial *serial = port->serial;
+       __le32 *buf;
+       int result, i, length;
+
+       /* Number of integers required to contain the array */
+       length = (((size - 1) | 3) + 1)/4;
+
+       buf = kmalloc(length * sizeof(__le32), GFP_KERNEL);
+       if (!buf) {
+               dev_err(&port->dev, "%s - out of memory.\n",
+                               __FUNCTION__);
+               return -ENOMEM;
+       }
+
+       /* Array of integers into bytes */
+       for (i = 0; i < length; i++)
+               buf[i] = cpu_to_le32(data[i]);
+
+       if (size > 2) {
+               result = usb_control_msg (serial->dev,
+                               usb_sndctrlpipe(serial->dev, 0),
+                               request, REQTYPE_HOST_TO_DEVICE, 0x0000,
+                               0, buf, size, 300);
+       } else {
+               result = usb_control_msg (serial->dev,
+                               usb_sndctrlpipe(serial->dev, 0),
+                               request, REQTYPE_HOST_TO_DEVICE, data[0],
+                               0, NULL, 0, 300);
+       }
+
+       kfree(buf);
+
+       if ((size > 2 && result != size) || result < 0) {
+               dev_err(&port->dev, "%s - Unable to send request, "
+                               "request=0x%x size=%d result=%d\n",
+                               __FUNCTION__, request, size, result);
+               return -EPROTO;
+       }
+
+       /* Single data value */
+       result = usb_control_msg (serial->dev,
+                       usb_sndctrlpipe(serial->dev, 0),
+                       request, REQTYPE_HOST_TO_DEVICE, data[0],
+                       0, NULL, 0, 300);
+       return 0;
+}
+
+/*
+ * cp2101_set_config_single
+ * Convenience function for calling cp2101_set_config on single data values
+ * without requiring an integer pointer
+ */
+static inline int cp2101_set_config_single(struct usb_serial_port* port,
+               u8 request, unsigned int data)
+{
+       return cp2101_set_config(port, request, &data, 2);
+}
+
 static int cp2101_open (struct usb_serial_port *port, struct file *filp)
 {
        struct usb_serial *serial = port->serial;
@@ -588,7 +650,7 @@ static int cp2101_open (struct usb_serial_port *port, struct file *filp)
        dbg("%s - port %d", __FUNCTION__, port->number);
 
        if (cp2101_set_config_single(port, CP2101_UART, UART_ENABLE)) {
-               DEV_ERR(&port->dev, "%s - Unable to enable UART\n",
+               dev_err(&port->dev, "%s - Unable to enable UART\n",
                                __FUNCTION__);
                return -EPROTO;
        }
@@ -601,9 +663,9 @@ static int cp2101_open (struct usb_serial_port *port, struct file *filp)
                        port->read_urb->transfer_buffer_length,
                        serial->type->read_bulk_callback,
                        port);
-       result = USB_SUBMIT_URB_KERNEL(port->read_urb);
+       result = usb_submit_urb(port->read_urb, GFP_KERNEL);
        if (result) {
-               DEV_ERR(&port->dev, "%s - failed resubmitting read urb, "
+               dev_err(&port->dev, "%s - failed resubmitting read urb, "
                                "error %d\n", __FUNCTION__, result);
                return result;
        }
@@ -623,22 +685,13 @@ static void cp2101_cleanup (struct usb_serial_port *port)
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
-       if (serial != NULL && serial->dev) {
+       if (serial->dev) {
                /* shutdown any bulk reads that might be going on */
                if (serial->num_bulk_out)
-                       USB_KILL_URB(port->write_urb);
+                       usb_kill_urb(port->write_urb);
                if (serial->num_bulk_in)
-                       USB_KILL_URB(port->read_urb);
+                       usb_kill_urb(port->read_urb);
        }
-
-#ifdef LINUX26
-       kfree (usb_get_serial_port_data(port));
-       usb_set_serial_port_data(port, NULL);
-#else
-       /*TODOGLA: port.private maybe?
-         Nobody is using that at the moement in this driver*/
-#endif
-
 }
 
 static void cp2101_close (struct usb_serial_port *port, struct file * filp)
@@ -647,12 +700,180 @@ static void cp2101_close (struct usb_serial_port *port, struct file * filp)
 
        /* shutdown our urbs */
        dbg("%s - shutting down urbs", __FUNCTION__);
-       USB_KILL_URB(port->write_urb);
-       USB_KILL_URB(port->read_urb);
+       usb_kill_urb(port->write_urb);
+       usb_kill_urb(port->read_urb);
 
        cp2101_set_config_single(port, CP2101_UART, UART_DISABLE);
 }
 
+static int cp2101_ioctl(struct usb_serial_port *port, struct file *file,
+               unsigned int cmd, unsigned long arg)
+{
+       dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
+
+       switch (cmd) {
+               
+       case TIOCMGET:
+       {
+               int result = cp2101_tiocmget(port, file);
+               if (copy_to_user(&arg, &result, sizeof(int)))
+                       return -EFAULT; 
+               return 0;
+       }
+       break;
+
+       case TIOCMSET:
+       case TIOCMBIS:
+
+       case TIOCMBIC:
+       {
+               int val = 0;
+
+               if (copy_from_user(&val, &arg, sizeof(int)))
+                       return -EFAULT;
+
+               /* this looks wrong: TIOCMSET isn't going to work right */
+               if (cp2101_tiocmset(port, file, cmd==TIOCMBIC ? 0 : val,
+                                       cmd==TIOCMBIC ? val : 0))
+                       return -EFAULT;
+               return 0;
+       }
+       break;
+
+       case IOCTL_GPIOGET:
+       if (cp2101_get_partnum(port) == CP210x_CP2103_VERSION) {
+               u8 gpio = 0;
+               if (!cp2101_gpioget(port, &gpio) && !copy_to_user((u8*)arg,
+                                       &gpio, sizeof(gpio)))
+                       return 0;
+       }
+       return -EFAULT;
+       break;
+
+       case IOCTL_GPIOSET:
+       if (cp2101_get_partnum(port) == CP210x_CP2103_VERSION &&
+                       !cp2101_gpioset(port, arg))
+               return 0;
+       return -EFAULT;
+       break;
+
+       case IOCTL_GPIOBIC:
+       case IOCTL_GPIOBIS:
+       if (cp2101_get_partnum(port) == CP210x_CP2103_VERSION &&
+                       !cp2101_gpiosetb(port, (cmd==IOCTL_GPIOBIC) ?  0 : arg,
+                       (cmd==IOCTL_GPIOBIC) ? arg : 0))
+               return 0;
+       return -EFAULT;
+       break;
+
+       case IOCTL_DEVICERESET:
+       return cp2101_reset(port);
+       break;
+
+       case IOCTL_PORTCONFGET:
+       {
+               cp2101_port_config_t config;
+               if (!cp2101_portconfget(port, &config) && !copy_to_user(
+                                       (cp2101_port_config_t*)arg, &config,
+                                       sizeof(config)))
+                       return 0;
+       }
+       return -EFAULT;
+       break;
+
+       case IOCTL_PORTCONFSET:
+       {
+       cp2101_port_config_t config;
+       if (!copy_from_user(&config, (cp2101_port_config_t*)arg,
+                       sizeof(config)) &&
+                       !cp2101_portconfset(port, &config))
+               return 0;
+       return -EFAULT;
+       }
+       break;
+
+       case IOCTL_SETVID:
+       {
+               unsigned int vid;
+               if (!copy_from_user(&vid, (unsigned int *)arg,
+                               sizeof(unsigned int)) &&
+                               !cp2101_setu16(port, 0x01, vid))
+                       return 0;
+               return -EFAULT;
+       }
+       break;
+
+       case IOCTL_SETPID:
+       {
+               unsigned int pid;
+               if (!copy_from_user(&pid, (unsigned int *)arg,
+                               sizeof(unsigned int)) &&
+                               !cp2101_setu16(port, 0x02, pid))
+                       return 0;
+               return -EFAULT;
+       }
+       break;
+
+       case IOCTL_SETMFG:
+#if 0 /* Silicon Labs apparently doesn't provide for setting of mfg desc */
+       {
+               char usbstr[CP210x_MAX_MFG_STRLEN * 2 + 2];
+               size_t len = copy_buf_from_user(usbstr + sizeof(usbstr) -
+                               CP210x_MAX_MFG_STRLEN, arg,
+                               CP210x_MAX_MFG_STRLEN);
+               len = make_usb_string(usbstr, sizeof(usbstr), str, len);
+               if (len && cp2101_setstr(port, 0x00, usbstr) == len)
+                       return 0;
+               return -EFAULT;
+       }
+#endif
+       break;
+
+       case IOCTL_SETPRODUCT:
+       {
+               char usbstr[CP210x_MAX_PRODUCT_STRLEN * 2 + 2];
+               char* str = usbstr + sizeof(usbstr) - CP210x_MAX_PRODUCT_STRLEN;
+               size_t len = copy_buf_from_user(str, arg,
+                               CP210x_MAX_PRODUCT_STRLEN);
+               len = make_usb_string(usbstr, sizeof(usbstr), str, len);
+               if (len && cp2101_setstr(port, 0x03, usbstr) == len)
+                       return 0;
+               return -EFAULT;
+       }
+       break;
+
+       case IOCTL_SETSERIAL:
+       {
+               char usbstr[CP210x_MAX_SERIAL_STRLEN * 2 + 2];
+               char* str = usbstr + sizeof(usbstr) - CP210x_MAX_SERIAL_STRLEN;
+               size_t len = copy_buf_from_user(str, arg,
+                               CP210x_MAX_SERIAL_STRLEN);
+               len = make_usb_string(usbstr, sizeof(usbstr), str, len);
+               if (len && cp2101_setstr(port, 0x04, usbstr) == len)
+                       return 0;
+               return -EFAULT;
+       }
+       break;
+
+       case IOCTL_SETDEVVER:
+       {
+               unsigned int ver;
+               if (!copy_from_user(&ver, (unsigned int *)arg,
+                               sizeof(unsigned int)) &&
+                               !cp2101_setu16(port, 0x07, ver))
+                       return 0;
+               return -EFAULT;
+       }
+       break;
+
+       default:
+       dbg("%s not supported = 0x%04x", __FUNCTION__, cmd);
+       break;
+       }
+
+       return -ENOIOCTLCMD;
+}
+
 /*
  * cp2101_get_termios
  * Reads the baud rate, data bits, parity, stop bits and flow control mode
@@ -667,11 +888,10 @@ static void cp2101_get_termios (struct usb_serial_port *port)
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
-       if ((!port->tty) || (!port->tty->termios)) {
+       if (!port->tty || !port->tty->termios) {
                dbg("%s - no tty structures", __FUNCTION__);
                return;
        }
-       cflag = port->tty->termios->c_cflag;
 
        cp2101_get_config(port, CP2101_BAUDRATE, &baud, 2);
        /* Convert to baudrate */
@@ -679,40 +899,9 @@ static void cp2101_get_termios (struct usb_serial_port *port)
                baud = BAUD_RATE_GEN_FREQ / baud;
 
        dbg("%s - baud rate = %d", __FUNCTION__, baud);
-       cflag &= ~CBAUD;
-       switch (baud) {
-               /*
-                * The baud rates which are commented out below
-                * appear to be supported by the device
-                * but are non-standard
-                */
-               case 600:       cflag |= B600;          break;
-               case 1200:      cflag |= B1200;         break;
-               case 1800:      cflag |= B1800;         break;
-               case 2400:      cflag |= B2400;         break;
-               case 4800:      cflag |= B4800;         break;
-               /*case 7200:    cflag |= B7200;         break;*/
-               case 9600:      cflag |= B9600;         break;
-               /*case 14400:   cflag |= B14400;        break;*/
-               case 19200:     cflag |= B19200;        break;
-               /*case 28800:   cflag |= B28800;        break;*/
-               case 38400:     cflag |= B38400;        break;
-               /*case 55854:   cflag |= B55054;        break;*/
-               case 57600:     cflag |= B57600;        break;
-               case 115200:    cflag |= B115200;       break;
-               /*case 127117:  cflag |= B127117;       break;*/
-               case 230400:    cflag |= B230400;       break;
-               case 460800:    cflag |= B460800;       break;
-               case 921600:    cflag |= B921600;       break;
-               /*case 3686400: cflag |= B3686400;      break;*/
-               default:
-                       dbg("%s - Baud rate is not supported, "
-                                       "using 9600 baud", __FUNCTION__);
-                       cflag |= B9600;
-                       cp2101_set_config_single(port, CP2101_BAUDRATE,
-                                       (BAUD_RATE_GEN_FREQ/9600));
-                       break;
-       }
+
+       tty_encode_baud_rate(port->tty, baud, baud);
+       cflag = port->tty->termios->c_cflag;
 
        cp2101_get_config(port, CP2101_BITS, &bits, 2);
        cflag &= ~CSIZE;
@@ -824,63 +1013,50 @@ static void cp2101_get_termios (struct usb_serial_port *port)
 }
 
 static void cp2101_set_termios (struct usb_serial_port *port,
-               struct termios *old_termios)
+               struct ktermios *old_termios)
 {
-       unsigned int cflag, old_cflag=0;
+       unsigned int cflag, old_cflag;
        int baud=0, bits;
        unsigned int modem_ctl[4];
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
-       if ((!port->tty) || (!port->tty->termios)) {
+       if (!port->tty || !port->tty->termios) {
                dbg("%s - no tty structures", __FUNCTION__);
                return;
        }
-       cflag = port->tty->termios->c_cflag;
-
-       /* Check that they really want us to change something */
-       if (old_termios) {
-               if ((cflag == old_termios->c_cflag) &&
-                               (RELEVANT_IFLAG(port->tty->termios->c_iflag)
-                               == RELEVANT_IFLAG(old_termios->c_iflag))) {
-                       dbg("%s - nothing to change...", __FUNCTION__);
-                       return;
-               }
+       port->tty->termios->c_cflag &= ~CMSPAR;
 
-               old_cflag = old_termios->c_cflag;
-       }
+       cflag = port->tty->termios->c_cflag;
+       old_cflag = old_termios->c_cflag;
+       baud = tty_get_baud_rate(port->tty);
 
        /* If the baud rate is to be updated*/
-       if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
-               switch (cflag & CBAUD) {
-                       /*
-                        * The baud rates which are commented out below
-                        * appear to be supported by the device
-                        * but are non-standard
-                        */
-                       case B0:        baud = 0;       break;
-                       case B600:      baud = 600;     break;
-                       case B1200:     baud = 1200;    break;
-                       case B1800:     baud = 1800;    break;
-                       case B2400:     baud = 2400;    break;
-                       case B4800:     baud = 4800;    break;
-                       /*case B7200:   baud = 7200;    break;*/
-                       case B9600:     baud = 9600;    break;
-                       /*ase B14400:   baud = 14400;   break;*/
-                       case B19200:    baud = 19200;   break;
-                       /*case B28800:  baud = 28800;   break;*/
-                       case B38400:    baud = 38400;   break;
-                       /*case B55854:  baud = 55054;   break;*/
-                       case B57600:    baud = 57600;   break;
-                       case B115200:   baud = 115200;  break;
-                       /*case B127117: baud = 127117;  break;*/
-                       case B230400:   baud = 230400;  break;
-                       case B460800:   baud = 460800;  break;
-                       case B921600:   baud = 921600;  break;
-                       /*case B3686400:        baud = 3686400; break;*/
+       if (baud != tty_termios_baud_rate(old_termios)) {
+               switch (baud) {
+                       case 0:
+                       case 600:
+                       case 1200:
+                       case 1800:
+                       case 2400:
+                       case 4800:
+                       case 7200:
+                       case 9600:
+                       case 14400:
+                       case 19200:
+                       case 28800:
+                       case 38400:
+                       case 55854:
+                       case 57600:
+                       case 115200:
+                       case 127117:
+                       case 230400:
+                       case 460800:
+                       case 921600:
+                       case 3686400:
+                               break;
                        default:
-                               DEV_ERR(&port->dev, "cp2101 driver does not "
-                                       "support the baudrate requested\n");
+                               baud = 9600;
                                break;
                }
 
@@ -888,11 +1064,15 @@ static void cp2101_set_termios (struct usb_serial_port *port,
                        dbg("%s - Setting baud rate to %d baud", __FUNCTION__,
                                        baud);
                        if (cp2101_set_config_single(port, CP2101_BAUDRATE,
-                                               (BAUD_RATE_GEN_FREQ / baud)))
-                               DEV_ERR(&port->dev, "Baud rate requested not "
+                                               (BAUD_RATE_GEN_FREQ / baud))) {
+                               dev_err(&port->dev, "Baud rate requested not "
                                                "supported by device\n");
+                               baud = tty_termios_baud_rate(old_termios);
+                       }
                }
        }
+       /* Report back the resulting baud rate */
+       tty_encode_baud_rate(port->tty, baud, baud);
 
        /* If the number of data bits is to be updated */
        if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
@@ -920,14 +1100,14 @@ static void cp2101_set_termios (struct usb_serial_port *port,
                                dbg("%s - data bits = 9", __FUNCTION__);
                                break;*/
                        default:
-                               DEV_ERR(&port->dev, "cp2101 driver does not "
+                               dev_err(&port->dev, "cp2101 driver does not "
                                        "support the number of bits requested,"
                                        " using 8 bit mode\n");
                                bits |= BITS_DATA_8;
                                break;
                }
                if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
-                       DEV_ERR(&port->dev,"Number of data bits requested "
+                       dev_err(&port->dev, "Number of data bits requested "
                                        "not supported by device\n");
        }
 
@@ -944,7 +1124,7 @@ static void cp2101_set_termios (struct usb_serial_port *port,
                        }
                }
                if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
-                       DEV_ERR(&port->dev,"Parity mode not supported "
+                       dev_err(&port->dev, "Parity mode not supported "
                                        "by device\n");
        }
 
@@ -959,7 +1139,7 @@ static void cp2101_set_termios (struct usb_serial_port *port,
                        dbg("%s - stop bits = 1", __FUNCTION__);
                }
                if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
-                       DEV_ERR(&port->dev,"Number of stop bits requested "
+                       dev_err(&port->dev, "Number of stop bits requested "
                                        "not supported by device\n");
        }
 
@@ -1053,287 +1233,6 @@ static void cp2101_break_ctl (struct usb_serial_port *port, int break_state)
        cp2101_set_config(port, CP2101_BREAK, &state, 2);
 }
 
-/* Set all gpio simultaneously */
-static int cp2101_gpioset(struct usb_serial_port *port, u8 gpio)
-{
-       dbg("%s - port %d, gpio = 0x%.2x", __FUNCTION__, port->number, gpio);
-
-    return cp2101_ctlmsg(port, 0xff, 0x40, 0x37e1,
-                       ((uint16_t)gpio << 8) | GPIO_MASK, 0, 0);
-}
-
-/* Set select gpio bits */
-static int cp2101_gpiosetb(struct usb_serial_port *port, u8 set, u8 clear)
-{
-       u16 gpio = 0;
-
-       /* The bitmask is in the LSB, the values in the MSB */
-       if (set & GPIO_0)
-               gpio |= (GPIO_0 << 8)|GPIO_0;
-       if (set & GPIO_1)
-               gpio |= (GPIO_1 << 8)|GPIO_1;
-       if (set & GPIO_2)
-               gpio |= (GPIO_2 << 8)|GPIO_2;
-       if (set & GPIO_3)
-               gpio |= (GPIO_3 << 8)|GPIO_3;
-       if (clear & GPIO_0)
-               gpio = (gpio & ~(GPIO_0 << 8))|GPIO_0;
-       if (clear & GPIO_1)
-               gpio = (gpio & ~(GPIO_1 << 8))|GPIO_1;
-       if (clear & GPIO_2)
-               gpio = (gpio & ~(GPIO_2 << 8))|GPIO_2;
-       if (clear & GPIO_3)
-               gpio = (gpio & ~(GPIO_3 << 8))|GPIO_3;
-
-       dbg("%s - port %d, gpiob = 0x%.4x", __FUNCTION__, port->number, gpio);
-
-       /* FIXME: how about REQTYPE_HOST_TO_DEVICE instead of 0x40? */
-    return cp2101_ctlmsg(port, 0xff, 0x40, 0x37e1, gpio, 0, 0);
-}
-
-static int cp2101_gpioget(struct usb_serial_port *port, u8* gpio)
-{
-       int ret;
-
-       dbg("%s - port %d", __FUNCTION__, port->number);
-
-       /* FIXME: how about REQTYPE_DEVICE_TO_HOST instead of 0xc0? */
-       ret = cp2101_ctlmsg(port, 0xff, 0xc0, 0x00c2, 0, gpio, 1);
-
-       dbg("%s - gpio = 0x%.2x (%d)", __FUNCTION__, *gpio, ret);
-
-       return (ret == 1) ? 0 : -1;
-}
-
-static int cp2101_portconfset(struct usb_serial_port *port,
-               cp2101_port_config_t* config)
-{
-       cp2101_port_config_t lconfig;
-       int ret;
-
-       dbg("%s", __FUNCTION__);
-
-       memcpy(&lconfig, config, sizeof(lconfig));
-
-       /* apparently not implemented yet */
-       lconfig.suspend.lowPower = 0;
-       lconfig.reset.lowPower = 0;
-
-       /* Words from cp2103 are MSB */
-       lconfig.reset.mode = cpu_to_be16(config->reset.mode);
-       /* lconfig.reset.lowPower = cpu_to_be16(config->reset.lowPower); */
-       lconfig.reset.latch = cpu_to_be16(config->reset.latch);
-       lconfig.suspend.mode = cpu_to_be16(config->suspend.mode);
-       /* lconfig.suspend.lowPower = cpu_to_be16(config->suspend.lowPower); */
-       lconfig.suspend.latch = cpu_to_be16(config->suspend.latch);
-
-       ret = cp2101_ctlmsg(port, 0xff, 0x40, 0x370c, 0, &lconfig, PORT_CONFIG_LEN);
-       if (ret == PORT_CONFIG_LEN)
-               return 0;
-       else if (ret >= 0)
-               return -1;
-       else
-               return ret;
-}
-
-static int cp2101_portconfget(struct usb_serial_port *port,
-               cp2101_port_config_t* config)
-{
-       int ret;
-
-       dbg("%s", __FUNCTION__);
-
-       ret = cp2101_ctlmsg(port, 0xff, 0xc0, 0x370c, 0, config, PORT_CONFIG_LEN);
-       if (ret == PORT_CONFIG_LEN) {
-               /* Words from cp2103 are MSB */
-               config->reset.mode = be16_to_cpu(config->reset.mode);
-               config->reset.lowPower = be16_to_cpu(config->reset.lowPower);
-               config->reset.latch = be16_to_cpu(config->reset.latch);
-               config->suspend.mode = be16_to_cpu(config->suspend.mode);
-               config->suspend.lowPower = be16_to_cpu(config->suspend.lowPower);
-               config->suspend.latch = be16_to_cpu(config->suspend.latch);
-
-               /* apparently not implemented yet */
-               config->reset.lowPower = 0;
-               config->suspend.lowPower = 0;
-
-               return 0;
-       } else if (ret >= 0)
-               return -1;
-       else
-               return ret;
-
-}
-
-static int cp2101_ioctl (struct usb_serial_port *port, struct file *file,
-               unsigned int cmd, unsigned long arg)
-{
-       dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
-
-       switch (cmd) {
-               
-#ifndef LINUX26
-               case TIOCMGET:
-            {
-                int result = cp2101_tiocmget(port, file);
-                if (copy_to_user(&arg, &result, sizeof(int)))
-                               return -EFAULT; 
-                               return 0;
-            }
-            break;
-            
-               case TIOCMSET:
-               case TIOCMBIS:
-
-               case TIOCMBIC:
-            {
-                int val = 0;
-
-                               if (copy_from_user(&val, &arg, sizeof(int)))
-                                       return -EFAULT;
-                
-/* this looks wrong:  TIOCMSET isn't going to work right */
-                if(cp2101_tiocmset(port, file, cmd==TIOCMBIC?0:val,  cmd==TIOCMBIC?val:0))
-                    return -EFAULT;
-                               return 0;
-            }
-            break;
-#endif
-
-               case IOCTL_GPIOGET:
-                       if (cp2101_get_partnum(port) == CP210x_CP2103_VERSION) {
-                               u8 gpio = 0;
-                if (!cp2101_gpioget(port, &gpio) &&
-                                               !copy_to_user((u8*)arg, &gpio, sizeof(gpio)))
-                                       return 0;
-            }
-                       return -EFAULT;
-            break;
-            
-               case IOCTL_GPIOSET:
-                       if (cp2101_get_partnum(port) == CP210x_CP2103_VERSION &&
-                                       !cp2101_gpioset(port, arg))
-                               return 0;
-                       return -EFAULT;
-            break;
-
-               case IOCTL_GPIOBIC:
-               case IOCTL_GPIOBIS:
-                       if (cp2101_get_partnum(port) == CP210x_CP2103_VERSION &&
-                                       !cp2101_gpiosetb(port, (cmd==IOCTL_GPIOBIC) ? 0 : arg,
-                                               (cmd==IOCTL_GPIOBIC) ? arg : 0))
-                               return 0;
-                       return -EFAULT;
-            break;
-
-               case IOCTL_DEVICERESET:
-                       return cp2101_reset(port);
-                       break;
-
-               case IOCTL_PORTCONFGET:
-                       {
-                               cp2101_port_config_t config;
-                               if (!cp2101_portconfget(port, &config) &&
-                                               !copy_to_user((cp2101_port_config_t*)arg, &config,
-                                                       sizeof(config)))
-                                       return 0;
-            }
-                       return -EFAULT;
-                       break;
-
-               case IOCTL_PORTCONFSET:
-                       {
-                               cp2101_port_config_t config;
-                   if (!copy_from_user(&config, (cp2101_port_config_t*)arg,
-                                                       sizeof(config)) &&
-                                               !cp2101_portconfset(port, &config))
-                                       return 0;
-                               return -EFAULT;
-                       }
-                       break;
-
-               case IOCTL_SETVID:
-                       {
-                               unsigned int vid;
-                   if (!copy_from_user(&vid, (unsigned int *)arg,
-                                                       sizeof(unsigned int)) &&
-                                               !cp2101_setu16(port, 0x01, vid))
-                                       return 0;
-                               return -EFAULT;
-            }
-            break;
-
-               case IOCTL_SETPID:
-                       {
-                               unsigned int pid;
-                   if (!copy_from_user(&pid, (unsigned int *)arg,
-                                                       sizeof(unsigned int)) &&
-                                               !cp2101_setu16(port, 0x02, pid))
-                                       return 0;
-                               return -EFAULT;
-            }
-            break;
-
-               case IOCTL_SETMFG:
-#if 0 /* Don't know how to set manufacturer desc yet */
-                       {
-                               char usbstr[CP210x_MAX_MFG_STRLEN * 2 + 2];
-                   size_t len = copy_buf_from_user(
-                                               usbstr + sizeof(usbstr) - CP210x_MAX_MFG_STRLEN, arg,
-                                               CP210x_MAX_MFG_STRLEN);
-                               len = make_usb_string(usbstr, sizeof(usbstr), str, len);
-                               if (len && cp2101_setstr(port, 0x00, usbstr) == len)
-                                       return 0;
-                               return -EFAULT;
-            }
-#endif
-            break;
-
-               case IOCTL_SETPRODUCT:
-                       {
-                               char usbstr[CP210x_MAX_PRODUCT_STRLEN * 2 + 2];
-                               char* str = usbstr + sizeof(usbstr) - CP210x_MAX_PRODUCT_STRLEN;
-                   size_t len = copy_buf_from_user(str, arg,
-                                               CP210x_MAX_PRODUCT_STRLEN);
-                               len = make_usb_string(usbstr, sizeof(usbstr), str, len);
-                               if (len && cp2101_setstr(port, 0x03, usbstr) == len)
-                                       return 0;
-                               return -EFAULT;
-            }
-            break;
-
-               case IOCTL_SETSERIAL:
-                       {
-                               char usbstr[CP210x_MAX_SERIAL_STRLEN * 2 + 2];
-                               char* str = usbstr + sizeof(usbstr) - CP210x_MAX_SERIAL_STRLEN;
-                   size_t len = copy_buf_from_user(str, arg,
-                                               CP210x_MAX_SERIAL_STRLEN);
-                               len = make_usb_string(usbstr, sizeof(usbstr), str, len);
-                               if (len && cp2101_setstr(port, 0x04, usbstr) == len)
-                                       return 0;
-                               return -EFAULT;
-            }
-            break;
-
-               case IOCTL_SETDEVVER:
-                       {
-                               unsigned int ver;
-                   if (!copy_from_user(&ver, (unsigned int *)arg,
-                                                       sizeof(unsigned int)) &&
-                                               !cp2101_setu16(port, 0x07, ver))
-                                       return 0;
-                               return -EFAULT;
-            }
-            break;
-
-               default:
-                       dbg("%s not supported = 0x%04x", __FUNCTION__, cmd);
-                       break;
-       }
-
-       return -ENOIOCTLCMD;
-}
-
 static int cp2101_startup (struct usb_serial *serial)
 {
        /* CP2101 buffers behave strangely unless device is reset */
@@ -1349,11 +1248,7 @@ static void cp2101_shutdown (struct usb_serial *serial)
 
        /* Stop reads and writes on all ports */
        for (i=0; i < serial->num_ports; ++i) {
-#ifdef LINUX26
                cp2101_cleanup(serial->port[i]);
-#else
-               cp2101_cleanup(&serial->port[i]);
-#endif
        }
 }
 
@@ -1365,14 +1260,13 @@ static int __init cp2101_init (void)
        if (retval)
                return retval; /* Failed to register */
 
-#ifdef LINUX26
-       retval = usb_register(&cp2101_driver);
+       retval = usb_register(&cp2101_driver);
        if (retval) {
                /* Failed to register */
                usb_serial_deregister(&cp2101_device);
                return retval;
        }
-#endif
+
        /* Success */
        info(DRIVER_DESC " " DRIVER_VERSION);
        return 0;
@@ -1380,9 +1274,7 @@ static int __init cp2101_init (void)
 
 static void __exit cp2101_exit (void)
 {
-#ifdef LINUX26
        usb_deregister (&cp2101_driver);
-#endif
        usb_serial_deregister (&cp2101_device);
 }
 
@@ -1390,17 +1282,8 @@ module_init(cp2101_init);
 module_exit(cp2101_exit);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 
-#ifdef LINUX26
-MODULE_VERSION(DRIVER_VERSION);
 module_param(debug, bool, S_IRUGO | S_IWUSR);
-#else
-MODULE_PARM(debug, "i");
-#endif
 MODULE_PARM_DESC(debug, "Enable verbose debugging messages");
-
-/*
-vi:ts=4
-*/
-