diff options
Diffstat (limited to 'drivers/usb/serial/ftdi_sio.c')
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 127 |
1 files changed, 91 insertions, 36 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index be84587..edd162d 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -73,7 +73,6 @@ struct ftdi_private { char prev_status; /* Used for TIOCMIWAIT */ bool dev_gone; /* Used to abort TIOCMIWAIT */ char transmit_empty; /* If transmitter is empty or not */ - struct usb_serial_port *port; __u16 interface; /* FT2232C, FT2232H or FT4232H port interface (0 for FT232/245) */ @@ -192,6 +191,7 @@ 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(NEWPORT_VID, NEWPORT_AGILIS_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) }, @@ -584,6 +584,7 @@ static struct usb_device_id id_table_combined [] = { /* * 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) }, @@ -670,6 +671,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) }, @@ -875,6 +877,8 @@ static struct usb_device_id id_table_combined [] = { { 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 */ }; @@ -923,6 +927,9 @@ static int ftdi_get_icount(struct tty_struct *tty, static int ftdi_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); static void ftdi_break_ctl(struct tty_struct *tty, int break_state); +static int ftdi_chars_in_buffer(struct tty_struct *tty); +static int ftdi_get_modem_status(struct tty_struct *tty, + unsigned char status[2]); static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base); static unsigned short int ftdi_232am_baud_to_divisor(int baud); @@ -957,6 +964,7 @@ static struct usb_serial_driver ftdi_sio_device = { .ioctl = ftdi_ioctl, .set_termios = ftdi_set_termios, .break_ctl = ftdi_break_ctl, + .chars_in_buffer = ftdi_chars_in_buffer, }; static struct usb_serial_driver * const serial_drivers[] = { @@ -1090,6 +1098,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, __func__, (set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged", (set & TIOCM_RTS) ? "HIGH" : (clear & TIOCM_RTS) ? "LOW" : "unchanged"); + rv = usb_translate_errors(rv); } else { dev_dbg(dev, "%s - DTR %s, RTS %s\n", __func__, (set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged", @@ -1682,7 +1691,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; @@ -1691,7 +1699,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) if (quirk && quirk->port_probe) quirk->port_probe(priv); - priv->port = port; usb_set_serial_port_data(port, priv); ftdi_determine_type(port); @@ -1781,7 +1788,7 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial) struct usb_device *udev = serial->dev; if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) || - (udev->product && !strcmp(udev->product, "BeagleBone/XDS100"))) + (udev->product && !strcmp(udev->product, "BeagleBone/XDS100V2"))) return ftdi_jtag_probe(serial); return 0; @@ -1879,24 +1886,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,9 +1960,8 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port, #define FTDI_RS_ERR_MASK (FTDI_RS_BI | FTDI_RS_PE | FTDI_RS_FE | FTDI_RS_OE) -static int ftdi_process_packet(struct tty_struct *tty, - struct usb_serial_port *port, struct ftdi_private *priv, - char *packet, int len) +static int ftdi_process_packet(struct usb_serial_port *port, + struct ftdi_private *priv, char *packet, int len) { int i; char status; @@ -2007,7 +2011,7 @@ static int ftdi_process_packet(struct tty_struct *tty, /* Overrun is special, not associated with a char */ if (packet[1] & FTDI_RS_OE) { priv->icount.overrun++; - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); } } @@ -2026,10 +2030,10 @@ static int ftdi_process_packet(struct tty_struct *tty, if (port->port.console && port->sysrq) { for (i = 0; i < len; i++, ch++) { if (!usb_serial_handle_sysrq_char(port, *ch)) - tty_insert_flip_char(tty, *ch, flag); + tty_insert_flip_char(&port->port, *ch, flag); } } else { - tty_insert_flip_string_fixed_flag(tty, ch, flag, len); + tty_insert_flip_string_fixed_flag(&port->port, ch, flag, len); } return len; @@ -2038,25 +2042,19 @@ static int ftdi_process_packet(struct tty_struct *tty, static void ftdi_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; - struct tty_struct *tty; struct ftdi_private *priv = usb_get_serial_port_data(port); char *data = (char *)urb->transfer_buffer; int i; int len; int count = 0; - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - for (i = 0; i < urb->actual_length; i += priv->max_packet_size) { len = min_t(int, urb->actual_length - i, priv->max_packet_size); - count += ftdi_process_packet(tty, port, priv, &data[i], len); + count += ftdi_process_packet(port, priv, &data[i], len); } if (count) - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_flip_buffer_push(&port->port); } static void ftdi_break_ctl(struct tty_struct *tty, int break_state) @@ -2089,6 +2087,29 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state) } +static int ftdi_chars_in_buffer(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + int chars; + unsigned char buf[2]; + int ret; + + chars = usb_serial_generic_chars_in_buffer(tty); + if (chars) + goto out; + + /* Check if hardware buffer is empty. */ + ret = ftdi_get_modem_status(tty, buf); + if (ret == 2) { + if (!(buf[1] & FTDI_RS_TEMT)) + chars = 1; + } +out: + dev_dbg(&port->dev, "%s - %d\n", __func__, chars); + + return chars; +} + /* old_termios contains the original termios settings and tty->termios contains * the new setting to be used * WARNING: set_termios calls this with old_termios in kernel space @@ -2272,7 +2293,14 @@ no_c_cflag_changes: } } -static int ftdi_tiocmget(struct tty_struct *tty) +/* + * Get modem-control status. + * + * Returns the number of status bytes retrieved (device dependant), or + * negative error code. + */ +static int ftdi_get_modem_status(struct tty_struct *tty, + unsigned char status[2]) { struct usb_serial_port *port = tty->driver_data; struct ftdi_private *priv = usb_get_serial_port_data(port); @@ -2312,16 +2340,43 @@ static int ftdi_tiocmget(struct tty_struct *tty) FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, 0, priv->interface, buf, len, WDR_TIMEOUT); - if (ret < 0) + if (ret < 0) { + dev_err(&port->dev, "failed to get modem status: %d\n", ret); + ret = usb_translate_errors(ret); goto out; + } - ret = (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | - (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | - (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | - (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) | - priv->last_dtr_rts; + status[0] = buf[0]; + if (ret > 1) + status[1] = buf[1]; + else + status[1] = 0; + + dev_dbg(&port->dev, "%s - 0x%02x%02x\n", __func__, status[0], + status[1]); out: kfree(buf); + + return ret; +} + +static int ftdi_tiocmget(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct ftdi_private *priv = usb_get_serial_port_data(port); + unsigned char buf[2]; + int ret; + + ret = ftdi_get_modem_status(tty, buf); + if (ret < 0) + return ret; + + ret = (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | + (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | + (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | + (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) | + priv->last_dtr_rts; + return ret; } |