diff options
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index be845873e23d..381515572235 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -923,6 +923,7 @@ 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); | ||
926 | 927 | ||
927 | static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base); | 928 | 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); | 929 | static unsigned short int ftdi_232am_baud_to_divisor(int baud); |
@@ -957,6 +958,7 @@ static struct usb_serial_driver ftdi_sio_device = { | |||
957 | .ioctl = ftdi_ioctl, | 958 | .ioctl = ftdi_ioctl, |
958 | .set_termios = ftdi_set_termios, | 959 | .set_termios = ftdi_set_termios, |
959 | .break_ctl = ftdi_break_ctl, | 960 | .break_ctl = ftdi_break_ctl, |
961 | .chars_in_buffer = ftdi_chars_in_buffer, | ||
960 | }; | 962 | }; |
961 | 963 | ||
962 | static struct usb_serial_driver * const serial_drivers[] = { | 964 | static struct usb_serial_driver * const serial_drivers[] = { |
@@ -2089,6 +2091,64 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state) | |||
2089 | 2091 | ||
2090 | } | 2092 | } |
2091 | 2093 | ||
2094 | static int ftdi_chars_in_buffer(struct tty_struct *tty) | ||
2095 | { | ||
2096 | struct usb_serial_port *port = tty->driver_data; | ||
2097 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
2098 | unsigned long flags; | ||
2099 | int chars; | ||
2100 | unsigned char *buf; | ||
2101 | int ret; | ||
2102 | |||
2103 | /* Check software buffer (code from | ||
2104 | * usb_serial_generic_chars_in_buffer()) */ | ||
2105 | spin_lock_irqsave(&port->lock, flags); | ||
2106 | chars = kfifo_len(&port->write_fifo) + port->tx_bytes; | ||
2107 | spin_unlock_irqrestore(&port->lock, flags); | ||
2108 | |||
2109 | /* Check hardware buffer */ | ||
2110 | switch (priv->chip_type) { | ||
2111 | case FT8U232AM: | ||
2112 | case FT232BM: | ||
2113 | case FT2232C: | ||
2114 | case FT232RL: | ||
2115 | case FT2232H: | ||
2116 | case FT4232H: | ||
2117 | case FT232H: | ||
2118 | case FTX: | ||
2119 | break; | ||
2120 | case SIO: | ||
2121 | default: | ||
2122 | return chars; | ||
2123 | } | ||
2124 | |||
2125 | buf = kmalloc(2, GFP_KERNEL); | ||
2126 | if (!buf) { | ||
2127 | dev_err(&port->dev, "kmalloc failed"); | ||
2128 | return chars; | ||
2129 | } | ||
2130 | |||
2131 | ret = usb_control_msg(port->serial->dev, | ||
2132 | usb_rcvctrlpipe(port->serial->dev, 0), | ||
2133 | FTDI_SIO_GET_MODEM_STATUS_REQUEST, | ||
2134 | FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, | ||
2135 | 0, priv->interface, | ||
2136 | buf, 2, WDR_TIMEOUT); | ||
2137 | |||
2138 | if (ret < 2) { | ||
2139 | dev_err(&port->dev, "Unable to read modem and line status: " | ||
2140 | "%i\n", ret); | ||
2141 | goto chars_in_buffer_out; | ||
2142 | } | ||
2143 | |||
2144 | if (!(buf[1] & FTDI_RS_TEMT)) | ||
2145 | chars++; | ||
2146 | |||
2147 | chars_in_buffer_out: | ||
2148 | kfree(buf); | ||
2149 | return chars; | ||
2150 | } | ||
2151 | |||
2092 | /* old_termios contains the original termios settings and tty->termios contains | 2152 | /* old_termios contains the original termios settings and tty->termios contains |
2093 | * the new setting to be used | 2153 | * the new setting to be used |
2094 | * WARNING: set_termios calls this with old_termios in kernel space | 2154 | * WARNING: set_termios calls this with old_termios in kernel space |