]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/usb/serial/cypress_m8.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394...
[linux-2.6-omap-h63xx.git] / drivers / usb / serial / cypress_m8.c
index 08c65c1a377163ded8eaf7f861674250852bcc6c..0230d3c0888af92e816d2d432f60a7171c4f547d 100644 (file)
@@ -94,6 +94,7 @@ static struct usb_device_id id_table_earthmate [] = {
 
 static struct usb_device_id id_table_cyphidcomrs232 [] = {
        { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
+       { USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) },
        { }                                             /* Terminating entry */
 };
 
@@ -106,6 +107,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
        { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
        { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
+       { USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) },
        { USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },
        { }                                             /* Terminating entry */
 };
@@ -120,6 +122,11 @@ static struct usb_driver cypress_driver = {
        .no_dynamic_id =        1,
 };
 
+enum packet_format {
+       packet_format_1,  /* b0:status, b1:payload count */
+       packet_format_2   /* b0[7:3]:status, b0[2:0]:payload count */
+};
+
 struct cypress_private {
        spinlock_t lock;                   /* private lock */
        int chiptype;                      /* identifier of device, for quirks/etc */
@@ -137,8 +144,9 @@ struct cypress_private {
        __u8 current_status;               /* received from last read - info on dsr,cts,cd,ri,etc */
        __u8 current_config;               /* stores the current configuration byte */
        __u8 rx_flags;                     /* throttling - used from whiteheat/ftdi_sio */
+       enum packet_format pkt_fmt;        /* format to use for packet send / receive */
+       int get_cfg_unsafe;                /* If true, the CYPRESS_GET_CONFIG is unsafe */
        int baud_rate;                     /* stores current baud rate in integer form */
-       int cbr_mask;                      /* stores current baud rate in masked form */
        int isthrottled;                   /* if throttled, discard reads */
        wait_queue_head_t delta_msr_wait;  /* used for TIOCMIWAIT */
        char prev_status, diff_status;     /* used for TIOCMIWAIT */
@@ -174,9 +182,6 @@ static void cypress_unthrottle              (struct usb_serial_port *port);
 static void cypress_set_dead           (struct usb_serial_port *port);
 static void cypress_read_int_callback  (struct urb *urb);
 static void cypress_write_int_callback (struct urb *urb);
-/* baud helper functions */
-static int      mask_to_rate           (unsigned mask);
-static unsigned  rate_to_mask          (int rate);
 /* write buffer functions */
 static struct cypress_buf *cypress_buf_alloc(unsigned int size);
 static void              cypress_buf_free(struct cypress_buf *cb);
@@ -195,10 +200,6 @@ static struct usb_serial_driver cypress_earthmate_device = {
        .description =                  "DeLorme Earthmate USB",
        .usb_driver =                   &cypress_driver,
        .id_table =                     id_table_earthmate,
-       .num_interrupt_in =             1,
-       .num_interrupt_out =            1,
-       .num_bulk_in =                  NUM_DONT_CARE,
-       .num_bulk_out =                 NUM_DONT_CARE,
        .num_ports =                    1,
        .attach =                       cypress_earthmate_startup,
        .shutdown =                     cypress_shutdown,
@@ -225,10 +226,6 @@ static struct usb_serial_driver cypress_hidcom_device = {
        .description =                  "HID->COM RS232 Adapter",
        .usb_driver =                   &cypress_driver,
        .id_table =                     id_table_cyphidcomrs232,
-       .num_interrupt_in =             1,
-       .num_interrupt_out =            1,
-       .num_bulk_in =                  NUM_DONT_CARE,
-       .num_bulk_out =                 NUM_DONT_CARE,
        .num_ports =                    1,
        .attach =                       cypress_hidcom_startup,
        .shutdown =                     cypress_shutdown,
@@ -255,10 +252,6 @@ static struct usb_serial_driver cypress_ca42v2_device = {
        .description =                  "Nokia CA-42 V2 Adapter",
        .usb_driver =                   &cypress_driver,
        .id_table =                     id_table_nokiaca42v2,
-       .num_interrupt_in =             1,
-       .num_interrupt_out =            1,
-       .num_bulk_in =                  NUM_DONT_CARE,
-       .num_bulk_out =                 NUM_DONT_CARE,
        .num_ports =                    1,
        .attach =                       cypress_ca42v2_startup,
        .shutdown =                     cypress_shutdown,
@@ -282,16 +275,62 @@ static struct usb_serial_driver cypress_ca42v2_device = {
  *****************************************************************************/
 
 
+static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)
+{
+       struct cypress_private *priv;
+       priv = usb_get_serial_port_data(port);
+
+       /*
+        * The general purpose firmware for the Cypress M8 allows for
+        * a maximum speed of 57600bps (I have no idea whether DeLorme
+        * chose to use the general purpose firmware or not), if you
+        * need to modify this speed setting for your own project
+        * please add your own chiptype and modify the code likewise.
+        * The Cypress HID->COM device will work successfully up to
+        * 115200bps (but the actual throughput is around 3kBps).
+        */
+       if (port->serial->dev->speed == USB_SPEED_LOW) {
+               /*
+                * Mike Isely <isely@pobox.com> 2-Feb-2008: The
+                * Cypress app note that describes this mechanism
+                * states the the low-speed part can't handle more
+                * than 800 bytes/sec, in which case 4800 baud is the
+                * safest speed for a part like that.
+                */
+               if (new_rate > 4800) {
+                       dbg("%s - failed setting baud rate, device incapable "
+                           "speed %d", __func__, new_rate);
+                       return -1;
+               }
+       }
+       switch (priv->chiptype) {
+       case CT_EARTHMATE:
+               if (new_rate <= 600) {
+                       /* 300 and 600 baud rates are supported under
+                        * the generic firmware, but are not used with
+                        * NMEA and SiRF protocols */
+                       dbg("%s - failed setting baud rate, unsupported speed "
+                           "of %d on Earthmate GPS", __func__, new_rate);
+                       return -1;
+               }
+               break;
+       default:
+               break;
+       }
+       return new_rate;
+}
+
+
 /* This function can either set or retrieve the current serial line settings */
-static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_mask, int data_bits, int stop_bits,
+static int cypress_serial_control (struct usb_serial_port *port, speed_t baud_rate, int data_bits, int stop_bits,
                                   int parity_enable, int parity_type, int reset, int cypress_request_type)
 {
        int new_baudrate = 0, retval = 0, tries = 0;
        struct cypress_private *priv;
-       __u8 feature_buffer[8];
+       __u8 feature_buffer[5];
        unsigned long flags;
 
-       dbg("%s", __FUNCTION__);
+       dbg("%s", __func__);
        
        priv = usb_get_serial_port_data(port);
 
@@ -300,58 +339,23 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
 
        switch(cypress_request_type) {
                case CYPRESS_SET_CONFIG:
-
-                       /*
-                        * The general purpose firmware for the Cypress M8 allows for a maximum speed
-                        * of 57600bps (I have no idea whether DeLorme chose to use the general purpose
-                        * firmware or not), if you need to modify this speed setting for your own
-                        * project please add your own chiptype and modify the code likewise.  The
-                        * Cypress HID->COM device will work successfully up to 115200bps (but the
-                        * actual throughput is around 3kBps).
-                        */
-                       if (baud_mask != priv->cbr_mask) {
-                               dbg("%s - baud rate is changing", __FUNCTION__);
-                               if ( priv->chiptype == CT_EARTHMATE ) {
-                                       /* 300 and 600 baud rates are supported under the generic firmware,
-                                        * but are not used with NMEA and SiRF protocols */
-                                       
-                                       if ( (baud_mask == B300) || (baud_mask == B600) ) {
-                                               err("%s - failed setting baud rate, unsupported speed",
-                                                   __FUNCTION__);
-                                               new_baudrate = priv->baud_rate;
-                                       } else if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
-                                               err("%s - failed setting baud rate, unsupported speed",
-                                                   __FUNCTION__);
-                                               new_baudrate = priv->baud_rate;
-                                       }
-                               } else if (priv->chiptype == CT_CYPHIDCOM) {
-                                       if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
-                                               err("%s - failed setting baud rate, unsupported speed",
-                                                   __FUNCTION__);
-                                               new_baudrate = priv->baud_rate;
-                                       }
-                               } else if (priv->chiptype == CT_CA42V2) {
-                                       if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
-                                               err("%s - failed setting baud rate, unsupported speed",
-                                                   __FUNCTION__);
-                                               new_baudrate = priv->baud_rate;
-                                       }
-                               } else if (priv->chiptype == CT_GENERIC) {
-                                       if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
-                                               err("%s - failed setting baud rate, unsupported speed",
-                                                   __FUNCTION__);
-                                               new_baudrate = priv->baud_rate;
-                                       }
-                               } else {
-                                       info("%s - please define your chiptype", __FUNCTION__);
-                                       new_baudrate = priv->baud_rate;
-                               }
-                       } else {  /* baud rate not changing, keep the old */
+                       new_baudrate = priv->baud_rate;
+                       /* 0 means 'Hang up' so doesn't change the true bit rate */
+                       if (baud_rate == 0)
                                new_baudrate = priv->baud_rate;
+                       /* Change of speed ? */
+                       else if (baud_rate != priv->baud_rate) {
+                               dbg("%s - baud rate is changing", __func__);
+                               retval = analyze_baud_rate(port, baud_rate);
+                               if (retval >=  0) {
+                                       new_baudrate = retval;
+                                       dbg("%s - New baud rate set to %d",
+                                           __func__, new_baudrate);
+                               }
                        }
-                       dbg("%s - baud rate is being sent as %d", __FUNCTION__, new_baudrate);
+                       dbg("%s - baud rate is being sent as %d", __func__, new_baudrate);
                        
-                       memset(feature_buffer, 0, 8);
+                       memset(feature_buffer, 0, sizeof(feature_buffer));
                        /* fill the feature_buffer with new configuration */
                        *((u_int32_t *)feature_buffer) = new_baudrate;
 
@@ -363,48 +367,65 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
                        /* 1 bit gap */
                        feature_buffer[4] |= (reset << 7);   /* assign reset at end of byte, 1 bit space */
                                
-                       dbg("%s - device is being sent this feature report:", __FUNCTION__);
-                       dbg("%s - %02X - %02X - %02X - %02X - %02X", __FUNCTION__, feature_buffer[0], feature_buffer[1],
+                       dbg("%s - device is being sent this feature report:", __func__);
+                       dbg("%s - %02X - %02X - %02X - %02X - %02X", __func__, feature_buffer[0], feature_buffer[1],
                            feature_buffer[2], feature_buffer[3], feature_buffer[4]);
                        
                        do {
-                       retval = usb_control_msg (port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0),
-                                                 HID_REQ_SET_REPORT, USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
-                                                         0x0300, 0, feature_buffer, 8, 500);
+                               retval = usb_control_msg(port->serial->dev,
+                                               usb_sndctrlpipe(port->serial->dev, 0),
+                                               HID_REQ_SET_REPORT,
+                                               USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
+                                               0x0300, 0, feature_buffer,
+                                               sizeof(feature_buffer), 500);
 
                                if (tries++ >= 3)
                                        break;
 
-                       } while (retval != 8 && retval != -ENODEV);
+                       } while (retval != sizeof(feature_buffer) &&
+                                retval != -ENODEV);
 
-                       if (retval != 8) {
-                               err("%s - failed sending serial line settings - %d", __FUNCTION__, retval);
+                       if (retval != sizeof(feature_buffer)) {
+                               err("%s - failed sending serial line settings - %d", __func__, retval);
                                cypress_set_dead(port);
                        } else {
                                spin_lock_irqsave(&priv->lock, flags);
                                priv->baud_rate = new_baudrate;
-                               priv->cbr_mask = baud_mask;
                                priv->current_config = feature_buffer[4];
                                spin_unlock_irqrestore(&priv->lock, flags);
+                               /* If we asked for a speed change encode it */
+                               if (baud_rate)
+                                       tty_encode_baud_rate(port->tty,
+                                                       new_baudrate, new_baudrate);
                        }
                break;
                case CYPRESS_GET_CONFIG:
-                       dbg("%s - retreiving serial line settings", __FUNCTION__);
+                       if (priv->get_cfg_unsafe) {
+                               /* Not implemented for this device,
+                                  and if we try to do it we're likely
+                                  to crash the hardware. */
+                               return -ENOTTY;
+                       }
+                       dbg("%s - retreiving serial line settings", __func__);
                        /* set initial values in feature buffer */
-                       memset(feature_buffer, 0, 8);
+                       memset(feature_buffer, 0, sizeof(feature_buffer));
 
                        do {
-                       retval = usb_control_msg (port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0),
-                                                 HID_REQ_GET_REPORT, USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
-                                                         0x0300, 0, feature_buffer, 8, 500);
-                               
+                               retval = usb_control_msg(port->serial->dev,
+                                               usb_rcvctrlpipe(port->serial->dev, 0),
+                                               HID_REQ_GET_REPORT,
+                                               USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
+                                               0x0300, 0, feature_buffer,
+                                               sizeof(feature_buffer), 500);
+
                                if (tries++ >= 3)
                                        break;
 
-                       } while (retval != 5 && retval != -ENODEV);
+                       } while (retval != sizeof(feature_buffer) &&
+                                retval != -ENODEV);
 
-                       if (retval != 5) {
-                               err("%s - failed to retrieve serial line settings - %d", __FUNCTION__, retval);
+                       if (retval != sizeof(feature_buffer)) {
+                               err("%s - failed to retrieve serial line settings - %d", __func__, retval);
                                cypress_set_dead(port);
                                return retval;
                        } else {
@@ -413,9 +434,6 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
                                /* store the config in one byte, and later use bit masks to check values */
                                priv->current_config = feature_buffer[4];
                                priv->baud_rate = *((u_int32_t *)feature_buffer);
-                               
-                               if ( (priv->cbr_mask = rate_to_mask(priv->baud_rate)) == 0x40)
-                                       dbg("%s - failed setting the baud mask (not defined)", __FUNCTION__);
                                spin_unlock_irqrestore(&priv->lock, flags);
                        }
        }
@@ -445,51 +463,6 @@ static void cypress_set_dead(struct usb_serial_port *port)
 }
 
 
-/* given a baud mask, it will return integer baud on success */
-static int mask_to_rate (unsigned mask)
-{
-       int rate;
-
-       switch (mask) {
-               case B0: rate = 0; break;
-               case B300: rate = 300; break;
-               case B600: rate = 600; break;
-               case B1200: rate = 1200; break;
-               case B2400: rate = 2400; break;
-               case B4800: rate = 4800; break;
-               case B9600: rate = 9600; break;
-               case B19200: rate = 19200; break;
-               case B38400: rate = 38400; break;
-               case B57600: rate = 57600; break;
-               case B115200: rate = 115200; break;
-               default: rate = -1;
-       }
-
-       return rate;
-}
-
-
-static unsigned rate_to_mask (int rate)
-{
-       unsigned mask;
-
-       switch (rate) {
-               case 0: mask = B0; break;
-               case 300: mask = B300; break;
-               case 600: mask = B600; break;
-               case 1200: mask = B1200; break;
-               case 2400: mask = B2400; break;
-               case 4800: mask = B4800; break;
-               case 9600: mask = B9600; break;
-               case 19200: mask = B19200; break;
-               case 38400: mask = B38400; break;
-               case 57600: mask = B57600; break;
-               case 115200: mask = B115200; break;
-               default: mask = 0x40;
-       }
-
-       return mask;
-}
 /*****************************************************************************
  * Cypress serial driver functions
  *****************************************************************************/
@@ -500,7 +473,7 @@ static int generic_startup (struct usb_serial *serial)
        struct cypress_private *priv;
        struct usb_serial_port *port = serial->port[0];
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        priv = kzalloc(sizeof (struct cypress_private), GFP_KERNEL);
        if (!priv)
@@ -521,17 +494,27 @@ static int generic_startup (struct usb_serial *serial)
        priv->line_control = 0;
        priv->termios_initialized = 0;
        priv->rx_flags = 0;
-       priv->cbr_mask = B300;
+       /* Default packet format setting is determined by packet size.
+          Anything with a size larger then 9 must have a separate
+          count field since the 3 bit count field is otherwise too
+          small.  Otherwise we can use the slightly more compact
+          format.  This is in accordance with the cypress_m8 serial
+          converter app note. */
+       if (port->interrupt_out_size > 9) {
+               priv->pkt_fmt = packet_format_1;
+       } else {
+               priv->pkt_fmt = packet_format_2;
+       }
        if (interval > 0) {
                priv->write_urb_interval = interval;
                priv->read_urb_interval = interval;
                dbg("%s - port %d read & write intervals forced to %d",
-                   __FUNCTION__,port->number,interval);
+                   __func__,port->number,interval);
        } else {
                priv->write_urb_interval = port->interrupt_out_urb->interval;
                priv->read_urb_interval = port->interrupt_in_urb->interval;
                dbg("%s - port %d intervals: read=%d write=%d",
-                   __FUNCTION__,port->number,
+                   __func__,port->number,
                    priv->read_urb_interval,priv->write_urb_interval);
        }
        usb_set_serial_port_data(port, priv);
@@ -543,17 +526,30 @@ static int generic_startup (struct usb_serial *serial)
 static int cypress_earthmate_startup (struct usb_serial *serial)
 {
        struct cypress_private *priv;
+       struct usb_serial_port *port = serial->port[0];
 
-       dbg("%s", __FUNCTION__);
+       dbg("%s", __func__);
 
        if (generic_startup(serial)) {
-               dbg("%s - Failed setting up port %d", __FUNCTION__,
-                               serial->port[0]->number);
+               dbg("%s - Failed setting up port %d", __func__,
+                               port->number);
                return 1;
        }
 
-       priv = usb_get_serial_port_data(serial->port[0]);
+       priv = usb_get_serial_port_data(port);
        priv->chiptype = CT_EARTHMATE;
+       /* All Earthmate devices use the separated-count packet
+          format!  Idiotic. */
+       priv->pkt_fmt = packet_format_1;
+       if (serial->dev->descriptor.idProduct != cpu_to_le16(PRODUCT_ID_EARTHMATEUSB)) {
+               /* The old original USB Earthmate seemed able to
+                  handle GET_CONFIG requests; everything they've
+                  produced since that time crashes if this command is
+                  attempted :-( */
+               dbg("%s - Marking this device as unsafe for GET_CONFIG "
+                   "commands", __func__);
+               priv->get_cfg_unsafe = !0;
+       }
 
        return 0;
 } /* cypress_earthmate_startup */
@@ -563,10 +559,10 @@ static int cypress_hidcom_startup (struct usb_serial *serial)
 {
        struct cypress_private *priv;
 
-       dbg("%s", __FUNCTION__);
+       dbg("%s", __func__);
 
        if (generic_startup(serial)) {
-               dbg("%s - Failed setting up port %d", __FUNCTION__,
+               dbg("%s - Failed setting up port %d", __func__,
                                serial->port[0]->number);
                return 1;
        }
@@ -582,10 +578,10 @@ static int cypress_ca42v2_startup (struct usb_serial *serial)
 {
        struct cypress_private *priv;
 
-       dbg("%s", __FUNCTION__);
+       dbg("%s", __func__);
 
        if (generic_startup(serial)) {
-               dbg("%s - Failed setting up port %d", __FUNCTION__,
+               dbg("%s - Failed setting up port %d", __func__,
                                serial->port[0]->number);
                return 1;
        }
@@ -601,7 +597,7 @@ static void cypress_shutdown (struct usb_serial *serial)
 {
        struct cypress_private *priv;
 
-       dbg ("%s - port %d", __FUNCTION__, serial->port[0]->number);
+       dbg ("%s - port %d", __func__, serial->port[0]->number);
 
        /* all open ports are closed at this point */
 
@@ -622,7 +618,7 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
        unsigned long flags;
        int result = 0;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        if (!priv->comm_is_ok)
                return -EIO;
@@ -650,16 +646,16 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
        result = cypress_write(port, NULL, 0);
 
        if (result) {
-               dev_err(&port->dev, "%s - failed setting the control lines - error %d\n", __FUNCTION__, 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", __FUNCTION__);    
+               dbg("%s - success setting the control lines", __func__);
 
        cypress_set_termios(port, &priv->tmp_termios);
 
        /* setup the port and start reading from the device */
        if(!port->interrupt_in_urb){
-               err("%s - interrupt_in_urb is empty!", __FUNCTION__);
+               err("%s - interrupt_in_urb is empty!", __func__);
                return(-1);
        }
 
@@ -670,7 +666,7 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
        result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 
        if (result){
-               dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
+               dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __func__, result);
                cypress_set_dead(port);
        }
 
@@ -686,7 +682,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
        long timeout;
        wait_queue_t wait;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        /* wait for data to drain from buffer */
        spin_lock_irq(&priv->lock);
@@ -724,7 +720,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
                timeout = 2*HZ;
        schedule_timeout_interruptible(timeout);
 
-       dbg("%s - stopping urbs", __FUNCTION__);
+       dbg("%s - stopping urbs", __func__);
        usb_kill_urb (port->interrupt_in_urb);
        usb_kill_urb (port->interrupt_out_urb);
 
@@ -753,7 +749,7 @@ static int cypress_write(struct usb_serial_port *port, const unsigned char *buf,
        struct cypress_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
        
-       dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
+       dbg("%s - port %d, %d bytes", __func__, port->number, count);
 
        /* line control commands, which need to be executed immediately,
           are not put into the buffer for obvious reasons.
@@ -786,12 +782,12 @@ static void cypress_send(struct usb_serial_port *port)
        if (!priv->comm_is_ok)
                return;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
-       dbg("%s - interrupt out size is %d", __FUNCTION__, port->interrupt_out_size);
+       dbg("%s - port %d", __func__, port->number);
+       dbg("%s - interrupt out size is %d", __func__, port->interrupt_out_size);
        
        spin_lock_irqsave(&priv->lock, flags);
        if (priv->write_urb_in_use) {
-               dbg("%s - can't write, urb in use", __FUNCTION__);
+               dbg("%s - can't write, urb in use", __func__);
                spin_unlock_irqrestore(&priv->lock, flags);
                return;
        }
@@ -801,21 +797,18 @@ static void cypress_send(struct usb_serial_port *port)
        memset(port->interrupt_out_urb->transfer_buffer, 0, port->interrupt_out_size);
 
        spin_lock_irqsave(&priv->lock, flags);
-       switch (port->interrupt_out_size) {
-               case 32:
-                       /* this is for the CY7C64013... */
-                       offset = 2;
-                       port->interrupt_out_buffer[0] = priv->line_control;
-                       break;
-               case 8:
-                       /* this is for the CY7C63743... */
-                       offset = 1;
-                       port->interrupt_out_buffer[0] = priv->line_control;
-                       break;
-               default:
-                       dbg("%s - wrong packet size", __FUNCTION__);
-                       spin_unlock_irqrestore(&priv->lock, flags);
-                       return;
+       switch (priv->pkt_fmt) {
+       default:
+       case packet_format_1:
+               /* this is for the CY7C64013... */
+               offset = 2;
+               port->interrupt_out_buffer[0] = priv->line_control;
+               break;
+       case packet_format_2:
+               /* this is for the CY7C63743... */
+               offset = 1;
+               port->interrupt_out_buffer[0] = priv->line_control;
+               break;
        }
 
        if (priv->line_control & CONTROL_RESET)
@@ -823,7 +816,7 @@ static void cypress_send(struct usb_serial_port *port)
 
        if (priv->cmd_ctrl) {
                priv->cmd_count++;
-               dbg("%s - line control command being issued", __FUNCTION__);
+               dbg("%s - line control command being issued", __func__);
                spin_unlock_irqrestore(&priv->lock, flags);
                goto send;
        } else
@@ -836,15 +829,16 @@ static void cypress_send(struct usb_serial_port *port)
                return;
        }
 
-       switch (port->interrupt_out_size) {
-               case 32:
-                       port->interrupt_out_buffer[1] = count;
-                       break;
-               case 8:
-                       port->interrupt_out_buffer[0] |= count;
+       switch (priv->pkt_fmt) {
+       default:
+       case packet_format_1:
+               port->interrupt_out_buffer[1] = count;
+               break;
+       case packet_format_2:
+               port->interrupt_out_buffer[0] |= count;
        }
 
-       dbg("%s - count is %d", __FUNCTION__, count);
+       dbg("%s - count is %d", __func__, count);
 
 send:
        spin_lock_irqsave(&priv->lock, flags);
@@ -854,9 +848,10 @@ send:
        if (priv->cmd_ctrl)
                actual_size = 1;
        else
-               actual_size = count + (port->interrupt_out_size == 32 ? 2 : 1);
-       
-       usb_serial_debug_data(debug, &port->dev, __FUNCTION__, port->interrupt_out_size,
+               actual_size = count +
+                             (priv->pkt_fmt == packet_format_1 ? 2 : 1);
+
+       usb_serial_debug_data(debug, &port->dev, __func__, port->interrupt_out_size,
                              port->interrupt_out_urb->transfer_buffer);
 
        usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev,
@@ -865,7 +860,7 @@ send:
                cypress_write_int_callback, port, priv->write_urb_interval);
        result = usb_submit_urb (port->interrupt_out_urb, GFP_ATOMIC);
        if (result) {
-               dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__,
+               dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __func__,
                        result);
                priv->write_urb_in_use = 0;
                cypress_set_dead(port);
@@ -889,13 +884,13 @@ static int cypress_write_room(struct usb_serial_port *port)
        int room = 0;
        unsigned long flags;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        spin_lock_irqsave(&priv->lock, flags);
        room = cypress_buf_space_avail(priv->buf);
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       dbg("%s - returns %d", __FUNCTION__, room);
+       dbg("%s - returns %d", __func__, room);
        return room;
 }
 
@@ -907,7 +902,7 @@ static int cypress_tiocmget (struct usb_serial_port *port, struct file *file)
        unsigned int result = 0;
        unsigned long flags;
        
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        spin_lock_irqsave(&priv->lock, flags);
        control = priv->line_control;
@@ -921,7 +916,7 @@ static int cypress_tiocmget (struct usb_serial_port *port, struct file *file)
                | ((status & UART_RI)         ? TIOCM_RI  : 0)
                | ((status & UART_CD)         ? TIOCM_CD  : 0);
 
-       dbg("%s - result = %x", __FUNCTION__, result);
+       dbg("%s - result = %x", __func__, result);
 
        return result;
 }
@@ -933,7 +928,7 @@ static int cypress_tiocmset (struct usb_serial_port *port, struct file *file,
        struct cypress_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
        
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        spin_lock_irqsave(&priv->lock, flags);
        if (set & TIOCM_RTS)
@@ -944,9 +939,9 @@ static int cypress_tiocmset (struct usb_serial_port *port, struct file *file,
                priv->line_control &= ~CONTROL_RTS;
        if (clear & TIOCM_DTR)
                priv->line_control &= ~CONTROL_DTR;
+       priv->cmd_ctrl = 1;
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       priv->cmd_ctrl = 1;
        return cypress_write(port, NULL, 0);
 }
 
@@ -955,23 +950,9 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi
 {
        struct cypress_private *priv = usb_get_serial_port_data(port);
 
-       dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
+       dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
 
        switch (cmd) {
-               case TIOCGSERIAL:
-                       if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct ktermios))) {
-                               return -EFAULT;
-                       }
-                       return (0);
-                       break;
-               case TIOCSSERIAL:
-                       if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct ktermios))) {
-                               return -EFAULT;
-                       }
-                       /* here we need to call cypress_set_termios to invoke the new settings */
-                       cypress_set_termios(port, &priv->tmp_termios);
-                       return (0);
-                       break;
                /* This code comes from drivers/char/serial.c and ftdi_sio.c */
                case TIOCMIWAIT:
                        while (priv != NULL) {
@@ -1007,7 +988,7 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi
                        break;
        }
 
-       dbg("%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h", __FUNCTION__, cmd);
+       dbg("%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h", __func__, cmd);
 
        return -ENOIOCTLCMD;
 } /* cypress_ioctl */
@@ -1019,18 +1000,14 @@ static void cypress_set_termios (struct usb_serial_port *port,
        struct cypress_private *priv = usb_get_serial_port_data(port);
        struct tty_struct *tty;
        int data_bits, stop_bits, parity_type, parity_enable;
-       unsigned cflag, iflag, baud_mask;
+       unsigned cflag, iflag;
        unsigned long flags;
        __u8 oldlines;
        int linechange = 0;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        tty = port->tty;
-       if ((!tty) || (!tty->termios)) {
-               dbg("%s - no tty structures", __FUNCTION__);
-               return;
-       }
 
        spin_lock_irqsave(&priv->lock, flags);
        if (!priv->termios_initialized) {
@@ -1038,40 +1015,37 @@ static void cypress_set_termios (struct usb_serial_port *port,
                        *(tty->termios) = tty_std_termios;
                        tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL |
                                CLOCAL;
+                       tty->termios->c_ispeed = 4800;
+                       tty->termios->c_ospeed = 4800;
                } else if (priv->chiptype == CT_CYPHIDCOM) {
                        *(tty->termios) = tty_std_termios;
                        tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
                                CLOCAL;
+                       tty->termios->c_ispeed = 9600;
+                       tty->termios->c_ospeed = 9600;
                } else if (priv->chiptype == CT_CA42V2) {
                        *(tty->termios) = tty_std_termios;
                        tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
                                CLOCAL;
+                       tty->termios->c_ispeed = 9600;
+                       tty->termios->c_ospeed = 9600;
                }
                priv->termios_initialized = 1;
        }
        spin_unlock_irqrestore(&priv->lock, flags);
 
+       /* Unsupported features need clearing */
+       tty->termios->c_cflag &= ~(CMSPAR|CRTSCTS);
+
        cflag = tty->termios->c_cflag;
        iflag = tty->termios->c_iflag;
 
        /* check if there are new settings */
        if (old_termios) {
-               if ((cflag != old_termios->c_cflag) ||
-                       (RELEVANT_IFLAG(iflag) !=
-                        RELEVANT_IFLAG(old_termios->c_iflag))) {
-                       dbg("%s - attempting to set new termios settings",
-                                       __FUNCTION__);
-                       /* should make a copy of this in case something goes
-                        * wrong in the function, we can restore it */
-                       spin_lock_irqsave(&priv->lock, flags);
-                       priv->tmp_termios = *(tty->termios);
-                       spin_unlock_irqrestore(&priv->lock, flags);
-               } else {
-                       dbg("%s - nothing to do, exiting", __FUNCTION__);
-                       return;
-               }
-       } else
-               return;
+               spin_lock_irqsave(&priv->lock, flags);
+               priv->tmp_termios = *(tty->termios);
+               spin_unlock_irqrestore(&priv->lock, flags);
+       }
 
        /* set number of data bits, parity, stop bits */
        /* when parity is disabled the parity type bit is ignored */
@@ -1102,7 +1076,7 @@ static void cypress_set_termios (struct usb_serial_port *port,
                                break;
                        default:
                                err("%s - CSIZE was set, but not CS5-CS8",
-                                               __FUNCTION__);
+                                               __func__);
                                data_bits = 3;
                }
        } else
@@ -1112,54 +1086,17 @@ static void cypress_set_termios (struct usb_serial_port *port,
        oldlines = priv->line_control;
        if ((cflag & CBAUD) == B0) {
                /* drop dtr and rts */
-               dbg("%s - dropping the lines, baud rate 0bps", __FUNCTION__);
-               baud_mask = B0;
+               dbg("%s - dropping the lines, baud rate 0bps", __func__);
                priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
-       } else {
-               baud_mask = (cflag & CBAUD);
-               switch(baud_mask) {
-                       case B300:
-                               dbg("%s - setting baud 300bps", __FUNCTION__);
-                               break;
-                       case B600:
-                               dbg("%s - setting baud 600bps", __FUNCTION__);
-                               break;
-                       case B1200:
-                               dbg("%s - setting baud 1200bps", __FUNCTION__);
-                               break;
-                       case B2400:
-                               dbg("%s - setting baud 2400bps", __FUNCTION__);
-                               break;
-                       case B4800:
-                               dbg("%s - setting baud 4800bps", __FUNCTION__);
-                               break;
-                       case B9600:
-                               dbg("%s - setting baud 9600bps", __FUNCTION__);
-                               break;
-                       case B19200:
-                               dbg("%s - setting baud 19200bps", __FUNCTION__);
-                               break;
-                       case B38400:
-                               dbg("%s - setting baud 38400bps", __FUNCTION__);
-                               break;
-                       case B57600:
-                               dbg("%s - setting baud 57600bps", __FUNCTION__);
-                               break;
-                       case B115200:
-                               dbg("%s - setting baud 115200bps", __FUNCTION__);
-                               break;
-                       default:
-                               dbg("%s - unknown masked baud rate", __FUNCTION__);
-               }
+       } else
                priv->line_control = (CONTROL_DTR | CONTROL_RTS);
-       }
        spin_unlock_irqrestore(&priv->lock, flags);
 
        dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, "
-                       "%d data_bits (+5)", __FUNCTION__, stop_bits,
+                       "%d data_bits (+5)", __func__, stop_bits,
                        parity_enable, parity_type, data_bits);
 
-       cypress_serial_control(port, baud_mask, data_bits, stop_bits,
+       cypress_serial_control(port, tty_get_baud_rate(tty), data_bits, stop_bits,
                        parity_enable, parity_type, 0, CYPRESS_SET_CONFIG);
 
        /* we perform a CYPRESS_GET_CONFIG so that the current settings are
@@ -1217,13 +1154,13 @@ static int cypress_chars_in_buffer(struct usb_serial_port *port)
        int chars = 0;
        unsigned long flags;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
        
        spin_lock_irqsave(&priv->lock, flags);
        chars = cypress_buf_data_avail(priv->buf);
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       dbg("%s - returns %d", __FUNCTION__, chars);
+       dbg("%s - returns %d", __func__, chars);
        return chars;
 }
 
@@ -1233,7 +1170,7 @@ static void cypress_throttle (struct usb_serial_port *port)
        struct cypress_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        spin_lock_irqsave(&priv->lock, flags);
        priv->rx_flags = THROTTLED;
@@ -1247,7 +1184,7 @@ static void cypress_unthrottle (struct usb_serial_port *port)
        int actually_throttled, result;
        unsigned long flags;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        spin_lock_irqsave(&priv->lock, flags);
        actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
@@ -1263,7 +1200,7 @@ static void cypress_unthrottle (struct usb_serial_port *port)
                result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
                if (result) {
                        dev_err(&port->dev, "%s - failed submitting read urb, "
-                                       "error %d\n", __FUNCTION__, result);
+                                       "error %d\n", __func__, result);
                        cypress_set_dead(port);
                }
        }
@@ -1272,7 +1209,7 @@ static void cypress_unthrottle (struct usb_serial_port *port)
 
 static void cypress_read_int_callback(struct urb *urb)
 {
-       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct usb_serial_port *port = urb->context;
        struct cypress_private *priv = usb_get_serial_port_data(port);
        struct tty_struct *tty;
        unsigned char *data = urb->transfer_buffer;
@@ -1284,7 +1221,7 @@ static void cypress_read_int_callback(struct urb *urb)
        int i = 0;
        int status = urb->status;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        switch (status) {
        case 0: /* success */
@@ -1300,14 +1237,14 @@ static void cypress_read_int_callback(struct urb *urb)
        default:
                /* something ugly is going on... */
                dev_err(&urb->dev->dev,"%s - unexpected nonzero read status received: %d\n",
-                       __FUNCTION__, status);
+                       __func__, status);
                cypress_set_dead(port);
                return;
        }
 
        spin_lock_irqsave(&priv->lock, flags);
        if (priv->rx_flags & THROTTLED) {
-               dbg("%s - now throttling", __FUNCTION__);
+               dbg("%s - now throttling", __func__);
                priv->rx_flags |= ACTUALLY_THROTTLED;
                spin_unlock_irqrestore(&priv->lock, flags);
                return;
@@ -1316,48 +1253,48 @@ static void cypress_read_int_callback(struct urb *urb)
 
        tty = port->tty;
        if (!tty) {
-               dbg("%s - bad tty pointer - exiting", __FUNCTION__);
+               dbg("%s - bad tty pointer - exiting", __func__);
                return;
        }
 
        spin_lock_irqsave(&priv->lock, flags);
-       switch(urb->actual_length) {
-               case 32:
-                       /* This is for the CY7C64013... */
-                       priv->current_status = data[0] & 0xF8;
-                       bytes = data[1] + 2;
-                       i = 2;
-                       if (bytes > 2)
-                               havedata = 1;
-                       break;
-               case 8:
-                       /* This is for the CY7C63743... */
-                       priv->current_status = data[0] & 0xF8;
-                       bytes = (data[0] & 0x07) + 1;
-                       i = 1;
-                       if (bytes > 1)
-                               havedata = 1;
-                       break;
-               default:
-                       dbg("%s - wrong packet size - received %d bytes",
-                                       __FUNCTION__, urb->actual_length);
-                       spin_unlock_irqrestore(&priv->lock, flags);
-                       goto continue_read;
+       result = urb->actual_length;
+       switch (priv->pkt_fmt) {
+       default:
+       case packet_format_1:
+               /* This is for the CY7C64013... */
+               priv->current_status = data[0] & 0xF8;
+               bytes = data[1] + 2;
+               i = 2;
+               if (bytes > 2)
+                       havedata = 1;
+               break;
+       case packet_format_2:
+               /* This is for the CY7C63743... */
+               priv->current_status = data[0] & 0xF8;
+               bytes = (data[0] & 0x07) + 1;
+               i = 1;
+               if (bytes > 1)
+                       havedata = 1;
+               break;
        }
        spin_unlock_irqrestore(&priv->lock, flags);
+       if (result < bytes) {
+               dbg("%s - wrong packet size - received %d bytes but packet "
+                   "said %d bytes", __func__, result, bytes);
+               goto continue_read;
+       }
 
-       usb_serial_debug_data (debug, &port->dev, __FUNCTION__,
+       usb_serial_debug_data (debug, &port->dev, __func__,
                        urb->actual_length, data);
 
        spin_lock_irqsave(&priv->lock, flags);
        /* check to see if status has changed */
-       if (priv != NULL) {
-               if (priv->current_status != priv->prev_status) {
-                       priv->diff_status |= priv->current_status ^
-                               priv->prev_status;
-                       wake_up_interruptible(&priv->delta_msr_wait);
-                       priv->prev_status = priv->current_status;
-               }
+       if (priv->current_status != priv->prev_status) {
+               priv->diff_status |= priv->current_status ^
+                       priv->prev_status;
+               wake_up_interruptible(&priv->delta_msr_wait);
+               priv->prev_status = priv->current_status;
        }
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -1365,7 +1302,7 @@ static void cypress_read_int_callback(struct urb *urb)
         * though */
        if (tty && !(tty->termios->c_cflag & CLOCAL) &&
                        !(priv->current_status & UART_CD)) {
-               dbg("%s - calling hangup", __FUNCTION__);
+               dbg("%s - calling hangup", __func__);
                tty_hangup(tty);
                goto continue_read;
        }
@@ -1378,7 +1315,7 @@ static void cypress_read_int_callback(struct urb *urb)
        if (priv->current_status & CYP_ERROR) {
                spin_unlock_irqrestore(&priv->lock, flags);
                tty_flag = TTY_PARITY;
-               dbg("%s - Parity Error detected", __FUNCTION__);
+               dbg("%s - Parity Error detected", __func__);
        } else
                spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -1412,7 +1349,7 @@ continue_read:
                result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
                if (result) {
                        dev_err(&urb->dev->dev, "%s - failed resubmitting "
-                                       "read urb, error %d\n", __FUNCTION__,
+                                       "read urb, error %d\n", __func__,
                                        result);
                        cypress_set_dead(port);
                }
@@ -1424,12 +1361,12 @@ continue_read:
 
 static void cypress_write_int_callback(struct urb *urb)
 {
-       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct usb_serial_port *port = urb->context;
        struct cypress_private *priv = usb_get_serial_port_data(port);
        int result;
        int status = urb->status;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        switch (status) {
                case 0:
@@ -1440,7 +1377,7 @@ static void cypress_write_int_callback(struct urb *urb)
                case -ESHUTDOWN:
                        /* this urb is terminated, clean up */
                        dbg("%s - urb shutting down with status: %d",
-                           __FUNCTION__, status);
+                           __func__, status);
                        priv->write_urb_in_use = 0;
                        return;
                case -EPIPE: /* no break needed; clear halt and resubmit */
@@ -1449,19 +1386,19 @@ static void cypress_write_int_callback(struct urb *urb)
                        usb_clear_halt(port->serial->dev, 0x02);
                        /* error in the urb, so we have to resubmit it */
                        dbg("%s - nonzero write bulk status received: %d",
-                           __FUNCTION__, status);
+                           __func__, status);
                        port->interrupt_out_urb->transfer_buffer_length = 1;
                        port->interrupt_out_urb->dev = port->serial->dev;
                        result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
                        if (!result)
                                return;
                        dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n",
-                               __FUNCTION__, result);
+                               __func__, result);
                        cypress_set_dead(port);
                        break;
                default:
                        dev_err(&urb->dev->dev,"%s - unexpected nonzero write status received: %d\n",
-                               __FUNCTION__, status);
+                               __func__, status);
                        cypress_set_dead(port);
                        break;
        }
@@ -1666,7 +1603,7 @@ static int __init cypress_init(void)
 {
        int retval;
        
-       dbg("%s", __FUNCTION__);
+       dbg("%s", __func__);
        
        retval = usb_serial_register(&cypress_earthmate_device);
        if (retval)
@@ -1697,7 +1634,7 @@ failed_em_register:
 
 static void __exit cypress_exit (void)
 {
-       dbg("%s", __FUNCTION__);
+       dbg("%s", __func__);
 
        usb_deregister (&cypress_driver);
        usb_serial_deregister (&cypress_earthmate_device);