diff options
Diffstat (limited to 'drivers/usb/serial/ftdi_sio.c')
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 82 |
1 files changed, 71 insertions, 11 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index be845873e23d..0a373b3ae96a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -73,7 +73,6 @@ struct ftdi_private { | |||
73 | char prev_status; /* Used for TIOCMIWAIT */ | 73 | char prev_status; /* Used for TIOCMIWAIT */ |
74 | bool dev_gone; /* Used to abort TIOCMIWAIT */ | 74 | bool dev_gone; /* Used to abort TIOCMIWAIT */ |
75 | char transmit_empty; /* If transmitter is empty or not */ | 75 | char transmit_empty; /* If transmitter is empty or not */ |
76 | struct usb_serial_port *port; | ||
77 | __u16 interface; /* FT2232C, FT2232H or FT4232H port interface | 76 | __u16 interface; /* FT2232C, FT2232H or FT4232H port interface |
78 | (0 for FT232/245) */ | 77 | (0 for FT232/245) */ |
79 | 78 | ||
@@ -192,6 +191,7 @@ static struct usb_device_id id_table_combined [] = { | |||
192 | { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) }, | 191 | { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) }, |
193 | { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) }, | 192 | { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) }, |
194 | { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) }, | 193 | { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) }, |
194 | { USB_DEVICE(NEWPORT_VID, NEWPORT_AGILIS_PID) }, | ||
195 | { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, | 195 | { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, |
196 | { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, | 196 | { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, |
197 | { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) }, | 197 | { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) }, |
@@ -923,6 +923,9 @@ static int ftdi_get_icount(struct tty_struct *tty, | |||
923 | static int ftdi_ioctl(struct tty_struct *tty, | 923 | static int ftdi_ioctl(struct tty_struct *tty, |
924 | unsigned int cmd, unsigned long arg); | 924 | unsigned int cmd, unsigned long arg); |
925 | static void ftdi_break_ctl(struct tty_struct *tty, int break_state); | 925 | static void ftdi_break_ctl(struct tty_struct *tty, int break_state); |
926 | static int ftdi_chars_in_buffer(struct tty_struct *tty); | ||
927 | static int ftdi_get_modem_status(struct tty_struct *tty, | ||
928 | unsigned char status[2]); | ||
926 | 929 | ||
927 | static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base); | 930 | static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base); |
928 | static unsigned short int ftdi_232am_baud_to_divisor(int baud); | 931 | static unsigned short int ftdi_232am_baud_to_divisor(int baud); |
@@ -957,6 +960,7 @@ static struct usb_serial_driver ftdi_sio_device = { | |||
957 | .ioctl = ftdi_ioctl, | 960 | .ioctl = ftdi_ioctl, |
958 | .set_termios = ftdi_set_termios, | 961 | .set_termios = ftdi_set_termios, |
959 | .break_ctl = ftdi_break_ctl, | 962 | .break_ctl = ftdi_break_ctl, |
963 | .chars_in_buffer = ftdi_chars_in_buffer, | ||
960 | }; | 964 | }; |
961 | 965 | ||
962 | static struct usb_serial_driver * const serial_drivers[] = { | 966 | static struct usb_serial_driver * const serial_drivers[] = { |
@@ -1090,6 +1094,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, | |||
1090 | __func__, | 1094 | __func__, |
1091 | (set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged", | 1095 | (set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged", |
1092 | (set & TIOCM_RTS) ? "HIGH" : (clear & TIOCM_RTS) ? "LOW" : "unchanged"); | 1096 | (set & TIOCM_RTS) ? "HIGH" : (clear & TIOCM_RTS) ? "LOW" : "unchanged"); |
1097 | rv = usb_translate_errors(rv); | ||
1093 | } else { | 1098 | } else { |
1094 | dev_dbg(dev, "%s - DTR %s, RTS %s\n", __func__, | 1099 | dev_dbg(dev, "%s - DTR %s, RTS %s\n", __func__, |
1095 | (set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged", | 1100 | (set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged", |
@@ -1682,7 +1687,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) | |||
1682 | 1687 | ||
1683 | kref_init(&priv->kref); | 1688 | kref_init(&priv->kref); |
1684 | mutex_init(&priv->cfg_lock); | 1689 | mutex_init(&priv->cfg_lock); |
1685 | memset(&priv->icount, 0x00, sizeof(priv->icount)); | ||
1686 | init_waitqueue_head(&priv->delta_msr_wait); | 1690 | init_waitqueue_head(&priv->delta_msr_wait); |
1687 | 1691 | ||
1688 | priv->flags = ASYNC_LOW_LATENCY; | 1692 | priv->flags = ASYNC_LOW_LATENCY; |
@@ -1691,7 +1695,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) | |||
1691 | if (quirk && quirk->port_probe) | 1695 | if (quirk && quirk->port_probe) |
1692 | quirk->port_probe(priv); | 1696 | quirk->port_probe(priv); |
1693 | 1697 | ||
1694 | priv->port = port; | ||
1695 | usb_set_serial_port_data(port, priv); | 1698 | usb_set_serial_port_data(port, priv); |
1696 | 1699 | ||
1697 | ftdi_determine_type(port); | 1700 | ftdi_determine_type(port); |
@@ -1781,7 +1784,7 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial) | |||
1781 | struct usb_device *udev = serial->dev; | 1784 | struct usb_device *udev = serial->dev; |
1782 | 1785 | ||
1783 | if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) || | 1786 | if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) || |
1784 | (udev->product && !strcmp(udev->product, "BeagleBone/XDS100"))) | 1787 | (udev->product && !strcmp(udev->product, "BeagleBone/XDS100V2"))) |
1785 | return ftdi_jtag_probe(serial); | 1788 | return ftdi_jtag_probe(serial); |
1786 | 1789 | ||
1787 | return 0; | 1790 | return 0; |
@@ -2089,6 +2092,29 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state) | |||
2089 | 2092 | ||
2090 | } | 2093 | } |
2091 | 2094 | ||
2095 | static int ftdi_chars_in_buffer(struct tty_struct *tty) | ||
2096 | { | ||
2097 | struct usb_serial_port *port = tty->driver_data; | ||
2098 | int chars; | ||
2099 | unsigned char buf[2]; | ||
2100 | int ret; | ||
2101 | |||
2102 | chars = usb_serial_generic_chars_in_buffer(tty); | ||
2103 | if (chars) | ||
2104 | goto out; | ||
2105 | |||
2106 | /* Check if hardware buffer is empty. */ | ||
2107 | ret = ftdi_get_modem_status(tty, buf); | ||
2108 | if (ret == 2) { | ||
2109 | if (!(buf[1] & FTDI_RS_TEMT)) | ||
2110 | chars = 1; | ||
2111 | } | ||
2112 | out: | ||
2113 | dev_dbg(&port->dev, "%s - %d\n", __func__, chars); | ||
2114 | |||
2115 | return chars; | ||
2116 | } | ||
2117 | |||
2092 | /* old_termios contains the original termios settings and tty->termios contains | 2118 | /* old_termios contains the original termios settings and tty->termios contains |
2093 | * the new setting to be used | 2119 | * the new setting to be used |
2094 | * WARNING: set_termios calls this with old_termios in kernel space | 2120 | * WARNING: set_termios calls this with old_termios in kernel space |
@@ -2272,7 +2298,14 @@ no_c_cflag_changes: | |||
2272 | } | 2298 | } |
2273 | } | 2299 | } |
2274 | 2300 | ||
2275 | static int ftdi_tiocmget(struct tty_struct *tty) | 2301 | /* |
2302 | * Get modem-control status. | ||
2303 | * | ||
2304 | * Returns the number of status bytes retrieved (device dependant), or | ||
2305 | * negative error code. | ||
2306 | */ | ||
2307 | static int ftdi_get_modem_status(struct tty_struct *tty, | ||
2308 | unsigned char status[2]) | ||
2276 | { | 2309 | { |
2277 | struct usb_serial_port *port = tty->driver_data; | 2310 | struct usb_serial_port *port = tty->driver_data; |
2278 | struct ftdi_private *priv = usb_get_serial_port_data(port); | 2311 | struct ftdi_private *priv = usb_get_serial_port_data(port); |
@@ -2312,16 +2345,43 @@ static int ftdi_tiocmget(struct tty_struct *tty) | |||
2312 | FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, | 2345 | FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, |
2313 | 0, priv->interface, | 2346 | 0, priv->interface, |
2314 | buf, len, WDR_TIMEOUT); | 2347 | buf, len, WDR_TIMEOUT); |
2315 | if (ret < 0) | 2348 | if (ret < 0) { |
2349 | dev_err(&port->dev, "failed to get modem status: %d\n", ret); | ||
2350 | ret = usb_translate_errors(ret); | ||
2316 | goto out; | 2351 | goto out; |
2352 | } | ||
2317 | 2353 | ||
2318 | ret = (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | | 2354 | status[0] = buf[0]; |
2319 | (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | | 2355 | if (ret > 1) |
2320 | (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | | 2356 | status[1] = buf[1]; |
2321 | (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) | | 2357 | else |
2322 | priv->last_dtr_rts; | 2358 | status[1] = 0; |
2359 | |||
2360 | dev_dbg(&port->dev, "%s - 0x%02x%02x\n", __func__, status[0], | ||
2361 | status[1]); | ||
2323 | out: | 2362 | out: |
2324 | kfree(buf); | 2363 | kfree(buf); |
2364 | |||
2365 | return ret; | ||
2366 | } | ||
2367 | |||
2368 | static int ftdi_tiocmget(struct tty_struct *tty) | ||
2369 | { | ||
2370 | struct usb_serial_port *port = tty->driver_data; | ||
2371 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
2372 | unsigned char buf[2]; | ||
2373 | int ret; | ||
2374 | |||
2375 | ret = ftdi_get_modem_status(tty, buf); | ||
2376 | if (ret < 0) | ||
2377 | return ret; | ||
2378 | |||
2379 | ret = (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | | ||
2380 | (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | | ||
2381 | (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | | ||
2382 | (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) | | ||
2383 | priv->last_dtr_rts; | ||
2384 | |||
2325 | return ret; | 2385 | return ret; |
2326 | } | 2386 | } |
2327 | 2387 | ||