summaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/Makefile2
-rw-r--r--drivers/usb/serial/digi_acceleport.c975
-rw-r--r--drivers/usb/serial/ezusb_convert.pl4
-rw-r--r--drivers/usb/serial/ftdi_sio.c2
-rw-r--r--drivers/usb/serial/keyspan_pda.c2
-rw-r--r--drivers/usb/serial/omninet.c2
-rw-r--r--drivers/usb/serial/usb-serial.h5
-rw-r--r--drivers/usb/serial/usbserial.c309
-rw-r--r--drivers/usb/serial/visor.c6
-rw-r--r--drivers/usb/serial/visor.h2
-rw-r--r--drivers/usb/serial/whiteheat.c169
-rw-r--r--drivers/usb/serial/whiteheat.h169
12 files changed, 1440 insertions, 207 deletions
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index bd4d51a6a..fa69fa52a 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -4,7 +4,7 @@
O_TARGET := usb-serial.o
M_OBJS := usb-serial.o
-O_OBJS := usbserial.o visor.o whiteheat.o ftdi_sio.o keyspan_pda.o omninet.o
+O_OBJS := usbserial.o visor.o whiteheat.o ftdi_sio.o keyspan_pda.o omninet.o digi_acceleport.o
MOD_LIST_NAME := USB_SERIAL_MODULES
include $(TOPDIR)/Rules.make
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
new file mode 100644
index 000000000..6700f9e01
--- /dev/null
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -0,0 +1,975 @@
+/*
+* Digi AccelePort USB-4 Serial Converter
+*
+* Copyright 2000 by Digi International
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* Shamelessly based on Brian Warner's keyspan_pda.c and Greg Kroah-Hartman's
+* usb-serial driver.
+*
+* Peter Berger (pberger@brimson.com)
+* Al Borchers (borchers@steinerpoint.com)
+*
+* (5/3/2000) pberger and borchers
+* First alpha version of the driver--many known limitations and bugs.
+*
+* $Id: digi_acceleport.c,v 1.28 2000/05/04 01:47:08 root Exp root $
+*/
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_DIGI_ACCELEPORT
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+#include <linux/usb.h>
+#include "usb-serial.h"
+
+
+/* Defines */
+
+/* port buffer length -- must be <= transfer buffer length - 2 */
+/* so we can be sure to send the full buffer in one urb */
+#define DIGI_PORT_BUF_LEN 16
+
+/* AccelePort USB Defines */
+
+/* ids */
+#define DIGI_VENDOR_ID 0x05c5
+#define DIGI_ID 0x0004
+
+/* commands */
+#define DIGI_CMD_SET_BAUD_RATE 0
+#define DIGI_CMD_SET_WORD_SIZE 1
+#define DIGI_CMD_SET_PARITY 2
+#define DIGI_CMD_SET_STOP_BITS 3
+#define DIGI_CMD_SET_INPUT_FLOW_CONTROL 4
+#define DIGI_CMD_SET_OUTPUT_FLOW_CONTROL 5
+#define DIGI_CMD_SET_DTR_SIGNAL 6
+#define DIGI_CMD_SET_RTS_SIGNAL 7
+#define DIGI_CMD_RECEIVE_ENABLE 10
+#define DIGI_CMD_BREAK_CONTROL 11
+#define DIGI_CMD_LOCAL_LOOPBACK 12
+#define DIGI_CMD_TRANSMIT_IDLE 13
+#define DIGI_CMD_WRITE_UART_REGISTER 15
+#define DIGI_CMD_AND_UART_REGISTER 16
+#define DIGI_CMD_OR_UART_REGISTER 17
+#define DIGI_CMD_SEND_DATA 18
+
+/* baud rates */
+#define DIGI_BAUD_50 0
+#define DIGI_BAUD_75 1
+#define DIGI_BAUD_110 2
+#define DIGI_BAUD_150 3
+#define DIGI_BAUD_200 4
+#define DIGI_BAUD_300 5
+#define DIGI_BAUD_600 6
+#define DIGI_BAUD_1200 7
+#define DIGI_BAUD_1800 8
+#define DIGI_BAUD_2400 9
+#define DIGI_BAUD_4800 10
+#define DIGI_BAUD_7200 11
+#define DIGI_BAUD_9600 12
+#define DIGI_BAUD_14400 13
+#define DIGI_BAUD_19200 14
+#define DIGI_BAUD_28800 15
+#define DIGI_BAUD_38400 16
+#define DIGI_BAUD_57600 17
+#define DIGI_BAUD_76800 18
+#define DIGI_BAUD_115200 19
+#define DIGI_BAUD_153600 20
+#define DIGI_BAUD_230400 21
+#define DIGI_BAUD_460800 22
+
+/* flow control arguments */
+#define DIGI_ENABLE_IXON_IXOFF_FLOW_CONTROL 1
+#define DIGI_ENABLE_RTS_CTS_FLOW_CONTROL 2
+#define DIGI_ENABLE_DTR_DSR_FLOW_CONTROL 4
+
+/* macros */
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+
+/* Structures */
+
+typedef struct digi_private {
+ spinlock_t dp_port_lock;
+ int dp_buf_len;
+ char dp_buf[32];
+} digi_private_t;
+
+struct s_digiusb {
+ u8 opcode;
+ u8 length;
+ u8 val;
+ u8 pad;
+};
+
+
+/* Local Function Declarations */
+
+static void digi_send_cmd( char *mes, struct usb_serial_port *port, int opcode,
+ int length, int val );
+static void digi_send_oob( char *mes, int opcode, int linenum, int data1, int data2 );
+static void digi_rx_throttle (struct usb_serial_port *port);
+static void digi_rx_unthrottle (struct usb_serial_port *port);
+static int digi_setbaud( struct usb_serial_port *port, int baud );
+static void digi_set_termios( struct usb_serial_port *port,
+ struct termios *old_termios );
+static void digi_break_ctl( struct usb_serial_port *port, int break_state );
+static int digi_get_modem_info( struct usb_serial *serial,
+ unsigned char *value );
+static int digi_set_modem_info( struct usb_serial *serial,
+ unsigned char value );
+static int digi_ioctl( struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg );
+static int digi_write( struct usb_serial_port *port, int from_user,
+ const unsigned char *buf, int count );
+static void digi_write_bulk_callback( struct urb *urb );
+static int digi_write_room( struct usb_serial_port *port );
+static int digi_chars_in_buffer( struct usb_serial_port *port );
+static int digi_open( struct usb_serial_port *port, struct file *filp );
+static void digi_close( struct usb_serial_port *port, struct file *filp );
+static int digi_startup (struct usb_serial *serial);
+static void digi_shutdown( struct usb_serial *serial );
+static void digi_read_bulk_callback( struct urb *urb );
+
+
+/* Statics */
+
+/* device info needed for the Digi serial converter */
+static __u16 digi_vendor_id = DIGI_VENDOR_ID;
+static __u16 digi_product_id = DIGI_ID;
+
+/* out of band port */
+static int oob_port_num; /* index of out-of-band port */
+static struct usb_serial_port *oob_port; /* out-of-band control port */
+static int oob_read_started = 0;
+
+/* config lock -- used to protect digi statics and globals, like oob vars */
+spinlock_t config_lock;
+
+
+/* Globals */
+
+struct usb_serial_device_type digi_acceleport_device = {
+ name: "Digi USB",
+ idVendor: &digi_vendor_id,
+ idProduct: &digi_product_id,
+ needs_interrupt_in: DONT_CARE,
+ needs_bulk_in: MUST_HAVE,
+ needs_bulk_out: MUST_HAVE,
+ num_interrupt_in: 0,
+ num_bulk_in: 5,
+ num_bulk_out: 5,
+ num_ports: 4,
+ open: digi_open,
+ close: digi_close,
+ write: digi_write,
+ write_room: digi_write_room,
+ write_bulk_callback: digi_write_bulk_callback,
+ read_bulk_callback: digi_read_bulk_callback,
+ chars_in_buffer: digi_chars_in_buffer,
+ throttle: digi_rx_throttle,
+ unthrottle: digi_rx_unthrottle,
+ ioctl: digi_ioctl,
+ set_termios: digi_set_termios,
+ break_ctl: digi_break_ctl,
+ startup: digi_startup,
+ shutdown: digi_shutdown,
+};
+
+
+/* Functions */
+
+/* Send message on the out-of-Band endpoint */
+static void digi_send_oob( char *mes, int opcode, int linenum, int data1, int data2 )
+{
+ int ret;
+ struct s_digiusb digiusb;
+ digi_private_t *priv = (digi_private_t *)(oob_port->private);
+
+
+dbg( "digi_send_oob: TOP: from '%s', opcode: %d, linenum:%d, data1: %d, data2: %d", mes, opcode, linenum, data1, data2 );
+
+ digiusb.opcode = (u8)opcode;
+ digiusb.length = (u8)linenum;
+ digiusb.val = (u8)data1;
+ digiusb.pad = (u8)data2;
+
+ spin_lock( &priv->dp_port_lock );
+
+ while (oob_port->write_urb->status == -EINPROGRESS) {
+dbg( "digi_send_oob: opcode:%d already writing...", opcode );
+ spin_unlock( &priv->dp_port_lock );
+ interruptible_sleep_on(&oob_port->write_wait);
+ if (signal_pending(current)) {
+ return;
+ }
+ spin_lock( &priv->dp_port_lock );
+ }
+
+ memcpy( oob_port->write_urb->transfer_buffer, &digiusb, sizeof(digiusb) );
+ oob_port->write_urb->transfer_buffer_length = sizeof(digiusb);
+ if( (ret=usb_submit_urb(oob_port->write_urb)) != 0 ) {
+ dbg(
+ "digi_send_oob: usb_submit_urb(write bulk) failed, opcode=%d, ret=%d",
+ opcode, ret );
+ }
+
+ spin_unlock( &priv->dp_port_lock );
+
+dbg( "digi_send_oob: opcode %d done", opcode );
+
+}
+
+
+static void digi_send_cmd( char *mes, struct usb_serial_port *port, int opcode,
+ int length, int val )
+{
+
+ int ret;
+ struct s_digiusb digiusb;
+ digi_private_t *priv = (digi_private_t *)(port->private);
+
+
+dbg( "digi_send_cmd: TOP: from '%s', opcode: %d, val: %d", mes, opcode, val );
+
+ digiusb.opcode = (u8)opcode;
+ digiusb.length = (u8)length;
+ digiusb.val = (u8)val;
+ digiusb.pad = 0;
+
+ spin_lock( &priv->dp_port_lock );
+
+ while( port->write_urb->status == -EINPROGRESS ) {
+dbg( "digi_send_cmd: opcode=%d already writing...", opcode );
+ spin_unlock( &priv->dp_port_lock );
+ interruptible_sleep_on( &port->write_wait );
+ if( signal_pending(current) ) {
+ return;
+ }
+ spin_lock( &priv->dp_port_lock );
+ }
+
+ memcpy( port->write_urb->transfer_buffer, &digiusb, sizeof(digiusb) );
+ port->write_urb->transfer_buffer_length = sizeof(digiusb);
+ if( (ret=usb_submit_urb(port->write_urb)) != 0 )
+ dbg(
+ "digi_send_cmd: usb_submit_urb(write bulk) failed, opcode=%d, ret=%d",
+ opcode, ret );
+
+dbg( "digi_send_cmd: opcode %d done", opcode );
+
+ spin_unlock( &priv->dp_port_lock );
+
+}
+
+
+static void digi_rx_throttle( struct usb_serial_port *port )
+{
+
+dbg( "digi_rx_throttle: TOP: port=%d", port->number );
+
+ /* stop receiving characters. We just turn off the URB request, and
+ let chars pile up in the device. If we're doing hardware
+ flowcontrol, the device will signal the other end when its buffer
+ fills up. If we're doing XON/XOFF, this would be a good time to
+ send an XOFF, although it might make sense to foist that off
+ upon the device too. */
+
+ // usb_unlink_urb(port->interrupt_in_urb);
+
+}
+
+
+static void digi_rx_unthrottle( struct usb_serial_port *port )
+{
+
+dbg( "digi_rx_unthrottle: TOP: port=%d", port->number );
+
+ /* just restart the receive interrupt URB */
+ //if (usb_submit_urb(port->interrupt_in_urb))
+ // dbg( "digi_rx_unthrottle: usb_submit_urb(read urb) failed" );
+
+}
+
+
+static int digi_setbaud( struct usb_serial_port *port, int baud )
+{
+
+ int bindex;
+
+
+dbg( "digi_setbaud: TOP: port=%d", port->number );
+
+ switch( baud ) {
+ case 50: bindex = DIGI_BAUD_50; break;
+ case 75: bindex = DIGI_BAUD_75; break;
+ case 110: bindex = DIGI_BAUD_110; break;
+ case 150: bindex = DIGI_BAUD_150; break;
+ case 200: bindex = DIGI_BAUD_200; break;
+ case 300: bindex = DIGI_BAUD_300; break;
+ case 600: bindex = DIGI_BAUD_600; break;
+ case 1200: bindex = DIGI_BAUD_1200; break;
+ case 1800: bindex = DIGI_BAUD_1800; break;
+ case 2400: bindex = DIGI_BAUD_2400; break;
+ case 4800: bindex = DIGI_BAUD_4800; break;
+ case 7200: bindex = DIGI_BAUD_7200; break;
+ case 9600: bindex = DIGI_BAUD_9600; break;
+ case 14400: bindex = DIGI_BAUD_14400; break;
+ case 19200: bindex = DIGI_BAUD_19200; break;
+ case 28800: bindex = DIGI_BAUD_28800; break;
+ case 38400: bindex = DIGI_BAUD_38400; break;
+ case 57600: bindex = DIGI_BAUD_57600; break;
+ case 76800: bindex = DIGI_BAUD_76800; break;
+ case 115200: bindex = DIGI_BAUD_115200; break;
+ case 153600: bindex = DIGI_BAUD_153600; break;
+ case 230400: bindex = DIGI_BAUD_230400; break;
+ case 460800: bindex = DIGI_BAUD_460800; break;
+ default:
+ dbg( "digi_setbaud: can't handle requested baud rate %d", baud );
+ return( -EINVAL );
+ break;
+ }
+
+ digi_send_cmd( "digi_setbaud:", port, DIGI_CMD_SET_BAUD_RATE, 2, bindex );
+
+ return( 0 ); /* FIX -- send_cmd should return a value??, return it */
+
+}
+
+
+static void digi_set_termios( struct usb_serial_port *port,
+ struct termios *old_termios )
+{
+
+ unsigned int iflag = port->tty->termios->c_iflag;
+ unsigned int old_iflag = old_termios->c_iflag;
+ unsigned int cflag = port->tty->termios->c_cflag;
+ unsigned int old_cflag = old_termios->c_cflag;
+ int arg;
+
+
+dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x", port->number, iflag, old_iflag, cflag, old_cflag );
+
+ /* set baud rate */
+ /* if( (cflag&CBAUD) != (old_cflag&CBAUD) ) */ {
+ switch( (cflag&CBAUD) ) {
+ case B50: digi_setbaud(port, 50); break;
+ case B75: digi_setbaud(port, 75); break;
+ case B110: digi_setbaud(port, 110); break;
+ case B150: digi_setbaud(port, 150); break;
+ case B200: digi_setbaud(port, 200); break;
+ case B300: digi_setbaud(port, 300); break;
+ case B600: digi_setbaud(port, 600); break;
+ case B1200: digi_setbaud(port, 1200); break;
+ case B1800: digi_setbaud(port, 1800); break;
+ case B2400: digi_setbaud(port, 2400); break;
+ case B4800: digi_setbaud(port, 4800); break;
+ case B9600: digi_setbaud(port, 9600); break;
+ case B19200: digi_setbaud(port, 19200); break;
+ case B38400: digi_setbaud(port, 38400); break;
+ case B57600: digi_setbaud(port, 57600); break;
+ case B115200: digi_setbaud(port, 115200); break;
+ default:
+ dbg( "digi_set_termios: can't handle baud rate 0x%x",
+ (cflag&CBAUD) );
+ break;
+ }
+ }
+
+ /* set input flow control */
+ /* if( (iflag&IXOFF) != (old_iflag&IXOFF)
+ || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) */ {
+
+ arg = 0;
+
+ if( (iflag&IXOFF) )
+ arg |= DIGI_ENABLE_IXON_IXOFF_FLOW_CONTROL;
+ if( (cflag&CRTSCTS) )
+ arg |= DIGI_ENABLE_RTS_CTS_FLOW_CONTROL;
+
+ digi_send_cmd( "digi_termios: set input flow control:", port,
+ DIGI_CMD_SET_INPUT_FLOW_CONTROL, 2, arg );
+
+ }
+
+ /* set output flow control */
+ /* if( (iflag&IXON) != (old_iflag&IXON)
+ || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) */ {
+
+ arg = 0;
+
+ if( (iflag&IXON) )
+ arg |= DIGI_ENABLE_IXON_IXOFF_FLOW_CONTROL;
+ if( (cflag&CRTSCTS) )
+ arg |= DIGI_ENABLE_RTS_CTS_FLOW_CONTROL;
+
+ digi_send_cmd( "digi_set_termios: set output flow control:", port,
+ DIGI_CMD_SET_OUTPUT_FLOW_CONTROL, 2, arg );
+
+ }
+
+}
+
+
+static void digi_break_ctl( struct usb_serial_port *port, int break_state )
+{
+dbg( "digi_break_ctl: TOP: port=%d", port->number );
+}
+
+
+/* modem control pins: DTR and RTS are outputs and can be controlled;
+ DCD, RI, DSR, CTS are inputs and can be read */
+
+static int digi_get_modem_info( struct usb_serial *serial,
+ unsigned char *value )
+{
+dbg( "digi_get_modem_info: TOP" );
+ return( 0 );
+}
+
+
+static int digi_set_modem_info( struct usb_serial *serial,
+ unsigned char value )
+{
+dbg( "digi_set_modem_info: TOP" );
+ return( 0 );
+}
+
+
+static int digi_ioctl( struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg )
+{
+ struct usb_serial *serial = port->serial;
+ int rc;
+ unsigned int value;
+ unsigned char status, mask;
+
+dbg( "digi_ioctl: TOP: port=%d, cmd=0x%x", port->number, cmd );
+return( -ENOIOCTLCMD );
+
+ switch (cmd) {
+ case TIOCMGET: /* get modem pins state */
+ rc = digi_get_modem_info(serial, &status);
+ if (rc < 0)
+ return rc;
+ value =
+ ((status & (1<<7)) ? TIOCM_DTR : 0) |
+ ((status & (1<<6)) ? TIOCM_CAR : 0) |
+ ((status & (1<<5)) ? TIOCM_RNG : 0) |
+ ((status & (1<<4)) ? TIOCM_DSR : 0) |
+ ((status & (1<<3)) ? TIOCM_CTS : 0) |
+ ((status & (1<<2)) ? TIOCM_RTS : 0);
+ if (copy_to_user((unsigned int *)arg, &value, sizeof(int)))
+ return -EFAULT;
+ return 0;
+ case TIOCMSET: /* set a state as returned by MGET */
+ if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
+ return -EFAULT;
+ status =
+ ((value & TIOCM_DTR) ? (1<<7) : 0) |
+ ((value & TIOCM_CAR) ? (1<<6) : 0) |
+ ((value & TIOCM_RNG) ? (1<<5) : 0) |
+ ((value & TIOCM_DSR) ? (1<<4) : 0) |
+ ((value & TIOCM_CTS) ? (1<<3) : 0) |
+ ((value & TIOCM_RTS) ? (1<<2) : 0);
+ rc = digi_set_modem_info(serial, status);
+ if (rc < 0)
+ return rc;
+ return 0;
+ case TIOCMBIS: /* set bits in bitmask <arg> */
+ case TIOCMBIC: /* clear bits from bitmask <arg> */
+ if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
+ return -EFAULT;
+ rc = digi_get_modem_info(serial, &status);
+ if (rc < 0)
+ return rc;
+ mask =
+ ((value & TIOCM_RTS) ? (1<<2) : 0) |
+ ((value & TIOCM_DTR) ? (1<<7) : 0);
+ if (cmd == TIOCMBIS)
+ status |= mask;
+ else
+ status &= ~mask;
+ rc = digi_set_modem_info(serial, status);
+ if (rc < 0)
+ return rc;
+ return 0;
+ case TIOCMIWAIT:
+ /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
+ /* TODO */
+ case TIOCGICOUNT:
+ /* return count of modemline transitions */
+ return 0; /* TODO */
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+
+static int digi_write( struct usb_serial_port *port, int from_user,
+ const unsigned char *buf, int count )
+{
+
+ int i,ret,data_len,new_len;
+ digi_private_t *priv = (digi_private_t *)(port->private);
+
+
+dbg( "digi_write: TOP: port=%d, count=%d, from_user=%d, in_interrupt=%d",
+port->number, count, from_user, in_interrupt() );
+
+ /* be sure only one write proceeds at a time */
+ /* there are races on the port private buffer */
+ /* and races to check write_urb->status */
+ spin_lock( &priv->dp_port_lock );
+
+ /* wait for urb status clear to submit another urb */
+ if( port->write_urb->status == -EINPROGRESS ) {
+
+dbg( "digi_write: -EINPROGRESS set" );
+
+ /* buffer the data if possible */
+ new_len = MIN( count, DIGI_PORT_BUF_LEN-priv->dp_buf_len );
+ memcpy( priv->dp_buf+priv->dp_buf_len, buf, new_len );
+ priv->dp_buf_len += new_len;
+
+ /* unlock and return number of bytes buffered */
+ spin_unlock( &priv->dp_port_lock );
+dbg( "digi_write: buffering, return %d", new_len );
+ return( new_len );
+
+ }
+
+ /* allow space for any buffered data and for new data, up to */
+ /* transfer buffer size - 2 (for command and length bytes) */
+ new_len = MIN( count, port->bulk_out_size-2-priv->dp_buf_len );
+ data_len = new_len + priv->dp_buf_len;
+
+dbg( "digi_write: counts: new data %d, buf data %d, total data %d (max %d)", new_len, priv->dp_buf_len, data_len, port->bulk_out_size-2 );
+
+ /* nothing to send */
+ if( data_len == 0 ) {
+ spin_unlock( &priv->dp_port_lock );
+ return( 0 );
+ }
+
+ /* set command and length bytes */
+ *((u8 *)(port->write_urb->transfer_buffer)) = (u8)DIGI_CMD_SEND_DATA;
+ *((u8 *)(port->write_urb->transfer_buffer)+1) = (u8)data_len;
+
+ /* set total transfer buffer length */
+ port->write_urb->transfer_buffer_length = data_len+2;
+
+ /* copy in buffered data first */
+ memcpy( port->write_urb->transfer_buffer+2, priv->dp_buf,
+ priv->dp_buf_len );
+
+ /* copy in new data */
+ if( from_user ) {
+ copy_from_user( port->write_urb->transfer_buffer+2+priv->dp_buf_len,
+ buf, new_len );
+ }
+ else {
+ memcpy( port->write_urb->transfer_buffer+2+priv->dp_buf_len,
+ buf, new_len );
+ }
+
+#ifdef DEBUG
+ printk( KERN_DEBUG __FILE__ ": digi_write: length=%d, data=",
+ port->write_urb->transfer_buffer_length );
+ for( i=0; i<port->write_urb->transfer_buffer_length; ++i ) {
+ printk( "%.2x ",
+ ((unsigned char *)port->write_urb->transfer_buffer)[i] );
+ }
+ printk( "\n" );
+#endif
+
+ /* submit urb */
+ if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
+ /* submit successful, return length of new data written */
+ ret = new_len;
+ /* clear buffer */
+ priv->dp_buf_len = 0;
+ }
+ else {
+ dbg( "digi_write: usb_submit_urb(write bulk) failed, ret=%d", ret );
+ /* no bytes written - should we return the error code or 0? */
+ ret = 0;
+ }
+
+ /* return length of new data written, or error */
+dbg( "digi_write: returning %d", ret );
+ spin_unlock( &priv->dp_port_lock );
+ return( ret );
+
+}
+
+
+static void digi_write_bulk_callback( struct urb *urb )
+{
+
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial = port->serial;
+ struct tty_struct *tty = port->tty;
+ digi_private_t *priv = (digi_private_t *)(port->private);
+ int ret;
+
+
+dbg( "digi_write_bulk_callback: TOP: port=%d", port->number );
+
+ /* handle callback on out-of-band port */
+ if( port->number == oob_port_num ) {
+ dbg( "digi_write_bulk_callback: oob callback" );
+ wake_up_interruptible( &port->write_wait );
+ return;
+ }
+
+ /* sanity checks */
+ if( port_paranoia_check( port, "digi_write_bulk_callback" )
+ || serial_paranoia_check( serial, "digi_write_bulk_callback" ) ) {
+ return;
+ }
+
+ /* try to send any buffered data on this port */
+ spin_lock( &priv->dp_port_lock );
+ if( port->write_urb->status != -EINPROGRESS && priv->dp_buf_len > 0 ) {
+
+ /* set command and length bytes */
+ *((u8 *)(port->write_urb->transfer_buffer))
+ = (u8)DIGI_CMD_SEND_DATA;
+ *((u8 *)(port->write_urb->transfer_buffer)+1)
+ = (u8)priv->dp_buf_len;
+
+ /* set total transfer buffer length */
+ port->write_urb->transfer_buffer_length = priv->dp_buf_len+2;
+
+ /* copy in buffered data */
+ memcpy( port->write_urb->transfer_buffer+2, priv->dp_buf,
+ priv->dp_buf_len );
+
+ /* submit urb */
+dbg( "digi_write_bulk_callback: submit urb to write buffer, data len=%d",
+priv->dp_buf_len );
+ if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
+ /* successful, clear buffer */
+ priv->dp_buf_len = 0;
+ }
+ else {
+ dbg( "digi_write_bulk_callback: usb_submit_urb(write bulk) failed, ret=%d", ret );
+ }
+
+ }
+ spin_unlock( &priv->dp_port_lock );
+
+ /* wake up port processes */
+ wake_up_interruptible( &port->write_wait );
+
+ /* wake up line discipline */
+ tty = port->tty;
+ if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup )
+ (tty->ldisc.write_wakeup)(tty);
+
+ /* wake up other tty processes */
+ wake_up_interruptible( &tty->write_wait );
+
+}
+
+
+static int digi_write_room( struct usb_serial_port *port )
+{
+
+ int room;
+ digi_private_t *priv = (digi_private_t *)(port->private);
+
+
+dbg( "digi_write_room: TOP: port=%d", port->number );
+
+ spin_lock( &priv->dp_port_lock );
+
+ if( port->write_urb->status == -EINPROGRESS )
+ room = 0;
+ else
+ room = port->bulk_out_size - 2 - priv->dp_buf_len;
+
+ spin_unlock( &priv->dp_port_lock );
+
+dbg( "digi_write_room: return room=%d", room );
+ return( room );
+
+}
+
+
+static int digi_chars_in_buffer( struct usb_serial_port *port )
+{
+
+ digi_private_t *priv = (digi_private_t *)(port->private);
+
+
+dbg( "digi_chars_in_buffer: TOP: port=%d", port->number );
+
+ if( port->write_urb->status == -EINPROGRESS ) {
+dbg( "digi_chars_in_buffer: return=%d", port->bulk_out_size );
+ return( port->bulk_out_size );
+ }
+ else {
+dbg( "digi_chars_in_buffer: return=%d", priv->dp_buf_len );
+ return( priv->dp_buf_len );
+ }
+
+}
+
+
+static int digi_open( struct usb_serial_port *port, struct file *filp )
+{
+
+ int ret;
+ digi_private_t *priv = (digi_private_t *)(port->private);
+
+
+dbg( "digi_open: TOP: port %d", port->number );
+
+ /* if port is already open, just return */
+ /* be sure exactly one open succeeds */
+ spin_lock( &priv->dp_port_lock );
+ if( port->active ) {
+ return( 0 );
+ }
+ port->active = 1;
+ spin_unlock( &priv->dp_port_lock );
+
+ /* start reading from the out-of-band port for the device */
+ /* be sure this happens exactly once */
+ spin_lock( &config_lock );
+ if( !oob_read_started ) {
+ if( (ret=usb_submit_urb(oob_port->read_urb)) != 0 ) {
+ dbg( "digi_open: usb_submit_urb(read bulk) for oob failed, ret=%d",
+ ret );
+ spin_unlock( &config_lock );
+ return( -ENXIO );
+ }
+ else {
+dbg( "digi_open: usb_submit_urb(read bulk) for oob succeeded" );
+ oob_read_started = 1;
+ }
+ }
+ spin_unlock( &config_lock );
+
+ /* initialize port */
+dbg( "digi_open: init..." );
+ /* set 9600, 8N1, DTR, RTS, RX enable, no input or output flow control */
+ digi_setbaud( port, 9600 );
+ digi_send_cmd( "digi_open: wordsize", port, DIGI_CMD_SET_WORD_SIZE, 2, 3 );
+ digi_send_cmd( "digi_open: parity", port, DIGI_CMD_SET_PARITY, 2, 0 );
+ digi_send_cmd( "digi_open: stopbits", port, DIGI_CMD_SET_STOP_BITS, 2, 0 );
+ digi_send_cmd( "digi_open: DTR on", port, DIGI_CMD_SET_DTR_SIGNAL, 2, 1 );
+ digi_send_cmd( "digi_open: RTS on", port, DIGI_CMD_SET_RTS_SIGNAL, 2, 1 );
+ digi_send_cmd( "digi_open: RX enable on", port, DIGI_CMD_RECEIVE_ENABLE, 2,
+ 1 );
+ digi_send_cmd( "digi_open: input flow control off", port,
+ DIGI_CMD_SET_INPUT_FLOW_CONTROL, 2, 0 );
+ digi_send_cmd( "digi_open: output flow control off", port,
+ DIGI_CMD_SET_OUTPUT_FLOW_CONTROL, 2, 0 );
+
+ /* start reading from the device */
+ if( (ret=usb_submit_urb(port->read_urb)) != 0 ) {
+ dbg( "digi_open: usb_submit_urb(read bulk) failed, ret=%d", ret );
+ return( -ENXIO );
+ }
+
+dbg( "digi_open: done" );
+ return( 0 );
+
+}
+
+
+static void digi_close( struct usb_serial_port *port, struct file *filp )
+{
+
+dbg( "digi_close: TOP: port %d", port->number );
+
+ /* Need to change the control lines here */
+ /* TODO */
+dbg( "digi_close: wanna clear DTR and RTS..." );
+
+//digi_send_cmd( "digi_close DTR off", port, 6, 2, 0); // clear DTR
+//digi_send_cmd( "digi_close RTS off", port, 7, 2, 0); // clear RTS
+//digi_send_cmd( "digi_close RX disable", port, 10, 2, 0); // Rx Disable
+
+digi_send_oob( "digi_close RTS off", DIGI_CMD_SET_RTS_SIGNAL,
+ port->number, 0, 0 ); // clear RTS
+digi_send_oob( "digi_close DTR off", DIGI_CMD_SET_DTR_SIGNAL,
+ port->number, 0, 0 ); // clear DTR
+
+ while( oob_port->write_urb->status == -EINPROGRESS ) {
+dbg ("digi_close: waiting for final writes to complete on oob port %d...", oob_port->number );
+ interruptible_sleep_on( &oob_port->write_wait );
+ if( signal_pending(current) ) {
+ break;
+ }
+ }
+
+ /* shutdown our bulk reads and writes */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+
+ port->active = 0;
+
+}
+
+
+static int digi_startup (struct usb_serial *serial)
+{
+
+ int i;
+ digi_private_t *priv;
+
+
+dbg( "digi_startup: TOP" );
+
+ /* initialize config lock */
+ spin_lock_init( &config_lock );
+
+ /* allocate the private data structures for all ports */
+ /* number of regular ports + 1 for the out-of-band port */
+ for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) {
+
+ /* allocate private structure */
+ priv = serial->port[i].private =
+ (digi_private_t *)kmalloc( sizeof(struct digi_private),
+ GFP_KERNEL );
+ if( priv == (digi_private_t *)0 )
+ return( 1 ); /* error */
+
+ /* initialize private structure */
+ priv->dp_buf_len = 0;
+ spin_lock_init( &priv->dp_port_lock );
+
+ /* initialize write wait queue for this port */
+ init_waitqueue_head(&serial->port[i].write_wait);
+
+ }
+
+ /* initialize out of band port info */
+ oob_port_num = digi_acceleport_device.num_ports;
+ oob_port = &serial->port[oob_port_num];
+ oob_read_started = 0;
+
+ return( 0 );
+
+}
+
+
+static void digi_shutdown( struct usb_serial *serial )
+{
+
+ int i;
+
+
+dbg( "digi_shutdown: TOP" );
+
+ /* stop writing and reading from the out-of-band port */
+ usb_unlink_urb( oob_port->write_urb );
+ usb_unlink_urb( oob_port->read_urb );
+ oob_read_started = 0;
+
+ /* free the private data structures for all ports */
+ /* number of regular ports + 1 for the out-of-band port */
+ for( i=0; i<digi_acceleport_device.num_ports+1; i++ )
+ kfree( serial->port[i].private );
+
+}
+
+
+static void digi_read_bulk_callback( struct urb *urb )
+{
+
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial = port->serial;
+ struct tty_struct *tty = port->tty;
+ unsigned char *data = urb->transfer_buffer;
+ int ret,i;
+
+
+dbg( "digi_read_bulk_callback: TOP: port=%d", port->number );
+
+ /* handle oob callback */
+ if( port->number == oob_port_num ) {
+dbg( "digi_read_bulk_callback: oob_port callback, opcode=%d, line=%d, status=%d, ret=%d", data[0], data[1], data[2], data[3] );
+ if( urb->status ) {
+ dbg( "digi_read_bulk_callback: nonzero read bulk status on oob: %d",
+ urb->status );
+ }
+ if( (ret=usb_submit_urb(urb)) != 0 ) {
+ dbg( "digi_read_bulk_callback: failed resubmitting oob urb, ret=%d",
+ ret );
+ }
+ return;
+ }
+
+ /* sanity checks */
+ if( port_paranoia_check( port, "digi_read_bulk_callback" )
+ || serial_paranoia_check( serial, "digi_read_bulk_callback" ) ) {
+ return;
+ }
+
+ /* check status */
+ if( urb->status ) {
+ dbg( "digi_read_bulk_callback: nonzero read bulk status: %d",
+ urb->status );
+ return;
+ }
+
+#ifdef DEBUG
+ if (urb->actual_length) {
+ printk( KERN_DEBUG __FILE__ ": digi_read_bulk_callback: length=%d, data=",
+ urb->actual_length );
+ for( i=0; i<urb->actual_length; ++i ) {
+ printk( "%.2x ", data[i] );
+ }
+ printk( "\n" );
+ }
+#endif
+
+ /* Digi read packets are: */
+ /* 0 1 2 3 4 ... 3+length-1 == 2+length*/
+ /* opcode, length, status, data[0], data[1]...data[length-2] */
+ if( urb->actual_length > 3 ) {
+ for( i=3; i<2+data[1]; ++i ) {
+ tty_insert_flip_char(tty, data[i], 0);
+ }
+ tty_flip_buffer_push(tty);
+ }
+
+ /* Continue trying to read */
+ if( (ret=usb_submit_urb(urb)) != 0 )
+ dbg( "digi_read_bulk_callback: failed resubmitting read urb, ret=%d",
+ ret );
+
+}
+
+#endif /* CONFIG_USB_SERIAL_DIGI_ACCELEPORT */
+
diff --git a/drivers/usb/serial/ezusb_convert.pl b/drivers/usb/serial/ezusb_convert.pl
index 3c69e4c1c..13f114691 100644
--- a/drivers/usb/serial/ezusb_convert.pl
+++ b/drivers/usb/serial/ezusb_convert.pl
@@ -16,8 +16,8 @@ while (<STDIN>) {
# ':' <len> <addr> <type> <len-data> <crc> '\r'
# len, type, crc are 2-char hex, addr is 4-char hex. type is 00 for
# normal records, 01 for EOF
- my($lenstring, $addrstring, $typestring, $reststring) =
- /^:(\w\w)(\w\w\w\w)(\w\w)(\w+)$/;
+ my($lenstring, $addrstring, $typestring, $reststring, $doscrap) =
+ /^:(\w\w)(\w\w\w\w)(\w\w)(\w+)(\r?)$/;
die "malformed line: $_" unless $reststring;
last if $typestring eq '01';
my($len) = hex($lenstring);
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index a305283bb..cdad3cabe 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1,7 +1,7 @@
/*
* USB FTDI SIO driver
*
- * (C) Copyright (C) 1999, 2000
+ * Copyright (C) 1999, 2000
* Greg Kroah-Hartman (greg@kroah.com)
* Bill Ryder (bryder@sgi.com)
*
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index c63f1b856..f91e1b592 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -1,7 +1,7 @@
/*
* USB Keyspan PDA Converter driver
*
- * (C) Copyright (C) 1999, 2000
+ * Copyright (C) 1999, 2000
* Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 2edcb6e86..9eb6767f0 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -8,6 +8,8 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * Please report both successes and troubles to the author at omninet@kroah.com
+ *
*/
#include <linux/config.h>
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index 8991f4be9..b8e2e1d74 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -1,7 +1,7 @@
/*
* USB Serial Converter driver
*
- * (C) Copyright (C) 1999, 2000
+ * Copyright (C) 1999, 2000
* Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,7 @@
#include <linux/config.h>
#define SERIAL_TTY_MAJOR 188 /* Nice legal number now */
-#define SERIAL_TTY_MINORS 16 /* Actually we are allowed 255, but this is good for now */
+#define SERIAL_TTY_MINORS 255 /* loads of devices :) */
#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */
@@ -123,6 +123,7 @@ extern struct usb_serial_device_type ftdi_sio_device;
extern struct usb_serial_device_type keyspan_pda_fake_device;
extern struct usb_serial_device_type keyspan_pda_device;
extern struct usb_serial_device_type zyxel_omninet_device;
+extern struct usb_serial_device_type digi_acceleport_device;
/* determine if we should include the EzUSB loader functions */
diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
index 588fed5d1..9fe65ae8d 100644
--- a/drivers/usb/serial/usbserial.c
+++ b/drivers/usb/serial/usbserial.c
@@ -1,7 +1,7 @@
/*
* USB Serial Converter driver
*
- * (C) Copyright (C) 1999, 2000
+ * Copyright (C) 1999, 2000
* Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or modify
@@ -14,6 +14,16 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (05/03/2000) gkh
+ * Added the Digi Acceleport driver from Al Borchers and Peter Berger.
+ *
+ * (05/02/2000) gkh
+ * Changed devfs and tty register code to work properly now. This was based on
+ * the ACM driver changes by Vojtech Pavlik.
+ *
+ * (04/27/2000) Ryan VanderBijl
+ * Put calls to *_paranoia_checks into one function.
+ *
* (04/23/2000) gkh
* Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports.
* Moved when the startup code printed out the devices that are supported.
@@ -282,15 +292,13 @@ static struct usb_serial_device_type *usb_serial_devices[] = {
#ifdef CONFIG_USB_SERIAL_OMNINET
&zyxel_omninet_device,
#endif
+#ifdef CONFIG_USB_SERIAL_DIGI_ACCELEPORT
+ &digi_acceleport_device,
+#endif
NULL
};
-/* variables needed for the tty_driver structure */
-static char *driver_name = "usb";
-static char *tty_driver_name = "usb/tty/%d";
-
-
/* local function prototypes */
static int serial_open (struct tty_struct *tty, struct file * filp);
static void serial_close (struct tty_struct *tty, struct file * filp);
@@ -312,12 +320,27 @@ static struct usb_driver usb_serial_driver = {
};
static int serial_refcount;
+static struct tty_driver serial_tty_driver;
static struct tty_struct * serial_tty[SERIAL_TTY_MINORS];
static struct termios * serial_termios[SERIAL_TTY_MINORS];
static struct termios * serial_termios_locked[SERIAL_TTY_MINORS];
static struct usb_serial *serial_table[SERIAL_TTY_MINORS] = {NULL, };
+static inline struct usb_serial* get_usb_serial (struct usb_serial_port *port, const char *function)
+{
+ /* if no port was specified, or it fails a paranoia check */
+ if (!port ||
+ port_paranoia_check (port, function) ||
+ serial_paranoia_check (port->serial, function)) {
+ /* then say that we dont have a valid usb_serial thing, which will
+ * end up genrating -ENODEV return values */
+ return NULL;
+ }
+
+ return port->serial;
+}
+
static struct usb_serial *get_serial_by_minor (int minor)
{
@@ -357,7 +380,7 @@ static struct usb_serial *get_free_serial (int num_ports, int *minor)
for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
serial_table[i] = serial;
return serial;
- }
+ }
return NULL;
}
@@ -454,16 +477,9 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
static void serial_close(struct tty_struct *tty, struct file * filp)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
+ struct usb_serial *serial = get_usb_serial (port, "serial_close");
- dbg("serial_close");
-
- if (port_paranoia_check (port, "serial_close")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_close")) {
+ if (!serial) {
return;
}
@@ -486,16 +502,9 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_write");
+ struct usb_serial *serial = get_usb_serial (port, "serial_write");
- if (port_paranoia_check (port, "serial_write")) {
- return -ENODEV;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_write")) {
+ if (!serial) {
return -ENODEV;
}
@@ -518,26 +527,19 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned
static int serial_write_room (struct tty_struct *tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_write_room");
-
- if (port_paranoia_check (port, "serial_write")) {
- return -ENODEV;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_write")) {
+ struct usb_serial *serial = get_usb_serial (port, "serial_write_room");
+
+ if (!serial) {
return -ENODEV;
}
-
+
dbg("serial_write_room port %d", port->number);
if (!port->active) {
dbg ("port not open");
return -EINVAL;
}
-
+
/* pass on to the driver specific version of this function if it is available */
if (serial->type->write_room) {
return (serial->type->write_room(port));
@@ -550,24 +552,17 @@ static int serial_write_room (struct tty_struct *tty)
static int serial_chars_in_buffer (struct tty_struct *tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_chars_in_buffer");
-
- if (port_paranoia_check (port, "serial_chars_in_buffer")) {
- return -ENODEV;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_chars_in_buffer")) {
+ struct usb_serial *serial = get_usb_serial (port, "serial_chars_in_buffer");
+
+ if (!serial) {
return -ENODEV;
}
-
+
if (!port->active) {
dbg ("port not open");
return -EINVAL;
}
-
+
/* pass on to the driver specific version of this function if it is available */
if (serial->type->chars_in_buffer) {
return (serial->type->chars_in_buffer(port));
@@ -580,21 +575,14 @@ static int serial_chars_in_buffer (struct tty_struct *tty)
static void serial_throttle (struct tty_struct * tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_throttle");
-
- if (port_paranoia_check (port, "serial_throttle")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_throttle")) {
+ struct usb_serial *serial = get_usb_serial (port, "serial_throttle");
+
+ if (!serial) {
return;
}
-
+
dbg("serial_throttle port %d", port->number);
-
+
if (!port->active) {
dbg ("port not open");
return;
@@ -612,21 +600,14 @@ static void serial_throttle (struct tty_struct * tty)
static void serial_unthrottle (struct tty_struct * tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_unthrottle");
-
- if (port_paranoia_check (port, "serial_unthrottle")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_unthrottle")) {
+ struct usb_serial *serial = get_usb_serial (port, "serial_unthrottle");
+
+ if (!serial) {
return;
}
-
+
dbg("serial_unthrottle port %d", port->number);
-
+
if (!port->active) {
dbg ("port not open");
return;
@@ -644,21 +625,14 @@ static void serial_unthrottle (struct tty_struct * tty)
static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_ioctl");
-
- if (port_paranoia_check (port, "serial_ioctl")) {
- return -ENODEV;
- }
+ struct usb_serial *serial = get_usb_serial (port, "serial_ioctl");
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_ioctl")) {
+ if (!serial) {
return -ENODEV;
}
-
+
dbg("serial_ioctl port %d", port->number);
-
+
if (!port->active) {
dbg ("port not open");
return -ENODEV;
@@ -676,16 +650,9 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in
static void serial_set_termios (struct tty_struct *tty, struct termios * old)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_set_termios");
-
- if (port_paranoia_check (port, "serial_set_termios")) {
- return;
- }
+ struct usb_serial *serial = get_usb_serial (port, "serial_set_termios");
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_set_termios")) {
+ if (!serial) {
return;
}
@@ -708,16 +675,9 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old)
static void serial_break (struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_break");
-
- if (port_paranoia_check (port, "serial_break")) {
- return;
- }
+ struct usb_serial *serial = get_usb_serial (port, "serial_break");
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_break")) {
+ if (!serial) {
return;
}
@@ -861,22 +821,15 @@ static int generic_chars_in_buffer (struct usb_serial_port *port)
static void generic_read_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial;
- struct tty_struct *tty;
- unsigned char *data = urb->transfer_buffer;
+ struct usb_serial *serial = get_usb_serial (port, "generic_read_bulk_callback");
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
int i;
- dbg("generic_read_bulk_callback");
-
- if (port_paranoia_check (port, "generic_read_bulk_callback")) {
+ if (!serial) {
return;
}
- serial = port->serial;
- if (serial_paranoia_check (serial, "generic_read_bulk_callback")) {
- return;
- }
-
if (urb->status) {
dbg("nonzero read bulk status received: %d", urb->status);
return;
@@ -911,20 +864,13 @@ static void generic_read_bulk_callback (struct urb *urb)
static void generic_write_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial;
- struct tty_struct *tty;
-
- dbg("generic_write_bulk_callback");
+ struct usb_serial *serial = get_usb_serial (port, "generic_write_bulk_callback");
+ struct tty_struct *tty;
- if (port_paranoia_check (port, "generic_write_bulk_callback")) {
+ if (!serial) {
return;
}
- serial = port->serial;
- if (serial_paranoia_check (serial, "generic_write_bulk_callback")) {
- return;
- }
-
if (urb->status) {
dbg("nonzero write bulk status received: %d", urb->status);
return;
@@ -940,48 +886,6 @@ static void generic_write_bulk_callback (struct urb *urb)
}
-static struct tty_driver * usb_serial_tty_driver_init (struct usb_serial *serial)
-{
- struct tty_driver *serial_tty_driver;
-
- if (!(serial_tty_driver = kmalloc(sizeof(struct tty_driver), GFP_KERNEL))) {
- err("Out of memory");
- return NULL;
- }
-
- memset (serial_tty_driver, 0x00, sizeof(struct tty_driver));
-
- /* initialize the entries that we don't want to be NULL */
- serial_tty_driver->magic = TTY_DRIVER_MAGIC;
- serial_tty_driver->driver_name = driver_name;
- serial_tty_driver->name = tty_driver_name;
- serial_tty_driver->major = SERIAL_TTY_MAJOR;
- serial_tty_driver->minor_start = serial->minor;
- serial_tty_driver->num = serial->num_ports;
- serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
- serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- serial_tty_driver->flags = TTY_DRIVER_REAL_RAW;
- serial_tty_driver->refcount = &serial_refcount;
- serial_tty_driver->table = serial_tty;
- serial_tty_driver->termios = serial_termios;
- serial_tty_driver->termios_locked = serial_termios_locked;
- serial_tty_driver->open = serial_open;
- serial_tty_driver->close = serial_close;
- serial_tty_driver->write = serial_write;
- serial_tty_driver->write_room = serial_write_room;
- serial_tty_driver->ioctl = serial_ioctl;
- serial_tty_driver->set_termios = serial_set_termios;
- serial_tty_driver->throttle = serial_throttle;
- serial_tty_driver->unthrottle = serial_unthrottle;
- serial_tty_driver->break_ctl = serial_break;
- serial_tty_driver->chars_in_buffer = serial_chars_in_buffer;
- serial_tty_driver->init_termios = tty_std_termios;
- serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-
- return serial_tty_driver;
-}
-
-
static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_serial *serial = NULL;
@@ -1101,18 +1005,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
serial->num_bulk_out = num_bulk_out;
serial->num_interrupt_in = num_interrupt_in;
- /* initialize a tty_driver for this device */
- serial->tty_driver = usb_serial_tty_driver_init (serial);
- if (serial->tty_driver == NULL) {
- err("Can't create a tty_serial_driver");
- goto probe_error;
- }
-
- if (tty_register_driver (serial->tty_driver)) {
- err("failed to register tty driver");
- goto probe_error;
- }
-
/* if this device type has a startup function, call it */
if (type->startup) {
if (type->startup (serial)) {
@@ -1196,14 +1088,16 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
max_endpoints = MAX(max_endpoints, num_interrupt_in);
for (i = 0; i < max_endpoints; ++i) {
port = &serial->port[i];
- port->number = i;
+ port->number = i + serial->minor;
port->serial = serial;
port->magic = USB_SERIAL_PORT_MAGIC;
}
+ /* initialize the devfs nodes for this device and let the user know what ports we are bound to */
for (i = 0; i < serial->num_ports; ++i) {
- info("%s converter now attached to ttyUSB%d",
- type->name, serial->minor + i);
+ tty_register_devfs (&serial_tty_driver, 0, serial->port[i].number);
+ info("%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)",
+ type->name, serial->port[i].number, serial->port[i].number);
}
return serial; /* success */
@@ -1235,13 +1129,6 @@ probe_error:
/* return the minor range that this device had */
return_serial (serial);
- /* if this device has a tty_driver, then unregister it and free it */
- if (serial->tty_driver) {
- tty_unregister_driver (serial->tty_driver);
- kfree (serial->tty_driver);
- serial->tty_driver = NULL;
- }
-
/* free up any memory that we allocated */
kfree (serial);
MOD_DEC_USE_COUNT;
@@ -1291,18 +1178,13 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
}
for (i = 0; i < serial->num_ports; ++i) {
- info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->minor + i);
+ tty_unregister_devfs (&serial_tty_driver, serial->port[i].number);
+ info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->port[i].number);
}
/* return the minor range that this device had */
return_serial (serial);
- /* if this device has a tty_driver, then unregister it and free it */
- if (serial->tty_driver) {
- tty_unregister_driver (serial->tty_driver);
- kfree (serial->tty_driver);
- serial->tty_driver = NULL;
- }
/* free up any memory that we allocated */
kfree (serial);
@@ -1314,6 +1196,35 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
}
+static struct tty_driver serial_tty_driver = {
+ magic: TTY_DRIVER_MAGIC,
+ driver_name: "usb-serial",
+ name: "usb/tts/%d",
+ major: SERIAL_TTY_MAJOR,
+ minor_start: 0,
+ num: SERIAL_TTY_MINORS,
+ type: TTY_DRIVER_TYPE_SERIAL,
+ subtype: SERIAL_TYPE_NORMAL,
+ flags: TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+
+ refcount: &serial_refcount,
+ table: serial_tty,
+ termios: serial_termios,
+ termios_locked: serial_termios_locked,
+
+ open: serial_open,
+ close: serial_close,
+ write: serial_write,
+ write_room: serial_write_room,
+ ioctl: serial_ioctl,
+ set_termios: serial_set_termios,
+ throttle: serial_throttle,
+ unthrottle: serial_unthrottle,
+ break_ctl: serial_break,
+ chars_in_buffer: serial_chars_in_buffer,
+};
+
+
int usb_serial_init(void)
{
int i;
@@ -1336,9 +1247,18 @@ int usb_serial_init(void)
if (!something)
info ("USB Serial driver is not configured for any devices!");
+ /* register the tty driver */
+ serial_tty_driver.init_termios = tty_std_termios;
+ serial_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ if (tty_register_driver (&serial_tty_driver)) {
+ err("failed to register tty driver");
+ return -1;
+ }
+
/* register the USB driver */
result = usb_register(&usb_serial_driver);
if (result < 0) {
+ tty_unregister_driver(&serial_tty_driver);
err("usb_register failed for the usb-serial driver. Error number %d", result);
return -1;
}
@@ -1350,6 +1270,7 @@ int usb_serial_init(void)
void usb_serial_exit(void)
{
usb_deregister(&usb_serial_driver);
+ tty_unregister_driver(&serial_tty_driver);
}
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 6832814da..979a56f01 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -1,7 +1,7 @@
/*
* USB HandSpring Visor driver
*
- * (C) Copyright (C) 1999, 2000
+ * Copyright (C) 1999, 2000
* Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or modify
@@ -11,6 +11,9 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (04/27/2000) Ryan VanderBijl
+ * Fixed memory leak in visor_close
+ *
* (03/26/2000) gkh
* Split driver up into device specific pieces.
*
@@ -110,6 +113,7 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
/* send a shutdown message to the device */
usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
+ kfree (transfer_buffer);
}
/* shutdown our bulk reads and writes */
diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
index a1173697d..6407a7811 100644
--- a/drivers/usb/serial/visor.h
+++ b/drivers/usb/serial/visor.h
@@ -1,7 +1,7 @@
/*
* USB HandSpring Visor driver
*
- * (C) Copyright (C) 1999, 2000
+ * Copyright (C) 1999, 2000
* Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index aa6c14b0b..58f761fbf 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -1,7 +1,7 @@
/*
* USB ConnectTech WhiteHEAT driver
*
- * (C) Copyright (C) 1999, 2000
+ * Copyright (C) 1999, 2000
* Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or modify
@@ -11,6 +11,10 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (05/04/2000) gkh
+ * First cut at open and close commands. Data can flow through the ports at
+ * default speeds now.
+ *
* (03/26/2000) gkh
* Split driver up into device specific pieces.
*
@@ -45,6 +49,7 @@
#include "whiteheat_fw.h" /* firmware for the ConnectTech WhiteHEAT device */
+#include "whiteheat.h" /* WhiteHEAT specific commands */
#define CONNECT_TECH_VENDOR_ID 0x0710
#define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001
@@ -57,6 +62,7 @@ static void whiteheat_set_termios (struct usb_serial_port *port, struct termios
static void whiteheat_throttle (struct usb_serial_port *port);
static void whiteheat_unthrottle (struct usb_serial_port *port);
static int whiteheat_startup (struct usb_serial *serial);
+static void whiteheat_shutdown (struct usb_serial *serial);
/* All of the device info needed for the Connect Tech WhiteHEAT */
static __u16 connecttech_vendor_id = CONNECT_TECH_VENDOR_ID;
@@ -91,14 +97,124 @@ struct usb_serial_device_type whiteheat_device = {
throttle: whiteheat_throttle,
unthrottle: whiteheat_unthrottle,
set_termios: whiteheat_set_termios,
+ shutdown: whiteheat_shutdown,
+};
+
+struct whiteheat_private {
+ __u8 command_finished;
+ wait_queue_head_t wait_command; /* for handling sleeping while waiting for a command to finish */
};
+#define COMMAND_PORT 4
+#define COMMAND_TIMEOUT (2*HZ) /* 2 second timeout for a command */
+
/*****************************************************************************
* Connect Tech's White Heat specific driver functions
*****************************************************************************/
+static void command_port_write_callback (struct urb *urb)
+{
+ unsigned char *data = urb->transfer_buffer;
+#ifdef DEBUG
+ int i;
+#endif
+
+ dbg ("command_port_write_callback");
+
+ if (urb->status) {
+ dbg ("nonzero urb status: %d", urb->status);
+ return;
+ }
+
+#ifdef DEBUG
+ if (urb->actual_length) {
+ printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+ for (i = 0; i < urb->actual_length; ++i) {
+ printk ("%.2x ", data[i]);
+ }
+ printk ("\n");
+ }
+#endif
+
+ return;
+}
+
+
+static void command_port_read_callback (struct urb *urb)
+{
+ struct whiteheat_private *info = (struct whiteheat_private *)urb->context;
+ unsigned char *data = urb->transfer_buffer;
+#ifdef DEBUG
+ int i;
+#endif
+
+ dbg ("command_port_write_callback");
+
+ if (urb->status) {
+ dbg ("nonzero urb status: %d", urb->status);
+ return;
+ }
+
+#ifdef DEBUG
+ if (urb->actual_length) {
+ printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+ for (i = 0; i < urb->actual_length; ++i) {
+ printk ("%.2x ", data[i]);
+ }
+ printk ("\n");
+ }
+#endif
+
+ /* right now, if the command is COMMAND_COMPLETE, just flip the bit saying the command finished */
+ /* in the future we're going to have to pay attention to the actual command that completed */
+ if (data[0] == WHITEHEAT_CMD_COMPLETE) {
+ info->command_finished = TRUE;
+ }
+
+ return;
+}
+
+
+static int whiteheat_send_cmd (struct usb_serial *serial, __u8 command, __u8 *data, __u8 datasize)
+{
+ struct whiteheat_private *info;
+ struct usb_serial_port *port;
+ int timeout;
+ __u8 *transfer_buffer;
+
+ dbg("whiteheat_send_cmd: %d", command);
+
+ port = &serial->port[COMMAND_PORT];
+ info = (struct whiteheat_private *)port->private;
+ info->command_finished = FALSE;
+
+ transfer_buffer = (__u8 *)port->write_urb->transfer_buffer;
+ transfer_buffer[0] = command;
+ memcpy (&transfer_buffer[1], data, datasize);
+ port->write_urb->transfer_buffer_length = datasize + 1;
+ if (usb_submit_urb (port->write_urb))
+ dbg ("submit urb failed");
+
+ /* wait for the command to complete */
+ timeout = COMMAND_TIMEOUT;
+ while (timeout && (info->command_finished == FALSE)) {
+ timeout = interruptible_sleep_on_timeout (&info->wait_command, timeout);
+ }
+
+ if (info->command_finished == FALSE) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
{
+ struct whiteheat_min_set open_command;
+ struct usb_serial_port *command_port;
+ struct whiteheat_private *info;
+
dbg("whiteheat_open port %d", port->number);
if (port->active) {
@@ -106,22 +222,50 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
return -EINVAL;
}
port->active = 1;
-
- /*Start reading from the device*/
+
+ /* set up some stuff for our command port */
+ command_port = &port->serial->port[COMMAND_PORT];
+ if (command_port->private == NULL) {
+ info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL);
+ if (info == NULL) {
+ err("out of memory");
+ return -ENOMEM;
+ }
+
+ init_waitqueue_head(&info->wait_command);
+ command_port->private = info;
+ command_port->write_urb->complete = command_port_write_callback;
+ command_port->read_urb->complete = command_port_read_callback;
+ usb_submit_urb (command_port->read_urb);
+ }
+
+ /* Start reading from the device */
if (usb_submit_urb(port->read_urb))
dbg("usb_submit_urb(read bulk) failed");
+ /* send an open port command */
+ open_command.port = port->number - port->minor;
+ whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command));
+
/* Need to do device specific setup here (control lines, baud rate, etc.) */
/* FIXME!!! */
+ dbg("whiteheat_open exit");
+
return (0);
}
static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
{
+ struct whiteheat_min_set close_command;
+
dbg("whiteheat_close port %d", port->number);
+ /* send a close command to the port */
+ close_command.port = port->number - port->minor;
+ whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command));
+
/* Need to change the control lines here */
/* FIXME */
@@ -243,7 +387,24 @@ static int whiteheat_startup (struct usb_serial *serial)
response = ezusb_set_reset (serial, 0);
/* we want this device to fail to have a driver assigned to it. */
- return (1);
+ return 1;
+}
+
+
+static void whiteheat_shutdown (struct usb_serial *serial)
+{
+ struct usb_serial_port *command_port;
+
+ dbg("whiteheat_shutdown");
+
+ /* set up some stuff for our command port */
+ command_port = &serial->port[COMMAND_PORT];
+ if (command_port->private != NULL) {
+ kfree (command_port->private);
+ command_port->private = NULL;
+ }
+
+ return;
}
#endif /* CONFIG_USB_SERIAL_WHITEHEAT */
diff --git a/drivers/usb/serial/whiteheat.h b/drivers/usb/serial/whiteheat.h
new file mode 100644
index 000000000..970a555c0
--- /dev/null
+++ b/drivers/usb/serial/whiteheat.h
@@ -0,0 +1,169 @@
+/*
+ * USB ConnectTech WhiteHEAT driver
+ *
+ * Copyright (C) 1999, 2000
+ * Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ */
+
+#ifndef __LINUX_USB_SERIAL_WHITEHEAT_H
+#define __LINUX_USB_SERIAL_WHITEHEAT_H
+
+
+#define FALSE 0
+#define TRUE 1
+
+/* WhiteHEAT commands */
+#define WHITEHEAT_OPEN 1 /* open the port */
+#define WHITEHEAT_CLOSE 2 /* close the port */
+#define WHITEHEAT_SETUP_PORT 3 /* change port settings */
+#define WHITEHEAT_SET_RTS 4 /* turn RTS on or off */
+#define WHITEHEAT_SET_DTR 5 /* turn DTR on or off */
+#define WHITEHEAT_SET_BREAK 6 /* turn BREAK on or off */
+#define WHITEHEAT_DUMP 7 /* dump memory */
+#define WHITEHEAT_STATUS 8 /* get status */
+#define WHITEHEAT_PURGE 9 /* clear the UART fifos */
+#define WHITEHEAT_GET_DTR_RTS 10 /* get the state of DTR and RTS for a port */
+#define WHITEHEAT_GET_HW_INFO 11 /* get EEPROM info and hardware ID */
+#define WHITEHEAT_REPORT_TX_DONE 12 /* get the next TX done */
+#define WHITEHEAT_EVENT 13 /* unsolicited status events */
+#define WHITEHEAT_ECHO 14 /* send data to the indicated IN endpoint */
+#define WHITEHEAT_DO_TEST 15 /* perform the specified test */
+#define WHITEHEAT_CMD_COMPLETE 16 /* reply for certain commands */
+
+/* Data for the WHITEHEAT_SETUP_PORT command */
+#define WHITEHEAT_CTS_FLOW 0x08
+#define WHITEHEAT_RTS_FLOW 0x80
+#define WHITEHEAT_DSR_FLOW 0x10
+#define WHITEHEAT_DTR_FLOW 0x02
+struct whiteheat_port_settings {
+ __u8 port; /* port number (1 to N) */
+ __u32 baud; /* any value allowed, default 9600, arrives little endian, range is 7 - 460800 */
+ __u8 bits; /* 5, 6, 7, or 8, default 8 */
+ __u8 stop; /* 1 or 2, default 1 (2 = 1.5 if bits = 5) */
+ __u8 parity; /* 'n, e, o, 0, or 1' (ascii), default 'n'
+ * n = none e = even o = odd
+ * 0 = force 0 1 = force 1 */
+ __u8 sflow; /* 'n, r, t, or b' (ascii), default 'n'
+ * n = none
+ * r = receive (XOFF/XON transmitted when receiver fills / empties)
+ * t = transmit (XOFF/XON received will stop/start TX)
+ * b = both */
+ __u8 xoff; /* XOFF byte value, default 0x13 */
+ __u8 xon; /* XON byte value, default 0x11 */
+ __u8 hflow; /* bits indicate mode as follows:
+ * CTS (0x08) (CTS off/on will control/cause TX off/on)
+ * DSR (0x10) (DSR off/on will control/cause TX off/on)
+ * RTS (0x80) (RTS off/on when receiver fills/empties)
+ * DTR (0x02) (DTR off/on when receiver fills/empties) */
+ __u8 lloop; /* local loopback 0 or 1, default 0 */
+};
+
+/* data for WHITEHEAT_SET_RTS, WHITEHEAT_SET_DTR, and WHITEHEAT_SET_BREAK commands */
+struct whiteheat_rdb_set {
+ __u8 port; /* port number (1 to N) */
+ __u8 state; /* 0 = off, non-zero = on */
+};
+
+/* data for:
+ WHITEHEAT_OPEN
+ WHITEHEAT_CLOSE
+ WHITEHEAT_STATUS
+ WHITEHEAT_GET_DTR_RTS
+ WHITEHEAT_REPORT_TX_DONE */
+struct whiteheat_min_set {
+ __u8 port; /* port number (1 to N) */
+};
+
+/* data for WHITEHEAT_PURGE command */
+#define WHITEHEAT_PURGE_INPUT 0x01
+#define WHITEHEAT_PURGE_OUTPUT 0x02
+struct whiteheat_purge_set {
+ __u8 port; /* port number (1 to N) */
+ __u8 what; /* bit pattern of what to purge */
+};
+
+/* data for WHITEHEAT_DUMP command */
+struct whiteheat_dump_info {
+ __u8 mem_type; /* memory type: 'd' = data, 'i' = idata, 'b' = bdata, 'x' = xdata */
+ __u16 addr; /* memory address to dump, address range depends on the above mem_type:
+ * 'd' = 0 to ff (80 to FF is SFR's)
+ * 'i' = 80 to ff
+ * 'b' = 20 to 2f (bits returned as bytes)
+ * 'x' = 0000 to ffff (also code space) */
+ __u16 length; /* number of bytes to dump, max 64 */
+};
+
+/* data for WHITEHEAT_ECHO command */
+struct whiteheat_echo_set {
+ __u8 port; /* port number (1 to N) */
+ __u8 length; /* length of message to echo */
+ __u8 echo_data[61]; /* data to echo */
+};
+
+/* data returned from WHITEHEAT_STATUS command */
+#define WHITEHEAT_OVERRUN_ERROR 0x02
+#define WHITEHEAT_PARITY_ERROR 0x04
+#define WHITEHEAT_FRAMING_ERROR 0x08
+#define WHITEHEAT_BREAK_ERROR 0x10
+
+#define WHITEHEAT_OHFLOW 0x01 /* TX is stopped by CTS (waiting for CTS to go ON) */
+#define WHITEHEAT_IHFLOW 0x02 /* remote TX is stopped by RTS */
+#define WHITEHEAT_OSFLOW 0x04 /* TX is stopped by XOFF received (waiting for XON to occur) */
+#define WHITEHEAT_ISFLOW 0x08 /* remote TX is stopped by XOFF transmitted */
+#define WHITEHEAT_TX_DONE 0x80 /* TX has completed */
+
+#define WHITEHEAT_MODEM_EVENT 0x01
+#define WHITEHEAT_ERROR_EVENT 0x02
+#define WHITEHEAT_FLOW_EVENT 0x04
+#define WHITEHEAT_CONNECT_EVENT 0x08
+struct whiteheat_status_info {
+ __u8 port; /* port number (1 to N) */
+ __u8 event; /* indicates which of the following bytes are the current event */
+ __u8 modem; /* modem signal status (copy of UART MSR register) */
+ __u8 error; /* PFO and RX break (copy of UART LSR register) */
+ __u8 flow; /* flow control state */
+ __u8 connect; /* connect state, non-zero value indicates connected */
+};
+
+/* data returned from WHITEHEAT_EVENT command */
+struct whiteheat_event {
+ __u8 port; /* port number (1 to N) */
+ __u8 event; /* indicates which of the following bytes are the current event */
+ __u8 info; /* either modem, error, flow, or connect information */
+};
+
+/* data retured by the WHITEHEAT_GET_HW_INFO command */
+struct whiteheat_hw_info {
+ __u8 hw_id; /* hardware id number, WhiteHEAT = 0 */
+ __u8 sw_major_rev; /* major version number */
+ __u8 sw_minor_rev; /* minor version number */
+ struct whiteheat_hw_eeprom_info {
+ __u8 b0; /* B0 */
+ __u8 vendor_id_low; /* vendor id (low byte) */
+ __u8 vendor_id_high; /* vendor id (high byte) */
+ __u8 product_id_low; /* product id (low byte) */
+ __u8 product_id_high; /* product id (high byte) */
+ __u8 device_id_low; /* device id (low byte) */
+ __u8 device_id_high; /* device id (high byte) */
+ __u8 not_used_1;
+ __u8 serial_number_0; /* serial number (low byte) */
+ __u8 serial_number_1; /* serial number */
+ __u8 serial_number_2; /* serial number */
+ __u8 serial_number_3; /* serial number (high byte) */
+ __u8 not_used_2;
+ __u8 not_used_3;
+ __u8 checksum_low; /* checksum (low byte) */
+ __u8 checksum_high; /* checksum (high byte */
+ } hw_eeprom_info; /* EEPROM contents */
+};
+
+#endif
+