All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lucy McCoy <lucy@keyspan.com>
To: greg@kroah.com
Cc: linux-kernel@vger.kernel.org,
	linux-usb-users@lists.sourceforge.net,
	linux-usb-devel@lists.sourceforge.net, lucy@keyspan.com
Subject: [PATCH 2.6.21] Usb Serial Keyspan: add support for USA-49WG & USA-28XG
Date: Tue, 15 May 2007 15:32:18 -0700	[thread overview]
Message-ID: <464A34F2.5060002@keyspan.com> (raw)

Add support for Keyspan adapters:  USA-49WG and USA-28XG

Signed-off-by: Lucy P. McCoy <lucy@keyspan.com>
---
diff -uprN -X linux-2.6.21-vanilla/Documentation/dontdiff 
linux-2.6.21-vanilla/drivers/usb/serial/keyspan.c 
linux-2.6.21-lpm/drivers/usb/serial/keyspan.c
--- linux-2.6.21-vanilla/drivers/usb/serial/keyspan.c    2007-04-25 
20:08:32.000000000 -0700
+++ linux-2.6.21-lpm/drivers/usb/serial/keyspan.c    2007-05-04 
13:35:23.000000000 -0700
@@ -28,6 +28,9 @@
 
   Change History
 
+    2007may02    LPM (Keyspan) add support for the USA28XG and USA49WG.
+                
+
     2003sep04    LPM (Keyspan) add support for new single port product 
USA19HS.
                 Improve setup message handling for all devices.
 
@@ -115,12 +118,13 @@ static int debug;
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.1.4"
+#define DRIVER_VERSION "v1.1.5"
 #define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
 #define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
 
 #define INSTAT_BUFLEN    32
 #define GLOCONT_BUFLEN    64
+#define INDAT49W_BUFLEN    512
 
     /* Per device and per port private data */
 struct keyspan_serial_private {
@@ -129,9 +133,15 @@ struct keyspan_serial_private {
     struct urb    *instat_urb;
     char        instat_buf[INSTAT_BUFLEN];
 
+    /* added to support 49wg, where data from all 4 ports comes in on 1 
EP */
+    /* and high-speed supported */
+    struct urb    *indat_urb;
+    char        indat_buf[INDAT49W_BUFLEN];
+
     /* XXX this one probably will need a lock */
     struct urb    *glocont_urb;
     char        glocont_buf[GLOCONT_BUFLEN];
+    char        ctrl_buf[8];            // for EP0 control message
 };
 
 struct keyspan_port_private {
@@ -179,12 +189,13 @@ struct keyspan_port_private {
 
     
 /* Include Keyspan message headers.  All current Keyspan Adapters
-   make use of one of four message formats which are referred
-   to as USA-26, USA-28 and USA-49, USA-90 by Keyspan and within this 
driver. */
+   make use of one of five message formats which are referred
+   to as USA-26, USA-28, USA-49, USA-90, USA-67 by Keyspan and within 
this driver. */
 #include "keyspan_usa26msg.h"
 #include "keyspan_usa28msg.h"
 #include "keyspan_usa49msg.h"
 #include "keyspan_usa90msg.h"
+#include "keyspan_usa67msg.h"
     
 
 /* Functions used by new usb-serial code. */
@@ -850,6 +861,82 @@ static void    usa49_indat_callback(struct
         }
 }
 
+
+static void    usa49wg_indat_callback(struct urb *urb)
+{
+    int            i, len, x, err;
+    struct usb_serial        *serial;
+    struct usb_serial_port        *port;
+
+    struct tty_struct    *tty;
+    unsigned char         *data = urb->transfer_buffer;
+
+
+    dbg ("%s", __FUNCTION__);
+
+    serial = (struct usb_serial *) urb->context;
+
+    if (urb->status) {
+        dbg("%s - nonzero status: %x", __FUNCTION__, urb->status);
+        return;
+    }
+
+    // inbound data is in the form P#, len, status, data */
+        
+    i = len = 0;
+
+    if (urb->actual_length) {
+        while (i < urb->actual_length) {
+
+            /* Check port number from message*/    
+            if (data[i] >= serial->num_ports) {
+                dbg ("%s - Unexpected port number %d", __FUNCTION__, 
data[i]);
+                return;
+            }
+            port = serial->port[data[i++]];
+            tty = port->tty;
+            len = data[i++];
+            
+            /* 0x80 bit is error flag */
+            if ((data[i] & 0x80) == 0) {
+                /* no error on any byte */
+                i++;
+                for (x = 1; x < len ; ++x)
+                    if (port->open_count)
+                        tty_insert_flip_char(tty, data[i++], 0);
+                    else
+                        i++;
+            }
+            else {
+                /* some bytes had errors, every byte has status */
+                for (x = 0; x + 1 < len; x += 2) {
+                    int stat = data[i], flag = 0;
+                    if (stat & RXERROR_OVERRUN)
+                        flag |= TTY_OVERRUN;
+                    if (stat & RXERROR_FRAMING)
+                        flag |= TTY_FRAME;
+                    if (stat & RXERROR_PARITY)
+                        flag |= TTY_PARITY;
+                    /* XXX should handle break (0x10) */
+                    if (port->open_count)
+                        tty_insert_flip_char(tty, data[i+1], flag);
+                    i+=2;
+                }
+            }
+            if (port->open_count)
+                tty_flip_buffer_push(tty);
+        }
+    }
+                
+    /* Resubmit urb so we continue receiving */
+    urb->dev = serial->dev;
+
+    if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
+        dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+    }
+}
+
+    
 /* not used, usa-49 doesn't have per-port control endpoints */
 static void    usa49_outcont_callback(struct urb *urb)
 {
@@ -995,6 +1082,88 @@ static void    usa90_outcont_callback(struc
     }
 }
 
+
+
+/* Status messages from the 28xg */
+static void    usa67_instat_callback(struct urb *urb)
+{
+    int                    err;
+    unsigned char                 *data = urb->transfer_buffer;
+    struct keyspan_usa67_portStatusMessage    *msg;
+    struct usb_serial            *serial;
+    struct usb_serial_port            *port;
+    struct keyspan_port_private         *p_priv;
+    int old_dcd_state;
+
+    dbg ("%s", __FUNCTION__);
+
+    serial = (struct usb_serial *) urb->context;
+
+    if (urb->status) {
+        dbg("%s - nonzero status: %x", __FUNCTION__, urb->status);
+        return;
+    }
+
+    if (urb->actual_length != sizeof(struct 
keyspan_usa67_portStatusMessage)) {
+        dbg("%s - bad length %d", __FUNCTION__, urb->actual_length);
+        return;
+    }
+
+    
+    /* Now do something useful with the data */
+    msg = (struct keyspan_usa67_portStatusMessage *)data;
+
+    /* Check port number from message and retrieve private data */    
+    if (msg->port >= serial->num_ports) {
+        dbg ("%s - Unexpected port number %d", __FUNCTION__, msg->port);
+        return;
+    }
+
+    port = serial->port[msg->port];
+    p_priv = usb_get_serial_port_data(port);
+    
+    /* Update handshaking pin state information */
+    old_dcd_state = p_priv->dcd_state;
+    p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
+    p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
+
+    if (port->tty && !C_CLOCAL(port->tty)
+        && old_dcd_state != p_priv->dcd_state) {
+        if (old_dcd_state)
+            tty_hangup(port->tty);
+        /*  else */
+        /*    wake_up_interruptible(&p_priv->open_wait); */
+    }
+    
+    /* Resubmit urb so we continue receiving */
+    urb->dev = serial->dev;
+    if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
+        dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+    }
+}
+
+static void    usa67_glocont_callback(struct urb *urb)
+{
+    struct usb_serial *serial;
+    struct usb_serial_port *port;
+    struct keyspan_port_private *p_priv;
+    int i;
+
+    dbg ("%s", __FUNCTION__);
+
+    serial = (struct usb_serial *) urb->context;
+    for (i = 0; i < serial->num_ports; ++i) {
+        port = serial->port[i];
+        p_priv = usb_get_serial_port_data(port);
+
+        if (p_priv->resend_cont) {
+            dbg ("%s - sending setup", __FUNCTION__);
+            keyspan_usa67_send_setup(serial, port, p_priv->resend_cont 
- 1);
+            break;
+        }
+    }
+}
+
 static int keyspan_write_room (struct usb_serial_port *port)
 {
     struct keyspan_port_private    *p_priv;
@@ -1311,6 +1480,11 @@ static struct urb *keyspan_setup_urb (st
         return NULL;
     }
 
+    if (endpoint == 0) {
+        /* control EP filled in when used */
+        return urb;
+    }
+
     ep_desc = find_ep(serial, endpoint);
     if (!ep_desc) {
         /* leak the urb, something's wrong and the callers don't care */
@@ -1380,6 +1554,14 @@ static struct callbacks {
         .outdat_callback =    usa2x_outdat_callback,
         .inack_callback =    usa28_inack_callback,
         .outcont_callback =    usa90_outcont_callback,
+    }, {
+        /* msg_usa67 callbacks */
+        .instat_callback =    usa67_instat_callback,
+        .glocont_callback =    usa67_glocont_callback,
+        .indat_callback =    usa26_indat_callback,
+        .outdat_callback =    usa2x_outdat_callback,
+        .inack_callback =    usa26_inack_callback,
+        .outcont_callback =    usa26_outcont_callback,
     }
 };
 
@@ -1410,6 +1592,11 @@ static void keyspan_setup_urbs(struct us
          serial, s_priv->instat_buf, INSTAT_BUFLEN,
          cback->instat_callback);
 
+    s_priv->indat_urb = keyspan_setup_urb
+        (serial, d_details->indat_endpoint, USB_DIR_IN,
+         serial, s_priv->indat_buf, INDAT49W_BUFLEN,
+         usa49wg_indat_callback);
+
     s_priv->glocont_urb = keyspan_setup_urb
         (serial, d_details->glocont_endpoint, USB_DIR_OUT,
          serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
@@ -1685,8 +1872,8 @@ static int keyspan_usa26_send_setup(stru
     }
 
     /* Save reset port val for resend.
-    Don't overwrite resend for close condition. */
-    if (p_priv->resend_cont != 3)
+       Don't overwrite resend for open/close condition. */
+    if ((reset_port+1) > p_priv->resend_cont)
         p_priv->resend_cont = reset_port + 1;
     if (this_urb->status == -EINPROGRESS) {
         /*  dbg ("%s - already writing", __FUNCTION__); */
@@ -1836,8 +2023,8 @@ static int keyspan_usa28_send_setup(stru
     }
 
     /* Save reset port val for resend.
-       Don't overwrite resend for close condition. */
-    if (p_priv->resend_cont != 3)
+       Don't overwrite resend for open/close condition. */
+    if ((reset_port+1) > p_priv->resend_cont)
         p_priv->resend_cont = reset_port + 1;
     if (this_urb->status == -EINPROGRESS) {
         dbg ("%s already writing", __FUNCTION__);
@@ -1940,21 +2127,22 @@ static int keyspan_usa49_send_setup(stru
                     struct usb_serial_port *port,
                     int reset_port)
 {
-    struct keyspan_usa49_portControlMessage    msg;        
+    struct keyspan_usa49_portControlMessage    msg;    
+    struct usb_ctrlrequest             *dr = NULL;    
     struct keyspan_serial_private         *s_priv;
     struct keyspan_port_private         *p_priv;
     const struct keyspan_device_details    *d_details;
-    int                     glocont_urb;
     struct urb                *this_urb;
     int                     err, device_port;
 
+
+
     dbg ("%s", __FUNCTION__);
 
     s_priv = usb_get_serial_data(serial);
     p_priv = usb_get_serial_port_data(port);
     d_details = s_priv->device_details;
 
-    glocont_urb = d_details->glocont_endpoint;
     this_urb = s_priv->glocont_urb;
 
         /* Work out which port within the device is being setup */
@@ -1968,10 +2156,12 @@ static int keyspan_usa49_send_setup(stru
         return -1;
     }
 
+
     /* Save reset port val for resend.
-       Don't overwrite resend for close condition. */
-    if (p_priv->resend_cont != 3)
+       Don't overwrite resend for open/close condition. */
+    if ((reset_port+1) > p_priv->resend_cont)
         p_priv->resend_cont = reset_port + 1;
+
     if (this_urb->status == -EINPROGRESS) {
         /*  dbg ("%s - already writing", __FUNCTION__); */
         mdelay(5);
@@ -2083,20 +2273,40 @@ static int keyspan_usa49_send_setup(stru
     msg.dtr = p_priv->dtr_state;
         
     p_priv->resend_cont = 0;
-    memcpy (this_urb->transfer_buffer, &msg, sizeof(msg));
+
+    /* if the device is a 49wg, we send control message on usb control 
EP 0 */
+
+    if (d_details->product_id == keyspan_usa49wg_product_id) {            
+        dr = (void *)(s_priv->ctrl_buf);
+        dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
+        dr->bRequest = 0xB0;    /* 49wg control message */;
+        dr->wValue = 0;    
+        dr->wIndex = 0;
+        dr->wLength = cpu_to_le16(sizeof(msg));
+
+        memcpy (s_priv->glocont_buf, &msg, sizeof(msg));
+
+        usb_fill_control_urb(this_urb, serial->dev, 
usb_sndctrlpipe(serial->dev, 0),
+                 (unsigned char *)dr, s_priv->glocont_buf, sizeof(msg),
+                 usa49_glocont_callback, serial);
+
+    }
+    else {
+        memcpy (this_urb->transfer_buffer, &msg, sizeof(msg));
     
-    /* send the data out the device on control endpoint */
-    this_urb->transfer_buffer_length = sizeof(msg);
+        /* send the data out the device on control endpoint */
+        this_urb->transfer_buffer_length = sizeof(msg);
 
-    this_urb->dev = serial->dev;
+        this_urb->dev = serial->dev;
+    }
     if ((err = usb_submit_urb(this_urb, GFP_ATOMIC)) != 0) {
         dbg("%s - usb_submit_urb(setup) failed (%d)", __FUNCTION__, err);
     }
 #if 0
     else {
         dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __FUNCTION__,
-            outcont_urb, this_urb->transfer_buffer_length,
-            usb_pipeendpoint(this_urb->pipe));
+               outcont_urb, this_urb->transfer_buffer_length,
+               usb_pipeendpoint(this_urb->pipe));
     }
 #endif
 
@@ -2241,6 +2451,157 @@ static int keyspan_usa90_send_setup(stru
     return (0);
 }
 
+static int keyspan_usa67_send_setup(struct usb_serial *serial,
+                    struct usb_serial_port *port,
+                    int reset_port)
+{
+    struct keyspan_usa67_portControlMessage    msg;    
+    struct keyspan_serial_private         *s_priv;
+    struct keyspan_port_private         *p_priv;
+    const struct keyspan_device_details    *d_details;
+    struct urb                *this_urb;
+    int                     err, device_port;
+
+    dbg ("%s", __FUNCTION__);
+
+    s_priv = usb_get_serial_data(serial);
+    p_priv = usb_get_serial_port_data(port);
+    d_details = s_priv->device_details;
+
+    this_urb = s_priv->glocont_urb;
+
+    /* Work out which port within the device is being setup */
+    device_port = port->number - port->serial->minor;
+
+    /* Make sure we have an urb then send the message */
+    if (this_urb == NULL) {
+        dbg("%s - oops no urb for port %d.", __FUNCTION__, port->number);
+        return -1;
+    }
+
+    /* Save reset port val for resend.
+       Don't overwrite resend for open/close condition. */
+    if ((reset_port + 1) > p_priv->resend_cont)
+        p_priv->resend_cont = reset_port + 1;
+    if (this_urb->status == -EINPROGRESS) {
+        /*  dbg ("%s - already writing", __FUNCTION__); */
+        mdelay(5);
+        return(-1);
+    }
+
+    memset(&msg, 0, sizeof (struct keyspan_usa67_portControlMessage));
+
+    msg.port = device_port;
+
+    /* Only set baud rate if it's changed */    
+    if (p_priv->old_baud != p_priv->baud) {
+        p_priv->old_baud = p_priv->baud;
+        msg.setClocking = 0xff;
+        if (d_details->calculate_baud_rate
+            (p_priv->baud, d_details->baudclk, &msg.baudHi,
+             &msg.baudLo, &msg.prescaler, device_port) == 
KEYSPAN_INVALID_BAUD_RATE ) {
+            dbg("%s - Invalid baud rate %d requested, using 9600.", 
__FUNCTION__,
+                p_priv->baud);
+            msg.baudLo = 0;
+            msg.baudHi = 125;    /* Values for 9600 baud */
+            msg.prescaler = 10;
+        }
+        msg.setPrescaler = 0xff;
+    }
+
+    msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1;
+    switch (p_priv->cflag & CSIZE) {
+    case CS5:
+        msg.lcr |= USA_DATABITS_5;
+        break;
+    case CS6:
+        msg.lcr |= USA_DATABITS_6;
+        break;
+    case CS7:
+        msg.lcr |= USA_DATABITS_7;
+        break;
+    case CS8:
+        msg.lcr |= USA_DATABITS_8;
+        break;
+    }
+    if (p_priv->cflag & PARENB) {
+        /* note USA_PARITY_NONE == 0 */
+        msg.lcr |= (p_priv->cflag & PARODD)?
+            USA_PARITY_ODD: USA_PARITY_EVEN;
+    }
+    msg.setLcr = 0xff;
+
+    msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
+    msg.xonFlowControl = 0;
+    msg.setFlowControl = 0xff;
+    msg.forwardingLength = 16;
+    msg.xonChar = 17;
+    msg.xoffChar = 19;
+
+    /* Opening port */
+    if (reset_port == 1) {
+        msg._txOn = 1;
+        msg._txOff = 0;
+        msg.txFlush = 0;
+        msg.txBreak = 0;
+        msg.rxOn = 1;
+        msg.rxOff = 0;
+        msg.rxFlush = 1;
+        msg.rxForward = 0;
+        msg.returnStatus = 0;
+        msg.resetDataToggle = 0xff;
+    }
+
+    /* Closing port */
+    else if (reset_port == 2) {
+        msg._txOn = 0;
+        msg._txOff = 1;
+        msg.txFlush = 0;
+        msg.txBreak = 0;
+        msg.rxOn = 0;
+        msg.rxOff = 1;
+        msg.rxFlush = 1;
+        msg.rxForward = 0;
+        msg.returnStatus = 0;
+        msg.resetDataToggle = 0;
+    }
+
+    /* Sending intermediate configs */
+    else {
+        msg._txOn = (! p_priv->break_on);
+        msg._txOff = 0;
+        msg.txFlush = 0;
+        msg.txBreak = (p_priv->break_on);
+        msg.rxOn = 0;
+        msg.rxOff = 0;
+        msg.rxFlush = 0;
+        msg.rxForward = 0;
+        msg.returnStatus = 0;
+        msg.resetDataToggle = 0x0;
+    }
+
+        /* Do handshaking outputs */    
+    msg.setTxTriState_setRts = 0xff;
+    msg.txTriState_rts = p_priv->rts_state;
+
+    msg.setHskoa_setDtr = 0xff;
+    msg.hskoa_dtr = p_priv->dtr_state;
+        
+    p_priv->resend_cont = 0;
+
+    memcpy (this_urb->transfer_buffer, &msg, sizeof(msg));
+    
+    /* send the data out the device on control endpoint */
+    this_urb->transfer_buffer_length = sizeof(msg);
+    this_urb->dev = serial->dev;
+    
+    if ((err = usb_submit_urb(this_urb, GFP_ATOMIC)) != 0) {
+        dbg("%s - usb_submit_urb(setup) failed (%d)", __FUNCTION__, err);
+    }
+    
+    return (0);
+}
+
 static void keyspan_send_setup(struct usb_serial_port *port, int 
reset_port)
 {
     struct usb_serial *serial = port->serial;
@@ -2265,6 +2626,9 @@ static void keyspan_send_setup(struct us
     case msg_usa90:
         keyspan_usa90_send_setup(serial, port, reset_port);
         break;
+    case msg_usa67:
+        keyspan_usa67_send_setup(serial, port, reset_port);
+        break;
     }
 }
 
@@ -2313,9 +2677,17 @@ static int keyspan_startup (struct usb_s
 
     keyspan_setup_urbs(serial);
 
-    s_priv->instat_urb->dev = serial->dev;
-    if ((err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL)) != 0) {
-        dbg("%s - submit instat urb failed %d", __FUNCTION__, err);
+    if (s_priv->instat_urb != NULL) {
+        s_priv->instat_urb->dev = serial->dev;
+        if ((err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL)) != 0) {
+            dbg("%s - submit instat urb failed %d", __FUNCTION__, err);
+        }
+    }
+    if (s_priv->indat_urb != NULL) {
+        s_priv->indat_urb->dev = serial->dev;
+        if ((err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL)) != 0) {
+            dbg("%s - submit indat urb failed %d", __FUNCTION__, err);
+        }
     }
             
     return (0);
@@ -2335,6 +2707,7 @@ static void keyspan_shutdown (struct usb
     /* Stop reading/writing urbs */
     stop_urb(s_priv->instat_urb);
     stop_urb(s_priv->glocont_urb);
+    stop_urb(s_priv->indat_urb);
     for (i = 0; i < serial->num_ports; ++i) {
         port = serial->port[i];
         p_priv = usb_get_serial_port_data(port);
@@ -2348,6 +2721,7 @@ static void keyspan_shutdown (struct usb
 
     /* Now free them */
     usb_free_urb(s_priv->instat_urb);
+    usb_free_urb(s_priv->indat_urb);
     usb_free_urb(s_priv->glocont_urb);
     for (i = 0; i < serial->num_ports; ++i) {
         port = serial->port[i];
diff -uprN -X linux-2.6.21-vanilla/Documentation/dontdiff 
linux-2.6.21-vanilla/drivers/usb/serial/keyspan.h 
linux-2.6.21-lpm/drivers/usb/serial/keyspan.h
--- linux-2.6.21-vanilla/drivers/usb/serial/keyspan.h    2007-04-25 
20:08:32.000000000 -0700
+++ linux-2.6.21-lpm/drivers/usb/serial/keyspan.h    2007-05-01 
14:14:53.000000000 -0700
@@ -99,6 +99,10 @@ static int  keyspan_usa90_send_setup    (st
                      struct usb_serial_port *port,
                      int reset_port);
 
+static int  keyspan_usa67_send_setup    (struct usb_serial *serial,
+                     struct usb_serial_port *port,
+                     int reset_port);
+
 /* Struct used for firmware - increased size of data section
    to allow Keyspan's 'C' firmware struct to be used unmodified */
 struct ezusb_hex_record {
@@ -229,15 +233,17 @@ struct ezusb_hex_record {
 #define    keyspan_usa28_product_id        0x010f
 #define    keyspan_usa28x_product_id        0x0110
 #define    keyspan_usa28xa_product_id        0x0115
+#define    keyspan_usa28xb_product_id        0x0110
+#define    keyspan_usa28xg_product_id        0x0135
 #define    keyspan_usa49w_product_id        0x010a
 #define    keyspan_usa49wlc_product_id        0x012a
-
+#define    keyspan_usa49wg_product_id        0x0131
 
 struct keyspan_device_details {
     /* product ID value */
     int    product_id;
 
-    enum    {msg_usa26, msg_usa28, msg_usa49, msg_usa90} msg_format;
+    enum    {msg_usa26, msg_usa28, msg_usa49, msg_usa90, msg_usa67} 
msg_format;
 
         /* Number of physical ports */
     int    num_ports;
@@ -264,6 +270,9 @@ struct keyspan_device_details {
         /* Endpoint used for input status */
     int    instat_endpoint;
 
+        /* Endpoint used for input data 49WG only */
+    int    indat_endpoint;
+
         /* Endpoint used for global control functions */
     int    glocont_endpoint;
 
@@ -287,6 +296,7 @@ static const struct keyspan_device_detai
     .inack_endpoints    = {0x85},
     .outcont_endpoints    = {0x05},
     .instat_endpoint    = 0x87,
+    .indat_endpoint        = -1,
     .glocont_endpoint    = 0x07,
     .calculate_baud_rate    = keyspan_usa19w_calc_baud,
     .baudclk        = KEYSPAN_USA18X_BAUDCLK,
@@ -303,6 +313,7 @@ static const struct keyspan_device_detai
     .inack_endpoints    = {0x83},
     .outcont_endpoints    = {0x03},
     .instat_endpoint    = 0x84,
+    .indat_endpoint        = -1,
     .glocont_endpoint    = -1,
     .calculate_baud_rate    = keyspan_usa19_calc_baud,
     .baudclk        = KEYSPAN_USA19_BAUDCLK,
@@ -319,6 +330,7 @@ static const struct keyspan_device_detai
     .inack_endpoints    = {0x83},
     .outcont_endpoints    = {0x03},
     .instat_endpoint    = 0x84,
+    .indat_endpoint        = -1,
     .glocont_endpoint    = -1,
     .calculate_baud_rate    = keyspan_usa28_calc_baud,
     .baudclk        = KEYSPAN_USA19_BAUDCLK,
@@ -335,6 +347,7 @@ static const struct keyspan_device_detai
     .inack_endpoints    = {0x83},
     .outcont_endpoints    = {0x03},
     .instat_endpoint    = 0x84,
+    .indat_endpoint        = -1,
     .glocont_endpoint    = -1,
     .calculate_baud_rate    = keyspan_usa28_calc_baud,
     .baudclk        = KEYSPAN_USA19_BAUDCLK,
@@ -351,6 +364,7 @@ static const struct keyspan_device_detai
     .inack_endpoints    = {0x85},
     .outcont_endpoints    = {0x05},
     .instat_endpoint    = 0x87,
+    .indat_endpoint        = -1,
     .glocont_endpoint    = 0x07,
     .calculate_baud_rate    = keyspan_usa19w_calc_baud,
     .baudclk        = KEYSPAN_USA19W_BAUDCLK,
@@ -367,6 +381,7 @@ static const struct keyspan_device_detai
     .inack_endpoints    = {0x85},
     .outcont_endpoints    = {0x05},
     .instat_endpoint    = 0x87,
+    .indat_endpoint        = -1,
     .glocont_endpoint    = 0x07,
     .calculate_baud_rate    = keyspan_usa19w_calc_baud,
     .baudclk        = KEYSPAN_USA19W_BAUDCLK,
@@ -383,6 +398,7 @@ static const struct keyspan_device_detai
     .inack_endpoints    = {-1},
     .outcont_endpoints    = {0x02},
     .instat_endpoint    = 0x82,
+    .indat_endpoint        = -1,
     .glocont_endpoint    = -1,
     .calculate_baud_rate    = keyspan_usa19hs_calc_baud,
     .baudclk        = KEYSPAN_USA19HS_BAUDCLK,
@@ -399,6 +415,7 @@ static const struct keyspan_device_detai
     .inack_endpoints    = {0x85, 0x86},
     .outcont_endpoints    = {0x05, 0x06},
     .instat_endpoint    = 0x87,
+    .indat_endpoint        = -1,
     .glocont_endpoint    = 0x07,
     .calculate_baud_rate    = keyspan_usa28_calc_baud,
     .baudclk        = KEYSPAN_USA28_BAUDCLK,        
@@ -415,6 +432,7 @@ static const struct keyspan_device_detai
     .inack_endpoints    = {0x85, 0x86},
     .outcont_endpoints    = {0x05, 0x06},
     .instat_endpoint    = 0x87,
+    .indat_endpoint        = -1,
     .glocont_endpoint    = 0x07,
     .calculate_baud_rate    = keyspan_usa19w_calc_baud,
     .baudclk        = KEYSPAN_USA28X_BAUDCLK,
@@ -431,11 +449,28 @@ static const struct keyspan_device_detai
     .inack_endpoints    = {0x85, 0x86},
     .outcont_endpoints    = {0x05, 0x06},
     .instat_endpoint    = 0x87,
+    .indat_endpoint        = -1,
     .glocont_endpoint    = 0x07,
     .calculate_baud_rate    = keyspan_usa19w_calc_baud,
     .baudclk        = KEYSPAN_USA28X_BAUDCLK,
 };
 
+static const struct keyspan_device_details usa28xg_device_details = {
+    .product_id        = keyspan_usa28xg_product_id,
+    .msg_format        = msg_usa67,
+    .num_ports        = 2,
+    .indat_endp_flip    = 0,
+    .outdat_endp_flip    = 0,
+    .indat_endpoints    = {0x84, 0x88},
+    .outdat_endpoints    = {0x02, 0x06},
+    .inack_endpoints    = {-1, -1},
+    .outcont_endpoints    = {-1, -1},
+    .instat_endpoint    = 0x81,
+    .indat_endpoint        = -1,
+    .glocont_endpoint    = 0x01,
+    .calculate_baud_rate    = keyspan_usa19w_calc_baud,
+    .baudclk        = KEYSPAN_USA28X_BAUDCLK,
+};
 /* We don't need a separate entry for the usa28xb as it appears as a 
28x anyway */
 
 static const struct keyspan_device_details usa49w_device_details = {
@@ -449,6 +484,7 @@ static const struct keyspan_device_detai
     .inack_endpoints    = {-1, -1, -1, -1},
     .outcont_endpoints    = {-1, -1, -1, -1},
     .instat_endpoint    = 0x87,
+    .indat_endpoint        = -1,
     .glocont_endpoint    = 0x07,
     .calculate_baud_rate    = keyspan_usa19w_calc_baud,
     .baudclk        = KEYSPAN_USA49W_BAUDCLK,
@@ -465,11 +501,29 @@ static const struct keyspan_device_detai
     .inack_endpoints    = {-1, -1, -1, -1},
     .outcont_endpoints    = {-1, -1, -1, -1},
     .instat_endpoint    = 0x87,
+    .indat_endpoint        = -1,
     .glocont_endpoint    = 0x07,
     .calculate_baud_rate    = keyspan_usa19w_calc_baud,
     .baudclk        = KEYSPAN_USA19W_BAUDCLK,
 };
 
+static const struct keyspan_device_details usa49wg_device_details = {
+    .product_id        = keyspan_usa49wg_product_id,
+    .msg_format        = msg_usa49,
+    .num_ports        = 4,
+    .indat_endp_flip    = 0,
+    .outdat_endp_flip    = 0,
+    .indat_endpoints    = {-1, -1, -1, -1},        /* single 'global' 
data in EP */
+    .outdat_endpoints    = {0x01, 0x02, 0x04, 0x06},
+    .inack_endpoints    = {-1, -1, -1, -1},
+    .outcont_endpoints    = {-1, -1, -1, -1},
+    .instat_endpoint    = 0x81,
+    .indat_endpoint        = 0x88,
+    .glocont_endpoint    = 0x00,                /* uses control EP */
+    .calculate_baud_rate    = keyspan_usa19w_calc_baud,
+    .baudclk        = KEYSPAN_USA19W_BAUDCLK,
+};
+
 static const struct keyspan_device_details *keyspan_devices[] = {
     &usa18x_device_details,
     &usa19_device_details,
@@ -481,9 +535,11 @@ static const struct keyspan_device_detai
     &usa28_device_details,
     &usa28x_device_details,
     &usa28xa_device_details,
+    &usa28xg_device_details,
     /* 28xb not required as it renumerates as a 28x */
     &usa49w_device_details,
     &usa49wlc_device_details,
+    &usa49wg_device_details,
     NULL,
 };
 
@@ -510,8 +566,11 @@ static struct usb_device_id keyspan_ids_
     { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
     { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
     { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
+    { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
+    { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) },    
     { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)},
     { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
+    { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)},
     { } /* Terminating entry */
 };
 
@@ -557,12 +616,15 @@ static struct usb_device_id keyspan_2por
     { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
     { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
     { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
+    { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
+    { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) },
     { } /* Terminating entry */
 };
 
 static struct usb_device_id keyspan_4port_ids[] = {
     { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id) },
     { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
+    { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)},
     { } /* Terminating entry */
 };
 
@@ -573,7 +635,6 @@ static struct usb_serial_driver keyspan_
         .name        = "keyspan_no_firm",
     },
     .description        = "Keyspan - (without firmware)",
-    .usb_driver        = &keyspan_driver,
     .id_table        = keyspan_pre_ids,
     .num_interrupt_in    = NUM_DONT_CARE,
     .num_bulk_in        = NUM_DONT_CARE,
@@ -588,7 +649,6 @@ static struct usb_serial_driver keyspan_
         .name        = "keyspan_1",
     },
     .description        = "Keyspan 1 port adapter",
-    .usb_driver        = &keyspan_driver,
     .id_table        = keyspan_1port_ids,
     .num_interrupt_in    = NUM_DONT_CARE,
     .num_bulk_in        = NUM_DONT_CARE,
@@ -616,7 +676,6 @@ static struct usb_serial_driver keyspan_
         .name        = "keyspan_2",
     },
     .description        = "Keyspan 2 port adapter",
-    .usb_driver        = &keyspan_driver,
     .id_table        = keyspan_2port_ids,
     .num_interrupt_in    = NUM_DONT_CARE,
     .num_bulk_in        = NUM_DONT_CARE,
@@ -644,11 +703,10 @@ static struct usb_serial_driver keyspan_
         .name        = "keyspan_4",
     },
     .description        = "Keyspan 4 port adapter",
-    .usb_driver        = &keyspan_driver,
     .id_table        = keyspan_4port_ids,
     .num_interrupt_in    = NUM_DONT_CARE,
-    .num_bulk_in        = 5,
-    .num_bulk_out        = 5,
+    .num_bulk_in        = NUM_DONT_CARE,
+    .num_bulk_out        = NUM_DONT_CARE,
     .num_ports        = 4,
     .open            = keyspan_open,
     .close            = keyspan_close,
diff -uprN -X linux-2.6.21-vanilla/Documentation/dontdiff 
linux-2.6.21-vanilla/drivers/usb/serial/keyspan_usa67msg.h 
linux-2.6.21-lpm/drivers/usb/serial/keyspan_usa67msg.h
--- linux-2.6.21-vanilla/drivers/usb/serial/keyspan_usa67msg.h   
 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.21-lpm/drivers/usb/serial/keyspan_usa67msg.h    2007-05-03 
17:07:08.000000000 -0700
@@ -0,0 +1,254 @@
+/*
+    usa67msg.h
+
+    Copyright (c) 1998-2007 InnoSys Incorporated.  All Rights Reserved
+    This file is available under a BSD-style copyright
+
+    Keyspan USB Async Firmware to run on Anchor FX1
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are
+    met:
+
+    1. Redistributions of source code must retain this licence text
+       without modification, this list of conditions, and the following
+       disclaimer.  The following copyright notice must appear 
immediately at
+       the beginning of all source files:
+
+            Copyright (c) 1998-2007 InnoSys Incorporated.  All Rights 
Reserved
+
+            This file is available under a BSD-style copyright
+
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+    3. The name of InnoSys Incorprated may not be used to endorse or 
promote
+       products derived from this software without specific prior written
+       permission.
+
+    THIS SOFTWARE IS PROVIDED BY INNOSYS CORP. ``AS IS'' AND ANY EXPRESS OR
+    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES
+    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
DISCLAIMED. IN
+    NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
ANY WAY
+    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.    
+
+    Fourth revision: This message format supports the USA28XG
+
+    Buffer formats for RX/TX data messages are not defined by
+    a structure, but are described here:
+
+    USB OUT (host -> USAxx, transmit) messages contain a
+    REQUEST_ACK indicator (set to 0xff to request an ACK at the
+    completion of transmit; 0x00 otherwise), followed by data:
+
+        RQSTACK DAT DAT DAT ...
+
+    with a total data length of up to 63.
+
+    USB IN (USAxx -> host, receive) messages begin with a status
+    byte in which the 0x80 bit is either:
+                       
+        (a)    0x80 bit clear
+            indicates that the bytes following it are all data
+            bytes:
+
+                STAT DATA DATA DATA DATA DATA ...
+
+            for a total of up to 63 DATA bytes,
+
+    or:
+
+        (b)    0x80 bit set
+            indiates that the bytes following alternate data and
+            status bytes:
+
+                STAT DATA STAT DATA STAT DATA STAT DATA ...
+
+            for a total of up to 32 DATA bytes.
+
+    The valid bits in the STAT bytes are:
+
+        OVERRUN    0x02
+        PARITY    0x04
+        FRAMING    0x08
+        BREAK    0x10
+
+    Notes:
+
+    (1) The OVERRUN bit can appear in either (a) or (b) format
+        messages, but the but the PARITY/FRAMING/BREAK bits
+        only appear in (b) format messages.
+    (2) For the host to determine the exact point at which the
+        overrun occurred (to identify the point in the data
+        stream at which the data was lost), it needs to count
+        128 characters, starting at the first character of the
+        message in which OVERRUN was reported; the lost character(s)
+        would have been received between the 128th and 129th
+        characters.
+    (3)    An RX data message in which the first byte has 0x80 clear
+        serves as a "break off" indicator.
+
+    revision history:
+
+    1999feb10    add reportHskiaChanges to allow us to ignore them
+    1999feb10    add txAckThreshold for fast+loose throughput enhancement
+    1999mar30    beef up support for RX error reporting
+    1999apr14    add resetDataToggle to control message
+    2000jan04    merge with usa17msg.h
+    2000jun01    add extended BSD-style copyright text
+    2001jul05    change message format to improve OVERRUN case
+    2002jun05    update copyright date, improve comments
+    2006feb06    modify for FX1 chip
+
+*/
+
+#ifndef    __USA67MSG__
+#define    __USA67MSG__
+
+
+// all things called "ControlMessage" are sent on the 'control' endpoint
+
+typedef struct keyspan_usa67_portControlMessage
+{
+    u8    port;        // 0 or 1 (selects port)
+    /*
+        there are three types of "commands" sent in the control message:
+
+        1.    configuration changes which must be requested by setting
+            the corresponding "set" flag (and should only be requested
+            when necessary, to reduce overhead on the device):
+    */
+    u8    setClocking,    // host requests baud rate be set
+        baudLo,            // host does baud divisor calculation
+        baudHi,            // baudHi is only used for first port (gives 
lower rates)
+        externalClock_txClocking,
+                        // 0=internal, other=external
+
+        setLcr,            // host requests lcr be set
+        lcr,            // use PARITY, STOPBITS, DATABITS below
+
+        setFlowControl,    // host requests flow control be set
+        ctsFlowControl,    // 1=use CTS flow control, 0=don't
+        xonFlowControl,    // 1=use XON/XOFF flow control, 0=don't
+        xonChar,        // specified in current character format
+        xoffChar,        // specified in current character format
+
+        setTxTriState_setRts,
+                        // host requests TX tri-state be set
+        txTriState_rts,    // 1=active (normal), 0=tristate (off)
+
+        setHskoa_setDtr,
+                        // host requests HSKOA output be set
+        hskoa_dtr,        // 1=on, 0=off
+
+        setPrescaler,    // host requests prescalar be set (default: 13)
+        prescaler;        // specified as N/8; values 8-ff are valid
+                        // must be set any time internal baud rate is set;
+                        // must not be set when external clocking is used
+
+    /*
+        3.    configuration data which is simply used as is (no overhead,
+            but must be specified correctly in every host message).
+    */
+    u8    forwardingLength,  // forward when this number of chars available
+        reportHskiaChanges_dsrFlowControl,
+                        // 1=normal; 0=ignore external clock
+                        // 1=use DSR flow control, 0=don't
+        txAckThreshold,    // 0=not allowed, 1=normal, 2-255 deliver 
ACK faster
+        loopbackMode;    // 0=no loopback, 1=loopback enabled
+
+    /*
+        4.    commands which are flags only; these are processed in order
+            (so that, e.g., if both _txOn and _txOff flags are set, the
+            port ends in a TX_OFF state); any non-zero value is respected
+    */
+    u8    _txOn,            // enable transmitting (and continue if 
there's data)
+        _txOff,            // stop transmitting
+        txFlush,        // toss outbound data
+        txBreak,        // turn on break (cleared by _txOn)
+        rxOn,            // turn on receiver
+        rxOff,            // turn off receiver
+        rxFlush,        // toss inbound data
+        rxForward,        // forward all inbound data, NOW (as if 
fwdLen==1)
+        returnStatus,    // return current status (even if it hasn't 
changed)
+        resetDataToggle;// reset data toggle state to DATA0
+    
+} keyspan_usa67_portControlMessage;
+
+// defines for bits in lcr
+#define    USA_DATABITS_5        0x00
+#define    USA_DATABITS_6        0x01
+#define    USA_DATABITS_7        0x02
+#define    USA_DATABITS_8        0x03
+#define    STOPBITS_5678_1        0x00    // 1 stop bit for all byte sizes
+#define    STOPBITS_5_1p5        0x04    // 1.5 stop bits for 5-bit byte
+#define    STOPBITS_678_2        0x04    // 2 stop bits for 6/7/8-bit byte
+#define    USA_PARITY_NONE        0x00
+#define    USA_PARITY_ODD        0x08
+#define    USA_PARITY_EVEN        0x18
+#define    PARITY_1            0x28
+#define    PARITY_0            0x38
+
+// all things called "StatusMessage" are sent on the status endpoint
+
+typedef struct keyspan_usa67_portStatusMessage    // one for each port
+{
+    u8    port,            // 0=first, 1=second, other=see below
+        hskia_cts,        // reports HSKIA pin
+        gpia_dcd,        // reports GPIA pin
+        _txOff,            // port has been disabled (by host)
+        _txXoff,        // port is in XOFF state (either host or RX XOFF)
+        txAck,            // indicates a TX message acknowledgement
+        rxEnabled,        // as configured by rxOn/rxOff 1=on, 0=off
+        controlResponse;// 1=a control message has been processed
+} keyspan_usa67_portStatusMessage;
+
+// bits in RX data message when STAT byte is included
+#define    RXERROR_OVERRUN    0x02
+#define    RXERROR_PARITY    0x04
+#define    RXERROR_FRAMING    0x08
+#define    RXERROR_BREAK    0x10
+
+typedef struct keyspan_usa67_globalControlMessage
+{
+    u8    port,                 // 3
+        sendGlobalStatus,    // 2=request for two status responses
+        resetStatusToggle,    // 1=reset global status toggle
+        resetStatusCount;    // a cycling value
+} keyspan_usa67_globalControlMessage;
+
+typedef struct keyspan_usa67_globalStatusMessage
+{
+    u8    port,                // 3
+        sendGlobalStatus,    // from request, decremented
+        resetStatusCount;    // as in request
+} keyspan_usa67_globalStatusMessage;
+
+typedef struct keyspan_usa67_globalDebugMessage
+{
+    u8    port,                // 2
+        a,
+        b,
+        c,
+        d;
+} keyspan_usa67_globalDebugMessage;
+
+// ie: the maximum length of an FX1 endpoint buffer
+#define    MAX_DATA_LEN            64
+
+// update status approx. 60 times a second (16.6666 ms)
+#define    STATUS_UPDATE_INTERVAL    16
+
+// status rationing tuning value (each port gets checked each n ms)
+#define    STATUS_RATION    10
+
+#endif
+
+


             reply	other threads:[~2007-05-15 22:52 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-05-15 22:32 Lucy McCoy [this message]
2007-05-16  6:47 ` [PATCH 2.6.21] Usb Serial Keyspan: add support for USA-49WG & USA-28XG Greg KH
2007-05-16 20:29   ` Lucy McCoy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=464A34F2.5060002@keyspan.com \
    --to=lucy@keyspan.com \
    --cc=greg@kroah.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb-devel@lists.sourceforge.net \
    --cc=linux-usb-users@lists.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.