What version of adapter do you have? I have a Keyspan USA-19QW and it
works fine on FC1 with the 2249 kernel.
On Wed, 2004-01-21 at 23:39, Randy Zagar wrote:
I have been testing Fedora core/1 on a Dell Inspiron 5100 for
the past
few weeks, and most things have gone well. Recently, however, I tried
using a keyspan usb-to-serial adapter, because the Inspiron 5100 has no
serial ports, and found that the current 2.4.22-1.2249.nptl kernel
doesn't completely support this device.
The attached patch files include changes to the kernel-2.4.spec file and
a patch file from the vendor:
http://www.keyspan.com/support/linux/files/currentversion/patch/
With these changes the kernel recognizes the device, uploads the
firmware, and registers the new serial port as /dev/ttyUSB0.
Just my $0.02,
-Randy
p.s. Sorry if this hits the list multiple times, I keep getting errors
from sendmail and I'm not sure if it made it or not...
______________________________________________________________________
--- kernel-2.4.spec-save 2004-01-21 12:34:01.000000000 -0600
+++ kernel-2.4.spec 2004-01-21 12:39:36.000000000 -0600
@@ -25,7 +25,7 @@
# that the kernel isn't the stock RHL kernel, for example by
# adding some text to the end of the version number.
#
-%define release %(R="$Revision: 1.2149 $"; RR="${R##: }"; echo
${RR%%?}).nptl
+%define release %(R="$Revision: 1.2149 $"; RR="${R##: }"; echo
${RR%%?}).nptl.1
%define sublevel 22
%define kversion 2.4.%{sublevel}
# /usr/src/%{kslnk} -> /usr/src/linux-%{KVERREL}
@@ -288,6 +288,7 @@
Patch5191: linux-2.4.2-cipe.patch
Patch5192: linux-2.4.9-cipenat.patch
Patch5193: linux-2.4.18-cipe-moreinterfaces.patch
+Patch5201: linux-2.4.22-keyspan.patch
#
# Patches 6000 and later are reserved for %if {something} patches
@@ -852,6 +853,9 @@
%patch5192 -p1
%patch5193 -p1
+# Keyspan USB-serial adapter
+%patch5201 -p1
+
#
# Soundblaster Live! Audigy driver
#
______________________________________________________________________
diff -Naur linux-2.4.22/drivers/usb/serial/keyspan.c
linux-2.4.22-modified/drivers/usb/serial/keyspan.c
--- linux-2.4.22/drivers/usb/serial/keyspan.c Fri Jun 13 07:51:37 2003
+++ linux-2.4.22-modified/drivers/usb/serial/keyspan.c Tue Sep 30 16:09:48 2003
@@ -28,6 +28,9 @@
Change History
+ 2003sep04 LPM (Keyspan) add support for new single port product USA19HS.
+ Improve setup message handling for all devices.
+
2003Apr16 LPM (Keyspan) fix delayed control message resend for multi-port
'Open' case. Fix 'mpr' entries in keyspan.h (previously broken)
@@ -174,6 +177,7 @@
int baud;
int old_baud;
unsigned int cflag;
+ unsigned int old_cflag;
enum {flow_none, flow_cts, flow_xon} flow_control;
int rts_state; /* Handshaking pins (outputs) */
int dtr_state;
@@ -189,11 +193,12 @@
/* Include Keyspan message headers. All current Keyspan Adapters
- make use of one of three message formats which are referred
- to as USA-26, USA-28 and USA-49 by Keyspan and within this driver. */
+ 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. */
#include "keyspan_usa26msg.h"
#include "keyspan_usa28msg.h"
#include "keyspan_usa49msg.h"
+#include "keyspan_usa90msg.h"
/* Functions used by new usb-serial code. */
@@ -327,8 +332,8 @@
return -ENOIOCTLCMD;
}
- /* Write function is generic for the three protocols used
- with only a minor change for usa49 required */
+ /* Write function is similar for the four protocols used
+ with only a minor change for usa90 (usa19hs) required */
static int keyspan_write(struct usb_serial_port *port, int from_user,
const unsigned char *buf, int count)
{
@@ -337,18 +342,27 @@
int flip;
int left, todo;
struct urb *this_urb;
- int err;
+ int err, maxDataLen, dataOffset;
p_priv = (struct keyspan_port_private *)(port->private);
d_details = p_priv->device_details;
+ if (d_details->msg_format == msg_usa90) {
+ maxDataLen = 64;
+ dataOffset = 0;
+ }
+ else {
+ maxDataLen = 63;
+ dataOffset = 1;
+ }
+
dbg("%s - for port %d (%d chars [%x]), flip=%d",
__FUNCTION__, port->number, count, buf[0], p_priv->out_flip);
for (left = count; left > 0; left -= todo) {
todo = left;
- if (todo > 63)
- todo = 63;
+ if (todo > maxDataLen)
+ todo = maxDataLen;
flip = p_priv->out_flip;
@@ -371,20 +385,20 @@
break;
}
- /* First byte in buffer is "last flag" - unused so
+ /* First byte in buffer is "last flag" (except for usa19hx) - unused so
for now so set to zero */
((char *)this_urb->transfer_buffer)[0] = 0;
if (from_user) {
- if (copy_from_user(this_urb->transfer_buffer + 1, buf, todo))
+ if (copy_from_user(this_urb->transfer_buffer + dataOffset, buf, todo))
return -EFAULT;
} else {
- memcpy (this_urb->transfer_buffer + 1, buf, todo);
+ memcpy (this_urb->transfer_buffer + dataOffset, buf, todo);
}
buf += todo;
/* send the data out the bulk port */
- this_urb->transfer_buffer_length = todo + 1;
+ this_urb->transfer_buffer_length = todo + dataOffset;
this_urb->transfer_flags &= ~USB_ASYNC_UNLINK;
this_urb->dev = port->serial->dev;
@@ -424,9 +438,12 @@
if (urb->actual_length) {
/* 0x80 bit is error flag */
if ((data[0] & 0x80) == 0) {
- /* no error on any byte */
+ /* no errors on individual bytes, only possible overrun err*/
+ if (data[0] & RXERROR_OVERRUN)
+ err = TTY_OVERRUN;
+ else err = 0;
for (i = 1; i < urb->actual_length ; ++i) {
- tty_insert_flip_char(tty, data[i], 0);
+ tty_insert_flip_char(tty, data[i], err);
}
} else {
/* some bytes had errors, every byte has status */
@@ -455,7 +472,7 @@
return;
}
- /* Outdat handling is common for usa26, usa28 and usa49 messages */
+ /* Outdat handling is common for all devices */
static void usa2x_outdat_callback(struct urb *urb)
{
struct usb_serial_port *port;
@@ -561,7 +578,7 @@
}
-static void usa28_indat_callback(struct urb *urb)
+static void usa28_indat_callback(struct urb *urb)
{
int i, err;
struct usb_serial_port *port;
@@ -848,28 +865,171 @@
}
+static void usa90_indat_callback(struct urb *urb)
+{
+ int i, err;
+ int endpoint;
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+
+ dbg ("%s", __FUNCTION__);
+
+ endpoint = usb_pipeendpoint(urb->pipe);
+
+
+ if (urb->status) {
+ dbg("%s - nonzero status: %x on endpoint %d.",
+ __FUNCTION__, urb->status, endpoint);
+ return;
+ }
+
+ port = (struct usb_serial_port *) urb->context;
+ p_priv = (struct keyspan_port_private *)(port->private);
+
+ tty = port->tty;
+ if (urb->actual_length) {
+
+ /* if current mode is DMA, looks like usa28 format
+ otherwise looks like usa26 data format */
+
+ if (p_priv->baud > 57600) {
+ for (i = 0; i < urb->actual_length ; ++i)
+ tty_insert_flip_char(tty, data[i], 0);
+ }
+ else {
+
+ /* 0x80 bit is error flag */
+ if ((data[0] & 0x80) == 0) {
+ /* no errors on individual bytes, only possible overrun err*/
+ if (data[0] & RXERROR_OVERRUN)
+ err = TTY_OVERRUN;
+ else err = 0;
+ for (i = 1; i < urb->actual_length ; ++i)
+ tty_insert_flip_char(tty, data[i], err);
+
+ }
+ else {
+ /* some bytes had errors, every byte has status */
+ dbg("%s - RX error!!!!", __FUNCTION__);
+ for (i = 0; i + 1 < urb->actual_length; i += 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) */
+ tty_insert_flip_char(tty, data[i+1], flag);
+ }
+ }
+ }
+ tty_flip_buffer_push(tty);
+ }
+
+ /* Resubmit urb so we continue receiving */
+ urb->dev = port->serial->dev;
+ if (port->open_count)
+ if ((err = usb_submit_urb(urb)) != 0) {
+ dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+ }
+ return;
+}
+
+
+static void usa90_instat_callback(struct urb *urb)
+{
+ unsigned char *data = urb->transfer_buffer;
+ struct keyspan_usa90_portStatusMessage *msg;
+ struct usb_serial *serial;
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
+ int old_dcd_state, err;
+
+ serial = (struct usb_serial *) urb->context;
+
+ if (urb->status) {
+ dbg("%s - nonzero status: %x", __FUNCTION__, urb->status);
+ return;
+ }
+ if (urb->actual_length < 14) {
+ dbg("%s - %d byte report??", __FUNCTION__, urb->actual_length);
+ goto exit;
+ }
+
+ msg = (struct keyspan_usa90_portStatusMessage *)data;
+
+ /* Now do something useful with the data */
+
+ port = &serial->port[0];
+ p_priv = (struct keyspan_port_private *)(port->private);
+
+ /* Update handshaking pin state information */
+ old_dcd_state = p_priv->dcd_state;
+ p_priv->cts_state = ((msg->cts) ? 1 : 0);
+ p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
+ p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
+ p_priv->ri_state = ((msg->ri) ? 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)) != 0) {
+ dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+ }
+exit:
+ ;
+}
+
+static void usa90_outcont_callback(struct urb *urb)
+{
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
+
+ port = (struct usb_serial_port *) urb->context;
+ p_priv = (struct keyspan_port_private *)(port->private);
+
+ if (p_priv->resend_cont) {
+ dbg ("%s - sending setup", __FUNCTION__);
+ keyspan_usa90_send_setup(port->serial, port, p_priv->resend_cont - 1);
+ }
+}
+
static int keyspan_write_room (struct usb_serial_port *port)
{
struct keyspan_port_private *p_priv;
const struct keyspan_device_details *d_details;
- int flip;
+ int flip,dataLen;
struct urb *this_urb;
dbg("%s", __FUNCTION__);
p_priv = (struct keyspan_port_private *)(port->private);
d_details = p_priv->device_details;
+ if (d_details->msg_format == msg_usa90)
+ dataLen = 64;
+ else dataLen = 63;
+
flip = p_priv->out_flip;
/* Check both endpoints to see if any are available. */
if ((this_urb = p_priv->out_urbs[flip]) != 0) {
if (this_urb->status != -EINPROGRESS)
- return (63);
+ return (dataLen);
flip = (flip + 1) & d_details->outdat_endp_flip;
if ((this_urb = p_priv->out_urbs[flip]) != 0)
if (this_urb->status != -EINPROGRESS)
- return (63);
+ return (dataLen);
}
return (0);
}
@@ -888,20 +1048,25 @@
struct usb_serial *serial = port->serial;
const struct keyspan_device_details *d_details;
int i, err;
+ int baud_rate, device_port;
struct urb *urb;
+ unsigned int cflag;
s_priv = (struct keyspan_serial_private *)(serial->private);
p_priv = (struct keyspan_port_private *)(port->private);
- d_details = s_priv->device_details;
+ d_details = p_priv->device_details;
dbg("%s - port%d.", __FUNCTION__, port->number);
- p_priv = (struct keyspan_port_private *)(port->private);
-
/* Set some sane defaults */
p_priv->rts_state = 1;
p_priv->dtr_state = 1;
+ p_priv->baud = 9600;
+ /* force baud and lcr to be set on open */
+ p_priv->old_baud = 0;
+ p_priv->old_cflag = 0;
+
p_priv->out_flip = 0;
p_priv->in_flip = 0;
@@ -910,7 +1075,10 @@
if ((urb = p_priv->in_urbs[i]) == NULL)
continue;
urb->dev = serial->dev;
- usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe),
0);
+
+ /* make sure endpoint data toggle is synchronized with the device */
+
+ usb_clear_halt(urb->dev, urb->pipe);
if ((err = usb_submit_urb(urb)) != 0) {
dbg("%s - submit urb %d failed (%d)", __FUNCTION__, i, err);
@@ -925,12 +1093,29 @@
/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe), 0); */
}
- // if the device is a USA49x, determine whether it is an W or WLC model
- // and set the baud clock accordingly
+ /* get the terminal config for the setup message now so we don't
+ * need to send 2 of them */
+
+ cflag = port->tty->termios->c_cflag;
+ device_port = port->number - port->serial->minor;
+
+ /* Baud rate calculation takes baud rate as an integer
+ so other rates can be generated if desired. */
+ baud_rate = tty_get_baud_rate(port->tty);
+ /* If no match or invalid, leave as default */
+ if (baud_rate >= 0
+ && d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
+ NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
+ p_priv->baud = baud_rate;
+ }
+
+ /* set CTS/RTS handshake etc. */
+ p_priv->cflag = cflag;
+ p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none;
keyspan_send_setup(port, 1);
//mdelay(100);
- keyspan_set_termios(port, NULL);
+ //keyspan_set_termios(port, NULL);
return (0);
}
@@ -965,7 +1150,7 @@
keyspan_send_setup(port, 2);
/* pilot-xfer seems to work best with this delay */
mdelay(100);
- keyspan_set_termios(port, NULL);
+ // keyspan_set_termios(port, NULL);
}
/*while (p_priv->outcont_urb->status == -EINPROGRESS) {
@@ -1160,6 +1345,14 @@
.outdat_callback = usa2x_outdat_callback,
.inack_callback = usa49_inack_callback,
.outcont_callback = usa49_outcont_callback,
+ }, {
+ /* msg_usa90 callbacks */
+ .instat_callback = usa90_instat_callback,
+ .glocont_callback = usa28_glocont_callback,
+ .indat_callback = usa90_indat_callback,
+ .outdat_callback = usa2x_outdat_callback,
+ .inack_callback = usa28_inack_callback,
+ .outcont_callback = usa90_outcont_callback,
}
};
@@ -1283,6 +1476,41 @@
return (KEYSPAN_BAUD_RATE_OK);
}
+/* usa19hs function doesn't require prescaler */
+static int keyspan_usa19hs_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
+ u8 *rate_low, u8 *prescaler, int portnum)
+{
+ u32 b16, /* baud rate times 16 (actual rate used internally) */
+ div; /* divisor */
+
+ dbg ("%s - %d.", __FUNCTION__, baud_rate);
+
+ /* prevent divide by zero... */
+ if( (b16 = (baud_rate * 16L)) == 0)
+ return (KEYSPAN_INVALID_BAUD_RATE);
+
+
+
+ /* calculate the divisor */
+ if( (div = (baudclk / b16)) == 0)
+ return (KEYSPAN_INVALID_BAUD_RATE);
+
+ if(div > 0xffff)
+ return (KEYSPAN_INVALID_BAUD_RATE);
+
+ /* return the counter values if non-null */
+ if (rate_low)
+ *rate_low = (u8) (div & 0xff);
+
+ if (rate_hi)
+ *rate_hi = (u8) ((div >> 8) & 0xff);
+
+ if (rate_low && rate_hi)
+ dbg ("%s - %d %02x %02x.", __FUNCTION__, baud_rate, *rate_hi, *rate_low);
+
+ return (KEYSPAN_BAUD_RATE_OK);
+}
+
static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
u8 *rate_low, u8 *prescaler, int portnum)
{
@@ -1435,6 +1663,7 @@
p_priv->resend_cont = reset_port + 1;
if (this_urb->status == -EINPROGRESS) {
/* dbg ("%s - already writing", __FUNCTION__); */
+ mdelay(5);
return(-1);
}
@@ -1585,6 +1814,7 @@
p_priv->resend_cont = reset_port + 1;
if (this_urb->status == -EINPROGRESS) {
dbg ("%s already writing", __FUNCTION__);
+ mdelay(5);
return(-1);
}
@@ -1717,6 +1947,7 @@
p_priv->resend_cont = reset_port + 1;
if (this_urb->status == -EINPROGRESS) {
/* dbg ("%s - already writing", __FUNCTION__); */
+ mdelay(5);
return(-1);
}
@@ -1845,6 +2076,144 @@
return (0);
}
+static int keyspan_usa90_send_setup(struct usb_serial *serial,
+ struct usb_serial_port *port,
+ int reset_port)
+{
+ struct keyspan_usa90_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;
+ u8 prescaler;
+
+ dbg ("%s", __FUNCTION__);
+
+ s_priv = (struct keyspan_serial_private *)(serial->private);
+ p_priv = (struct keyspan_port_private *)(port->private);
+ d_details = s_priv->device_details;
+
+ /* only do something if we have a bulk out endpoint */
+ if ((this_urb = p_priv->outcont_urb) == NULL) {
+ dbg("%s - oops no urb.", __FUNCTION__);
+ 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_usa90_portControlMessage));
+
+ /* 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 = 0x01;
+ if (d_details->calculate_baud_rate
+ (p_priv->baud, d_details->baudclk, &msg.baudHi,
+ &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE ) {
+ dbg("%s - Invalid baud rate %d requested, using 9600.", __FUNCTION__,
+ p_priv->baud);
+ p_priv->baud = 9600;
+ d_details->calculate_baud_rate (p_priv->baud, d_details->baudclk,
+ &msg.baudHi, &msg.baudLo, &prescaler, 0);
+ }
+ msg.setRxMode = 1;
+ msg.setTxMode = 1;
+ }
+
+ /* modes must always be correctly specified */
+ if (p_priv->baud > 57600)
+ {
+ msg.rxMode = RXMODE_DMA;
+ msg.txMode = TXMODE_DMA;
+ }
+ else
+ {
+ msg.rxMode = RXMODE_BYHAND;
+ msg.txMode = TXMODE_BYHAND;
+ }
+
+ 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;
+ }
+ if (p_priv->old_cflag != p_priv->cflag) {
+ p_priv->old_cflag = p_priv->cflag;
+ msg.setLcr = 0x01;
+ }
+
+ if (p_priv->flow_control == flow_cts)
+ msg.txFlowControl = TXFLOW_CTS;
+ msg.setTxFlowControl = 0x01;
+ msg.setRxFlowControl = 0x01;
+
+ msg.rxForwardingLength = 16;
+ msg.rxForwardingTimeout = 16;
+ msg.txAckSetting = 0;
+ msg.xonChar = 17;
+ msg.xoffChar = 19;
+
+ /* Opening port */
+ if (reset_port == 1) {
+ msg.portEnabled = 1;
+ msg.rxFlush = 1;
+ msg.txBreak = (p_priv->break_on);
+ }
+ /* Closing port */
+ else if (reset_port == 2) {
+ msg.portEnabled = 0;
+ }
+ /* Sending intermediate configs */
+ else {
+ if (port->open_count)
+ msg.portEnabled = 1;
+ msg.txBreak = (p_priv->break_on);
+ }
+
+ /* Do handshaking outputs */
+ msg.setRts = 0x01;
+ msg.rts = p_priv->rts_state;
+
+ msg.setDtr = 0x01;
+ msg.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)) != 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;
@@ -1866,9 +2235,13 @@
case msg_usa49:
keyspan_usa49_send_setup(serial, port, reset_port);
break;
+ case msg_usa90:
+ keyspan_usa90_send_setup(serial, port, reset_port);
+ break;
}
}
+
/* Gets called by the "real" driver (ie once firmware is loaded
and renumeration has taken place. */
static int keyspan_startup (struct usb_serial *serial)
diff -Naur linux-2.4.22/drivers/usb/serial/keyspan.h
linux-2.4.22-modified/drivers/usb/serial/keyspan.h
--- linux-2.4.22/drivers/usb/serial/keyspan.h Fri Jun 13 07:51:37 2003
+++ linux-2.4.22-modified/drivers/usb/serial/keyspan.h Tue Sep 30 16:09:55 2003
@@ -77,6 +77,10 @@
u8 *rate_hi, u8 *rate_low,
u8 *prescaler, int portnum);
+static int keyspan_usa19hs_calc_baud (u32 baud_rate, u32 baudclk,
+ u8 *rate_hi, u8 *rate_low,
+ u8 *prescaler, int portnum);
+
static int keyspan_usa28_send_setup (struct usb_serial *serial,
struct usb_serial_port *port,
int reset_port);
@@ -87,6 +91,9 @@
struct usb_serial_port *port,
int reset_port);
+static int keyspan_usa90_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 */
@@ -178,6 +185,7 @@
#define KEYSPAN_USA18X_BAUDCLK (12000000L) /* a guess */
#define KEYSPAN_USA19_BAUDCLK (12000000L)
#define KEYSPAN_USA19W_BAUDCLK (24000000L)
+#define KEYSPAN_USA19HS_BAUDCLK (14769231L)
#define KEYSPAN_USA28_BAUDCLK (1843200L)
#define KEYSPAN_USA28X_BAUDCLK (12000000L)
#define KEYSPAN_USA49W_BAUDCLK (48000000L)
@@ -210,6 +218,7 @@
#define keyspan_usa18x_product_id 0x0112
#define keyspan_usa19_product_id 0x0107
#define keyspan_usa19qi_product_id 0x010c
+#define keyspan_usa19hs_product_id 0x0121
#define keyspan_mpr_product_id 0x011c
#define keyspan_usa19qw_product_id 0x0119
#define keyspan_usa19w_product_id 0x0108
@@ -225,7 +234,7 @@
/* product ID value */
int product_id;
- enum {msg_usa26, msg_usa28, msg_usa49} msg_format;
+ enum {msg_usa26, msg_usa28, msg_usa49, msg_usa90} msg_format;
/* Number of physical ports */
int num_ports;
@@ -361,6 +370,22 @@
baudclk: KEYSPAN_USA19W_BAUDCLK,
};
+static const struct keyspan_device_details usa19hs_device_details = {
+ product_id: keyspan_usa19hs_product_id,
+ msg_format: msg_usa90,
+ num_ports: 1,
+ indat_endp_flip: 0,
+ outdat_endp_flip: 0,
+ indat_endpoints: {0x81},
+ outdat_endpoints: {0x01},
+ inack_endpoints: {-1},
+ outcont_endpoints: {0x02},
+ instat_endpoint: 0x82,
+ glocont_endpoint: -1,
+ calculate_baud_rate: keyspan_usa19hs_calc_baud,
+ baudclk: KEYSPAN_USA19HS_BAUDCLK,
+};
+
static const struct keyspan_device_details usa28_device_details = {
product_id: keyspan_usa28_product_id,
msg_format: msg_usa28,
@@ -450,6 +475,7 @@
&mpr_device_details,
&usa19qw_device_details,
&usa19w_device_details,
+ &usa19hs_device_details,
&usa28_device_details,
&usa28x_device_details,
&usa28xa_device_details,
@@ -477,6 +503,7 @@
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) },
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
@@ -512,6 +539,7 @@
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) },
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) },
{ } /* Terminating entry */
};
@@ -547,8 +575,8 @@
name: "Keyspan 1 port adapter",
id_table: keyspan_1port_ids,
num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: 3,
- num_bulk_out: 4,
+ num_bulk_in: NUM_DONT_CARE,
+ num_bulk_out: NUM_DONT_CARE,
num_ports: 1,
open: keyspan_open,
close: keyspan_close,
diff -Naur linux-2.4.22/drivers/usb/serial/keyspan_usa90msg.h
linux-2.4.22-modified/drivers/usb/serial/keyspan_usa90msg.h
--- linux-2.4.22/drivers/usb/serial/keyspan_usa90msg.h Wed Dec 31 16:00:00 1969
+++ linux-2.4.22-modified/drivers/usb/serial/keyspan_usa90msg.h Thu Oct 2 14:11:55 2003
@@ -0,0 +1,198 @@
+/*
+ usa90msg.h
+
+ Copyright (c) 1998-2003 InnoSys Incorporated. All Rights Reserved
+ This file is available under a BSD-style copyright
+
+ Keyspan USB Async Message Formats for the USA19HS
+
+ 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-2003 InnoSys Incorporated. All Rights Reserved
+
+ This file is available under a BSD-style copyright
+
+ 2. 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.
+
+ Revisions:
+
+ 2003feb14 add setTxMode/txMode and cancelRxXoff to portControl
+ 2003mar21 change name of PARITY_0/1 to add MARK/SPACE
+*/
+
+#ifndef __USA90MSG__
+#define __USA90MSG__
+
+struct keyspan_usa90_portControlMessage
+{
+ /*
+ 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, // host does baud divisor calculation
+
+ setLcr, // host requests lcr be set
+ lcr, // use PARITY, STOPBITS, DATABITS below
+
+ setRxMode, // set receive mode
+ rxMode, // RXMODE_DMA or RXMODE_BYHAND
+
+ setTxMode, // set transmit mode
+ txMode, // TXMODE_DMA or TXMODE_BYHAND
+
+ setTxFlowControl, // host requests tx flow control be set
+ txFlowControl , // use TX_FLOW... bits below
+ setRxFlowControl, // host requests rx flow control be set
+ rxFlowControl, // use RX_FLOW... bits below
+ sendXoff, // host requests XOFF transmitted immediately
+ sendXon, // host requests XON char transmitted
+ xonChar, // specified in current character format
+ xoffChar, // specified in current character format
+
+ sendChar, // host requests char transmitted immediately
+ txChar, // character to send
+
+ setRts, // host requests RTS output be set
+ rts, // 1=on, 0=off
+ setDtr, // host requests DTR output be set
+ dtr; // 1=on, 0=off
+
+
+ /*
+ 2. configuration data which is simply used as is
+ and must be specified correctly in every host message.
+ */
+
+ u8 rxForwardingLength, // forward when this number of chars available
+ rxForwardingTimeout, // (1-31 in ms)
+ txAckSetting; // 0=don't ack, 1=normal, 2-255 TBD...
+ /*
+ 3. Firmware states which cause actions if they change
+ and must be specified correctly in every host message.
+ */
+
+ u8 portEnabled, // 0=disabled, 1=enabled
+ txFlush, // 0=normal, 1=toss outbound data
+ txBreak, // 0=break off, 1=break on
+ loopbackMode; // 0=no loopback, 1=loopback enabled
+
+ /*
+ 4. commands which are flags only; these are processed in order
+ (so that, e.g., if rxFlush and rxForward flags are set, the
+ port will have no data to forward); any non-zero value
+ is respected
+ */
+
+ u8 rxFlush, // toss inbound data
+ rxForward, // forward all inbound data, NOW (as if fwdLen==1)
+ cancelRxXoff, // cancel any receive XOFF state (_txXoff)
+ returnStatus; // return current status NOW
+};
+
+// 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-8 bit byte
+#define USA_PARITY_NONE 0x00
+#define USA_PARITY_ODD 0x08
+#define USA_PARITY_EVEN 0x18
+#define PARITY_MARK_1 0x28 // force parity MARK
+#define PARITY_SPACE_0 0x38 // force parity SPACE
+
+#define TXFLOW_CTS 0x04
+#define TXFLOW_DSR 0x08
+#define TXFLOW_XOFF 0x01
+#define TXFLOW_XOFF_ANY 0x02
+#define TXFLOW_XOFF_BITS (TXFLOW_XOFF | TXFLOW_XOFF_ANY)
+
+#define RXFLOW_XOFF 0x10
+#define RXFLOW_RTS 0x20
+#define RXFLOW_DTR 0x40
+#define RXFLOW_DSR_SENSITIVITY 0x80
+
+#define RXMODE_BYHAND 0x00
+#define RXMODE_DMA 0x02
+
+#define TXMODE_BYHAND 0x00
+#define TXMODE_DMA 0x02
+
+
+// all things called "StatusMessage" are sent on the status endpoint
+
+struct keyspan_usa90_portStatusMessage
+{
+ u8 msr, // reports the actual MSR register
+ cts, // reports CTS pin
+ dcd, // reports DCD pin
+ dsr, // reports DSR pin
+ ri, // reports RI pin
+ _txXoff, // port is in XOFF state (we received XOFF)
+ rxBreak, // reports break state
+ rxOverrun, // count of overrun errors (since last reported)
+ rxParity, // count of parity errors (since last reported)
+ rxFrame, // count of frame errors (since last reported)
+ portState, // PORTSTATE_xxx bits (useful for debugging)
+ messageAck, // message acknowledgement
+ charAck, // character acknowledgement
+ controlResponse; // (value = returnStatus) a control message has been processed
+};
+
+// 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
+
+#define PORTSTATE_ENABLED 0x80
+#define PORTSTATE_TXFLUSH 0x01
+#define PORTSTATE_TXBREAK 0x02
+#define PORTSTATE_LOOPBACK 0x04
+
+// MSR bits
+
+#define MSR_dCTS 0x01 // CTS has changed since last report
+#define MSR_dDSR 0x02
+#define MSR_dRI 0x04
+#define MSR_dDCD 0x08
+
+#define MSR_CTS 0x10 // current state of CTS
+#define MSR_DSR 0x20
+#define MSR_RI 0x40
+#define MSR_DCD 0x80
+
+// ie: the maximum length of an endpoint buffer
+#define MAX_DATA_LEN 64
+
+#endif