Hello,

  Here is an update to the cypress_m8 kernel module.  It fixes a few
 known and reported issues along with other various improvments listed below.
 If the inline patch is mangled, please see raw patch available here:

  http://gnome.dnsalias.net/cypress_m8-503.patch



  Thank you,
   Lonnie Mendez
------

 Fixed problem where setting or retreiving the serial config would fail with
EPIPE.  Removed CRTS toggling so the driver behaves more like other usbserial 
adapters.  Issued new interval of 1ms instead of the default bInterval.  As a 
result, 
transfer speed has been substantially increased.  From avg. 850bps to avg. 
3300bps.
Also added new module parameter 'interval' to tweak the interval in case this 
change
causes problems for someone.  Cleaned up code and formatting issues so source is
more readable.  Replaced the C++ style comments.  Various other code cleanups.


Signed-off-by: Lonnie Mendez <[EMAIL PROTECTED]>

--- a/cypress_m8.c 2005-05-03 01:45:42.000000000 -0500
+++ b/cypress_m8.c 2005-05-03 04:49:47.000000000 -0500
@@ -16,6 +16,14 @@
  * See http://geocities.com/i0xox0i for information on this driver and the
  * earthmate usb device.
  *
+ *  Lonnie Mendez <[EMAIL PROTECTED]>
+ *  4-29-2005
+ * Fixed problem where setting or retreiving the serial config would fail with
+ *  EPIPE.  Removed CRTS toggling so the driver behaves more like other 
usbserial
+ *  adapters.  Issued new interval of 1ms instead of the default 10ms.  As a
+ *  result, transfer speed has been substantially increased.  From avg. 850bps 
to
+ *  avg. 3300bps.  initial termios has also been modified.  Cleaned up code and
+ *  formatting issues so it is more readable.  Replaced the C++ style comments.
  *
  *  Lonnie Mendez <[EMAIL PROTECTED]>
  *  12-15-2004
@@ -32,12 +40,6 @@
  *  10-2003
  * Driver first released.
  *
- *
- * Long Term TODO:
- * Improve transfer speeds - both read/write are somewhat slow
- *   at this point.
- *      Improve debugging.  Show modem line status with debug output and
- *   implement filtering for certain data as a module parameter.
  */
 
 /* Thanks to Neil Whelchel for writing the first cypress m8 implementation for 
linux. */
@@ -72,11 +74,12 @@
  static int debug;
 #endif
 static int stats;
+static int interval;
 
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.08"
+#define DRIVER_VERSION "v1.09"
 #define DRIVER_AUTHOR "Lonnie Mendez <[EMAIL PROTECTED]>, Neil Whelchel 
<[EMAIL PROTECTED]>"
 #define DRIVER_DESC "Cypress USB to Serial Driver"
 
@@ -130,7 +133,6 @@
  char prev_status, diff_status;    /* used for TIOCMIWAIT */
  /* we pass a pointer to this as the arguement sent to cypress_set_termios 
old_termios */
  struct termios tmp_termios;     /* stores the old termios settings */
- char calledfromopen;     /* used when issuing lines on open - fixes rts drop 
bug */
 };
 
 /* write buffer structure */
@@ -168,10 +170,8 @@
 static void    cypress_buf_clear(struct cypress_buf *cb);
 static unsigned int   cypress_buf_data_avail(struct cypress_buf *cb);
 static unsigned int   cypress_buf_space_avail(struct cypress_buf *cb);
-static unsigned int   cypress_buf_put(struct cypress_buf *cb, const char *buf,
-       unsigned int count);
-static unsigned int   cypress_buf_get(struct cypress_buf *cb, char *buf,
-       unsigned int count);
+static unsigned int   cypress_buf_put(struct cypress_buf *cb, const char *buf, 
unsigned int count);
+static unsigned int   cypress_buf_get(struct cypress_buf *cb, char *buf, 
unsigned int count);
 
 
 static struct usb_serial_device_type cypress_earthmate_device = {
@@ -238,10 +238,9 @@
 static int cypress_serial_control (struct usb_serial_port *port, unsigned 
baud_mask, int data_bits, int stop_bits,
        int parity_enable, int parity_type, int reset, int cypress_request_type)
 {
- int i, n_baud_rate = 0, retval = 0;
+ int new_baudrate = 0, retval = 0, tries = 0;
  struct cypress_private *priv;
- __u8 feature_buffer[5];
- __u8 config;
+ __u8 feature_buffer[8];
  unsigned long flags;
 
  dbg("%s", __FUNCTION__);
@@ -256,7 +255,8 @@
      * 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.
+    * 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__);
@@ -265,109 +265,114 @@
       * but are not used with NMEA and SiRF protocols */
      
      if ( (baud_mask == B300) || (baud_mask == B600) ) {
-      err("%s - failed setting baud rate, unsupported speed (default to 4800)",
+      err("%s - failed setting baud rate, unsupported speed",
           __FUNCTION__);
-      n_baud_rate = 4800;
-     } else if ( (n_baud_rate = mask_to_rate(baud_mask)) == -1) {
-      err("%s - failed setting baud rate, unsupported speed (default to 4800)",
+      new_baudrate = priv->baud_rate;
+     } else if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
+      err("%s - failed setting baud rate, unsupported speed",
           __FUNCTION__);
-      n_baud_rate = 4800;
+      new_baudrate = priv->baud_rate;
      }
     } else if (priv->chiptype == CT_CYPHIDCOM) {
-     if ( (n_baud_rate = mask_to_rate(baud_mask)) == -1) {
-      err("%s - failed setting baud rate, unsupported speed (default to 4800)",
+     if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
+      err("%s - failed setting baud rate, unsupported speed",
           __FUNCTION__);
-      n_baud_rate = 4800;
+      new_baudrate = priv->baud_rate;
      }
     } else if (priv->chiptype == CT_GENERIC) {
-     if ( (n_baud_rate = mask_to_rate(baud_mask)) == -1) {
-      err("%s - failed setting baud rate, unsupported speed (default to 4800)",
+     if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
+      err("%s - failed setting baud rate, unsupported speed",
           __FUNCTION__);
-      n_baud_rate = 4800;
+      new_baudrate = priv->baud_rate;
      }
     } else {
-     info("%s - please define your chiptype, using 4800bps default", 
__FUNCTION__);
-     n_baud_rate = 4800;
+     info("%s - please define your chiptype", __FUNCTION__);
+     new_baudrate = priv->baud_rate;
     }
    } else {  /* baud rate not changing, keep the old */
-    n_baud_rate = priv->baud_rate;
+    new_baudrate = priv->baud_rate;
    }
-   dbg("%s - baud rate is being sent as %d", __FUNCTION__, n_baud_rate);
-
+   dbg("%s - baud rate is being sent as %d", __FUNCTION__, new_baudrate);
    
-   /*
-    * This algorithm accredited to Jiang Jay Zhang... thanks for all the help!
-    */
-   for (i = 0; i < 4; ++i) {
-    feature_buffer[i] = ( n_baud_rate >> (i*8) & 0xFF );
-   }
+   memset(feature_buffer, 0, 8);
+   /* fill the feature_buffer with new configuration */
+   *((u_int32_t *)feature_buffer) = new_baudrate;
 
-   config = 0;                  // reset config byte
-   config |= data_bits;          // assign data bits in 2 bit space ( max 3 )
+   feature_buffer[4] |= data_bits;   /* assign data bits in 2 bit space ( max 
3 ) */
    /* 1 bit gap */
-   config |= (stop_bits << 3);      // assign stop bits in 1 bit space
-   config |= (parity_enable << 4);  // assign parity flag in 1 bit space
-   config |= (parity_type << 5);   // assign parity type in 1 bit space
+   feature_buffer[4] |= (stop_bits << 3);   /* assign stop bits in 1 bit space 
*/
+   feature_buffer[4] |= (parity_enable << 4);   /* assign parity flag in 1 bit 
space */
+   feature_buffer[4] |= (parity_type << 5);   /* assign parity type in 1 bit 
space */
    /* 1 bit gap */
-   config |= (reset << 7);   // assign reset at end of byte, 1 bit space
-
-   feature_buffer[4] = config;
+   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],
               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, 5, 500);
+           0x0300, 0, feature_buffer, 8, 500);
+
+    if (tries++ >= 3)
+     break;
+
+    if (retval == EPIPE)
+     usb_clear_halt(port->serial->dev, 0x00);
+   } while (retval != 8 && retval != ENODEV);
 
-   if (retval != 5)
+   if (retval != 8)
     err("%s - failed sending serial line settings - %d", __FUNCTION__, retval);
    else {
     spin_lock_irqsave(&priv->lock, flags);
-    priv->baud_rate = n_baud_rate;
+    priv->baud_rate = new_baudrate;
     priv->cbr_mask = baud_mask;
-    priv->current_config = config;
-    ++priv->cmd_count;
+    priv->current_config = feature_buffer[4];
     spin_unlock_irqrestore(&priv->lock, flags);
    }
   break;
   case CYPRESS_GET_CONFIG:
    dbg("%s - retreiving serial line settings", __FUNCTION__);
-   /* reset values in feature buffer */
-   memset(feature_buffer, 0, 5);
+   /* set initial values in feature buffer */
+   memset(feature_buffer, 0, 8);
 
+   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, 5, 500);
+         0x0300, 0, feature_buffer, 8, 500);
+    
+    if (tries++ >= 3)
+     break;
+
+    if (retval == EPIPE)
+     usb_clear_halt(port->serial->dev, 0x00);
+   } while (retval != 5 && retval != ENODEV);
+
    if (retval != 5) {
     err("%s - failed to retreive serial line settings - %d", __FUNCTION__, 
retval);
     return retval;
    } else {
     spin_lock_irqsave(&priv->lock, flags);
+
     /* store the config in one byte, and later use bit masks to check values */
     priv->current_config = feature_buffer[4];
-    /* reverse the process above to get the baud_mask value */
-    n_baud_rate = 0; // reset bits
-    for (i = 0; i < 4; ++i) {
-     n_baud_rate |= ( feature_buffer[i] << (i*8) );
-    }
+    priv->baud_rate = *((u_int32_t *)feature_buffer);
     
-    priv->baud_rate = n_baud_rate;
-    if ( (priv->cbr_mask = rate_to_mask(n_baud_rate)) == 0x40)
+    if ( (priv->cbr_mask = rate_to_mask(priv->baud_rate)) == 0x40)
      dbg("%s - failed setting the baud mask (not defined)", __FUNCTION__);
-    ++priv->cmd_count;
     spin_unlock_irqrestore(&priv->lock, flags);
    }
-   break;
-  default:
-   err("%s - unsupported serial control command issued", __FUNCTION__);
  }
+ spin_lock_irqsave(&priv->lock, flags);
+ ++priv->cmd_count;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
  return retval;
 } /* cypress_serial_control */
 
 
-/* given a baud mask, it will return speed on success */
+/* given a baud mask, it will return integer baud on success */
 static int mask_to_rate (unsigned mask)
 {
  int rate;
@@ -438,11 +443,12 @@
  
  usb_reset_configuration (serial->dev);
  
+ interval = 1;
  priv->cmd_ctrl = 0;
  priv->line_control = 0;
  priv->termios_initialized = 0;
- priv->calledfromopen = 0;
  priv->rx_flags = 0;
+ priv->cbr_mask = B300;
  usb_set_serial_port_data(serial->port[0], priv);
  
  return (0); 
@@ -513,7 +519,6 @@
  dbg("%s - port %d", __FUNCTION__, port->number);
 
  /* clear halts before open */
- usb_clear_halt(serial->dev, 0x00);
  usb_clear_halt(serial->dev, 0x81);
  usb_clear_halt(serial->dev, 0x02);
 
@@ -531,7 +536,6 @@
  /* raise both lines and set termios */
  spin_lock_irqsave(&priv->lock, flags);
  priv->line_control = CONTROL_DTR | CONTROL_RTS;
- priv->calledfromopen = 1;
  priv->cmd_ctrl = 1;
  spin_unlock_irqrestore(&priv->lock, flags);
  result = cypress_write(port, NULL, 0);
@@ -553,7 +557,7 @@
  usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
   usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
   port->interrupt_in_urb->transfer_buffer, 
port->interrupt_in_urb->transfer_buffer_length,
-  cypress_read_int_callback, port, port->interrupt_in_urb->interval);
+  cypress_read_int_callback, port, interval);
  result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 
  if (result){
@@ -680,12 +684,12 @@
  spin_lock_irqsave(&priv->lock, flags);
  switch (port->interrupt_out_size) {
   case 32:
-   // this is for the CY7C64013...
+   /* this is for the CY7C64013... */
    offset = 2;
    port->interrupt_out_buffer[0] = priv->line_control;
    break;
   case 8:
-   // this is for the CY7C63743...
+   /* this is for the CY7C63743... */
    offset = 1;
    port->interrupt_out_buffer[0] = priv->line_control;
    break;
@@ -738,6 +742,7 @@
 
  port->interrupt_out_urb->transfer_buffer_length = actual_size;
  port->interrupt_out_urb->dev = port->serial->dev;
+ port->interrupt_out_urb->interval = 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__,
@@ -910,7 +915,7 @@
  unsigned cflag, iflag, baud_mask;
  unsigned long flags;
  __u8 oldlines;
- int linechange;
+ int linechange = 0;
  
  dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -996,15 +1001,7 @@
    case B115200: dbg("%s - setting baud 115200bps", __FUNCTION__); break;
    default: dbg("%s - unknown masked baud rate", __FUNCTION__);
   }
-  priv->line_control |= CONTROL_DTR;
-  
-  /* toggle CRTSCTS? - don't do this if being called from cypress_open */
-  if (!priv->calledfromopen) {
-   if (cflag & CRTSCTS)
-    priv->line_control |= CONTROL_RTS;
-   else
-    priv->line_control &= ~CONTROL_RTS;
-  }
+  priv->line_control = (CONTROL_DTR | CONTROL_RTS);
  }
  spin_unlock_irqrestore(&priv->lock, flags);
  
@@ -1014,8 +1011,6 @@
  cypress_serial_control(port, baud_mask, data_bits, stop_bits, parity_enable,
           parity_type, 0, CYPRESS_SET_CONFIG);
 
- msleep(50);   /* give some time between change and read (50ms) */
-
  /* we perform a CYPRESS_GET_CONFIG so that the current settings are filled 
into the private structure
          * this should confirm that all is working if it returns what we just 
set */
  cypress_serial_control(port, 0, 0, 0, 0, 0, 0, CYPRESS_GET_CONFIG);
@@ -1031,7 +1026,6 @@
   dbg("Using custom termios settings for a baud rate of 4800bps.");
   /* define custom termios settings for NMEA protocol */
 
-  
   tty->termios->c_iflag /* input modes - */
    &= ~(IGNBRK  /* disable ignore break */
    | BRKINT  /* disable break causes interrupt */
@@ -1052,23 +1046,16 @@
    | ISIG   /* disable interrupt, quit, and suspend special characters */
    | IEXTEN);  /* disable non-POSIX special characters */
 
- } else if (priv->chiptype == CT_CYPHIDCOM) {
-
-  // Software app handling it for device... 
+ } /* CT_CYPHIDCOM: Application should handle this for device */
 
- }
  linechange = (priv->line_control != oldlines);
  spin_unlock_irqrestore(&priv->lock, flags);
 
  /* if necessary, set lines */
- if (!priv->calledfromopen && linechange) {
+ if (linechange) {
   priv->cmd_ctrl = 1;
   cypress_write(port, NULL, 0);
  }
-
- if (priv->calledfromopen)
-  priv->calledfromopen = 0;
- 
 } /* cypress_set_termios */
 
  
@@ -1164,7 +1151,7 @@
  spin_lock_irqsave(&priv->lock, flags);
  switch(urb->actual_length) {
   case 32:
-   // This is for the CY7C64013...
+   /* This is for the CY7C64013... */
    priv->current_status = data[0] & 0xF8;
    bytes = data[1]+2;
    i=2;
@@ -1172,7 +1159,7 @@
     havedata = 1;
    break;
   case 8:
-   // This is for the CY7C63743...
+   /* This is for the CY7C63743... */
    priv->current_status = data[0] & 0xF8;
    bytes = (data[0] & 0x07)+1;
    i=1;
@@ -1245,7 +1232,7 @@
   port->interrupt_in_urb->transfer_buffer,
   port->interrupt_in_urb->transfer_buffer_length,
   cypress_read_int_callback, port,
-  port->interrupt_in_urb->interval);
+  interval);
  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__, result);
@@ -1274,6 +1261,8 @@
    dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
    priv->write_urb_in_use = 0;
    return;
+  case -EPIPE: /* no break needed */
+   usb_clear_halt(port->serial->dev, 0x02);
   default:
    /* error in the urb, so we have to resubmit it */
    dbg("%s - Overflow in write", __FUNCTION__);
@@ -1535,3 +1525,5 @@
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 module_param(stats, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(stats, "Enable statistics or not");
+module_param(interval, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(interval, "Overrides interrupt interval");


-------------------------------------------------------
This SF.Net email is sponsored by: NEC IT Guy Games.
Get your fingers limbered up and give it your best shot. 4 great events, 4
opportunities to win big! Highest score wins.NEC IT Guy Games. Play to
win an NEC 61 plasma display. Visit http://www.necitguy.com/?r=20
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to