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) */
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 unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base);
static unsigned short int ftdi_232am_baud_to_divisor(int baud);
.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[] = {
__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",
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;
if (quirk && quirk->port_probe)
quirk->port_probe(priv);
- priv->port = port;
usb_set_serial_port_data(port, priv);
ftdi_determine_type(port);
}
+static int ftdi_chars_in_buffer(struct tty_struct *tty)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ int chars;
+ unsigned char *buf;
+ int ret;
+
+ /* Check software buffer (code from
+ * usb_serial_generic_chars_in_buffer()) */
+ spin_lock_irqsave(&port->lock, flags);
+ chars = kfifo_len(&port->write_fifo) + port->tx_bytes;
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ /* Check hardware buffer */
+ switch (priv->chip_type) {
+ case FT8U232AM:
+ case FT232BM:
+ case FT2232C:
+ case FT232RL:
+ case FT2232H:
+ case FT4232H:
+ case FT232H:
+ case FTX:
+ break;
+ case SIO:
+ default:
+ return chars;
+ }
+
+ buf = kmalloc(2, GFP_KERNEL);
+ if (!buf) {
+ dev_err(&port->dev, "kmalloc failed");
+ return chars;
+ }
+
+ ret = usb_control_msg(port->serial->dev,
+ usb_rcvctrlpipe(port->serial->dev, 0),
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST,
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
+ 0, priv->interface,
+ buf, 2, WDR_TIMEOUT);
+
+ if (ret < 2) {
+ dev_err(&port->dev, "Unable to read modem and line status: "
+ "%i\n", ret);
+ goto chars_in_buffer_out;
+ }
+
+ if (!(buf[1] & FTDI_RS_TEMT))
+ chars++;
+
+chars_in_buffer_out:
+ kfree(buf);
+ 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
}
}
-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);
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;
}