diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-11-28 03:58:46 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-11-28 03:58:46 +0000 |
commit | b63ad0882a16a5d28003e57f2b0b81dee3fb322b (patch) | |
tree | 0a343ce219e2b8b38a5d702d66032c57b83d9720 /drivers/usb/serial | |
parent | a9d7bff9a84dba79609a0002e5321b74c4d64c64 (diff) |
Merge with 2.4.0-test11.
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r-- | drivers/usb/serial/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/serial/belkin_sa.c | 576 | ||||
-rw-r--r-- | drivers/usb/serial/belkin_sa.h | 113 | ||||
-rw-r--r-- | drivers/usb/serial/digi_acceleport.c | 75 | ||||
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 368 | ||||
-rw-r--r-- | drivers/usb/serial/keyspan.c | 3 | ||||
-rw-r--r-- | drivers/usb/serial/keyspan.h | 121 | ||||
-rw-r--r-- | drivers/usb/serial/keyspan_pda.c | 28 | ||||
-rw-r--r-- | drivers/usb/serial/omninet.c | 16 | ||||
-rw-r--r-- | drivers/usb/serial/usb-serial.h | 7 | ||||
-rw-r--r-- | drivers/usb/serial/usbserial.c | 38 | ||||
-rw-r--r-- | drivers/usb/serial/visor.c | 18 | ||||
-rw-r--r-- | drivers/usb/serial/whiteheat.c | 39 |
13 files changed, 1125 insertions, 278 deletions
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index ce5d7b128..b90d4f52d 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o obj-$(CONFIG_USB_SERIAL_KEYSPAN) += keyspan.o obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT) += digi_acceleport.o +obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o # Objects that export symbols. export-objs := usbserial.o diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c new file mode 100644 index 000000000..8d38a7a9d --- /dev/null +++ b/drivers/usb/serial/belkin_sa.c @@ -0,0 +1,576 @@ +/* + * Belkin USB Serial Adapter Driver + * + * Copyright (C) 2000 + * William Greathouse (wgreathouse@smva.com) + * + * This program is largely derived from work by the linux-usb group + * and associated source files. Please see the usb/serial files for + * individual credits and copyrights. + * + * 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 + * + * TODO: + * -- Add true modem contol line query capability. Currently we track the + * states reported by the interrupt and the states we request. + * -- Add error reporting back to application for UART error conditions. + * Just point me at how to implement this and I'll do it. I've put the + * framework in, but haven't analyzed the "tty_flip" interface yet. + * -- Add support for flush commands + * -- Add everything that is missing :) + * + * (11/06/2000) gkh + * - Added support for the old Belkin and Peracom devices. + * - Made the port able to be opened multiple times. + * - Added some defaults incase the line settings are things these devices + * can't support. + * + * 18-Oct-2000 William Greathouse + * Released into the wild (linux-usb-devel) + * + * 17-Oct-2000 William Greathouse + * Add code to recognize firmware version and set hardware flow control + * appropriately. Belkin states that firmware prior to 3.05 does not + * operate correctly in hardware handshake mode. I have verified this + * on firmware 2.05 -- for both RTS and DTR input flow control, the control + * line is not reset. The test performed by the Belkin Win* driver is + * to enable hardware flow control for firmware 2.06 or greater and + * for 1.00 or prior. I am only enabling for 2.06 or greater. + * + * 12-Oct-2000 William Greathouse + * First cut at supporting Belkin USB Serial Adapter F5U103 + * I did not have a copy of the original work to support this + * adapter, so pardon any stupid mistakes. All of the information + * I am using to write this driver was acquired by using a modified + * UsbSnoop on Windows2000 and from examining the other USB drivers. + */ + +#include <linux/config.h> +#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" +#include "belkin_sa.h" + +/* function prototypes for a Belkin USB Serial Adapter F5U103 */ +static int belkin_sa_startup (struct usb_serial *serial); +static void belkin_sa_shutdown (struct usb_serial *serial); +static int belkin_sa_open (struct usb_serial_port *port, struct file *filp); +static void belkin_sa_close (struct usb_serial_port *port, struct file *filp); +static void belkin_sa_read_int_callback (struct urb *urb); +static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios * old); +static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); +static void belkin_sa_break_ctl (struct usb_serial_port *port, int break_state ); + + +static __devinitdata struct usb_device_id id_table_combined [] = { + { idVendor: BELKIN_SA_VID, idProduct: BELKIN_SA_PID }, + { idVendor: BELKIN_OLD_VID, idProduct: BELKIN_OLD_PID }, + { idVendor: PERACOM_VID, idProduct: PERACOM_PID }, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id belkin_sa_table [] = { + { idVendor: BELKIN_SA_VID, idProduct: BELKIN_SA_PID }, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id belkin_old_table [] = { + { idVendor: BELKIN_OLD_VID, idProduct: BELKIN_OLD_PID }, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id peracom_table [] = { + { idVendor: PERACOM_VID, idProduct: PERACOM_PID }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, id_table_combined); + +/* All of the device info needed for the Belkin serial converter */ +struct usb_serial_device_type belkin_sa_device = { + name: "Belkin F5U103 USB Serial Adapter", + id_table: belkin_sa_table, /* the Belkin F5U103 device */ + needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: belkin_sa_open, + close: belkin_sa_close, + read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */ + ioctl: belkin_sa_ioctl, + set_termios: belkin_sa_set_termios, + break_ctl: belkin_sa_break_ctl, + startup: belkin_sa_startup, + shutdown: belkin_sa_shutdown, +}; + + +/* This driver also supports the "old" school Belkin single port adaptor */ +struct usb_serial_device_type belkin_old_device = { + name: "Belkin USB Serial Adapter", + id_table: belkin_old_table, /* the old Belkin device */ + needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: belkin_sa_open, + close: belkin_sa_close, + read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */ + ioctl: belkin_sa_ioctl, + set_termios: belkin_sa_set_termios, + break_ctl: belkin_sa_break_ctl, + startup: belkin_sa_startup, + shutdown: belkin_sa_shutdown, +}; + +/* this driver also works for the Peracom single port adapter */ +struct usb_serial_device_type peracom_device = { + name: "Peracom single port USB Serial Adapter", + id_table: peracom_table, /* the Peracom device */ + needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: belkin_sa_open, + close: belkin_sa_close, + read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */ + ioctl: belkin_sa_ioctl, + set_termios: belkin_sa_set_termios, + break_ctl: belkin_sa_break_ctl, + startup: belkin_sa_startup, + shutdown: belkin_sa_shutdown, +}; + + +struct belkin_sa_private { + unsigned long control_state; + unsigned char last_lsr; + unsigned char last_msr; + int bad_flow_control; +}; + + +/* + * *************************************************************************** + * Belkin USB Serial Adapter F5U103 specific driver functions + * *************************************************************************** + */ + +#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */ + +/* assumes that struct usb_serial *serial is available */ +#define BSA_USB_CMD(c,v) usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), \ + (c), BELKIN_SA_SET_REQUEST_TYPE, \ + (v), 0, NULL, 0, WDR_TIMEOUT) + +/* do some startup allocations not currently performed by usb_serial_probe() */ +static int belkin_sa_startup (struct usb_serial *serial) +{ + struct usb_device *dev = serial->dev; + struct belkin_sa_private *priv; + + /* allocate the private data structure */ + serial->port->private = kmalloc(sizeof(struct belkin_sa_private), GFP_KERNEL); + if (!serial->port->private) + return (-1); /* error */ + priv = (struct belkin_sa_private *)serial->port->private; + /* set initial values for control structures */ + priv->control_state = 0; + priv->last_lsr = 0; + priv->last_msr = 0; + /* see comments at top of file */ + priv->bad_flow_control = (dev->descriptor.bcdDevice <= 0x0206) ? 1 : 0; + info("bcdDevice: %04x, bfc: %d", dev->descriptor.bcdDevice, priv->bad_flow_control); + + init_waitqueue_head(&serial->port->write_wait); + + return (0); +} + + +static void belkin_sa_shutdown (struct usb_serial *serial) +{ + int i; + + dbg (__FUNCTION__); + + /* stop reads and writes on all ports */ + for (i=0; i < serial->num_ports; ++i) { + while (serial->port[i].open_count > 0) { + belkin_sa_close (&serial->port[i], NULL); + } + /* My special items, the standard routines free my urbs */ + if (serial->port->private) + kfree(serial->port->private); + } +} + + +static int belkin_sa_open (struct usb_serial_port *port, struct file *filp) +{ + unsigned long flags; + + dbg(__FUNCTION__" port %d", port->number); + + spin_lock_irqsave (&port->port_lock, flags); + + ++port->open_count; + MOD_INC_USE_COUNT; + + if (!port->active) { + port->active = 1; + + /*Start reading from the device*/ + /* TODO: Look at possibility of submitting mulitple URBs to device to + * enhance buffering. Win trace shows 16 initial read URBs. + */ + port->read_urb->dev = port->serial->dev; + if (usb_submit_urb(port->read_urb)) + err("usb_submit_urb(read bulk) failed"); + + port->interrupt_in_urb->dev = port->serial->dev; + if (usb_submit_urb(port->interrupt_in_urb)) + err(" usb_submit_urb(read int) failed"); + } + + spin_unlock_irqrestore (&port->port_lock, flags); + + return 0; +} /* belkin_sa_open */ + + +static void belkin_sa_close (struct usb_serial_port *port, struct file *filp) +{ + unsigned long flags; + + dbg(__FUNCTION__" port %d", port->number); + + spin_lock_irqsave (&port->port_lock, flags); + + --port->open_count; + MOD_DEC_USE_COUNT; + + if (port->open_count <= 0) { + /* shutdown our bulk reads and writes */ + usb_unlink_urb (port->write_urb); + usb_unlink_urb (port->read_urb); + usb_unlink_urb (port->interrupt_in_urb); /* wgg - do I need this? I think so. */ + port->active = 0; + } + + spin_unlock_irqrestore (&port->port_lock, flags); +} /* belkin_sa_close */ + + +static void belkin_sa_read_int_callback (struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private; + struct usb_serial *serial; + unsigned char *data = urb->transfer_buffer; + + /* the urb might have been killed. */ + if (urb->status) + return; + + if (port_paranoia_check (port, "belkin_sa_read_interrupt")) return; + + serial = port->serial; + if (serial_paranoia_check (serial, "belkin_sa_read_interrupt")) return; + + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + + /* Handle known interrupt data */ + /* ignore data[0] and data[1] */ + + priv->last_msr = data[BELKIN_SA_MSR_INDEX]; + + /* Record Control Line states */ + if (priv->last_msr & BELKIN_SA_MSR_DSR) + priv->control_state |= TIOCM_DSR; + else + priv->control_state &= ~TIOCM_DSR; + + if (priv->last_msr & BELKIN_SA_MSR_CTS) + priv->control_state |= TIOCM_CTS; + else + priv->control_state &= ~TIOCM_CTS; + + if (priv->last_msr & BELKIN_SA_MSR_RI) + priv->control_state |= TIOCM_RI; + else + priv->control_state &= ~TIOCM_RI; + + if (priv->last_msr & BELKIN_SA_MSR_CD) + priv->control_state |= TIOCM_CD; + else + priv->control_state &= ~TIOCM_CD; + + /* Now to report any errors */ + priv->last_lsr = data[BELKIN_SA_LSR_INDEX]; +#if 0 + /* + * fill in the flip buffer here, but I do not know the relation + * to the current/next receive buffer or characters. I need + * to look in to this before committing any code. + */ + if (priv->last_lsr & BELKIN_SA_LSR_ERR) { + tty = port->tty; + /* Overrun Error */ + if (priv->last_lsr & BELKIN_SA_LSR_OE) { + } + /* Parity Error */ + if (priv->last_lsr & BELKIN_SA_LSR_PE) { + } + /* Framing Error */ + if (priv->last_lsr & BELKIN_SA_LSR_FE) { + } + /* Break Indicator */ + if (priv->last_lsr & BELKIN_SA_LSR_BI) { + } + } +#endif + + /* INT urbs are automatically re-submitted */ +} + +static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios *old_termios) +{ + struct usb_serial *serial = port->serial; + struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private; + unsigned int iflag = port->tty->termios->c_iflag; + unsigned int cflag = port->tty->termios->c_cflag; + unsigned int old_iflag = old_termios->c_iflag; + unsigned int old_cflag = old_termios->c_cflag; + __u16 urb_value = 0; /* Will hold the new flags */ + + /* Set the baud rate */ + if( (cflag&CBAUD) != (old_cflag&CBAUD) ) { + /* reassert DTR and (maybe) RTS on transition from B0 */ + if( (old_cflag&CBAUD) == B0 ) { + priv->control_state |= (TIOCM_DTR|TIOCM_RTS); + if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 1) < 0) + err("Set DTR error"); + /* don't set RTS if using hardware flow control */ + if (!(old_cflag&CRTSCTS) ) + if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 1) < 0) + err("Set RTS error"); + } + + switch(cflag & CBAUD) { + case B0: /* handled below */ break; + case B300: urb_value = BELKIN_SA_BAUD(300); break; + case B600: urb_value = BELKIN_SA_BAUD(600); break; + case B1200: urb_value = BELKIN_SA_BAUD(1200); break; + case B2400: urb_value = BELKIN_SA_BAUD(2400); break; + case B4800: urb_value = BELKIN_SA_BAUD(4800); break; + case B9600: urb_value = BELKIN_SA_BAUD(9600); break; + case B19200: urb_value = BELKIN_SA_BAUD(19200); break; + case B38400: urb_value = BELKIN_SA_BAUD(38400); break; + case B57600: urb_value = BELKIN_SA_BAUD(57600); break; + case B115200: urb_value = BELKIN_SA_BAUD(115200); break; + case B230400: urb_value = BELKIN_SA_BAUD(230400); break; + default: err("BELKIN USB Serial Adapter: unsupported baudrate request, using default of 9600"); + urb_value = BELKIN_SA_BAUD(9600); break; + } + if ((cflag & CBAUD) != B0 ) { + if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0) + err("Set baudrate error"); + } else { + /* Disable flow control */ + if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, BELKIN_SA_FLOW_NONE) < 0) + err("Disable flowcontrol error"); + + /* Drop RTS and DTR */ + priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); + if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 0) < 0) + err("DTR LOW error"); + if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 0) < 0) + err("RTS LOW error"); + } + } + + /* set the parity */ + if( (cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD)) ) { + if (cflag & PARENB) + urb_value = (cflag & PARODD) ? BELKIN_SA_PARITY_ODD : BELKIN_SA_PARITY_EVEN; + else + urb_value = BELKIN_SA_PARITY_NONE; + if (BSA_USB_CMD(BELKIN_SA_SET_PARITY_REQUEST, urb_value) < 0) + err("Set parity error"); + } + + /* set the number of data bits */ + if( (cflag&CSIZE) != (old_cflag&CSIZE) ) { + switch (cflag & CSIZE) { + case CS5: urb_value = BELKIN_SA_DATA_BITS(5); break; + case CS6: urb_value = BELKIN_SA_DATA_BITS(6); break; + case CS7: urb_value = BELKIN_SA_DATA_BITS(7); break; + case CS8: urb_value = BELKIN_SA_DATA_BITS(8); break; + default: err("CSIZE was not CS5-CS8, using default of 8"); + urb_value = BELKIN_SA_DATA_BITS(8); + break; + } + if (BSA_USB_CMD(BELKIN_SA_SET_DATA_BITS_REQUEST, urb_value) < 0) + err("Set data bits error"); + } + + /* set the number of stop bits */ + if( (cflag&CSTOPB) != (old_cflag&CSTOPB) ) { + urb_value = (cflag & CSTOPB) ? BELKIN_SA_STOP_BITS(2) : BELKIN_SA_STOP_BITS(1); + if (BSA_USB_CMD(BELKIN_SA_SET_STOP_BITS_REQUEST, urb_value) < 0) + err("Set stop bits error"); + } + + /* Set flow control */ + if( (iflag&IXOFF) != (old_iflag&IXOFF) + || (iflag&IXON) != (old_iflag&IXON) + || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) { + urb_value = 0; + if ((iflag & IXOFF) || (iflag & IXON)) + urb_value |= (BELKIN_SA_FLOW_OXON | BELKIN_SA_FLOW_IXON); + else + urb_value &= ~(BELKIN_SA_FLOW_OXON | BELKIN_SA_FLOW_IXON); + + if (cflag & CRTSCTS) + urb_value |= (BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS); + else + urb_value &= ~(BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS); + + if (priv->bad_flow_control) + urb_value &= ~(BELKIN_SA_FLOW_IRTS); + + if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, urb_value) < 0) + err("Set flow control error"); + } +} /* belkin_sa_set_termios */ + + +static void belkin_sa_break_ctl( struct usb_serial_port *port, int break_state ) +{ + struct usb_serial *serial = port->serial; + + if (BSA_USB_CMD(BELKIN_SA_SET_BREAK_REQUEST, break_state ? 1 : 0) < 0) + err("Set break_ctl %d", break_state); +} + + +static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) +{ + struct usb_serial *serial = port->serial; + __u16 urb_value; /* Will hold the new flags */ + struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private; + int ret, mask; + + /* Based on code from acm.c and others */ + switch (cmd) { + case TIOCMGET: + return put_user(priv->control_state, (unsigned long *) arg); + break; + + case TIOCMSET: /* Turns on and off the lines as specified by the mask */ + case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */ + case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */ + if ((ret = get_user(mask, (unsigned long *) arg))) return ret; + + if ((cmd == TIOCMSET) || (mask & TIOCM_RTS)) { + /* RTS needs set */ + urb_value = ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) || (cmd == TIOCMBIS) ? 1 : 0; + if (urb_value) + priv->control_state |= TIOCM_RTS; + else + priv->control_state &= ~TIOCM_RTS; + + if ((ret = BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, urb_value)) < 0) { + err("Set RTS error %d", ret); + return(ret); + } + } + + if ((cmd == TIOCMSET) || (mask & TIOCM_DTR)) { + /* DTR needs set */ + urb_value = ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) || (cmd == TIOCMBIS) ? 1 : 0; + if (urb_value) + priv->control_state |= TIOCM_DTR; + else + priv->control_state &= ~TIOCM_DTR; + if ((ret = BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, urb_value)) < 0) { + err("Set DTR error %d", ret); + return(ret); + } + } + break; + + case TIOCMIWAIT: + /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/ + /* TODO */ + return( 0 ); + + case TIOCGICOUNT: + /* return count of modemline transitions */ + /* TODO */ + return 0; + + default: + dbg("belkin_sa_ioctl arg not supported - 0x%04x",cmd); + return(-ENOIOCTLCMD); + break; + } + return 0; +} /* belkin_sa_ioctl */ + + +static int __init belkin_sa_init (void) +{ + usb_serial_register (&belkin_sa_device); + usb_serial_register (&belkin_old_device); + usb_serial_register (&peracom_device); + return 0; +} + + +static void __exit belkin_sa_exit (void) +{ + usb_serial_deregister (&belkin_sa_device); + usb_serial_deregister (&belkin_old_device); + usb_serial_deregister (&peracom_device); +} + + +module_init (belkin_sa_init); +module_exit (belkin_sa_exit); + +MODULE_DESCRIPTION("USB Belkin Serial converter driver"); diff --git a/drivers/usb/serial/belkin_sa.h b/drivers/usb/serial/belkin_sa.h new file mode 100644 index 000000000..ee3603863 --- /dev/null +++ b/drivers/usb/serial/belkin_sa.h @@ -0,0 +1,113 @@ +/* + * Definitions for Belkin USB Serial Adapter Driver + * + * Copyright (C) 2000 + * William Greathouse (wgreathouse@smva.com) + * + * This program is largely derived from work by the linux-usb group + * and associated source files. Please see the usb/serial files for + * individual credits and copyrights. + * + * 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 + * + * (11/06/2000) gkh + * Added old Belkin and Peracom device ids, which this driver supports + * + * 12-Oct-2000 William Greathouse + * First cut at supporting Belkin USB Serial Adapter F5U103 + * I did not have a copy of the original work to support this + * adapter, so pardon any stupid mistakes. All of the information + * I am using to write this driver was acquired by using a modified + * UsbSnoop on Windows2000. + * + */ + +#ifndef __LINUX_USB_SERIAL_BSA_H +#define __LINUX_USB_SERIAL_BSA_H + +#define BELKIN_SA_VID 0x050d /* Vendor Id */ +#define BELKIN_SA_PID 0x0103 /* Product Id */ + +#define BELKIN_OLD_VID 0x056c /* Belkin's "old" vendor id */ +#define BELKIN_OLD_PID 0x8007 /* Belkin's "old" single port serial converter's id */ + +#define PERACOM_VID 0x0565 /* Peracom's vendor id */ +#define PERACOM_PID 0x0001 /* Peracom's single port serial converter's id */ + +/* Vendor Request Interface */ +#define BELKIN_SA_SET_BAUDRATE_REQUEST 0 /* Set baud rate */ +#define BELKIN_SA_SET_STOP_BITS_REQUEST 1 /* Set stop bits (1,2) */ +#define BELKIN_SA_SET_DATA_BITS_REQUEST 2 /* Set data bits (5,6,7,8) */ +#define BELKIN_SA_SET_PARITY_REQUEST 3 /* Set parity (None, Even, Odd) */ + +#define BELKIN_SA_SET_DTR_REQUEST 10 /* Set DTR state */ +#define BELKIN_SA_SET_RTS_REQUEST 11 /* Set RTS state */ +#define BELKIN_SA_SET_BREAK_REQUEST 12 /* Set BREAK state */ + +#define BELKIN_SA_SET_FLOW_CTRL_REQUEST 16 /* Set flow control mode */ + + +#ifdef WHEN_I_LEARN_THIS +#define BELKIN_SA_SET_MAGIC_REQUEST 17 /* I don't know, possibly flush */ + /* (always in Wininit sequence before flow control) */ +#define BELKIN_SA_RESET xx /* Reset the port */ +#define BELKIN_SA_GET_MODEM_STATUS xx /* Force return of modem status register */ +#endif + +#define BELKIN_SA_SET_REQUEST_TYPE 0x40 + +#define BELKIN_SA_BAUD(b) (230400/b) + +#define BELKIN_SA_STOP_BITS(b) (b-1) + +#define BELKIN_SA_DATA_BITS(b) (b-5) + +#define BELKIN_SA_PARITY_NONE 0 +#define BELKIN_SA_PARITY_EVEN 1 +#define BELKIN_SA_PARITY_ODD 2 +#define BELKIN_SA_PARITY_MARK 3 +#define BELKIN_SA_PARITY_SPACE 4 + +#define BELKIN_SA_FLOW_NONE 0x0000 /* No flow control */ +#define BELKIN_SA_FLOW_OCTS 0x0001 /* use CTS input to throttle output */ +#define BELKIN_SA_FLOW_ODSR 0x0002 /* use DSR input to throttle output */ +#define BELKIN_SA_FLOW_IDSR 0x0004 /* use DSR input to enable receive */ +#define BELKIN_SA_FLOW_IDTR 0x0008 /* use DTR output for input flow control */ +#define BELKIN_SA_FLOW_IRTS 0x0010 /* use RTS output for input flow control */ +#define BELKIN_SA_FLOW_ORTS 0x0020 /* use RTS to indicate data available to send */ +#define BELKIN_SA_FLOW_ERRSUB 0x0040 /* ???? guess ???? substitute inline errors */ +#define BELKIN_SA_FLOW_OXON 0x0080 /* use XON/XOFF for output flow control */ +#define BELKIN_SA_FLOW_IXON 0x0100 /* use XON/XOFF for input flow control */ + +/* + * It seems that the interrupt pipe is closely modelled after the + * 16550 register layout. This is probably because the adapter can + * be used in a "DOS" environment to simulate a standard hardware port. + */ +#define BELKIN_SA_LSR_INDEX 2 /* Line Status Register */ +#define BELKIN_SA_LSR_RDR 0x01 /* receive data ready */ +#define BELKIN_SA_LSR_OE 0x02 /* overrun error */ +#define BELKIN_SA_LSR_PE 0x04 /* parity error */ +#define BELKIN_SA_LSR_FE 0x08 /* framing error */ +#define BELKIN_SA_LSR_BI 0x10 /* break indicator */ +#define BELKIN_SA_LSR_THE 0x20 /* transmit holding register empty */ +#define BELKIN_SA_LSR_TE 0x40 /* transmit register empty */ +#define BELKIN_SA_LSR_ERR 0x80 /* OE | PE | FE | BI */ + +#define BELKIN_SA_MSR_INDEX 3 /* Modem Status Register */ +#define BELKIN_SA_MSR_DCTS 0x01 /* Delta CTS */ +#define BELKIN_SA_MSR_DDSR 0x02 /* Delta DSR */ +#define BELKIN_SA_MSR_DRI 0x04 /* Delta RI */ +#define BELKIN_SA_MSR_DCD 0x08 /* Delta CD */ +#define BELKIN_SA_MSR_CTS 0x10 /* Current CTS */ +#define BELKIN_SA_MSR_DSR 0x20 /* Current DSR */ +#define BELKIN_SA_MSR_RI 0x40 /* Current RI */ +#define BELKIN_SA_MSR_CD 0x80 /* Current CD */ + +#endif /* __LINUX_USB_SERIAL_BSA_H */ + diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index f5635bb01..197752224 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -1,5 +1,5 @@ /* -* Digi AccelePort USB-4 Serial Converter +* Digi AccelePort USB-4 and USB-2 Serial Converters * * Copyright 2000 by Digi International * @@ -14,6 +14,16 @@ * Peter Berger (pberger@brimson.com) * Al Borchers (borchers@steinerpoint.com) * +* (11/01/2000) Adam J. Richter +* usb_device_id table support +* +* (11/01/2000) pberger and borchers +* -- Turned off the USB_DISABLE_SPD flag for write bulk urbs--it caused +* USB 4 ports to hang on startup. +* -- Serialized access to write urbs by adding the dp_write_urb_in_use +* flag; otherwise, the driver caused SMP system hangs. Watching the +* urb status is not sufficient. +* * (10/05/2000) gkh * -- Fixed bug with urb->dev not being set properly, now that the usb * core needs it. @@ -213,7 +223,7 @@ * - Following Documentation/DocBook/kernel-locking.pdf no spin locks * are held when calling copy_to/from_user or printk. * -* $Id: digi_acceleport.c,v 1.80 2000/08/09 06:36:18 root Exp $ +* $Id: digi_acceleport.c,v 1.80.1.2 2000/11/02 05:45:08 root Exp $ */ #include <linux/config.h> @@ -411,6 +421,7 @@ typedef struct digi_port { int dp_in_buf_len; unsigned char dp_in_buf[DIGI_IN_BUF_SIZE]; unsigned char dp_in_flag_buf[DIGI_IN_BUF_SIZE]; + int dp_write_urb_in_use; unsigned int dp_modem_signals; wait_queue_head_t dp_modem_change_wait; int dp_open_count; /* inc on open, dec on close */ @@ -461,15 +472,29 @@ static int digi_read_oob_callback( struct urb *urb ); /* Statics */ +static __devinitdata struct usb_device_id id_table_combined [] = { + { idVendor: DIGI_VENDOR_ID, idProduct: DIGI_2_ID }, + { idVendor: DIGI_VENDOR_ID, idProduct: DIGI_4_ID }, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id id_table_2 [] = { + { idVendor: DIGI_VENDOR_ID, idProduct: DIGI_2_ID }, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id id_table_4 [] = { + { idVendor: DIGI_VENDOR_ID, idProduct: DIGI_4_ID }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, id_table_combined); + /* device info needed for the Digi serial converter */ -static u16 digi_vendor_id = DIGI_VENDOR_ID; -static u16 digi_product_2_id = DIGI_2_ID; /* USB 2 */ -static u16 digi_product_4_id = DIGI_4_ID; /* USB 4 */ static struct usb_serial_device_type digi_acceleport_2_device = { name: "Digi USB", - idVendor: &digi_vendor_id, - idProduct: &digi_product_2_id, + id_table: id_table_2, needs_interrupt_in: DONT_CARE, needs_bulk_in: MUST_HAVE, needs_bulk_out: MUST_HAVE, @@ -495,8 +520,7 @@ static struct usb_serial_device_type digi_acceleport_2_device = { static struct usb_serial_device_type digi_acceleport_4_device = { name: "Digi USB", - idVendor: &digi_vendor_id, - idProduct: &digi_product_4_id, + id_table: id_table_4, needs_interrupt_in: DONT_CARE, needs_bulk_in: MUST_HAVE, needs_bulk_out: MUST_HAVE, @@ -629,7 +653,8 @@ dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, co while( count > 0 ) { - while( oob_port->write_urb->status == -EINPROGRESS ) { + while( oob_port->write_urb->status == -EINPROGRESS + || oob_priv->dp_write_urb_in_use ) { cond_wait_interruptible_timeout_irqrestore( &oob_port->write_wait, DIGI_RETRY_TIMEOUT, &oob_priv->dp_port_lock, flags ); @@ -647,8 +672,9 @@ dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, co memcpy( oob_port->write_urb->transfer_buffer, buf, len ); oob_port->write_urb->transfer_buffer_length = len; oob_port->write_urb->dev = port->serial->dev; - + if( (ret=usb_submit_urb(oob_port->write_urb)) == 0 ) { + oob_priv->dp_write_urb_in_use = 1; count -= len; buf += len; } @@ -702,8 +728,8 @@ count ); while( count > 0 && ret == 0 ) { - while( port->write_urb->status == -EINPROGRESS - && jiffies < timeout ) { + while( (port->write_urb->status == -EINPROGRESS + || priv->dp_write_urb_in_use) && jiffies < timeout ) { cond_wait_interruptible_timeout_irqrestore( &port->write_wait, DIGI_RETRY_TIMEOUT, &priv->dp_port_lock, flags ); @@ -736,6 +762,7 @@ count ); port->write_urb->dev = port->serial->dev; if( (ret=usb_submit_urb(port->write_urb)) == 0 ) { + priv->dp_write_urb_in_use = 1; priv->dp_out_buf_len = 0; count -= len; buf += len; @@ -783,7 +810,8 @@ port_priv->dp_port_num, modem_signals ); spin_lock_irqsave( &oob_priv->dp_port_lock, flags ); spin_lock( &port_priv->dp_port_lock ); - while( oob_port->write_urb->status == -EINPROGRESS ) { + while( oob_port->write_urb->status == -EINPROGRESS + || oob_priv->dp_write_urb_in_use ) { spin_unlock( &port_priv->dp_port_lock ); cond_wait_interruptible_timeout_irqrestore( &oob_port->write_wait, DIGI_RETRY_TIMEOUT, @@ -811,6 +839,7 @@ port_priv->dp_port_num, modem_signals ); oob_port->write_urb->dev = port->serial->dev; if( (ret=usb_submit_urb(oob_port->write_urb)) == 0 ) { + oob_priv->dp_write_urb_in_use = 1; port_priv->dp_modem_signals = (port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS)) | (modem_signals&(TIOCM_DTR|TIOCM_RTS)); @@ -1249,7 +1278,8 @@ priv->dp_port_num, count, from_user, in_interrupt() ); spin_lock_irqsave( &priv->dp_port_lock, flags ); /* wait for urb status clear to submit another urb */ - if( port->write_urb->status == -EINPROGRESS ) { + if( port->write_urb->status == -EINPROGRESS + || priv->dp_write_urb_in_use ) { /* buffer data if count is 1 (probably put_char) if possible */ if( count == 1 ) { @@ -1292,6 +1322,7 @@ priv->dp_port_num, count, from_user, in_interrupt() ); memcpy( data, from_user ? user_buf : buf, new_len ); if( (ret=usb_submit_urb(port->write_urb)) == 0 ) { + priv->dp_write_urb_in_use = 1; ret = new_len; priv->dp_out_buf_len = 0; } @@ -1337,6 +1368,7 @@ dbg( "digi_write_bulk_callback: TOP, urb->status=%d", urb->status ); == ((digi_serial_t *)(serial->private))->ds_oob_port_num ) { dbg( "digi_write_bulk_callback: oob callback" ); spin_lock( &priv->dp_port_lock ); + priv->dp_write_urb_in_use = 0; wake_up_interruptible( &port->write_wait ); spin_unlock( &priv->dp_port_lock ); return; @@ -1349,6 +1381,7 @@ dbg( "digi_write_bulk_callback: TOP, urb->status=%d", urb->status ); /* try to send any buffered data on this port, if it is open */ spin_lock( &priv->dp_port_lock ); + priv->dp_write_urb_in_use = 0; if( priv->dp_open_count && port->write_urb->status != -EINPROGRESS && priv->dp_out_buf_len > 0 ) { @@ -1365,6 +1398,7 @@ dbg( "digi_write_bulk_callback: TOP, urb->status=%d", urb->status ); priv->dp_out_buf_len ); if( (ret=usb_submit_urb(port->write_urb)) == 0 ) { + priv->dp_write_urb_in_use = 1; priv->dp_out_buf_len = 0; } @@ -1397,7 +1431,8 @@ static int digi_write_room( struct usb_serial_port *port ) spin_lock_irqsave( &priv->dp_port_lock, flags ); - if( port->write_urb->status == -EINPROGRESS ) + if( port->write_urb->status == -EINPROGRESS + || priv->dp_write_urb_in_use ) room = 0; else room = port->bulk_out_size - 2 - priv->dp_out_buf_len; @@ -1416,7 +1451,8 @@ static int digi_chars_in_buffer( struct usb_serial_port *port ) digi_port_t *priv = (digi_port_t *)(port->private); - if( port->write_urb->status == -EINPROGRESS ) { + if( port->write_urb->status == -EINPROGRESS + || priv->dp_write_urb_in_use ) { dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, port->bulk_out_size - 2 ); /* return( port->bulk_out_size - 2 ); */ return( 256 ); @@ -1601,6 +1637,7 @@ dbg( "digi_close: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, po spin_lock_irqsave( &priv->dp_port_lock, flags ); port->active = 0; + priv->dp_write_urb_in_use = 0; priv->dp_in_close = 0; --priv->dp_open_count; MOD_DEC_USE_COUNT; @@ -1641,7 +1678,6 @@ static int digi_startup_device( struct usb_serial *serial ) port = &serial->port[i]; - port->write_urb->transfer_flags |= USB_DISABLE_SPD; port->write_urb->dev = port->serial->dev; if( (ret=usb_submit_urb(port->read_urb)) != 0 ) { @@ -1689,6 +1725,7 @@ dbg( "digi_startup: TOP" ); priv->dp_port_num = i; priv->dp_out_buf_len = 0; priv->dp_in_buf_len = 0; + priv->dp_write_urb_in_use = 0; priv->dp_modem_signals = 0; init_waitqueue_head( &priv->dp_modem_change_wait ); priv->dp_open_count = 0; @@ -2047,5 +2084,5 @@ module_exit(digi_exit); MODULE_AUTHOR("Peter Berger <pberger@brimson.com>, Al Borchers <borchers@steinerpoint.com>"); -MODULE_DESCRIPTION("Digi AccelePort USB-4 Serial Converter driver"); +MODULE_DESCRIPTION("Digi AccelePort USB-2/USB-4 Serial Converter driver"); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 70f4cd1b0..fcdf71e84 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -12,6 +12,16 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (11/13/2000) Bill Ryder + * Added spinlock protected open code and close code. + * Multiple opens work (sort of - see webpage). + * Cleaned up comments. Removed multiple PID/VID definitions. + * Factorised cts/dtr code + * Made use of __FUNCTION__ in dbg's + * + * (11/01/2000) Adam J. Richter + * usb_device_id table support + * * (10/05/2000) gkh * Fixed bug with urb->dev not being set properly, now that the usb * core needs it. @@ -68,8 +78,17 @@ #include "ftdi_sio.h" -#define FTDI_VENDOR_ID 0x0403 -#define FTDI_SIO_SERIAL_CONVERTER_ID 0x8372 +#define FTDI_VENDOR_ID FTDI_VID +#define FTDI_SIO_SERIAL_CONVERTER_ID FTDI_SIO_PID +#define FTDI_8U232AM_PID 0x6001 + +static __devinitdata struct usb_device_id id_table_sio [] = { + { idVendor: FTDI_VID, idProduct: FTDI_SIO_PID }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, id_table_sio); + /* function prototypes for a FTDI serial converter */ static int ftdi_sio_startup (struct usb_serial *serial); @@ -82,12 +101,9 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios * static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); /* All of the device info needed for the FTDI SIO serial converter */ -static __u16 ftdi_vendor_id = FTDI_VENDOR_ID; -static __u16 ftdi_sio_product_id = FTDI_SIO_SERIAL_CONVERTER_ID; struct usb_serial_device_type ftdi_sio_device = { name: "FTDI SIO", - idVendor: &ftdi_vendor_id, /* the FTDI vendor ID */ - idProduct: &ftdi_sio_product_id, /* the FTDI SIO product id */ + id_table: id_table_sio, needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ @@ -105,63 +121,55 @@ struct usb_serial_device_type ftdi_sio_device = { startup: ftdi_sio_startup, }; - /* * *************************************************************************** * FTDI SIO Serial Converter specific driver functions * *************************************************************************** * - * Bill Ryder bryder@sgi.com of Silicon Graphics, Inc. did the FTDI_SIO code - * Thanx to FTDI for so kindly providing details of the protocol required - * to talk to the device - http://www.ftdi.co.uk - * - * Tested as at this version - other stuff might work - * 23 March 2000 - * Works: - * Baudrates - 9600, 38400,19200, 57600, 115200 - * TIOCMBIC - TIOCM_DTR / TIOCM_RTS - * TIOCMBIS - TIOCM_DTR / TIOCM_RTS - * TIOCMSET - DTR on/RTSon / DTR off, RTS off - * no parity:CS8 even parity:CS7 odd parity:CS7 - * CRTSCTS flow control - * - * Pilot-xfer zillions of times - * - * cu works with dir option - * - * Not Tested (ie might not work): - * xon/xoff flow control - * ppp (modem handling in general) - * - * KNOWN BUGS: - * Multiple Opens - * ============== - * Seems to have problem when opening an already open port, - * Get I/O error on first attempt, then it lets you in. - * Need to do proper usage counting - keep registered callbacks for first opener. - * - * Reproduce with: - * cu -l /dev/ttyUSB0 dir - * whilst cu is running do: - * stty -a < /dev/ttyUSB0 - * - * from stty get: 'bash: /dev/ttyUSB0: Invalid argument ' - * from cu get - * write: Invalid argument - * - * Initialisation Problem - * ====================== - * Pilot transfer required me to run the serial_loopback program before it would work. - * Still working on this. See the webpage http://reality.sgi.com/bryder_wellington/ftdi_sio + * See the webpage http://reality.sgi.com/bryder_wellington/ftdi_sio for upto date + * testing information + * * */ #define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */ +/* utility functions to set and unset dtr and rts */ +#define HIGH 1 +#define LOW 0 +static int set_rts(struct usb_device *dev, + unsigned int pipe, + int high_or_low) +{ + static char buf[1]; + unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_RTS_HIGH : + FTDI_SIO_SET_RTS_LOW); + return(usb_control_msg(dev, pipe, + FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + ftdi_high_or_low, 0, + buf, 0, WDR_TIMEOUT)); +} +static int set_dtr(struct usb_device *dev, + unsigned int pipe, + int high_or_low) +{ + static char buf[1]; + unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_DTR_HIGH : + FTDI_SIO_SET_DTR_LOW); + return(usb_control_msg(dev, pipe, + FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + ftdi_high_or_low, 0, + buf, 0, WDR_TIMEOUT)); +} + + /* do some startup allocations not currently performed by usb_serial_probe() */ static int ftdi_sio_startup (struct usb_serial *serial) { init_waitqueue_head(&serial->port[0].write_wait); + return (0); } @@ -170,65 +178,55 @@ static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp) { /* ftdi_sio_open */ struct termios tmp_termios; struct usb_serial *serial = port->serial; + unsigned long flags; /* Used for spinlock */ int result; char buf[1]; /* Needed for the usb_control_msg I think */ - dbg("ftdi_sio_open port %d", port->number); + dbg(__FUNCTION__ " port %d", port->number); - /* FIXME - multiple concurrent opens cause trouble */ - if (port->active) { - err ("port already open"); - return -EINVAL; - } - port->active = 1; /* FIXME - For multiple open this should increment */ + spin_lock_irqsave (&port->port_lock, flags); + + MOD_INC_USE_COUNT; + ++port->open_count; - /* See ftdi_sio.h for description of what is reset */ - usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, - FTDI_SIO_RESET_SIO, - 0, buf, 0, WDR_TIMEOUT); + if (!port->active){ + port->active = 1; + spin_unlock_irqrestore (&port->port_lock, flags); - /* Setup termios */ - port->tty->termios->c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; + /* See ftdi_sio.h for description of what is reset */ + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, + FTDI_SIO_RESET_SIO, + 0, buf, 0, WDR_TIMEOUT); - - ftdi_sio_set_termios(port, &tmp_termios); + /* Setup termios */ + port->tty->termios->c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; - /* Disable flow control */ - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, - FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, - buf, 0, WDR_TIMEOUT) < 0) { - err("error from flowcontrol urb"); - return(-EINVAL); - } - - /* Turn on RTS and DTR since we are not flow controlling*/ - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - (unsigned)FTDI_SIO_SET_DTR_HIGH, 0, - buf, 0, WDR_TIMEOUT) < 0) { - err("Error from DTR HIGH urb"); - } - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - (unsigned)FTDI_SIO_SET_RTS_HIGH, 0, - buf, 0, WDR_TIMEOUT) < 0) { - err("Error from RTS HIGH urb"); - } + /* ftdi_sio_set_termios will send usb control messages */ + /* ftdi_sio_set_termios will set up port according to above list */ + + ftdi_sio_set_termios(port, &tmp_termios); + + /* Turn on RTS and DTR since we are not flow controlling*/ + if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) { + err("Error from DTR HIGH urb"); + } + if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){ + err("Error from RTS HIGH urb"); + } - /* Start reading from the device */ - FILL_BULK_URB(port->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, - ftdi_sio_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb); - if (result) - err(__FUNCTION__ " - failed submitting read urb, error %d", result); + /* Start reading from the device */ + FILL_BULK_URB(port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, + ftdi_sio_read_bulk_callback, port); + result = usb_submit_urb(port->read_urb); + if (result) + err(__FUNCTION__ " - failed submitting read urb, error %d", result); + } else { /* the port was already active - so no initialisation was done */ + spin_unlock_irqrestore (&port->port_lock, flags); + } return (0); } /* ftdi_sio_open */ @@ -239,41 +237,48 @@ static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp) struct usb_serial *serial = port->serial; unsigned int c_cflag = port->tty->termios->c_cflag; char buf[1]; + unsigned long flags; + + dbg( __FUNCTION__ " port %d", port->number); + + spin_lock_irqsave (&port->port_lock, flags); + --port->open_count; + + if (port->open_count <= 0) { + spin_unlock_irqrestore (&port->port_lock, flags); + if (c_cflag & HUPCL){ + /* Disable flow control */ + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, + 0, 0, + buf, 0, WDR_TIMEOUT) < 0) { + err("error from flowcontrol urb"); + } + + /* drop DTR */ + if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), LOW) < 0){ + err("Error from DTR LOW urb"); + } + /* drop RTS */ + if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0) { + err("Error from RTS LOW urb"); + } + } /* Note change no line is hupcl is off */ + + /* shutdown our bulk reads and writes */ + usb_unlink_urb (port->write_urb); + usb_unlink_urb (port->read_urb); + port->active = 0; + port->open_count = 0; + } else { + spin_unlock_irqrestore (&port->port_lock, flags); + } + + MOD_DEC_USE_COUNT; - dbg("ftdi_sio_close port %d", port->number); - - if (c_cflag & HUPCL){ - /* Disable flow control */ - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, - FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, - buf, 0, WDR_TIMEOUT) < 0) { - err("error from flowcontrol urb"); - } - /* drop DTR */ - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - (unsigned)FTDI_SIO_SET_DTR_LOW, 0, - buf, 0, WDR_TIMEOUT) < 0) { - err("Error from DTR LOW urb"); - } - /* drop RTS */ - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - (unsigned)FTDI_SIO_SET_RTS_LOW, 0, - buf, 0, WDR_TIMEOUT) < 0) { - err("Error from RTS LOW urb"); - } - } - /* shutdown our bulk reads and writes */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->read_urb); - port->active = 0; } /* ftdi_sio_close */ @@ -292,7 +297,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user, int result; DECLARE_WAITQUEUE(wait, current); - dbg("ftdi_sio_serial_write port %d, %d bytes", port->number, count); + dbg(__FUNCTION__ " port %d, %d bytes", port->number, count); if (count == 0) { err("write request of 0 bytes"); @@ -309,8 +314,10 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user, add_wait_queue(&port->write_wait, &wait); set_current_state (TASK_INTERRUPTIBLE); while (port->write_urb->status == -EINPROGRESS) { - dbg("ftdi_sio - write in progress - retrying"); + dbg(__FUNCTION__ " write in progress - retrying"); if (0 /* file->f_flags & O_NONBLOCK */) { + remove_wait_queue(&port->write_wait, &wait); + set_current_state(TASK_RUNNING); rc = -EAGAIN; goto err; } @@ -321,6 +328,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user, goto err; } schedule(); + set_current_state (TASK_INTERRUPTIBLE); } remove_wait_queue(&port->write_wait, &wait); set_current_state(TASK_RUNNING); @@ -345,7 +353,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user, first_byte = port->write_urb->transfer_buffer; *first_byte = 1 | ((count-data_offset) << 2) ; - dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]); + dbg(__FUNCTION__ "Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]); usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte); /* send the data out the bulk port */ @@ -360,7 +368,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user, return 0; } - dbg("write returning: %d", count - data_offset); + dbg(__FUNCTION__ " write returning: %d", count - data_offset); return (count - data_offset); } @@ -412,7 +420,7 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb) int i; int result; - dbg("ftdi_sio read callback"); + dbg(__FUNCTION__); if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) { return; @@ -422,10 +430,6 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb) if (serial_paranoia_check (serial, "ftdi_sio_read_bulk_callback")) { return; } - - /* TO DO -- check for hung up line and handle appropriately: */ - /* send hangup (need to find out how to do this) */ - if (urb->status) { /* This will happen at close every time so it is a dbg not an err */ @@ -439,6 +443,12 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb) dbg("Just status"); } + /* TO DO -- check for hung up line and handle appropriately: */ + /* send hangup (need to find out how to do this) */ + /* See acm.c - you do a tty_hangup - eg tty_hangup(tty) */ + /* if CD is dropped and the line is not CLOCAL then we should hangup */ + + if (urb->actual_length > data_offset) { for (i = data_offset ; i < urb->actual_length ; ++i) { tty_insert_flip_char(tty, data[i], 0); @@ -468,10 +478,10 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios * { /* ftdi_sio_set_termios */ struct usb_serial *serial = port->serial; unsigned int cflag = port->tty->termios->c_cflag; - __u16 urb_value; /* Will hold the new flags */ + __u16 urb_value; /* will hold the new flags */ char buf[1]; /* Perhaps I should dynamically alloc this? */ - dbg("ftdi_sio_set_termios port %d", port->number); + dbg(__FUNCTION__ " port %d", port->number); /* FIXME -For this cut I don't care if the line is really changing or @@ -522,7 +532,7 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios * case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break; case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break; case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break; - default: dbg("FTDI_SIO does not support the baudrate requested"); + default: dbg(__FUNCTION__ "FTDI_SIO does not support the baudrate requested"); /* FIXME - how to return an error for this? */ break; } if ((cflag & CBAUD) == B0 ) { @@ -535,18 +545,10 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios * err("error from disable flowcontrol urb"); } /* Drop RTS and DTR */ - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - (unsigned)FTDI_SIO_SET_DTR_LOW, 0, - buf, 0, WDR_TIMEOUT) < 0) { + if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){ err("Error from DTR LOW urb"); } - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - (unsigned)FTDI_SIO_SET_RTS_LOW, 0, - buf, 0, WDR_TIMEOUT) < 0) { + if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){ err("Error from RTS LOW urb"); } @@ -563,7 +565,7 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios * /* Set flow control */ /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ if (cflag & CRTSCTS) { - dbg("Setting to CRTSCTS flow control"); + dbg(__FUNCTION__ "Setting to CRTSCTS flow control"); if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, @@ -576,7 +578,7 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios * } else { /* CHECK Assuming XON/XOFF handled by stack - not by device */ /* Disable flow control */ - dbg("Turning off hardware flow control"); + dbg(__FUNCTION__ "Turning off hardware flow control"); if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, @@ -597,13 +599,13 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns char buf[1]; int ret, mask; - dbg("ftdi_sio_ioctl - cmd 0x%04x", cmd); + dbg(__FUNCTION__ " cmd 0x%04x", cmd); /* Based on code from acm.c and others */ switch (cmd) { case TIOCMGET: - dbg("TIOCMGET"); + dbg(__FUNCTION__ "TIOCMGET"); /* Request the status from the device */ if ((ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), @@ -611,7 +613,7 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, 0, 0, buf, 1, HZ * 5)) < 0 ) { - dbg("Get not get modem status of device"); + dbg(__FUNCTION__ "Get not get modem status of device"); return(ret); } @@ -623,7 +625,7 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns break; case TIOCMSET: /* Turns on and off the lines as specified by the mask */ - dbg("TIOCMSET"); + dbg(__FUNCTION__ "TIOCMSET"); if ((ret = get_user(mask, (unsigned long *) arg))) return ret; urb_value = ((mask & TIOCM_DTR) ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW); if ((ret = usb_control_msg(serial->dev, @@ -648,26 +650,20 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns break; case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */ - dbg("TIOCMBIS"); + dbg(__FUNCTION__ "TIOCMBIS"); if ((ret = get_user(mask, (unsigned long *) arg))) return ret; if (mask & TIOCM_DTR){ - if ((ret = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - FTDI_SIO_SET_DTR_HIGH , 0, - buf, 0, WDR_TIMEOUT)) < 0){ + if ((ret = set_dtr(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + HIGH)) < 0) { err("Urb to set DTR failed"); return(ret); - } } - if (mask & TIOCM_RTS) { - if ((ret = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - FTDI_SIO_SET_RTS_HIGH , 0, - buf, 0, WDR_TIMEOUT)) < 0){ + } + if (mask & TIOCM_RTS) { + if ((ret = set_rts(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + HIGH)) < 0){ err("Urb to set RTS failed"); return(ret); } @@ -675,26 +671,20 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns break; case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */ - dbg("TIOCMBIC"); + dbg(__FUNCTION__ "TIOCMBIC"); if ((ret = get_user(mask, (unsigned long *) arg))) return ret; if (mask & TIOCM_DTR){ - if ((ret = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - FTDI_SIO_SET_DTR_LOW , 0, - buf, 0, WDR_TIMEOUT)) < 0){ + if ((ret = set_dtr(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + LOW)) < 0){ err("Urb to unset DTR failed"); return(ret); } } if (mask & TIOCM_RTS) { - if ((ret = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - FTDI_SIO_SET_RTS_LOW , 0, - buf, 0, WDR_TIMEOUT)) < 0){ + if ((ret = set_rts(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + LOW)) < 0){ err("Urb to unset RTS failed"); return(ret); } @@ -714,11 +704,11 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns /* This is not an error - turns out the higher layers will do * some ioctls itself (see comment above) */ - dbg("ftdi_sio ioctl arg not supported - it was 0x%04x",cmd); + dbg(__FUNCTION__ "arg not supported - it was 0x%04x",cmd); return(-ENOIOCTLCMD); break; } - dbg("ftdi_sio_ioctl returning 0"); + dbg(__FUNCTION__ " returning 0"); return 0; } /* ftdi_sio_ioctl */ diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 9c509ff15..885108cd0 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -22,6 +22,9 @@ Tip 'o the hat to Linuxcare for supporting staff in their work on open source projects. + (11/01/2000) Adam J. Richter + usb_device_id table support. + (10/05/2000) gkh Fixed bug with urb->dev not being set properly, now that the usb core needs it. diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 666946181..8d249916c 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -117,28 +117,96 @@ struct ezusb_hex_record { /* Device info for the Keyspan serial converter */ #define KEYSPAN_VENDOR_ID (0x06cd) -static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID; /* Product IDs for the five products supported, pre-renumeration */ -static __u16 keyspan_usa18x_pre_product_id = 0x0105; -static __u16 keyspan_usa19_pre_product_id = 0x0103; -static __u16 keyspan_usa19w_pre_product_id = 0x0106; -static __u16 keyspan_usa28_pre_product_id = 0x0101; -static __u16 keyspan_usa28x_pre_product_id = 0x0102; +#define keyspan_usa18x_pre_product_id 0x0105 +#define keyspan_usa19_pre_product_id 0x0103 +#define keyspan_usa19w_pre_product_id 0x0106 +#define keyspan_usa28_pre_product_id 0x0101 +#define keyspan_usa28x_pre_product_id 0x0102 /* Product IDs post-renumeration */ -static __u16 keyspan_usa18x_product_id = 0x0112; -static __u16 keyspan_usa19_product_id = 0x0107; -static __u16 keyspan_usa19w_product_id = 0x0108; -static __u16 keyspan_usa28_product_id = 0x010f; -static __u16 keyspan_usa28x_product_id = 0x0110; +#define keyspan_usa18x_product_id 0x0112 +#define keyspan_usa19_product_id 0x0107 +#define keyspan_usa19w_product_id 0x0108 +#define keyspan_usa28_product_id 0x010f +#define keyspan_usa28x_product_id 0x0110 + +static __devinitdata struct usb_device_id keyspan_ids_combined[] = { + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa18x_pre_product_id}, + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19_pre_product_id}, + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19w_pre_product_id}, + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28_pre_product_id}, + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28x_pre_product_id}, + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa18x_product_id}, + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19_product_id}, + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19w_product_id}, + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28_product_id}, + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28x_product_id}, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, keyspan_ids_combined); + +/* Eventually, we will not need separate id tables for each USB + ID pattern. But, for now, it looks like we need slightly different + behavior for each match. */ + +static __devinitdata struct usb_device_id keyspan_usa18x_pre_ids[] = { + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa18x_pre_product_id}, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id keyspan_usa19_pre_ids[] = { + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19_pre_product_id}, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id keyspan_usa19w_pre_ids[] = { + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19w_pre_product_id}, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id keyspan_usa28_pre_ids[] = { + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28_pre_product_id}, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id keyspan_usa28x_pre_ids[] = { + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28x_pre_product_id}, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id keyspan_usa18x_ids[] = { + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa18x_product_id}, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id keyspan_usa19_ids[] = { + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19_product_id}, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id keyspan_usa19w_ids[] = { + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19w_product_id}, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id keyspan_usa28_ids[] = { + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28_product_id}, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id keyspan_usa28x_ids[] = { + {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28x_product_id}, + { } /* Terminating entry */ +}; /* Structs for the devices, pre and post renumeration. These are incomplete at present - HAB 20000708 */ struct usb_serial_device_type keyspan_usa18x_pre_device = { name: "Keyspan USA18X - (prerenumeration)", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa18x_pre_product_id, + id_table: keyspan_usa18x_pre_ids, needs_interrupt_in: DONT_CARE, needs_bulk_in: DONT_CARE, needs_bulk_out: DONT_CARE, @@ -151,8 +219,7 @@ struct usb_serial_device_type keyspan_usa18x_pre_device = { struct usb_serial_device_type keyspan_usa19_pre_device = { name: "Keyspan USA19 - (prerenumeration)", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa19_pre_product_id, + id_table: keyspan_usa19_pre_ids, needs_interrupt_in: DONT_CARE, needs_bulk_in: DONT_CARE, needs_bulk_out: DONT_CARE, @@ -166,8 +233,7 @@ struct usb_serial_device_type keyspan_usa19_pre_device = { struct usb_serial_device_type keyspan_usa19w_pre_device = { name: "Keyspan USA19W - (prerenumeration)", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa19w_pre_product_id, + id_table: keyspan_usa19w_pre_ids, needs_interrupt_in: DONT_CARE, needs_bulk_in: DONT_CARE, needs_bulk_out: DONT_CARE, @@ -181,8 +247,7 @@ struct usb_serial_device_type keyspan_usa19w_pre_device = { struct usb_serial_device_type keyspan_usa28_pre_device = { name: "Keyspan USA28 - (prerenumeration)", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa28_pre_product_id, + id_table: keyspan_usa28_pre_ids, needs_interrupt_in: DONT_CARE, needs_bulk_in: DONT_CARE, needs_bulk_out: DONT_CARE, @@ -195,8 +260,7 @@ struct usb_serial_device_type keyspan_usa28_pre_device = { struct usb_serial_device_type keyspan_usa28x_pre_device = { name: "Keyspan USA28X - (prerenumeration)", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa28x_pre_product_id, + id_table: keyspan_usa28x_pre_ids, needs_interrupt_in: DONT_CARE, needs_bulk_in: DONT_CARE, needs_bulk_out: DONT_CARE, @@ -210,8 +274,7 @@ struct usb_serial_device_type keyspan_usa28x_pre_device = { struct usb_serial_device_type keyspan_usa18x_device = { name: "Keyspan USA18X", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa18x_product_id, + id_table: keyspan_usa18x_ids, needs_interrupt_in: DONT_CARE, needs_bulk_in: DONT_CARE, needs_bulk_out: DONT_CARE, @@ -228,8 +291,7 @@ struct usb_serial_device_type keyspan_usa18x_device = { struct usb_serial_device_type keyspan_usa19_device = { name: "Keyspan USA19", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa19_product_id, + id_table: keyspan_usa19_ids, needs_interrupt_in: DONT_CARE, needs_bulk_in: MUST_HAVE, needs_bulk_out: MUST_HAVE, @@ -256,8 +318,7 @@ struct usb_serial_device_type keyspan_usa19_device = { struct usb_serial_device_type keyspan_usa19w_device = { name: "Keyspan USA19W", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa19w_product_id, + id_table: keyspan_usa19w_ids, needs_interrupt_in: DONT_CARE, needs_bulk_in: DONT_CARE, needs_bulk_out: DONT_CARE, @@ -275,8 +336,7 @@ struct usb_serial_device_type keyspan_usa19w_device = { struct usb_serial_device_type keyspan_usa28_device = { name: "Keyspan USA28", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa28_product_id, + id_table: keyspan_usa28_ids, needs_interrupt_in: DONT_CARE, needs_bulk_in: DONT_CARE, needs_bulk_out: DONT_CARE, @@ -294,8 +354,7 @@ struct usb_serial_device_type keyspan_usa28_device = { struct usb_serial_device_type keyspan_usa28x_device = { name: "Keyspan USA28X", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa28x_product_id, + id_table: keyspan_usa28x_ids, needs_interrupt_in: DONT_CARE, needs_bulk_in: DONT_CARE, needs_bulk_out: DONT_CARE, diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 51a1f10df..3114322c8 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -12,6 +12,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (11/01/2000) Adam J. Richter + * usb_device_id table support + * * (10/05/2000) gkh * Fixed bug with urb->dev not being set properly, now that the usb * core needs it. @@ -93,12 +96,23 @@ struct keyspan_pda_private { #define KEYSPAN_PDA_FAKE_ID 0x0103 #define KEYSPAN_PDA_ID 0x0104 /* no clue */ -/* All of the device info needed for the Keyspan PDA serial converter */ -static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID; -static __u16 keyspan_pda_fake_product_id = KEYSPAN_PDA_FAKE_ID; -static __u16 keyspan_pda_product_id = KEYSPAN_PDA_ID; +static __devinitdata struct usb_device_id id_table_combined [] = { + { idVendor: KEYSPAN_VENDOR_ID, idProduct: KEYSPAN_PDA_FAKE_ID }, + { idVendor: KEYSPAN_VENDOR_ID, idProduct: KEYSPAN_PDA_ID }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, id_table_combined); +static __devinitdata struct usb_device_id id_table_std [] = { + { idVendor: KEYSPAN_VENDOR_ID, idProduct: KEYSPAN_PDA_ID }, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id id_table_fake [] = { + { idVendor: KEYSPAN_VENDOR_ID, idProduct: KEYSPAN_PDA_FAKE_ID }, + { } /* Terminating entry */ +}; static void keyspan_pda_wakeup_write( struct usb_serial_port *port ) { @@ -746,8 +760,7 @@ static void keyspan_pda_shutdown (struct usb_serial *serial) struct usb_serial_device_type keyspan_pda_fake_device = { name: "Keyspan PDA - (prerenumeration)", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_pda_fake_product_id, + id_table: id_table_fake, needs_interrupt_in: DONT_CARE, needs_bulk_in: DONT_CARE, needs_bulk_out: DONT_CARE, @@ -760,8 +773,7 @@ struct usb_serial_device_type keyspan_pda_fake_device = { struct usb_serial_device_type keyspan_pda_device = { name: "Keyspan PDA", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_pda_product_id, + id_table: id_table_std, needs_interrupt_in: MUST_HAVE, needs_bulk_in: DONT_CARE, needs_bulk_out: MUST_HAVE, diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index dc832fa53..2b9f99f7c 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -10,6 +10,9 @@ * * Please report both successes and troubles to the author at omninet@kroah.com * + * (11/01/2000) Adam J. Richter + * usb_device_id table support + * * (10/05/2000) gkh * Fixed bug with urb->dev not being set properly, now that the usb * core needs it. @@ -66,14 +69,17 @@ static int omninet_write (struct usb_serial_port *port, int from_user, const u static int omninet_write_room (struct usb_serial_port *port); static void omninet_shutdown (struct usb_serial *serial); -/* All of the device info needed for the omni.net */ -static __u16 zyxel_vendor_id = ZYXEL_VENDOR_ID; -static __u16 zyxel_omninet_product_id = ZYXEL_OMNINET_ID; +static __devinitdata struct usb_device_id id_table [] = { + { idVendor: ZYXEL_VENDOR_ID, idProduct: ZYXEL_OMNINET_ID }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, id_table); + struct usb_serial_device_type zyxel_omninet_device = { name: "ZyXEL - omni.net lcd plus usb", - idVendor: &zyxel_vendor_id, - idProduct: &zyxel_omninet_product_id, + id_table: id_table, needs_interrupt_in: MUST_HAVE, needs_bulk_in: MUST_HAVE, needs_bulk_out: MUST_HAVE, diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h index 5dde77426..913fb2f26 100644 --- a/drivers/usb/serial/usb-serial.h +++ b/drivers/usb/serial/usb-serial.h @@ -112,8 +112,7 @@ struct usb_serial { /* This structure defines the individual serial converter. */ struct usb_serial_device_type { char *name; - __u16 *idVendor; - __u16 *idProduct; + const struct usb_device_id *id_table; char needs_interrupt_in; char needs_bulk_in; char needs_bulk_out; @@ -125,7 +124,9 @@ struct usb_serial_device_type { struct list_head driver_list; /* function call to make before accepting driver */ - int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */ + /* return 0 to continue initialization, anything else to abort */ + int (*startup) (struct usb_serial *serial); + void (*shutdown) (struct usb_serial *serial); /* serial function calls */ diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c index 902a4e1d0..6b5d6e7f0 100644 --- a/drivers/usb/serial/usbserial.c +++ b/drivers/usb/serial/usbserial.c @@ -15,6 +15,11 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (11/01/2000) Adam J. Richter + * instead of using idVendor/idProduct pairs, usb serial drivers + * now identify their hardware interest with usb_device_id tables, + * which they usually have anyhow for use with MODULE_DEVICE_TABLE. + * * (10/05/2000) gkh * Fixed bug with urb->dev not being set properly, now that the usb * core needs it. @@ -288,11 +293,12 @@ MODULE_PARM_DESC(vendor, "User specified USB idVendor"); MODULE_PARM(product, "i"); MODULE_PARM_DESC(product, "User specified USB idProduct"); +static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ + /* All of the device info needed for the Generic Serial Converter */ static struct usb_serial_device_type generic_device = { name: "Generic", - idVendor: &vendor, /* use the user specified vendor id */ - idProduct: &product, /* use the user specified product id */ + id_table: generic_device_ids, needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ @@ -316,15 +322,25 @@ 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); static void serial_set_termios (struct tty_struct *tty, struct termios * old); -static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum); +static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum, + const struct usb_device_id *id); static void usb_serial_disconnect(struct usb_device *dev, void *ptr); static struct usb_driver usb_serial_driver = { name: "serial", probe: usb_serial_probe, disconnect: usb_serial_disconnect, + id_table: NULL, /* check all devices */ }; +/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead + the MODULE_DEVICE_TABLE declarations in each serial driver + cause the "hotplug" program to pull in whatever module is necessary + via modprobe, and modprobe will load usbserial because the serial + drivers depend on it. +*/ + + static int serial_refcount; static struct tty_driver serial_tty_driver; static struct tty_struct * serial_tty[SERIAL_TTY_MINORS]; @@ -957,7 +973,8 @@ static void port_softint(void *private) -static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) +static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum, + const struct usb_device_id *id) { struct usb_serial *serial = NULL; struct usb_serial_port *port; @@ -981,19 +998,17 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) int num_bulk_out = 0; int num_ports; int max_endpoints; + const struct usb_device_id *id_pattern = NULL; /* loop through our list of known serial converters, and see if this device matches. */ found = 0; + interface = &dev->actconfig->interface[ifnum]; list_for_each (tmp, &usb_serial_driver_list) { type = list_entry(tmp, struct usb_serial_device_type, driver_list); - dbg ("Looking at %s Vendor id=%.4x Product id=%.4x", - type->name, *(type->idVendor), *(type->idProduct)); - - /* look at the device descriptor */ - if ((dev->descriptor.idVendor == *(type->idVendor)) && - (dev->descriptor.idProduct == *(type->idProduct))) { + id_pattern = usb_match_id(dev, interface, type->id_table); + if (id_pattern != NULL) { dbg("descriptor matches"); found = 1; break; @@ -1009,7 +1024,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT; /* check out the endpoints */ - interface = &dev->actconfig->interface[ifnum]; iface_desc = &interface->altsetting[0]; for (i = 0; i < iface_desc->bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i]; @@ -1335,6 +1349,8 @@ int usb_serial_init(void) } #ifdef CONFIG_USB_SERIAL_GENERIC + generic_device_ids[0].idVendor = vendor; + generic_device_ids[0].idProduct = product; /* register our generic driver with ourselves */ usb_serial_register (&generic_device); #endif diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 868333c87..c078704f0 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -11,6 +11,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (11/01/2000) Adam J. Richter + * usb_device_id table support + * * (10/05/2000) gkh * Fixed bug with urb->dev not being set properly, now that the usb * core needs it. @@ -101,13 +104,20 @@ static void visor_set_termios (struct usb_serial_port *port, struct termios *old static void visor_write_bulk_callback (struct urb *urb); static void visor_read_bulk_callback (struct urb *urb); + +static __devinitdata struct usb_device_id id_table [] = { + { idVendor: HANDSPRING_VENDOR_ID, idProduct: HANDSPRING_VISOR_ID }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, id_table); + + + /* All of the device info needed for the Handspring Visor */ -static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID; -static __u16 handspring_product_id = HANDSPRING_VISOR_ID; struct usb_serial_device_type handspring_device = { name: "Handspring Visor", - idVendor: &handspring_vendor_id, /* the Handspring vendor ID */ - idProduct: &handspring_product_id, /* the Handspring Visor product id */ + id_table: id_table, needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 55abab383..83a822225 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -11,6 +11,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (11/01/2000) Adam J. Richter + * usb_device_id table support + * * (10/05/2000) gkh * Fixed bug with urb->dev not being set properly, now that the usb * core needs it. @@ -77,6 +80,31 @@ #define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001 #define CONNECT_TECH_WHITE_HEAT_ID 0x8001 +/* + ID tables for whiteheat are unusual, because we want to different + things for different versions of the device. Eventually, this + will be doable from a single table. But, for now, we define two + separate ID tables, and then a third table that combines them + just for the purpose of exporting the autoloading information. +*/ +static __devinitdata struct usb_device_id id_table_std [] = { + {idVendor: CONNECT_TECH_VENDOR_ID, idProduct: CONNECT_TECH_WHITE_HEAT_ID}, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id id_table_prerenumeration [] = { + {idVendor: CONNECT_TECH_VENDOR_ID, idProduct: CONNECT_TECH_WHITE_HEAT_ID}, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id id_table_combined [] = { + {idVendor: CONNECT_TECH_VENDOR_ID, idProduct: CONNECT_TECH_WHITE_HEAT_ID}, + {idVendor: CONNECT_TECH_VENDOR_ID, idProduct: CONNECT_TECH_FAKE_WHITE_HEAT_ID}, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, id_table_combined); + /* function prototypes for the Connect Tech WhiteHEAT serial converter */ static int whiteheat_open (struct usb_serial_port *port, struct file *filp); static void whiteheat_close (struct usb_serial_port *port, struct file *filp); @@ -87,14 +115,9 @@ 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; -static __u16 connecttech_whiteheat_fake_product_id = CONNECT_TECH_FAKE_WHITE_HEAT_ID; -static __u16 connecttech_whiteheat_product_id = CONNECT_TECH_WHITE_HEAT_ID; struct usb_serial_device_type whiteheat_fake_device = { name: "Connect Tech - WhiteHEAT - (prerenumeration)", - idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */ - idProduct: &connecttech_whiteheat_fake_product_id, /* the White Heat initial product id */ + id_table: id_table_prerenumeration, needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ @@ -104,10 +127,10 @@ struct usb_serial_device_type whiteheat_fake_device = { num_ports: 1, startup: whiteheat_startup }; + struct usb_serial_device_type whiteheat_device = { name: "Connect Tech - WhiteHEAT", - idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */ - idProduct: &connecttech_whiteheat_product_id, /* the White Heat real product id */ + id_table: id_table_std, needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ |