ChangeSet 1.1439, 2003/10/03 16:22:11-07:00, greg@kroah.com [PATCH] USB: port keyspan patch from 2.4 to 2.6 Original patch from lucy@innosys.com Changes include: Add support for new USA19H(s) USB Serial Adapter Improve handing of config/control messages for all devices Note that the new adapter doesn't currently require a firmware download. We will add support for re-programming the eeprom with updated firmware when new firmware is required. drivers/usb/serial/keyspan.c | 420 ++++++++++++++++++++++++++++++++-- drivers/usb/serial/keyspan.h | 33 ++ drivers/usb/serial/keyspan_usa90msg.h | 198 ++++++++++++++++ 3 files changed, 625 insertions(+), 26 deletions(-) diff -Nru a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c --- a/drivers/usb/serial/keyspan.c Fri Oct 3 16:43:54 2003 +++ b/drivers/usb/serial/keyspan.c Fri Oct 3 16:43:55 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. + Wed Feb 19 22:00:00 PST 2003 (Jeffrey S. Laing ) Merged the current (1/31/03) Keyspan code with the current (2.4.21-pre4) Linux source tree. The Linux tree lacked support for the 49WLC and @@ -172,6 +175,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; @@ -187,11 +191,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. */ @@ -346,8 +351,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) { @@ -356,18 +361,26 @@ int flip; int left, todo; struct urb *this_urb; - int err; + int err, maxDataLen, dataOffset; p_priv = usb_get_serial_port_data(port); 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), flip=%d", __FUNCTION__, port->number, count, 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; @@ -390,20 +403,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 &= ~URB_ASYNC_UNLINK; this_urb->dev = port->serial->dev; @@ -443,9 +456,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 */ @@ -474,7 +490,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 pt_regs *regs) { struct usb_serial_port *port; @@ -577,7 +593,7 @@ } -static void usa28_indat_callback(struct urb *urb, struct pt_regs *regs) +static void usa28_indat_callback(struct urb *urb, struct pt_regs *regs) { int i, err; struct usb_serial_port *port; @@ -861,29 +877,172 @@ dbg ("%s", __FUNCTION__); } +static void usa90_indat_callback(struct urb *urb, struct pt_regs *regs) +{ + 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 = usb_get_serial_port_data(port); + + 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, GFP_ATOMIC)) != 0) { + dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err); + } + return; +} + + +static void usa90_instat_callback(struct urb *urb, struct pt_regs *regs) +{ + 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 = usb_get_serial_port_data(port); + + /* 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, GFP_ATOMIC)) != 0) { + dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err); + } +exit: + ; +} + +static void usa90_outcont_callback(struct urb *urb, struct pt_regs *regs) +{ + struct usb_serial_port *port; + struct keyspan_port_private *p_priv; + + port = (struct usb_serial_port *) urb->context; + p_priv = usb_get_serial_port_data(port); + + 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 data_len; struct urb *this_urb; dbg("%s", __FUNCTION__); p_priv = usb_get_serial_port_data(port); d_details = p_priv->device_details; + if (d_details->msg_format == msg_usa90) + data_len = 64; + else + data_len = 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 (data_len); 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 (data_len); } return (0); } @@ -902,17 +1061,24 @@ 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 = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); - d_details = s_priv->device_details; + d_details = p_priv->device_details; dbg("%s - port%d.", __FUNCTION__, port->number); /* 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; @@ -922,7 +1088,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, GFP_KERNEL)) != 0) { dbg("%s - submit urb %d failed (%d)", __FUNCTION__, i, err); @@ -937,12 +1106,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); } @@ -977,7 +1163,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) { @@ -1172,6 +1358,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, } }; @@ -1295,6 +1489,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) { @@ -1447,6 +1676,7 @@ p_priv->resend_cont = reset_port + 1; if (this_urb->status == -EINPROGRESS) { /* dbg ("%s - already writing", __FUNCTION__); */ + mdelay(5); return(-1); } @@ -1597,6 +1827,7 @@ p_priv->resend_cont = reset_port + 1; if (this_urb->status == -EINPROGRESS) { dbg ("%s already writing", __FUNCTION__); + mdelay(5); return(-1); } @@ -1729,6 +1960,7 @@ p_priv->resend_cont = reset_port + 1; if (this_urb->status == -EINPROGRESS) { /* dbg ("%s - already writing", __FUNCTION__); */ + mdelay(5); return(-1); } @@ -1857,6 +2089,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 = usb_get_serial_data(serial); + p_priv = usb_get_serial_port_data(port); + 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, 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; @@ -1878,8 +2248,12 @@ 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. */ diff -Nru a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h --- a/drivers/usb/serial/keyspan.h Fri Oct 3 16:43:55 2003 +++ b/drivers/usb/serial/keyspan.h Fri Oct 3 16:43:55 2003 @@ -82,6 +82,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); @@ -92,6 +96,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 */ @@ -183,6 +190,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) @@ -215,6 +223,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 @@ -230,7 +239,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; @@ -349,6 +358,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, @@ -437,6 +462,7 @@ &usa19qi_device_details, &usa19qw_device_details, &usa19w_device_details, + &usa19hs_device_details, &usa28_device_details, &usa28x_device_details, &usa28xa_device_details, @@ -464,6 +490,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) }, @@ -544,8 +571,8 @@ .short_name = "keyspan_1", .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 -Nru a/drivers/usb/serial/keyspan_usa90msg.h b/drivers/usb/serial/keyspan_usa90msg.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/serial/keyspan_usa90msg.h Fri Oct 3 16:43: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