USB: ftdi_sio: fix status line change handling for TIOCMIWAIT and TIOCGICOUNT
[linux-flexiantxendom0.git] / drivers / usb / serial / ftdi_sio.c
index ff3db5d..cfc8e59 100644 (file)
@@ -75,7 +75,7 @@ struct ftdi_private {
        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 +188,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) },
@@ -536,6 +537,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) },
@@ -797,6 +802,7 @@ 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(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID) },
        { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
        { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
@@ -805,6 +811,8 @@ static struct usb_device_id id_table_combined [] = {
        { 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 +844,16 @@ 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),
                .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) },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
@@ -863,7 +876,8 @@ static const char *ftdi_chip_name[] = {
        [FT232RL] = "FT232RL",
        [FT2232H] = "FT2232H",
        [FT4232H] = "FT4232H",
-       [FT232H]  = "FT232H"
+       [FT232H]  = "FT232H",
+       [FTX]     = "FT-X"
 };
 
 
@@ -1164,7 +1178,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 +1348,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 +1468,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 +1603,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 +1626,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);
                }
        }
@@ -1759,7 +1779,8 @@ 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/XDS100")))
                return ftdi_jtag_probe(serial);
 
        return 0;
@@ -1824,6 +1845,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 +1864,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);
@@ -1955,17 +1979,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_all(&priv->delta_msr_wait);
                priv->prev_status = status;
        }
 
@@ -2277,6 +2303,7 @@ static int ftdi_tiocmget(struct tty_struct *tty)
        case FT2232H:
        case FT4232H:
        case FT232H:
+       case FTX:
                len = 2;
                break;
        default: