Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0ca1268e authored by Lucy McCoy's avatar Lucy McCoy Committed by Greg Kroah-Hartman
Browse files

USB Serial Keyspan: add support for USA-49WG & USA-28XG



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

Signed-off-by: default avatarLucy P. McCoy <lucy@keyspan.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 87e71b47
Loading
Loading
Loading
Loading
+389 −25
Original line number Diff line number Diff line
@@ -115,12 +115,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 +130,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 +186,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 +858,82 @@ static void usa49_indat_callback(struct urb *urb)
		}
}

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 = 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 = 0;
	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;

	err = usb_submit_urb(urb, GFP_ATOMIC);
	if (err != 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)
{
@@ -869,7 +953,6 @@ static void usa90_indat_callback(struct urb *urb)

	endpoint = usb_pipeendpoint(urb->pipe);


	if (urb->status) {
		dbg("%s - nonzero status: %x on endpoint %d.",
		    __FUNCTION__, urb->status, endpoint);
@@ -995,6 +1078,87 @@ static void usa90_outcont_callback(struct urb *urb)
	}
}

/* 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 = 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;
	err = usb_submit_urb(urb, GFP_ATOMIC);
	if (err != 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 = 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 +1475,11 @@ static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
		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 +1549,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 +1587,11 @@ static void keyspan_setup_urbs(struct usb_serial *serial)
		 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 +1867,8 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
	}

	/* 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 +2018,8 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
	}

	/* 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__);
@@ -1941,10 +2123,10 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
				    int reset_port)
{
	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;

@@ -1954,7 +2136,6 @@ static int keyspan_usa49_send_setup(struct usb_serial *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 */
@@ -1969,9 +2150,10 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
	}

	/* 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,12 +2265,31 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
	msg.dtr = p_priv->dtr_state;
		
	p_priv->resend_cont = 0;

	/* 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);

		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);
	}
@@ -2241,6 +2442,154 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial,
	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;

	if (reset_port == 1) {
		/* Opening port */
		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;
	} else if (reset_port == 2) {
		/* Closing port */
		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;
	} else {
		/* Sending intermediate configs */
		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;

	err = usb_submit_urb(this_urb, GFP_ATOMIC);
	if (err != 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 +2614,9 @@ static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
	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 +2665,19 @@ static int keyspan_startup (struct usb_serial *serial)

	keyspan_setup_urbs(serial);

	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);
		err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
		if (err != 0)
			dbg("%s - submit instat urb failed %d", __FUNCTION__,
				err);
	}
	if (s_priv->indat_urb != NULL) {
		s_priv->indat_urb->dev = serial->dev;
		err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
		if (err != 0)
			dbg("%s - submit indat urb failed %d", __FUNCTION__,
				err);
	}
			
	return (0);
@@ -2335,6 +2697,7 @@ static void keyspan_shutdown (struct usb_serial *serial)
	/* 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 +2711,7 @@ static void keyspan_shutdown (struct usb_serial *serial)

	/* 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];
+66 −8
Original line number Diff line number Diff line
@@ -99,6 +99,10 @@ static int keyspan_usa90_send_setup (struct usb_serial *serial,
					 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_details usa18x_device_details = {
	.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_details usa19_device_details = {
	.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_details usa19qi_device_details = {
	.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_details mpr_device_details = {
	.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_details usa19qw_device_details = {
	.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_details usa19w_device_details = {
	.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_details usa19hs_device_details = {
	.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_details usa28_device_details = {
	.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_details usa28x_device_details = {
	.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_details usa28xa_device_details = {
	.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_details usa49w_device_details = {
	.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_details usa49wlc_device_details = {
	.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_details *keyspan_devices[] = {
	&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_combined[] = {
	{ 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_2port_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) },
	{ } /* 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_pre_device = {
		.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_1port_device = {
		.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_2port_device = {
		.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_4port_device = {
		.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,
+254 −0

File added.

Preview size limit exceeded, changes collapsed.