aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/cyberjack.c19
-rw-r--r--drivers/usb/serial/ftdi_sio.c908
-rw-r--r--drivers/usb/serial/ftdi_sio.h14
-rw-r--r--drivers/usb/serial/generic.c24
-rw-r--r--drivers/usb/serial/ipaq.c5
-rw-r--r--drivers/usb/serial/ipw.c14
-rw-r--r--drivers/usb/serial/ir-usb.c16
-rw-r--r--drivers/usb/serial/keyspan_pda.c19
-rw-r--r--drivers/usb/serial/omninet.c17
-rw-r--r--drivers/usb/serial/option.c228
-rw-r--r--drivers/usb/serial/safe_serial.c13
-rw-r--r--drivers/usb/serial/usb-serial.c1
-rw-r--r--drivers/usb/serial/usb-serial.h3
13 files changed, 407 insertions, 874 deletions
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 46a204cd40e..b5b431067b0 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -213,10 +213,14 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
return (0);
}
- if (port->write_urb->status == -EINPROGRESS) {
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
dbg("%s - already writing", __FUNCTION__);
- return (0);
+ return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
spin_lock_irqsave(&priv->lock, flags);
@@ -224,6 +228,7 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
/* To much data for buffer. Reset buffer. */
priv->wrfilled=0;
spin_unlock_irqrestore(&priv->lock, flags);
+ port->write_urb_busy = 0;
return (0);
}
@@ -268,6 +273,7 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
priv->wrfilled=0;
priv->wrsent=0;
spin_unlock_irqrestore(&priv->lock, flags);
+ port->write_urb_busy = 0;
return 0;
}
@@ -412,7 +418,8 @@ static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs
struct cyberjack_private *priv = usb_get_serial_port_data(port);
dbg("%s - port %d", __FUNCTION__, port->number);
-
+
+ port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;
@@ -424,12 +431,6 @@ static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs
if( priv->wrfilled ) {
int length, blksize, result;
- if (port->write_urb->status == -EINPROGRESS) {
- dbg("%s - already writing", __FUNCTION__);
- spin_unlock(&priv->lock);
- return;
- }
-
dbg("%s - transmitting data (frame n)", __FUNCTION__);
length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ?
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 3bfcc7b9f86..d1964a0c416 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -264,16 +264,26 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v1.4.2"
+#define DRIVER_VERSION "v1.4.3"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>"
#define DRIVER_DESC "USB FTDI Serial Converters Driver"
static int debug;
-static struct usb_device_id id_table_sio [] = {
- { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
- { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
- { } /* Terminating entry */
+/* struct ftdi_sio_quirk is used by devices requiring special attention. */
+struct ftdi_sio_quirk {
+ void (*setup)(struct usb_serial *); /* Special settings during startup. */
+};
+
+static void ftdi_USB_UIRT_setup (struct usb_serial *serial);
+static void ftdi_HE_TIRA1_setup (struct usb_serial *serial);
+
+static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {
+ .setup = ftdi_USB_UIRT_setup,
+};
+
+static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
+ .setup = ftdi_HE_TIRA1_setup,
};
/*
@@ -288,237 +298,11 @@ static struct usb_device_id id_table_sio [] = {
* the bcdDevice value is used to differentiate FT232BM and FT245BM from
* the earlier FT8U232AM and FT8U232BM. For now, include all known VID/PID
* combinations in both tables.
- * FIXME: perhaps bcdDevice can also identify 12MHz devices, but I don't know
- * if those ever went into mass production. [Ian Abbott]
+ * FIXME: perhaps bcdDevice can also identify 12MHz FT8U232AM devices,
+ * but I don't know if those ever went into mass production. [Ian Abbott]
*/
-static struct usb_device_id id_table_8U232AM [] = {
- { USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) },
- { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
- { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
- { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_547_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_633_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_631_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_635_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_640_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_642_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_DSS20_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2104_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_3_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_4_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_3_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_4_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_3_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_4_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_3_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_4_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_5_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_6_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_7_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_8_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_3_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_4_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_5_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_6_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_7_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_8_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_3_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_4_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_5_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_6_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_7_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(IDTECH_VID, IDTECH_IDT1221U_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(OCT_VID, OCT_US101_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_1, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, INSIDE_ACCESSO, 0, 0x3ff) },
- { USB_DEVICE_VER(INTREPID_VID, INTREPID_VALUECAN_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_RM_CANVIEW_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, EVER_ECO_PRO_CDS, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID, 0, 0x3ff) },
- { } /* Terminating entry */
-};
-
-
-static struct usb_device_id id_table_FT232BM [] = {
- { USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_547_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_633_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_631_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_635_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_640_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_642_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_DSS20_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_3_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_PIEGROUP_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2104_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_3_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_3_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_3_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_3_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_5_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_6_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_7_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_8_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_3_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_5_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_6_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_7_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_8_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_3_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_5_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_6_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_7_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(IDTECH_VID, IDTECH_IDT1221U_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(OCT_VID, OCT_US101_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_1, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E808_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E809_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80A_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80B_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80C_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80D_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80E_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80F_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E888_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E889_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88A_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88B_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88C_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88D_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
- { USB_DEVICE_VER(FTDI_VID, INSIDE_ACCESSO, 0x400, 0xffff) },
- { USB_DEVICE_VER(INTREPID_VID, INTREPID_VALUECAN_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_RM_CANVIEW_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, EVER_ECO_PRO_CDS, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID, 0x400, 0xffff) },
- { } /* Terminating entry */
-};
-
-
-static struct usb_device_id id_table_USB_UIRT [] = {
- { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) },
- { } /* Terminating entry */
-};
-
-
-static struct usb_device_id id_table_HE_TIRA1 [] = {
- { USB_DEVICE_VER(FTDI_VID, FTDI_HE_TIRA1_PID, 0x400, 0xffff) },
- { } /* Terminating entry */
-};
-
-
-static struct usb_device_id id_table_FT2232C[] = {
- { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) },
- { } /* Terminating entry */
-};
-
static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
@@ -540,14 +324,14 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) },
{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_3_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID, 0x400, 0xffff) },
+ { USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_MTXORB_1_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_MTXORB_2_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_MTXORB_3_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) },
@@ -597,35 +381,37 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) },
{ USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) },
{ USB_DEVICE(OCT_VID, OCT_US101_PID) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_HE_TIRA1_PID, 0x400, 0xffff) },
- { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_HE_TIRA1_quirk },
+ { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_USB_UIRT_quirk },
{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_1) },
{ USB_DEVICE(FTDI_VID, PROTEGO_R2X0) },
{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) },
{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E808_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E809_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80A_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80B_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80C_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80D_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80E_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80F_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E888_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E889_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88A_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88B_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88C_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88D_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E808_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E809_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80A_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80B_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80C_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80D_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80E_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80F_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E888_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E889_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88A_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88B_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88C_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88D_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88E_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88F_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) },
- { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) },
+ { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
{ USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },
@@ -642,7 +428,10 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
{ USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID, 0x400, 0xffff) },
+ { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) },
+ { USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
{ } /* Terminating entry */
};
@@ -705,12 +494,8 @@ struct ftdi_private {
ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP )
/* function prototypes for a FTDI serial converter */
-static int ftdi_SIO_startup (struct usb_serial *serial);
-static int ftdi_8U232AM_startup (struct usb_serial *serial);
-static int ftdi_FT232BM_startup (struct usb_serial *serial);
-static int ftdi_FT2232C_startup (struct usb_serial *serial);
-static int ftdi_USB_UIRT_startup (struct usb_serial *serial);
-static int ftdi_HE_TIRA1_startup (struct usb_serial *serial);
+static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id);
+static int ftdi_sio_attach (struct usb_serial *serial);
static void ftdi_shutdown (struct usb_serial *serial);
static int ftdi_open (struct usb_serial_port *port, struct file *filp);
static void ftdi_close (struct usb_serial_port *port, struct file *filp);
@@ -733,146 +518,16 @@ static unsigned short int ftdi_232am_baud_to_divisor (int baud);
static __u32 ftdi_232bm_baud_base_to_divisor (int baud, int base);
static __u32 ftdi_232bm_baud_to_divisor (int baud);
-static struct usb_serial_device_type ftdi_SIO_device = {
- .owner = THIS_MODULE,
- .name = "FTDI SIO",
- .id_table = id_table_sio,
- .num_interrupt_in = 0,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
- .num_ports = 1,
- .open = ftdi_open,
- .close = ftdi_close,
- .throttle = ftdi_throttle,
- .unthrottle = ftdi_unthrottle,
- .write = ftdi_write,
- .write_room = ftdi_write_room,
- .chars_in_buffer = ftdi_chars_in_buffer,
- .read_bulk_callback = ftdi_read_bulk_callback,
- .write_bulk_callback = ftdi_write_bulk_callback,
- .tiocmget = ftdi_tiocmget,
- .tiocmset = ftdi_tiocmset,
- .ioctl = ftdi_ioctl,
- .set_termios = ftdi_set_termios,
- .break_ctl = ftdi_break_ctl,
- .attach = ftdi_SIO_startup,
- .shutdown = ftdi_shutdown,
-};
-
-static struct usb_serial_device_type ftdi_8U232AM_device = {
- .owner = THIS_MODULE,
- .name = "FTDI 8U232AM Compatible",
- .id_table = id_table_8U232AM,
- .num_interrupt_in = 0,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
- .num_ports = 1,
- .open = ftdi_open,
- .close = ftdi_close,
- .throttle = ftdi_throttle,
- .unthrottle = ftdi_unthrottle,
- .write = ftdi_write,
- .write_room = ftdi_write_room,
- .chars_in_buffer = ftdi_chars_in_buffer,
- .read_bulk_callback = ftdi_read_bulk_callback,
- .write_bulk_callback = ftdi_write_bulk_callback,
- .tiocmget = ftdi_tiocmget,
- .tiocmset = ftdi_tiocmset,
- .ioctl = ftdi_ioctl,
- .set_termios = ftdi_set_termios,
- .break_ctl = ftdi_break_ctl,
- .attach = ftdi_8U232AM_startup,
- .shutdown = ftdi_shutdown,
-};
-
-static struct usb_serial_device_type ftdi_FT232BM_device = {
- .owner = THIS_MODULE,
- .name = "FTDI FT232BM Compatible",
- .id_table = id_table_FT232BM,
- .num_interrupt_in = 0,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
- .num_ports = 1,
- .open = ftdi_open,
- .close = ftdi_close,
- .throttle = ftdi_throttle,
- .unthrottle = ftdi_unthrottle,
- .write = ftdi_write,
- .write_room = ftdi_write_room,
- .chars_in_buffer = ftdi_chars_in_buffer,
- .read_bulk_callback = ftdi_read_bulk_callback,
- .write_bulk_callback = ftdi_write_bulk_callback,
- .tiocmget = ftdi_tiocmget,
- .tiocmset = ftdi_tiocmset,
- .ioctl = ftdi_ioctl,
- .set_termios = ftdi_set_termios,
- .break_ctl = ftdi_break_ctl,
- .attach = ftdi_FT232BM_startup,
- .shutdown = ftdi_shutdown,
-};
-
-static struct usb_serial_device_type ftdi_FT2232C_device = {
- .owner = THIS_MODULE,
- .name = "FTDI FT2232C Compatible",
- .id_table = id_table_FT2232C,
- .num_interrupt_in = 0,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
- .num_ports = 1,
- .open = ftdi_open,
- .close = ftdi_close,
- .throttle = ftdi_throttle,
- .unthrottle = ftdi_unthrottle,
- .write = ftdi_write,
- .write_room = ftdi_write_room,
- .chars_in_buffer = ftdi_chars_in_buffer,
- .read_bulk_callback = ftdi_read_bulk_callback,
- .write_bulk_callback = ftdi_write_bulk_callback,
- .tiocmget = ftdi_tiocmget,
- .tiocmset = ftdi_tiocmset,
- .ioctl = ftdi_ioctl,
- .set_termios = ftdi_set_termios,
- .break_ctl = ftdi_break_ctl,
- .attach = ftdi_FT2232C_startup,
- .shutdown = ftdi_shutdown,
-};
-
-static struct usb_serial_device_type ftdi_USB_UIRT_device = {
- .owner = THIS_MODULE,
- .name = "USB-UIRT Infrared Tranceiver",
- .id_table = id_table_USB_UIRT,
- .num_interrupt_in = 0,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
- .num_ports = 1,
- .open = ftdi_open,
- .close = ftdi_close,
- .throttle = ftdi_throttle,
- .unthrottle = ftdi_unthrottle,
- .write = ftdi_write,
- .write_room = ftdi_write_room,
- .chars_in_buffer = ftdi_chars_in_buffer,
- .read_bulk_callback = ftdi_read_bulk_callback,
- .write_bulk_callback = ftdi_write_bulk_callback,
- .tiocmget = ftdi_tiocmget,
- .tiocmset = ftdi_tiocmset,
- .ioctl = ftdi_ioctl,
- .set_termios = ftdi_set_termios,
- .break_ctl = ftdi_break_ctl,
- .attach = ftdi_USB_UIRT_startup,
- .shutdown = ftdi_shutdown,
-};
-
-/* The TIRA1 is based on a FT232BM which requires a fixed baud rate of 100000
- * and which requires RTS-CTS to be enabled. */
-static struct usb_serial_device_type ftdi_HE_TIRA1_device = {
+static struct usb_serial_device_type ftdi_sio_device = {
.owner = THIS_MODULE,
- .name = "Home-Electronics TIRA-1 IR Transceiver",
- .id_table = id_table_HE_TIRA1,
+ .name = "FTDI USB Serial Device",
+ .short_name = "ftdi_sio",
+ .id_table = id_table_combined,
.num_interrupt_in = 0,
.num_bulk_in = 1,
.num_bulk_out = 1,
.num_ports = 1,
+ .probe = ftdi_sio_probe,
.open = ftdi_open,
.close = ftdi_close,
.throttle = ftdi_throttle,
@@ -887,13 +542,13 @@ static struct usb_serial_device_type ftdi_HE_TIRA1_device = {
.ioctl = ftdi_ioctl,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
- .attach = ftdi_HE_TIRA1_startup,
+ .attach = ftdi_sio_attach,
.shutdown = ftdi_shutdown,
};
-
#define WDR_TIMEOUT 5000 /* default urb timeout */
+#define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */
/* High and low are for DTR, RTS etc etc */
#define HIGH 1
@@ -942,62 +597,59 @@ static __u32 ftdi_232bm_baud_to_divisor(int baud)
return(ftdi_232bm_baud_base_to_divisor(baud, 48000000));
}
-static int set_rts(struct usb_serial_port *port, int high_or_low)
+#define set_mctrl(port, set) update_mctrl((port), (set), 0)
+#define clear_mctrl(port, clear) update_mctrl((port), 0, (clear))
+
+static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned int clear)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
char *buf;
- unsigned ftdi_high_or_low;
+ unsigned urb_value;
int rv;
-
- buf = kmalloc(1, GFP_NOIO);
- if (!buf)
- return -ENOMEM;
-
- if (high_or_low) {
- ftdi_high_or_low = FTDI_SIO_SET_RTS_HIGH;
- priv->last_dtr_rts |= TIOCM_RTS;
- } else {
- ftdi_high_or_low = FTDI_SIO_SET_RTS_LOW;
- priv->last_dtr_rts &= ~TIOCM_RTS;
- }
- rv = usb_control_msg(port->serial->dev,
- usb_sndctrlpipe(port->serial->dev, 0),
- FTDI_SIO_SET_MODEM_CTRL_REQUEST,
- FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
- ftdi_high_or_low, priv->interface,
- buf, 0, WDR_TIMEOUT);
-
- kfree(buf);
- return rv;
-}
+ if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
+ dbg("%s - DTR|RTS not being set|cleared", __FUNCTION__);
+ return 0; /* no change */
+ }
-static int set_dtr(struct usb_serial_port *port, int high_or_low)
-{
- struct ftdi_private *priv = usb_get_serial_port_data(port);
- char *buf;
- unsigned ftdi_high_or_low;
- int rv;
-
buf = kmalloc(1, GFP_NOIO);
- if (!buf)
+ if (!buf) {
return -ENOMEM;
-
- if (high_or_low) {
- ftdi_high_or_low = FTDI_SIO_SET_DTR_HIGH;
- priv->last_dtr_rts |= TIOCM_DTR;
- } else {
- ftdi_high_or_low = FTDI_SIO_SET_DTR_LOW;
- priv->last_dtr_rts &= ~TIOCM_DTR;
}
+
+ clear &= ~set; /* 'set' takes precedence over 'clear' */
+ urb_value = 0;
+ if (clear & TIOCM_DTR)
+ urb_value |= FTDI_SIO_SET_DTR_LOW;
+ if (clear & TIOCM_RTS)
+ urb_value |= FTDI_SIO_SET_RTS_LOW;
+ if (set & TIOCM_DTR)
+ urb_value |= FTDI_SIO_SET_DTR_HIGH;
+ if (set & TIOCM_RTS)
+ urb_value |= FTDI_SIO_SET_RTS_HIGH;
rv = usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_MODEM_CTRL_REQUEST,
FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
- ftdi_high_or_low, priv->interface,
+ urb_value, priv->interface,
buf, 0, WDR_TIMEOUT);
kfree(buf);
+ if (rv < 0) {
+ err("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
+ __FUNCTION__,
+ (set & TIOCM_DTR) ? "HIGH" :
+ (clear & TIOCM_DTR) ? "LOW" : "unchanged",
+ (set & TIOCM_RTS) ? "HIGH" :
+ (clear & TIOCM_RTS) ? "LOW" : "unchanged");
+ } else {
+ dbg("%s - DTR %s, RTS %s", __FUNCTION__,
+ (set & TIOCM_DTR) ? "HIGH" :
+ (clear & TIOCM_DTR) ? "LOW" : "unchanged",
+ (set & TIOCM_RTS) ? "HIGH" :
+ (clear & TIOCM_RTS) ? "LOW" : "unchanged");
+ priv->last_dtr_rts = (priv->last_dtr_rts & ~clear) | set;
+ }
return rv;
}
@@ -1030,7 +682,7 @@ static int change_speed(struct usb_serial_port *port)
FTDI_SIO_SET_BAUDRATE_REQUEST,
FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
urb_value, urb_index,
- buf, 0, 100);
+ buf, 0, WDR_SHORT_TIMEOUT);
kfree(buf);
return rv;
@@ -1212,13 +864,66 @@ check_and_exit:
} /* set_serial_info */
+/* Determine type of FTDI chip based on USB config and descriptor. */
+static void ftdi_determine_type(struct usb_serial_port *port)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ struct usb_device *udev = serial->dev;
+ unsigned version;
+ unsigned interfaces;
+
+ /* Assume it is not the original SIO device for now. */
+ priv->baud_base = 48000000 / 16;
+ priv->write_offset = 0;
+
+ version = le16_to_cpu(udev->descriptor.bcdDevice);
+ interfaces = udev->actconfig->desc.bNumInterfaces;
+ dbg("%s: bcdDevice = 0x%x, bNumInterfaces = %u", __FUNCTION__,
+ version, interfaces);
+ if (interfaces > 1) {
+ int inter;
+
+ /* Multiple interfaces. Assume FT2232C. */
+ priv->chip_type = FT2232C;
+ /* Determine interface code. */
+ inter = serial->interface->altsetting->desc.bInterfaceNumber;
+ if (inter == 0) {
+ priv->interface = PIT_SIOA;
+ } else {
+ priv->interface = PIT_SIOB;
+ }
+ /* BM-type devices have a bug where bcdDevice gets set
+ * to 0x200 when iSerialNumber is 0. */
+ if (version < 0x500) {
+ dbg("%s: something fishy - bcdDevice too low for multi-interface device",
+ __FUNCTION__);
+ }
+ } else if (version < 0x200) {
+ /* Old device. Assume its the original SIO. */
+ priv->chip_type = SIO;
+ priv->baud_base = 12000000 / 16;
+ priv->write_offset = 1;
+ } else if (version < 0x400) {
+ /* Assume its an FT8U232AM (or FT8U245AM) */
+ /* (It might be a BM because of the iSerialNumber bug,
+ * but it will still work as an AM device.) */
+ priv->chip_type = FT8U232AM;
+ } else {
+ /* Assume its an FT232BM (or FT245BM) */
+ priv->chip_type = FT232BM;
+ }
+ info("Detected %s", ftdi_chip_name[priv->chip_type]);
+}
+
+
/*
* ***************************************************************************
* Sysfs Attribute
* ***************************************************************************
*/
-static ssize_t show_latency_timer(struct device *dev, char *buf)
+static ssize_t show_latency_timer(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -1245,7 +950,7 @@ static ssize_t show_latency_timer(struct device *dev, char *buf)
}
/* Write a new value of the latency timer, in units of milliseconds. */
-static ssize_t store_latency_timer(struct device *dev, const char *valbuf,
+static ssize_t store_latency_timer(struct device *dev, struct device_attribute *attr, const char *valbuf,
size_t count)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
@@ -1276,7 +981,7 @@ static ssize_t store_latency_timer(struct device *dev, const char *valbuf,
/* Write an event character directly to the FTDI register. The ASCII
value is in the low 8 bits, with the enable bit in the 9th bit. */
-static ssize_t store_event_char(struct device *dev, const char *valbuf,
+static ssize_t store_event_char(struct device *dev, struct device_attribute *attr, const char *valbuf,
size_t count)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
@@ -1355,12 +1060,20 @@ static void remove_sysfs_attrs(struct usb_serial *serial)
* ***************************************************************************
*/
-/* Common startup subroutine */
-/* Called from ftdi_SIO_startup, etc. */
-static int ftdi_common_startup (struct usb_serial *serial)
+/* Probe function to check for special devices */
+static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id)
+{
+ usb_set_serial_data(serial, (void *)id->driver_info);
+
+ return (0);
+}
+
+/* attach subroutine */
+static int ftdi_sio_attach (struct usb_serial *serial)
{
struct usb_serial_port *port = serial->port[0];
struct ftdi_private *priv;
+ struct ftdi_sio_quirk *quirk;
dbg("%s",__FUNCTION__);
@@ -1400,150 +1113,49 @@ static int ftdi_common_startup (struct usb_serial *serial)
port->bulk_out_buffer = NULL;
usb_set_serial_port_data(serial->port[0], priv);
-
- return (0);
-}
-
-
-/* Startup for the SIO chip */
-/* Called from usbserial:serial_probe */
-static int ftdi_SIO_startup (struct usb_serial *serial)
-{
- struct ftdi_private *priv;
- int err;
-
- dbg("%s",__FUNCTION__);
- err = ftdi_common_startup(serial);
- if (err){
- return (err);
- }
-
- priv = usb_get_serial_port_data(serial->port[0]);
- priv->chip_type = SIO;
- priv->baud_base = 12000000 / 16;
- priv->write_offset = 1;
-
- return (0);
-}
-
-/* Startup for the 8U232AM chip */
-/* Called from usbserial:serial_probe */
-static int ftdi_8U232AM_startup (struct usb_serial *serial)
-{ /* ftdi_8U232AM_startup */
- struct ftdi_private *priv;
- int err;
-
- dbg("%s",__FUNCTION__);
- err = ftdi_common_startup(serial);
- if (err){
- return (err);
- }
-
- priv = usb_get_serial_port_data(serial->port[0]);
- priv->chip_type = FT8U232AM;
- priv->baud_base = 48000000 / 2; /* Would be / 16, but FTDI supports 0.125, 0.25 and 0.5 divisor fractions! */
-
+ ftdi_determine_type (serial->port[0]);
create_sysfs_attrs(serial);
-
- return (0);
-} /* ftdi_8U232AM_startup */
-
-/* Startup for the FT232BM chip */
-/* Called from usbserial:serial_probe */
-static int ftdi_FT232BM_startup (struct usb_serial *serial)
-{ /* ftdi_FT232BM_startup */
- struct ftdi_private *priv;
- int err;
- dbg("%s",__FUNCTION__);
- err = ftdi_common_startup(serial);
- if (err){
- return (err);
+ /* Check for device requiring special set up. */
+ quirk = (struct ftdi_sio_quirk *)usb_get_serial_data(serial);
+ if (quirk && quirk->setup) {
+ quirk->setup(serial);
}
-
- priv = usb_get_serial_port_data(serial->port[0]);
- priv->chip_type = FT232BM;
- priv->baud_base = 48000000 / 2; /* Would be / 16, but FT232BM supports multiple of 0.125 divisor fractions! */
- create_sysfs_attrs(serial);
-
return (0);
-} /* ftdi_FT232BM_startup */
-
-/* Startup for the FT2232C chip */
-/* Called from usbserial:serial_probe */
-static int ftdi_FT2232C_startup (struct usb_serial *serial)
-{ /* ftdi_FT2232C_startup */
- struct ftdi_private *priv;
- int err;
- int inter;
-
- dbg("%s",__FUNCTION__);
- err = ftdi_common_startup(serial);
- if (err){
- return (err);
- }
-
- priv = usb_get_serial_port_data(serial->port[0]);
- priv->chip_type = FT2232C;
- inter = serial->interface->altsetting->desc.bInterfaceNumber;
-
- if (inter) {
- priv->interface = PIT_SIOB;
- }
- else {
- priv->interface = PIT_SIOA;
- }
- priv->baud_base = 48000000 / 2; /* Would be / 16, but FT2232C supports multiple of 0.125 divisor fractions! */
-
- create_sysfs_attrs(serial);
+} /* ftdi_sio_attach */
- return (0);
-} /* ftdi_FT2232C_startup */
-/* Startup for the USB-UIRT device, which requires hardwired baudrate (38400 gets mapped to 312500) */
+/* Setup for the USB-UIRT device, which requires hardwired
+ * baudrate (38400 gets mapped to 312500) */
/* Called from usbserial:serial_probe */
-static int ftdi_USB_UIRT_startup (struct usb_serial *serial)
-{ /* ftdi_USB_UIRT_startup */
+static void ftdi_USB_UIRT_setup (struct usb_serial *serial)
+{
struct ftdi_private *priv;
- int err;
dbg("%s",__FUNCTION__);
- err = ftdi_8U232AM_startup(serial);
- if (err){
- return (err);
- }
priv = usb_get_serial_port_data(serial->port[0]);
priv->flags |= ASYNC_SPD_CUST;
priv->custom_divisor = 77;
priv->force_baud = B38400;
-
- return (0);
-} /* ftdi_USB_UIRT_startup */
+} /* ftdi_USB_UIRT_setup */
-/* Startup for the HE-TIRA1 device, which requires hardwired
- * baudrate (38400 gets mapped to 100000) */
-static int ftdi_HE_TIRA1_startup (struct usb_serial *serial)
-{ /* ftdi_HE_TIRA1_startup */
+/* Setup for the HE-TIRA1 device, which requires hardwired
+ * baudrate (38400 gets mapped to 100000) and RTS-CTS enabled. */
+static void ftdi_HE_TIRA1_setup (struct usb_serial *serial)
+{
struct ftdi_private *priv;
- int err;
dbg("%s",__FUNCTION__);
- err = ftdi_FT232BM_startup(serial);
- if (err){
- return (err);
- }
priv = usb_get_serial_port_data(serial->port[0]);
priv->flags |= ASYNC_SPD_CUST;
priv->custom_divisor = 240;
priv->force_baud = B38400;
priv->force_rtscts = 1;
-
- return (0);
-} /* ftdi_HE_TIRA1_startup */
+} /* ftdi_HE_TIRA1_setup */
/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
@@ -1608,12 +1220,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
/* FIXME: Flow control might be enabled, so it should be checked -
we have no control of defaults! */
/* Turn on RTS and DTR since we are not flow controlling by default */
- if (set_dtr(port, HIGH) < 0) {
- err("%s Error from DTR HIGH urb", __FUNCTION__);
- }
- if (set_rts(port, HIGH) < 0){
- err("%s Error from RTS HIGH urb", __FUNCTION__);
- }
+ set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
/* Not throttled */
spin_lock_irqsave(&priv->rx_lock, flags);
@@ -1663,14 +1270,8 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
err("error from flowcontrol urb");
}
- /* drop DTR */
- if (set_dtr(port, LOW) < 0){
- err("Error from DTR LOW urb");
- }
- /* drop RTS */
- if (set_rts(port, LOW) < 0) {
- err("Error from RTS LOW urb");
- }
+ /* drop RTS and DTR */
+ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
} /* Note change no line if hupcl is off */
/* cancel any scheduled reading */
@@ -2186,7 +1787,7 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
FTDI_SIO_SET_DATA_REQUEST,
FTDI_SIO_SET_DATA_REQUEST_TYPE,
urb_value , priv->interface,
- buf, 0, 100) < 0) {
+ buf, 0, WDR_SHORT_TIMEOUT) < 0) {
err("%s FAILED to set databits/stopbits/parity", __FUNCTION__);
}
@@ -2201,25 +1802,14 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
err("%s error from disable flowcontrol urb", __FUNCTION__);
}
/* Drop RTS and DTR */
- if (set_dtr(port, LOW) < 0){
- err("%s Error from DTR LOW urb", __FUNCTION__);
- }
- if (set_rts(port, LOW) < 0){
- err("%s Error from RTS LOW urb", __FUNCTION__);
- }
-
+ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
} else {
/* set the baudrate determined before */
if (change_speed(port)) {
err("%s urb failed to set baurdrate", __FUNCTION__);
}
/* Ensure RTS and DTR are raised */
- else if (set_dtr(port, HIGH) < 0){
- err("%s Error from DTR HIGH urb", __FUNCTION__);
- }
- else if (set_rts(port, HIGH) < 0){
- err("%s Error from RTS HIGH urb", __FUNCTION__);
- }
+ set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
}
/* Set flow control */
@@ -2331,35 +1921,8 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear)
{
- int ret;
-
dbg("%s TIOCMSET", __FUNCTION__);
- if (set & TIOCM_DTR){
- if ((ret = set_dtr(port, HIGH)) < 0) {
- err("Urb to set DTR failed");
- return(ret);
- }
- }
- if (set & TIOCM_RTS) {
- if ((ret = set_rts(port, HIGH)) < 0){
- err("Urb to set RTS failed");
- return(ret);
- }
- }
-
- if (clear & TIOCM_DTR){
- if ((ret = set_dtr(port, LOW)) < 0){
- err("Urb to unset DTR failed");
- return(ret);
- }
- }
- if (clear & TIOCM_RTS) {
- if ((ret = set_rts(port, LOW)) < 0){
- err("Urb to unset RTS failed");
- return(ret);
- }
- }
- return(0);
+ return update_mctrl(port, set, clear);
}
@@ -2367,60 +1930,11 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- int ret, mask;
-
dbg("%s cmd 0x%04x", __FUNCTION__, cmd);
/* Based on code from acm.c and others */
switch (cmd) {
- case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
- dbg("%s TIOCMBIS", __FUNCTION__);
- if (get_user(mask, (unsigned long __user *) arg))
- return -EFAULT;
- if (mask & TIOCM_DTR){
- if ((ret = set_dtr(port, HIGH)) < 0) {
- err("Urb to set DTR failed");
- return(ret);
- }
- }
- if (mask & TIOCM_RTS) {
- if ((ret = set_rts(port, HIGH)) < 0){
- err("Urb to set RTS failed");
- return(ret);
- }
- }
- return(0);
- break;
-
- case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
- dbg("%s TIOCMBIC", __FUNCTION__);
- if (get_user(mask, (unsigned long __user *) arg))
- return -EFAULT;
- if (mask & TIOCM_DTR){
- if ((ret = set_dtr(port, LOW)) < 0){
- err("Urb to unset DTR failed");
- return(ret);
- }
- }
- if (mask & TIOCM_RTS) {
- if ((ret = set_rts(port, LOW)) < 0){
- err("Urb to unset RTS failed");
- return(ret);
- }
- }
- return(0);
- break;
-
- /*
- * I had originally implemented TCSET{A,S}{,F,W} and
- * TCGET{A,S} here separately, however when testing I
- * found that the higher layers actually do the termios
- * conversions themselves and pass the call onto
- * ftdi_sio_set_termios.
- *
- */
-
case TIOCGSERIAL: /* gets serial port data */
return get_serial_info(port, (struct serial_struct __user *) arg);
@@ -2516,24 +2030,9 @@ static int __init ftdi_init (void)
int retval;
dbg("%s", __FUNCTION__);
- retval = usb_serial_register(&ftdi_SIO_device);
- if (retval)
- goto failed_SIO_register;
- retval = usb_serial_register(&ftdi_8U232AM_device);
- if (retval)
- goto failed_8U232AM_register;
- retval = usb_serial_register(&ftdi_FT232BM_device);
- if (retval)
- goto failed_FT232BM_register;
- retval = usb_serial_register(&ftdi_FT2232C_device);
- if (retval)
- goto failed_FT2232C_register;
- retval = usb_serial_register(&ftdi_USB_UIRT_device);
- if (retval)
- goto failed_USB_UIRT_register;
- retval = usb_serial_register(&ftdi_HE_TIRA1_device);
+ retval = usb_serial_register(&ftdi_sio_device);
if (retval)
- goto failed_HE_TIRA1_register;
+ goto failed_sio_register;
retval = usb_register(&ftdi_driver);
if (retval)
goto failed_usb_register;
@@ -2541,18 +2040,8 @@ static int __init ftdi_init (void)
info(DRIVER_VERSION ":" DRIVER_DESC);
return 0;
failed_usb_register:
- usb_serial_deregister(&ftdi_HE_TIRA1_device);
-failed_HE_TIRA1_register:
- usb_serial_deregister(&ftdi_USB_UIRT_device);
-failed_USB_UIRT_register:
- usb_serial_deregister(&ftdi_FT2232C_device);
-failed_FT2232C_register:
- usb_serial_deregister(&ftdi_FT232BM_device);
-failed_FT232BM_register:
- usb_serial_deregister(&ftdi_8U232AM_device);
-failed_8U232AM_register:
- usb_serial_deregister(&ftdi_SIO_device);
-failed_SIO_register:
+ usb_serial_deregister(&ftdi_sio_device);
+failed_sio_register:
return retval;
}
@@ -2563,12 +2052,7 @@ static void __exit ftdi_exit (void)
dbg("%s", __FUNCTION__);
usb_deregister (&ftdi_driver);
- usb_serial_deregister (&ftdi_HE_TIRA1_device);
- usb_serial_deregister (&ftdi_USB_UIRT_device);
- usb_serial_deregister (&ftdi_FT2232C_device);
- usb_serial_deregister (&ftdi_FT232BM_device);
- usb_serial_deregister (&ftdi_8U232AM_device);
- usb_serial_deregister (&ftdi_SIO_device);
+ usb_serial_deregister (&ftdi_sio_device);
}
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 8866376823a..9f4342093e8 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -265,10 +265,24 @@
#define MOBILITY_USB_SERIAL_PID 0x0202 /* EasiDock USB 200 serial */
/*
+ * microHAM product IDs (http://www.microham.com).
+ * Submitted by Justin Burket (KL1RL) <zorton@jtan.com>.
+ */
+#define FTDI_MHAM_Y6_PID 0xEEEA /* USB-Y6 interface */
+#define FTDI_MHAM_Y8_PID 0xEEEB /* USB-Y8 interface */
+
+/*
* Active Robots product ids.
*/
#define FTDI_ACTIVE_ROBOTS_PID 0xE548 /* USB comms board */
+/*
+ * Evolution Robotics products (http://www.evolution.com/).
+ * Submitted by Shawn M. Lavelle.
+ */
+#define EVOLUTION_VID 0xDEEE /* Vendor ID */
+#define EVOLUTION_ER1_PID 0x0300 /* ER1 Control Module */
+
/* Commands */
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 99214aa3cd1..ddde5fb13f6 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -174,10 +174,14 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *
/* only do something if we have a bulk out endpoint */
if (serial->num_bulk_out) {
- if (port->write_urb->status == -EINPROGRESS) {
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
dbg("%s - already writing", __FUNCTION__);
- return (0);
+ return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
@@ -195,17 +199,20 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *
usb_serial_generic_write_bulk_callback), port);
/* send the data out the bulk port */
+ port->write_urb_busy = 1;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
- if (result)
+ if (result) {
dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
- else
+ /* don't have to grab the lock here, as we will retry if != 0 */
+ port->write_urb_busy = 0;
+ } else
result = count;
return result;
}
/* no bulk out, so return 0 bytes written */
- return (0);
+ return 0;
}
int usb_serial_generic_write_room (struct usb_serial_port *port)
@@ -214,9 +221,9 @@ int usb_serial_generic_write_room (struct usb_serial_port *port)
int room = 0;
dbg("%s - port %d", __FUNCTION__, port->number);
-
+
if (serial->num_bulk_out) {
- if (port->write_urb->status != -EINPROGRESS)
+ if (port->write_urb_busy)
room = port->bulk_out_size;
}
@@ -232,7 +239,7 @@ int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port)
dbg("%s - port %d", __FUNCTION__, port->number);
if (serial->num_bulk_out) {
- if (port->write_urb->status == -EINPROGRESS)
+ if (port->write_urb_busy)
chars = port->write_urb->transfer_buffer_length;
}
@@ -291,6 +298,7 @@ void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *re
dbg("%s - port %d", __FUNCTION__, port->number);
+ port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 3bd69c4ef24..c05c2a2a0f3 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -818,11 +818,6 @@ static void ipaq_write_gather(struct usb_serial_port *port)
struct ipaq_packet *pkt, *tmp;
struct urb *urb = port->write_urb;
- if (urb->status == -EINPROGRESS) {
- /* Should never happen */
- err("%s - flushing while urb is active !", __FUNCTION__);
- return;
- }
room = URBDATA_SIZE;
list_for_each_entry_safe(pkt, tmp, &priv->queue, list) {
count = min(room, (int)(pkt->len - pkt->written));
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 11105d74f46..85e242459c2 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -399,16 +399,21 @@ static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int
dbg("%s - write request of 0 bytes", __FUNCTION__);
return 0;
}
-
- /* Racy and broken, FIXME properly! */
- if (port->write_urb->status == -EINPROGRESS)
+
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
+ dbg("%s - already writing", __FUNCTION__);
return 0;
+ }
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
count = min(count, port->bulk_out_size);
memcpy(port->bulk_out_buffer, buf, count);
dbg("%s count now:%d", __FUNCTION__, count);
-
+
usb_fill_bulk_urb(port->write_urb, dev,
usb_sndbulkpipe(dev, port->bulk_out_endpointAddress),
port->write_urb->transfer_buffer,
@@ -418,6 +423,7 @@ static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int
ret = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (ret != 0) {
+ port->write_urb_busy = 0;
dbg("%s - usb_submit_urb(write bulk) failed with error = %d", __FUNCTION__, ret);
return ret;
}
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 59f234df5f8..937b2fdd717 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -341,10 +341,14 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int
if (count == 0)
return 0;
- if (port->write_urb->status == -EINPROGRESS) {
- dbg ("%s - already writing", __FUNCTION__);
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
+ dbg("%s - already writing", __FUNCTION__);
return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
transfer_buffer = port->write_urb->transfer_buffer;
transfer_size = min(count, port->bulk_out_size - 1);
@@ -374,9 +378,10 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int
port->write_urb->transfer_flags = URB_ZERO_PACKET;
result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
- if (result)
+ if (result) {
+ port->write_urb_busy = 0;
dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
- else
+ } else
result = transfer_size;
return result;
@@ -387,7 +392,8 @@ static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
dbg("%s - port %d", __FUNCTION__, port->number);
-
+
+ port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 7fd0aa9eccf..635c384cb15 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -520,9 +520,13 @@ static int keyspan_pda_write(struct usb_serial_port *port,
the TX urb is in-flight (wait until it completes)
the device is full (wait until it says there is room)
*/
- if (port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) {
- return( 0 );
+ spin_lock(&port->lock);
+ if (port->write_urb_busy || priv->tx_throttled) {
+ spin_unlock(&port->lock);
+ return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
/* At this point the URB is in our control, nobody else can submit it
again (the only sudden transition was the one from EINPROGRESS to
@@ -570,7 +574,7 @@ static int keyspan_pda_write(struct usb_serial_port *port,
memcpy (port->write_urb->transfer_buffer, buf, count);
/* send the data out the bulk port */
port->write_urb->transfer_buffer_length = count;
-
+
priv->tx_room -= count;
port->write_urb->dev = port->serial->dev;
@@ -593,6 +597,8 @@ static int keyspan_pda_write(struct usb_serial_port *port,
rc = count;
exit:
+ if (rc < 0)
+ port->write_urb_busy = 0;
return rc;
}
@@ -602,6 +608,7 @@ static void keyspan_pda_write_bulk_callback (struct urb *urb, struct pt_regs *re
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct keyspan_pda_private *priv;
+ port->write_urb_busy = 0;
priv = usb_get_serial_port_data(port);
/* queue up a wakeup at scheduler time */
@@ -626,12 +633,12 @@ static int keyspan_pda_write_room (struct usb_serial_port *port)
static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
{
struct keyspan_pda_private *priv;
-
+
priv = usb_get_serial_port_data(port);
-
+
/* when throttled, return at least WAKEUP_CHARS to tell select() (via
n_tty.c:normal_poll() ) that we're not writeable. */
- if( port->write_urb->status == -EINPROGRESS || priv->tx_throttled )
+ if (port->write_urb_busy || priv->tx_throttled)
return 256;
return 0;
}
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index b5f2c06d4f3..6a99ae192df 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -254,10 +254,15 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf
dbg("%s - write request of 0 bytes", __FUNCTION__);
return (0);
}
- if (wport->write_urb->status == -EINPROGRESS) {
+
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
dbg("%s - already writing", __FUNCTION__);
- return (0);
+ return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
@@ -275,9 +280,10 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf
wport->write_urb->dev = serial->dev;
result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
- if (result)
+ if (result) {
+ port->write_urb_busy = 0;
err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
- else
+ } else
result = count;
return result;
@@ -291,7 +297,7 @@ static int omninet_write_room (struct usb_serial_port *port)
int room = 0; // Default: no room
- if (wport->write_urb->status != -EINPROGRESS)
+ if (wport->write_urb_busy)
room = wport->bulk_out_size - OMNINET_HEADERLEN;
// dbg("omninet_write_room returns %d", room);
@@ -306,6 +312,7 @@ static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
// dbg("omninet_write_bulk_callback, port %0x\n", port);
+ port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index b722175f108..e9256408757 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -12,14 +12,25 @@
History:
2005-05-19 v0.1 Initial version, based on incomplete docs
- and analysis of misbehavior of the standard driver
+ and analysis of misbehavior with the standard driver
2005-05-20 v0.2 Extended the input buffer to avoid losing
random 64-byte chunks of data
2005-05-21 v0.3 implemented chars_in_buffer()
turned on low_latency
simplified the code somewhat
+ 2005-05-24 v0.4 option_write() sometimes deadlocked under heavy load
+ removed some dead code
+ added sponsor notice
+ coding style clean-up
+ 2005-06-20 v0.4.1 add missing braces :-/
+ killed end-of-line whitespace
+ 2005-07-15 v0.4.2 rename WLAN product to FUSION, add FUSION2
+
+ Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
+
*/
-#define DRIVER_VERSION "v0.3"
+
+#define DRIVER_VERSION "v0.4"
#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
#define DRIVER_DESC "Option Card (PC-Card to) USB to Serial Driver"
@@ -44,7 +55,6 @@ static int option_write_room (struct usb_serial_port *port);
static void option_instat_callback(struct urb *urb, struct pt_regs *regs);
-
static int option_write (struct usb_serial_port *port,
const unsigned char *buf, int count);
@@ -60,14 +70,17 @@ static int option_tiocmset (struct usb_serial_port *port, struct file *file,
static int option_send_setup (struct usb_serial_port *port);
/* Vendor and product IDs */
-#define OPTION_VENDOR_ID 0x0AF0
+#define OPTION_VENDOR_ID 0x0AF0
+
+#define OPTION_PRODUCT_OLD 0x5000
+#define OPTION_PRODUCT_FUSION 0x6000
+#define OPTION_PRODUCT_FUSION2 0x6300
-#define OPTION_PRODUCT_OLD 0x5000
-#define OPTION_PRODUCT_WLAN 0x6000
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_WLAN) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
{ } /* Terminating entry */
};
@@ -85,58 +98,62 @@ static struct usb_driver option_driver = {
* recognizes separately, thus num_port=1.
*/
static struct usb_serial_device_type option_3port_device = {
- .owner = THIS_MODULE,
- .name = "Option 3-port card",
- .short_name = "option",
- .id_table = option_ids,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
- .num_ports = 1, /* 3 */
- .open = option_open,
- .close = option_close,
- .write = option_write,
- .write_room = option_write_room,
- .chars_in_buffer = option_chars_in_buffer,
- .throttle = option_rx_throttle,
- .unthrottle = option_rx_unthrottle,
- .ioctl = option_ioctl,
- .set_termios = option_set_termios,
- .break_ctl = option_break_ctl,
- .tiocmget = option_tiocmget,
- .tiocmset = option_tiocmset,
- .attach = option_startup,
- .shutdown = option_shutdown,
- .read_int_callback = option_instat_callback,
+ .owner = THIS_MODULE,
+ .name = "Option 3G data card",
+ .short_name = "option",
+ .id_table = option_ids,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = NUM_DONT_CARE,
+ .num_bulk_out = NUM_DONT_CARE,
+ .num_ports = 1, /* 3, but the card reports its ports separately */
+ .open = option_open,
+ .close = option_close,
+ .write = option_write,
+ .write_room = option_write_room,
+ .chars_in_buffer = option_chars_in_buffer,
+ .throttle = option_rx_throttle,
+ .unthrottle = option_rx_unthrottle,
+ .ioctl = option_ioctl,
+ .set_termios = option_set_termios,
+ .break_ctl = option_break_ctl,
+ .tiocmget = option_tiocmget,
+ .tiocmset = option_tiocmset,
+ .attach = option_startup,
+ .shutdown = option_shutdown,
+ .read_int_callback = option_instat_callback,
};
+#ifdef CONFIG_USB_DEBUG
static int debug;
+#else
+#define debug 0
+#endif
+
/* per port private data */
-#define N_IN_URB 4
-#define N_OUT_URB 1
-#define IN_BUFLEN 1024
-#define OUT_BUFLEN 1024
+#define N_IN_URB 4
+#define N_OUT_URB 1
+#define IN_BUFLEN 1024
+#define OUT_BUFLEN 128
struct option_port_private {
/* Input endpoints and buffer for this port */
- struct urb *in_urbs[N_IN_URB];
- char in_buffer[N_IN_URB][IN_BUFLEN];
+ struct urb *in_urbs[N_IN_URB];
+ char in_buffer[N_IN_URB][IN_BUFLEN];
/* Output endpoints and buffer for this port */
- struct urb *out_urbs[N_OUT_URB];
- char out_buffer[N_OUT_URB][OUT_BUFLEN];
+ struct urb *out_urbs[N_OUT_URB];
+ char out_buffer[N_OUT_URB][OUT_BUFLEN];
/* Settings for the port */
- int rts_state; /* Handshaking pins (outputs) */
- int dtr_state;
- int cts_state; /* Handshaking pins (inputs) */
- int dsr_state;
- int dcd_state;
- int ri_state;
- // int break_on;
-
- unsigned long tx_start_time[N_OUT_URB];
+ int rts_state; /* Handshaking pins (outputs) */
+ int dtr_state;
+ int cts_state; /* Handshaking pins (inputs) */
+ int dsr_state;
+ int dcd_state;
+ int ri_state;
+
+ unsigned long tx_start_time[N_OUT_URB];
};
@@ -190,13 +207,13 @@ static void
option_break_ctl (struct usb_serial_port *port, int break_state)
{
/* Unfortunately, I don't know how to send a break */
- dbg("%s", __FUNCTION__);
+ dbg("%s", __FUNCTION__);
}
static void
option_set_termios (struct usb_serial_port *port,
- struct termios *old_termios)
+ struct termios *old_termios)
{
dbg("%s", __FUNCTION__);
@@ -204,10 +221,10 @@ option_set_termios (struct usb_serial_port *port,
}
static int
-option_tiocmget(struct usb_serial_port *port, struct file *file)
+option_tiocmget (struct usb_serial_port *port, struct file *file)
{
- unsigned int value;
- struct option_port_private *portdata;
+ unsigned int value;
+ struct option_port_private *portdata;
portdata = usb_get_serial_port_data(port);
@@ -225,7 +242,7 @@ static int
option_tiocmset (struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear)
{
- struct option_port_private *portdata;
+ struct option_port_private *portdata;
portdata = usb_get_serial_port_data(port);
@@ -250,71 +267,50 @@ option_ioctl (struct usb_serial_port *port, struct file *file,
/* Write */
static int
-option_write(struct usb_serial_port *port,
- const unsigned char *buf, int count)
+option_write (struct usb_serial_port *port,
+ const unsigned char *buf, int count)
{
- struct option_port_private *portdata;
- int i;
- int left, todo;
- struct urb *this_urb = NULL; /* spurious */
- int err;
+ struct option_port_private *portdata;
+ int i;
+ int left, todo;
+ struct urb *this_urb = NULL; /* spurious */
+ int err;
portdata = usb_get_serial_port_data(port);
dbg("%s: write (%d chars)", __FUNCTION__, count);
-#if 0
- spin_lock(&port->lock);
- if (port->write_urb_busy) {
- spin_unlock(&port->lock);
- dbg("%s: already writing", __FUNCTION__);
- return 0;
- }
- port->write_urb_busy = 1;
- spin_unlock(&port->lock);
-#endif
-
i = 0;
left = count;
- while (left>0) {
+ for (i=0; left > 0 && i < N_OUT_URB; i++) {
todo = left;
if (todo > OUT_BUFLEN)
todo = OUT_BUFLEN;
- for (;i < N_OUT_URB; i++) {
- /* Check we have a valid urb/endpoint before we use it... */
- this_urb = portdata->out_urbs[i];
- if (this_urb->status != -EINPROGRESS)
- break;
+ this_urb = portdata->out_urbs[i];
+ if (this_urb->status == -EINPROGRESS) {
if (this_urb->transfer_flags & URB_ASYNC_UNLINK)
continue;
if (time_before(jiffies, portdata->tx_start_time[i] + 10 * HZ))
continue;
this_urb->transfer_flags |= URB_ASYNC_UNLINK;
usb_unlink_urb(this_urb);
+ continue;
}
-
- if (i == N_OUT_URB) {
- /* no bulk out free! */
- dbg("%s: no output urb -- left %d", __FUNCTION__,count-left);
-#if 0
- port->write_urb_busy = 0;
-#endif
- return count-left;
- }
+ if (this_urb->status != 0)
+ dbg("usb_write %p failed (err=%d)", this_urb, this_urb->status);
dbg("%s: endpoint %d buf %d", __FUNCTION__, usb_pipeendpoint(this_urb->pipe), i);
+ /* send the data */
memcpy (this_urb->transfer_buffer, buf, todo);
-
- /* send the data out the bulk port */
this_urb->transfer_buffer_length = todo;
this_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
this_urb->dev = port->serial->dev;
err = usb_submit_urb(this_urb, GFP_ATOMIC);
if (err) {
- dbg("usb_submit_urb %p (write bulk) failed (%d,, has %d)", this_urb, err, this_urb->status);
+ dbg("usb_submit_urb %p (write bulk) failed (%d, has %d)", this_urb, err, this_urb->status);
continue;
}
portdata->tx_start_time[i] = jiffies;
@@ -323,9 +319,6 @@ option_write(struct usb_serial_port *port,
}
count -= left;
-#if 0
- port->write_urb_busy = 0;
-#endif
dbg("%s: wrote (did %d)", __FUNCTION__, count);
return count;
}
@@ -333,7 +326,7 @@ option_write(struct usb_serial_port *port,
static void
option_indat_callback (struct urb *urb, struct pt_regs *regs)
{
- int i, err;
+ int i, err;
int endpoint;
struct usb_serial_port *port;
struct tty_struct *tty;
@@ -444,10 +437,11 @@ option_write_room (struct usb_serial_port *port)
portdata = usb_get_serial_port_data(port);
- for (i=0; i < N_OUT_URB; i++)
+ for (i=0; i < N_OUT_URB; i++) {
this_urb = portdata->out_urbs[i];
if (this_urb && this_urb->status != -EINPROGRESS)
data_len += OUT_BUFLEN;
+ }
dbg("%s: %d", __FUNCTION__, data_len);
return data_len;
@@ -464,11 +458,11 @@ option_chars_in_buffer (struct usb_serial_port *port)
portdata = usb_get_serial_port_data(port);
- for (i=0; i < N_OUT_URB; i++)
+ for (i=0; i < N_OUT_URB; i++) {
this_urb = portdata->out_urbs[i];
if (this_urb && this_urb->status == -EINPROGRESS)
data_len += this_urb->transfer_buffer_length;
-
+ }
dbg("%s: %d", __FUNCTION__, data_len);
return data_len;
}
@@ -477,10 +471,10 @@ option_chars_in_buffer (struct usb_serial_port *port)
static int
option_open (struct usb_serial_port *port, struct file *filp)
{
- struct option_port_private *portdata;
- struct usb_serial *serial = port->serial;
- int i, err;
- struct urb *urb;
+ struct option_port_private *portdata;
+ struct usb_serial *serial = port->serial;
+ int i, err;
+ struct urb *urb;
portdata = usb_get_serial_port_data(port);
@@ -528,7 +522,7 @@ option_open (struct usb_serial_port *port, struct file *filp)
}
static inline void
-stop_urb(struct urb *urb)
+stop_urb (struct urb *urb)
{
if (urb && urb->status == -EINPROGRESS) {
urb->transfer_flags &= ~URB_ASYNC_UNLINK;
@@ -537,11 +531,11 @@ stop_urb(struct urb *urb)
}
static void
-option_close(struct usb_serial_port *port, struct file *filp)
+option_close (struct usb_serial_port *port, struct file *filp)
{
- int i;
- struct usb_serial *serial = port->serial;
- struct option_port_private *portdata;
+ int i;
+ struct usb_serial *serial = port->serial;
+ struct option_port_private *portdata;
dbg("%s", __FUNCTION__);
portdata = usb_get_serial_port_data(port);
@@ -589,11 +583,11 @@ option_setup_urb (struct usb_serial *serial, int endpoint,
/* Setup urbs */
static void
-option_setup_urbs(struct usb_serial *serial)
+option_setup_urbs (struct usb_serial *serial)
{
- int j;
- struct usb_serial_port *port;
- struct option_port_private *portdata;
+ int j;
+ struct usb_serial_port *port;
+ struct option_port_private *portdata;
dbg("%s", __FUNCTION__);
@@ -617,7 +611,7 @@ option_setup_urbs(struct usb_serial *serial)
static int
-option_send_setup(struct usb_serial_port *port)
+option_send_setup (struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct option_port_private *portdata;
@@ -644,9 +638,9 @@ option_send_setup(struct usb_serial_port *port)
static int
option_startup (struct usb_serial *serial)
{
- int i, err;
- struct usb_serial_port *port;
- struct option_port_private *portdata;
+ int i, err;
+ struct usb_serial_port *port;
+ struct option_port_private *portdata;
dbg("%s", __FUNCTION__);
@@ -677,9 +671,9 @@ option_startup (struct usb_serial *serial)
static void
option_shutdown (struct usb_serial *serial)
{
- int i, j;
- struct usb_serial_port *port;
- struct option_port_private *portdata;
+ int i, j;
+ struct usb_serial_port *port;
+ struct option_port_private *portdata;
dbg("%s", __FUNCTION__);
@@ -724,6 +718,8 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
+#ifdef CONFIG_USB_DEBUG
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug messages");
+#endif
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 0e85ed6c6c1..96a17568cbf 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -299,10 +299,14 @@ static int safe_write (struct usb_serial_port *port, const unsigned char *buf, i
dbg ("%s - write request of 0 bytes", __FUNCTION__);
return (0);
}
- if (port->write_urb->status == -EINPROGRESS) {
- dbg ("%s - already writing", __FUNCTION__);
- return (0);
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
+ dbg("%s - already writing", __FUNCTION__);
+ return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
packet_length = port->bulk_out_size; // get max packetsize
@@ -354,6 +358,7 @@ static int safe_write (struct usb_serial_port *port, const unsigned char *buf, i
#endif
port->write_urb->dev = port->serial->dev;
if ((result = usb_submit_urb (port->write_urb, GFP_KERNEL))) {
+ port->write_urb_busy = 0;
err ("%s - failed submitting write urb, error %d", __FUNCTION__, result);
return 0;
}
@@ -368,7 +373,7 @@ static int safe_write_room (struct usb_serial_port *port)
dbg ("%s", __FUNCTION__);
- if (port->write_urb->status != -EINPROGRESS)
+ if (port->write_urb_busy)
room = port->bulk_out_size - (safe ? 2 : 0);
if (room) {
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 5da76dd8fb2..0267b26dde1 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -1047,6 +1047,7 @@ int usb_serial_probe(struct usb_interface *interface,
memset(port, 0x00, sizeof(struct usb_serial_port));
port->number = i + serial->minor;
port->serial = serial;
+ spin_lock_init(&port->lock);
INIT_WORK(&port->work, usb_serial_port_softint, port);
serial->port[i] = port;
}
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index d1f0c4057fa..57f92f054c7 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -69,6 +69,7 @@
* usb_serial_port: structure for the specific ports of a device.
* @serial: pointer back to the struct usb_serial owner of this port.
* @tty: pointer to the corresponding tty for this port.
+ * @lock: spinlock to grab when updating portions of this structure.
* @number: the number of the port (the minor number).
* @interrupt_in_buffer: pointer to the interrupt in buffer for this port.
* @interrupt_in_urb: pointer to the interrupt in struct urb for this port.
@@ -98,6 +99,7 @@
struct usb_serial_port {
struct usb_serial * serial;
struct tty_struct * tty;
+ spinlock_t lock;
unsigned char number;
unsigned char * interrupt_in_buffer;
@@ -117,6 +119,7 @@ struct usb_serial_port {
unsigned char * bulk_out_buffer;
int bulk_out_size;
struct urb * write_urb;
+ int write_urb_busy;
__u8 bulk_out_endpointAddress;
wait_queue_head_t write_wait;