usb: serial: option: add Olivetti Olicard 200
[pandora-kernel.git] / drivers / usb / serial / ftdi_sio.c
index ff3db5d..ce9f87f 100644 (file)
@@ -74,8 +74,7 @@ struct ftdi_private {
        int flags;              /* some ASYNC_xxxx flags are supported */
        unsigned long last_dtr_rts;     /* saved modem control outputs */
        struct async_icount     icount;
-       wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
-       char prev_status, diff_status;        /* Used for TIOCMIWAIT */
+       char prev_status;        /* Used for TIOCMIWAIT */
        char transmit_empty;    /* If transmitter is empty or not */
        struct usb_serial_port *port;
        __u16 interface;        /* FT2232C, FT2232H or FT4232H port interface
@@ -188,6 +187,7 @@ static struct usb_device_id id_table_combined [] = {
                .driver_info = (kernel_ulong_t)&ftdi_8u2232c_quirk },
        { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_232H_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_FTX_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) },
@@ -195,6 +195,10 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_BOOST_PID) },
+       { USB_DEVICE(NEWPORT_VID, NEWPORT_AGILIS_PID) },
+       { USB_DEVICE(NEWPORT_VID, NEWPORT_CONEX_CC_PID) },
+       { USB_DEVICE(NEWPORT_VID, NEWPORT_CONEX_AGP_PID) },
        { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
        { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) },
@@ -536,6 +540,10 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_6_PID) },
        { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) },
        { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) },
+       { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_1_PID) },
+       { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_2_PID) },
+       { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_3_PID) },
+       { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_4_PID) },
        { USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) },
        { USB_DEVICE(OCT_VID, OCT_US101_PID) },
        { USB_DEVICE(OCT_VID, OCT_DK201_PID) },
@@ -578,9 +586,12 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        /*
         * ELV devices:
         */
+       { USB_DEVICE(FTDI_ELV_VID, FTDI_ELV_WS300_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) },
@@ -638,6 +649,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
        { USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) },
        { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) },
+       { USB_DEVICE(MITSUBISHI_VID, MITSUBISHI_FXUSB_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
@@ -667,6 +679,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) },
        { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) },
        { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_OMNI1509) },
        { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MHAM_KW_PID) },
@@ -698,6 +711,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_NZR_SEM_USB_PID) },
        { USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) },
        { USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) },
        { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) },
@@ -731,6 +745,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
        { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) },
        { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_RTS01_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) },
        { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
@@ -797,14 +812,38 @@ static struct usb_device_id id_table_combined [] = {
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID,
+                                       USB_CLASS_VENDOR_SPEC,
+                                       USB_SUBCLASS_VENDOR_SPEC, 0x00) },
        { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
        { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) },
        { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) },
+       { USB_DEVICE(FTDI_VID, PI_C865_PID) },
+       { USB_DEVICE(FTDI_VID, PI_C857_PID) },
+       { USB_DEVICE(PI_VID, PI_C866_PID) },
+       { USB_DEVICE(PI_VID, PI_C663_PID) },
+       { USB_DEVICE(PI_VID, PI_C725_PID) },
+       { USB_DEVICE(PI_VID, PI_E517_PID) },
+       { USB_DEVICE(PI_VID, PI_C863_PID) },
+       { USB_DEVICE(PI_VID, PI_E861_PID) },
+       { USB_DEVICE(PI_VID, PI_C867_PID) },
+       { USB_DEVICE(PI_VID, PI_E609_PID) },
+       { USB_DEVICE(PI_VID, PI_E709_PID) },
+       { USB_DEVICE(PI_VID, PI_100F_PID) },
+       { USB_DEVICE(PI_VID, PI_1011_PID) },
+       { USB_DEVICE(PI_VID, PI_1012_PID) },
+       { USB_DEVICE(PI_VID, PI_1013_PID) },
+       { USB_DEVICE(PI_VID, PI_1014_PID) },
+       { USB_DEVICE(PI_VID, PI_1015_PID) },
+       { USB_DEVICE(PI_VID, PI_1016_PID) },
+       { USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) },
        { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) },
        { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(FTDI_VID, TI_XDS100V2_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) },
        { USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) },
        { USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) },
@@ -836,11 +875,20 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
        { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
-       { USB_DEVICE(ST_VID, ST_STMCLT1030_PID),
+       { USB_DEVICE(ST_VID, ST_STMCLT_2232_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(ST_VID, ST_STMCLT_4232_PID),
                .driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_RF_R106) },
+       { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) },
+       /* Crucible Devices */
+       { USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
@@ -863,7 +911,8 @@ static const char *ftdi_chip_name[] = {
        [FT232RL] = "FT232RL",
        [FT2232H] = "FT2232H",
        [FT4232H] = "FT4232H",
-       [FT232H]  = "FT232H"
+       [FT232H]  = "FT232H",
+       [FTX]     = "FT-X"
 };
 
 
@@ -1164,7 +1213,8 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
                break;
        case FT232BM: /* FT232BM chip */
        case FT2232C: /* FT2232C chip */
-       case FT232RL:
+       case FT232RL: /* FT232RL chip */
+       case FTX:     /* FT-X series */
                if (baud <= 3000000) {
                        __u16 product_id = le16_to_cpu(
                                port->serial->dev->descriptor.idProduct);
@@ -1333,8 +1383,7 @@ static int set_serial_info(struct tty_struct *tty,
                goto check_and_exit;
        }
 
-       if ((new_serial.baud_base != priv->baud_base) &&
-           (new_serial.baud_base < 9600)) {
+       if (new_serial.baud_base != priv->baud_base) {
                mutex_unlock(&priv->cfg_lock);
                return -EINVAL;
        }
@@ -1454,10 +1503,14 @@ static void ftdi_determine_type(struct usb_serial_port *port)
        } else if (version < 0x900) {
                /* Assume it's an FT232RL */
                priv->chip_type = FT232RL;
-       } else {
+       } else if (version < 0x1000) {
                /* Assume it's an FT232H */
                priv->chip_type = FT232H;
+       } else {
+               /* Assume it's an FT-X series device */
+               priv->chip_type = FTX;
        }
+
        dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]);
 }
 
@@ -1585,7 +1638,8 @@ static int create_sysfs_attrs(struct usb_serial_port *port)
                     priv->chip_type == FT232RL ||
                     priv->chip_type == FT2232H ||
                     priv->chip_type == FT4232H ||
-                    priv->chip_type == FT232H)) {
+                    priv->chip_type == FT232H ||
+                    priv->chip_type == FTX)) {
                        retval = device_create_file(&port->dev,
                                                    &dev_attr_latency_timer);
                }
@@ -1607,7 +1661,8 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
                    priv->chip_type == FT232RL ||
                    priv->chip_type == FT2232H ||
                    priv->chip_type == FT4232H ||
-                    priv->chip_type == FT232H) {
+                   priv->chip_type == FT232H ||
+                   priv->chip_type == FTX) {
                        device_remove_file(&port->dev, &dev_attr_latency_timer);
                }
        }
@@ -1656,7 +1711,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
        kref_init(&priv->kref);
        mutex_init(&priv->cfg_lock);
        memset(&priv->icount, 0x00, sizeof(priv->icount));
-       init_waitqueue_head(&priv->delta_msr_wait);
 
        priv->flags = ASYNC_LOW_LATENCY;
 
@@ -1759,15 +1813,19 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial)
 
        dbg("%s", __func__);
 
-       if (strcmp(udev->manufacturer, "CALAO Systems") == 0)
+       if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) ||
+           (udev->product && !strcmp(udev->product, "BeagleBone/XDS100V2")))
                return ftdi_jtag_probe(serial);
 
        return 0;
 }
 
 /*
- * First and second port on STMCLiteadaptors is reserved for JTAG interface
- * and the forth port for pio
+ * First two ports on JTAG adaptors using an FT4232 such as STMicroelectronics's
+ * ST Micro Connect Lite are reserved for JTAG or other non-UART interfaces and
+ * can be accessed from userspace.
+ * The next two ports are enabled as UARTs by default, where port 2 is
+ * a conventional RS-232 UART.
  */
 static int ftdi_stmclite_probe(struct usb_serial *serial)
 {
@@ -1776,12 +1834,13 @@ static int ftdi_stmclite_probe(struct usb_serial *serial)
 
        dbg("%s", __func__);
 
-       if (interface == udev->actconfig->interface[2])
-               return 0;
-
-       dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n");
+       if (interface == udev->actconfig->interface[0] ||
+           interface == udev->actconfig->interface[1]) {
+               dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n");
+               return -ENODEV;
+       }
 
-       return -ENODEV;
+       return 0;
 }
 
 /*
@@ -1815,6 +1874,8 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
 
        dbg("%s", __func__);
 
+       wake_up_interruptible(&port->delta_msr_wait);
+
        remove_sysfs_attrs(port);
 
        kref_put(&priv->kref, ftdi_sio_priv_release);
@@ -1824,6 +1885,7 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
 
 static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
+       struct ktermios dummy;
        struct usb_device *dev = port->serial->dev;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        int result;
@@ -1842,8 +1904,10 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
           This is same behaviour as serial.c/rs_open() - Kuba */
 
        /* ftdi_set_termios  will send usb control messages */
-       if (tty)
-               ftdi_set_termios(tty, port, tty->termios);
+       if (tty) {
+               memset(&dummy, 0, sizeof(dummy));
+               ftdi_set_termios(tty, port, &dummy);
+       }
 
        /* Start reading from the device */
        result = usb_serial_generic_open(tty, port);
@@ -1857,24 +1921,22 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
 
-       mutex_lock(&port->serial->disc_mutex);
-       if (!port->serial->disconnected) {
-               /* Disable flow control */
-               if (!on && usb_control_msg(port->serial->dev,
+       /* Disable flow control */
+       if (!on) {
+               if (usb_control_msg(port->serial->dev,
                            usb_sndctrlpipe(port->serial->dev, 0),
                            FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                            FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
                            0, priv->interface, NULL, 0,
                            WDR_TIMEOUT) < 0) {
-                           dev_err(&port->dev, "error from flowcontrol urb\n");
+                       dev_err(&port->dev, "error from flowcontrol urb\n");
                }
-               /* drop RTS and DTR */
-               if (on)
-                       set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
-               else
-                       clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
        }
-       mutex_unlock(&port->serial->disc_mutex);
+       /* drop RTS and DTR */
+       if (on)
+               set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+       else
+               clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
 }
 
 /*
@@ -1955,17 +2017,19 @@ static int ftdi_process_packet(struct tty_struct *tty,
           N.B. packet may be processed more than once, but differences
           are only processed once.  */
        status = packet[0] & FTDI_STATUS_B0_MASK;
-       if (status & FTDI_RS0_CTS)
-               priv->icount.cts++;
-       if (status & FTDI_RS0_DSR)
-               priv->icount.dsr++;
-       if (status & FTDI_RS0_RI)
-               priv->icount.rng++;
-       if (status & FTDI_RS0_RLSD)
-               priv->icount.dcd++;
        if (status != priv->prev_status) {
-               priv->diff_status |= status ^ priv->prev_status;
-               wake_up_interruptible(&priv->delta_msr_wait);
+               char diff_status = status ^ priv->prev_status;
+
+               if (diff_status & FTDI_RS0_CTS)
+                       priv->icount.cts++;
+               if (diff_status & FTDI_RS0_DSR)
+                       priv->icount.dsr++;
+               if (diff_status & FTDI_RS0_RI)
+                       priv->icount.rng++;
+               if (diff_status & FTDI_RS0_RLSD)
+                       priv->icount.dcd++;
+
+               wake_up_interruptible(&port->delta_msr_wait);
                priv->prev_status = status;
        }
 
@@ -2105,6 +2169,9 @@ static void ftdi_set_termios(struct tty_struct *tty,
 
        cflag = termios->c_cflag;
 
+       if (!old_termios)
+               goto no_skip;
+
        if (old_termios->c_cflag == termios->c_cflag
            && old_termios->c_ispeed == termios->c_ispeed
            && old_termios->c_ospeed == termios->c_ospeed)
@@ -2118,6 +2185,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
            (termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB)))
                goto no_data_parity_stop_changes;
 
+no_skip:
        /* Set number of data bits, parity, stop bits */
 
        urb_value = 0;
@@ -2277,6 +2345,7 @@ static int ftdi_tiocmget(struct tty_struct *tty)
        case FT2232H:
        case FT4232H:
        case FT232H:
+       case FTX:
                len = 2;
                break;
        default:
@@ -2363,15 +2432,16 @@ static int ftdi_ioctl(struct tty_struct *tty,
         */
        case TIOCMIWAIT:
                cprev = priv->icount;
-               while (1) {
-                       interruptible_sleep_on(&priv->delta_msr_wait);
+               for (;;) {
+                       interruptible_sleep_on(&port->delta_msr_wait);
                        /* see if a signal did it */
                        if (signal_pending(current))
                                return -ERESTARTSYS;
+
+                       if (port->serial->disconnected)
+                               return -EIO;
+
                        cnow = priv->icount;
-                       if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
-                           cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
-                               return -EIO; /* no change => error */
                        if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
                            ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
                            ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
@@ -2380,8 +2450,6 @@ static int ftdi_ioctl(struct tty_struct *tty,
                        }
                        cprev = cnow;
                }
-               /* not reached */
-               break;
        case TIOCSERGETLSR:
                return get_lsr_info(port, (struct serial_struct __user *)arg);
                break;