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