Patch for Keyspan USB-serial adapter...
Kent Pirkle
kpirkle at kphome.net
Thu Jan 22 22:03:02 UTC 2004
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
More information about the fedora-devel-list
mailing list