diff options
Diffstat (limited to 'drivers/usb/serial/ftdi_sio.c')
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 149 |
1 files changed, 88 insertions, 61 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d9fcdaedf389..683304d60615 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -89,6 +89,7 @@ struct ftdi_private { | |||
89 | int force_rtscts; /* if non-zero, force RTS-CTS to always | 89 | int force_rtscts; /* if non-zero, force RTS-CTS to always |
90 | be enabled */ | 90 | be enabled */ |
91 | 91 | ||
92 | unsigned int latency; /* latency setting in use */ | ||
92 | spinlock_t tx_lock; /* spinlock for transmit state */ | 93 | spinlock_t tx_lock; /* spinlock for transmit state */ |
93 | unsigned long tx_bytes; | 94 | unsigned long tx_bytes; |
94 | unsigned long tx_outstanding_bytes; | 95 | unsigned long tx_outstanding_bytes; |
@@ -719,8 +720,8 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port); | |||
719 | static int ftdi_sio_port_remove(struct usb_serial_port *port); | 720 | static int ftdi_sio_port_remove(struct usb_serial_port *port); |
720 | static int ftdi_open(struct tty_struct *tty, | 721 | static int ftdi_open(struct tty_struct *tty, |
721 | struct usb_serial_port *port, struct file *filp); | 722 | struct usb_serial_port *port, struct file *filp); |
722 | static void ftdi_close(struct tty_struct *tty, | 723 | static void ftdi_close(struct usb_serial_port *port); |
723 | struct usb_serial_port *port, struct file *filp); | 724 | static void ftdi_dtr_rts(struct usb_serial_port *port, int on); |
724 | static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port, | 725 | static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port, |
725 | const unsigned char *buf, int count); | 726 | const unsigned char *buf, int count); |
726 | static int ftdi_write_room(struct tty_struct *tty); | 727 | static int ftdi_write_room(struct tty_struct *tty); |
@@ -758,6 +759,7 @@ static struct usb_serial_driver ftdi_sio_device = { | |||
758 | .port_remove = ftdi_sio_port_remove, | 759 | .port_remove = ftdi_sio_port_remove, |
759 | .open = ftdi_open, | 760 | .open = ftdi_open, |
760 | .close = ftdi_close, | 761 | .close = ftdi_close, |
762 | .dtr_rts = ftdi_dtr_rts, | ||
761 | .throttle = ftdi_throttle, | 763 | .throttle = ftdi_throttle, |
762 | .unthrottle = ftdi_unthrottle, | 764 | .unthrottle = ftdi_unthrottle, |
763 | .write = ftdi_write, | 765 | .write = ftdi_write, |
@@ -1037,7 +1039,54 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port) | |||
1037 | return rv; | 1039 | return rv; |
1038 | } | 1040 | } |
1039 | 1041 | ||
1042 | static int write_latency_timer(struct usb_serial_port *port) | ||
1043 | { | ||
1044 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
1045 | struct usb_device *udev = port->serial->dev; | ||
1046 | char buf[1]; | ||
1047 | int rv = 0; | ||
1048 | int l = priv->latency; | ||
1049 | |||
1050 | if (priv->flags & ASYNC_LOW_LATENCY) | ||
1051 | l = 1; | ||
1052 | |||
1053 | dbg("%s: setting latency timer = %i", __func__, l); | ||
1054 | |||
1055 | rv = usb_control_msg(udev, | ||
1056 | usb_sndctrlpipe(udev, 0), | ||
1057 | FTDI_SIO_SET_LATENCY_TIMER_REQUEST, | ||
1058 | FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, | ||
1059 | l, priv->interface, | ||
1060 | buf, 0, WDR_TIMEOUT); | ||
1061 | |||
1062 | if (rv < 0) | ||
1063 | dev_err(&port->dev, "Unable to write latency timer: %i\n", rv); | ||
1064 | return rv; | ||
1065 | } | ||
1066 | |||
1067 | static int read_latency_timer(struct usb_serial_port *port) | ||
1068 | { | ||
1069 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
1070 | struct usb_device *udev = port->serial->dev; | ||
1071 | unsigned short latency = 0; | ||
1072 | int rv = 0; | ||
1073 | |||
1040 | 1074 | ||
1075 | dbg("%s", __func__); | ||
1076 | |||
1077 | rv = usb_control_msg(udev, | ||
1078 | usb_rcvctrlpipe(udev, 0), | ||
1079 | FTDI_SIO_GET_LATENCY_TIMER_REQUEST, | ||
1080 | FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, | ||
1081 | 0, priv->interface, | ||
1082 | (char *) &latency, 1, WDR_TIMEOUT); | ||
1083 | |||
1084 | if (rv < 0) { | ||
1085 | dev_err(&port->dev, "Unable to read latency timer: %i\n", rv); | ||
1086 | return -EIO; | ||
1087 | } | ||
1088 | return latency; | ||
1089 | } | ||
1041 | 1090 | ||
1042 | static int get_serial_info(struct usb_serial_port *port, | 1091 | static int get_serial_info(struct usb_serial_port *port, |
1043 | struct serial_struct __user *retinfo) | 1092 | struct serial_struct __user *retinfo) |
@@ -1097,6 +1146,7 @@ static int set_serial_info(struct tty_struct *tty, | |||
1097 | priv->custom_divisor = new_serial.custom_divisor; | 1146 | priv->custom_divisor = new_serial.custom_divisor; |
1098 | 1147 | ||
1099 | tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; | 1148 | tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; |
1149 | write_latency_timer(port); | ||
1100 | 1150 | ||
1101 | check_and_exit: | 1151 | check_and_exit: |
1102 | if ((old_priv.flags & ASYNC_SPD_MASK) != | 1152 | if ((old_priv.flags & ASYNC_SPD_MASK) != |
@@ -1192,27 +1242,13 @@ static ssize_t show_latency_timer(struct device *dev, | |||
1192 | { | 1242 | { |
1193 | struct usb_serial_port *port = to_usb_serial_port(dev); | 1243 | struct usb_serial_port *port = to_usb_serial_port(dev); |
1194 | struct ftdi_private *priv = usb_get_serial_port_data(port); | 1244 | struct ftdi_private *priv = usb_get_serial_port_data(port); |
1195 | struct usb_device *udev = port->serial->dev; | 1245 | if (priv->flags & ASYNC_LOW_LATENCY) |
1196 | unsigned short latency = 0; | 1246 | return sprintf(buf, "1\n"); |
1197 | int rv = 0; | 1247 | else |
1198 | 1248 | return sprintf(buf, "%i\n", priv->latency); | |
1199 | |||
1200 | dbg("%s", __func__); | ||
1201 | |||
1202 | rv = usb_control_msg(udev, | ||
1203 | usb_rcvctrlpipe(udev, 0), | ||
1204 | FTDI_SIO_GET_LATENCY_TIMER_REQUEST, | ||
1205 | FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, | ||
1206 | 0, priv->interface, | ||
1207 | (char *) &latency, 1, WDR_TIMEOUT); | ||
1208 | |||
1209 | if (rv < 0) { | ||
1210 | dev_err(dev, "Unable to read latency timer: %i\n", rv); | ||
1211 | return -EIO; | ||
1212 | } | ||
1213 | return sprintf(buf, "%i\n", latency); | ||
1214 | } | 1249 | } |
1215 | 1250 | ||
1251 | |||
1216 | /* Write a new value of the latency timer, in units of milliseconds. */ | 1252 | /* Write a new value of the latency timer, in units of milliseconds. */ |
1217 | static ssize_t store_latency_timer(struct device *dev, | 1253 | static ssize_t store_latency_timer(struct device *dev, |
1218 | struct device_attribute *attr, const char *valbuf, | 1254 | struct device_attribute *attr, const char *valbuf, |
@@ -1220,25 +1256,13 @@ static ssize_t store_latency_timer(struct device *dev, | |||
1220 | { | 1256 | { |
1221 | struct usb_serial_port *port = to_usb_serial_port(dev); | 1257 | struct usb_serial_port *port = to_usb_serial_port(dev); |
1222 | struct ftdi_private *priv = usb_get_serial_port_data(port); | 1258 | struct ftdi_private *priv = usb_get_serial_port_data(port); |
1223 | struct usb_device *udev = port->serial->dev; | ||
1224 | char buf[1]; | ||
1225 | int v = simple_strtoul(valbuf, NULL, 10); | 1259 | int v = simple_strtoul(valbuf, NULL, 10); |
1226 | int rv = 0; | 1260 | int rv = 0; |
1227 | 1261 | ||
1228 | dbg("%s: setting latency timer = %i", __func__, v); | 1262 | priv->latency = v; |
1229 | 1263 | rv = write_latency_timer(port); | |
1230 | rv = usb_control_msg(udev, | 1264 | if (rv < 0) |
1231 | usb_sndctrlpipe(udev, 0), | ||
1232 | FTDI_SIO_SET_LATENCY_TIMER_REQUEST, | ||
1233 | FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, | ||
1234 | v, priv->interface, | ||
1235 | buf, 0, WDR_TIMEOUT); | ||
1236 | |||
1237 | if (rv < 0) { | ||
1238 | dev_err(dev, "Unable to write latency timer: %i\n", rv); | ||
1239 | return -EIO; | 1265 | return -EIO; |
1240 | } | ||
1241 | |||
1242 | return count; | 1266 | return count; |
1243 | } | 1267 | } |
1244 | 1268 | ||
@@ -1392,6 +1416,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) | |||
1392 | usb_set_serial_port_data(port, priv); | 1416 | usb_set_serial_port_data(port, priv); |
1393 | 1417 | ||
1394 | ftdi_determine_type(port); | 1418 | ftdi_determine_type(port); |
1419 | read_latency_timer(port); | ||
1395 | create_sysfs_attrs(port); | 1420 | create_sysfs_attrs(port); |
1396 | return 0; | 1421 | return 0; |
1397 | } | 1422 | } |
@@ -1514,6 +1539,8 @@ static int ftdi_open(struct tty_struct *tty, | |||
1514 | if (tty) | 1539 | if (tty) |
1515 | tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; | 1540 | tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; |
1516 | 1541 | ||
1542 | write_latency_timer(port); | ||
1543 | |||
1517 | /* No error checking for this (will get errors later anyway) */ | 1544 | /* No error checking for this (will get errors later anyway) */ |
1518 | /* See ftdi_sio.h for description of what is reset */ | 1545 | /* See ftdi_sio.h for description of what is reset */ |
1519 | usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | 1546 | usb_control_msg(dev, usb_sndctrlpipe(dev, 0), |
@@ -1529,11 +1556,6 @@ static int ftdi_open(struct tty_struct *tty, | |||
1529 | if (tty) | 1556 | if (tty) |
1530 | ftdi_set_termios(tty, port, tty->termios); | 1557 | ftdi_set_termios(tty, port, tty->termios); |
1531 | 1558 | ||
1532 | /* FIXME: Flow control might be enabled, so it should be checked - | ||
1533 | we have no control of defaults! */ | ||
1534 | /* Turn on RTS and DTR since we are not flow controlling by default */ | ||
1535 | set_mctrl(port, TIOCM_DTR | TIOCM_RTS); | ||
1536 | |||
1537 | /* Not throttled */ | 1559 | /* Not throttled */ |
1538 | spin_lock_irqsave(&priv->rx_lock, flags); | 1560 | spin_lock_irqsave(&priv->rx_lock, flags); |
1539 | priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED); | 1561 | priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED); |
@@ -1558,6 +1580,30 @@ static int ftdi_open(struct tty_struct *tty, | |||
1558 | } /* ftdi_open */ | 1580 | } /* ftdi_open */ |
1559 | 1581 | ||
1560 | 1582 | ||
1583 | static void ftdi_dtr_rts(struct usb_serial_port *port, int on) | ||
1584 | { | ||
1585 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
1586 | char buf[1]; | ||
1587 | |||
1588 | mutex_lock(&port->serial->disc_mutex); | ||
1589 | if (!port->serial->disconnected) { | ||
1590 | /* Disable flow control */ | ||
1591 | if (!on && usb_control_msg(port->serial->dev, | ||
1592 | usb_sndctrlpipe(port->serial->dev, 0), | ||
1593 | FTDI_SIO_SET_FLOW_CTRL_REQUEST, | ||
1594 | FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, | ||
1595 | 0, priv->interface, buf, 0, | ||
1596 | WDR_TIMEOUT) < 0) { | ||
1597 | dev_err(&port->dev, "error from flowcontrol urb\n"); | ||
1598 | } | ||
1599 | /* drop RTS and DTR */ | ||
1600 | if (on) | ||
1601 | set_mctrl(port, TIOCM_DTR | TIOCM_RTS); | ||
1602 | else | ||
1603 | clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); | ||
1604 | } | ||
1605 | mutex_unlock(&port->serial->disc_mutex); | ||
1606 | } | ||
1561 | 1607 | ||
1562 | /* | 1608 | /* |
1563 | * usbserial:__serial_close only calls ftdi_close if the point is open | 1609 | * usbserial:__serial_close only calls ftdi_close if the point is open |
@@ -1567,31 +1613,12 @@ static int ftdi_open(struct tty_struct *tty, | |||
1567 | * | 1613 | * |
1568 | */ | 1614 | */ |
1569 | 1615 | ||
1570 | static void ftdi_close(struct tty_struct *tty, | 1616 | static void ftdi_close(struct usb_serial_port *port) |
1571 | struct usb_serial_port *port, struct file *filp) | ||
1572 | { /* ftdi_close */ | 1617 | { /* ftdi_close */ |
1573 | unsigned int c_cflag = tty->termios->c_cflag; | ||
1574 | struct ftdi_private *priv = usb_get_serial_port_data(port); | 1618 | struct ftdi_private *priv = usb_get_serial_port_data(port); |
1575 | char buf[1]; | ||
1576 | 1619 | ||
1577 | dbg("%s", __func__); | 1620 | dbg("%s", __func__); |
1578 | 1621 | ||
1579 | mutex_lock(&port->serial->disc_mutex); | ||
1580 | if (c_cflag & HUPCL && !port->serial->disconnected) { | ||
1581 | /* Disable flow control */ | ||
1582 | if (usb_control_msg(port->serial->dev, | ||
1583 | usb_sndctrlpipe(port->serial->dev, 0), | ||
1584 | FTDI_SIO_SET_FLOW_CTRL_REQUEST, | ||
1585 | FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, | ||
1586 | 0, priv->interface, buf, 0, | ||
1587 | WDR_TIMEOUT) < 0) { | ||
1588 | dev_err(&port->dev, "error from flowcontrol urb\n"); | ||
1589 | } | ||
1590 | |||
1591 | /* drop RTS and DTR */ | ||
1592 | clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); | ||
1593 | } /* Note change no line if hupcl is off */ | ||
1594 | mutex_unlock(&port->serial->disc_mutex); | ||
1595 | 1622 | ||
1596 | /* cancel any scheduled reading */ | 1623 | /* cancel any scheduled reading */ |
1597 | cancel_delayed_work_sync(&priv->rx_work); | 1624 | cancel_delayed_work_sync(&priv->rx_work); |