aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/ftdi_sio.c
diff options
context:
space:
mode:
authorIan Abbott <abbotti@mev.co.uk>2005-07-29 15:16:41 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-07-29 16:12:52 -0400
commit74ede0ff59fb18787213ed979641624a2f234821 (patch)
treef3edc4df478c45684a856bbca6f90047ab457862 /drivers/usb/serial/ftdi_sio.c
parent9b1513d91e195af46b8e59626f74d3d41a7565af (diff)
[PATCH] USB: ftdi_sio: Update RTS and DTR simultaneously
ftdi_sio: Update RTS and DTR simultaneously, using a single control URB instead of separate control URBs for RTS and DTR. Reinhard Bergmann observed time differences of up to 680 ms with his application on a 2.4.22 kernel when RTS and DTR were updated using separate control URBs, which is unacceptable. Signed-off-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/usb/serial/ftdi_sio.c')
-rw-r--r--drivers/usb/serial/ftdi_sio.c138
1 files changed, 43 insertions, 95 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index cfb77ceced58..d1d2aeebd20a 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -596,62 +596,59 @@ static __u32 ftdi_232bm_baud_to_divisor(int baud)
596 return(ftdi_232bm_baud_base_to_divisor(baud, 48000000)); 596 return(ftdi_232bm_baud_base_to_divisor(baud, 48000000));
597} 597}
598 598
599static int set_rts(struct usb_serial_port *port, int high_or_low) 599#define set_mctrl(port, set) update_mctrl((port), (set), 0)
600#define clear_mctrl(port, clear) update_mctrl((port), 0, (clear))
601
602static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned int clear)
600{ 603{
601 struct ftdi_private *priv = usb_get_serial_port_data(port); 604 struct ftdi_private *priv = usb_get_serial_port_data(port);
602 char *buf; 605 char *buf;
603 unsigned ftdi_high_or_low; 606 unsigned urb_value;
604 int rv; 607 int rv;
605
606 buf = kmalloc(1, GFP_NOIO);
607 if (!buf)
608 return -ENOMEM;
609
610 if (high_or_low) {
611 ftdi_high_or_low = FTDI_SIO_SET_RTS_HIGH;
612 priv->last_dtr_rts |= TIOCM_RTS;
613 } else {
614 ftdi_high_or_low = FTDI_SIO_SET_RTS_LOW;
615 priv->last_dtr_rts &= ~TIOCM_RTS;
616 }
617 rv = usb_control_msg(port->serial->dev,
618 usb_sndctrlpipe(port->serial->dev, 0),
619 FTDI_SIO_SET_MODEM_CTRL_REQUEST,
620 FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
621 ftdi_high_or_low, priv->interface,
622 buf, 0, WDR_TIMEOUT);
623
624 kfree(buf);
625 return rv;
626}
627 608
609 if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
610 dbg("%s - DTR|RTS not being set|cleared", __FUNCTION__);
611 return 0; /* no change */
612 }
628 613
629static int set_dtr(struct usb_serial_port *port, int high_or_low)
630{
631 struct ftdi_private *priv = usb_get_serial_port_data(port);
632 char *buf;
633 unsigned ftdi_high_or_low;
634 int rv;
635
636 buf = kmalloc(1, GFP_NOIO); 614 buf = kmalloc(1, GFP_NOIO);
637 if (!buf) 615 if (!buf) {
638 return -ENOMEM; 616 return -ENOMEM;
639
640 if (high_or_low) {
641 ftdi_high_or_low = FTDI_SIO_SET_DTR_HIGH;
642 priv->last_dtr_rts |= TIOCM_DTR;
643 } else {
644 ftdi_high_or_low = FTDI_SIO_SET_DTR_LOW;
645 priv->last_dtr_rts &= ~TIOCM_DTR;
646 } 617 }
618
619 clear &= ~set; /* 'set' takes precedence over 'clear' */
620 urb_value = 0;
621 if (clear & TIOCM_DTR)
622 urb_value |= FTDI_SIO_SET_DTR_LOW;
623 if (clear & TIOCM_RTS)
624 urb_value |= FTDI_SIO_SET_RTS_LOW;
625 if (set & TIOCM_DTR)
626 urb_value |= FTDI_SIO_SET_DTR_HIGH;
627 if (set & TIOCM_RTS)
628 urb_value |= FTDI_SIO_SET_RTS_HIGH;
647 rv = usb_control_msg(port->serial->dev, 629 rv = usb_control_msg(port->serial->dev,
648 usb_sndctrlpipe(port->serial->dev, 0), 630 usb_sndctrlpipe(port->serial->dev, 0),
649 FTDI_SIO_SET_MODEM_CTRL_REQUEST, 631 FTDI_SIO_SET_MODEM_CTRL_REQUEST,
650 FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, 632 FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
651 ftdi_high_or_low, priv->interface, 633 urb_value, priv->interface,
652 buf, 0, WDR_TIMEOUT); 634 buf, 0, WDR_TIMEOUT);
653 635
654 kfree(buf); 636 kfree(buf);
637 if (rv < 0) {
638 err("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
639 __FUNCTION__,
640 (set & TIOCM_DTR) ? "HIGH" :
641 (clear & TIOCM_DTR) ? "LOW" : "unchanged",
642 (set & TIOCM_RTS) ? "HIGH" :
643 (clear & TIOCM_RTS) ? "LOW" : "unchanged");
644 } else {
645 dbg("%s - DTR %s, RTS %s", __FUNCTION__,
646 (set & TIOCM_DTR) ? "HIGH" :
647 (clear & TIOCM_DTR) ? "LOW" : "unchanged",
648 (set & TIOCM_RTS) ? "HIGH" :
649 (clear & TIOCM_RTS) ? "LOW" : "unchanged");
650 priv->last_dtr_rts = (priv->last_dtr_rts & ~clear) | set;
651 }
655 return rv; 652 return rv;
656} 653}
657 654
@@ -1222,12 +1219,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
1222 /* FIXME: Flow control might be enabled, so it should be checked - 1219 /* FIXME: Flow control might be enabled, so it should be checked -
1223 we have no control of defaults! */ 1220 we have no control of defaults! */
1224 /* Turn on RTS and DTR since we are not flow controlling by default */ 1221 /* Turn on RTS and DTR since we are not flow controlling by default */
1225 if (set_dtr(port, HIGH) < 0) { 1222 set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
1226 err("%s Error from DTR HIGH urb", __FUNCTION__);
1227 }
1228 if (set_rts(port, HIGH) < 0){
1229 err("%s Error from RTS HIGH urb", __FUNCTION__);
1230 }
1231 1223
1232 /* Not throttled */ 1224 /* Not throttled */
1233 spin_lock_irqsave(&priv->rx_lock, flags); 1225 spin_lock_irqsave(&priv->rx_lock, flags);
@@ -1277,14 +1269,8 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
1277 err("error from flowcontrol urb"); 1269 err("error from flowcontrol urb");
1278 } 1270 }
1279 1271
1280 /* drop DTR */ 1272 /* drop RTS and DTR */
1281 if (set_dtr(port, LOW) < 0){ 1273 clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
1282 err("Error from DTR LOW urb");
1283 }
1284 /* drop RTS */
1285 if (set_rts(port, LOW) < 0) {
1286 err("Error from RTS LOW urb");
1287 }
1288 } /* Note change no line if hupcl is off */ 1274 } /* Note change no line if hupcl is off */
1289 1275
1290 /* cancel any scheduled reading */ 1276 /* cancel any scheduled reading */
@@ -1815,25 +1801,14 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
1815 err("%s error from disable flowcontrol urb", __FUNCTION__); 1801 err("%s error from disable flowcontrol urb", __FUNCTION__);
1816 } 1802 }
1817 /* Drop RTS and DTR */ 1803 /* Drop RTS and DTR */
1818 if (set_dtr(port, LOW) < 0){ 1804 clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
1819 err("%s Error from DTR LOW urb", __FUNCTION__);
1820 }
1821 if (set_rts(port, LOW) < 0){
1822 err("%s Error from RTS LOW urb", __FUNCTION__);
1823 }
1824
1825 } else { 1805 } else {
1826 /* set the baudrate determined before */ 1806 /* set the baudrate determined before */
1827 if (change_speed(port)) { 1807 if (change_speed(port)) {
1828 err("%s urb failed to set baurdrate", __FUNCTION__); 1808 err("%s urb failed to set baurdrate", __FUNCTION__);
1829 } 1809 }
1830 /* Ensure RTS and DTR are raised */ 1810 /* Ensure RTS and DTR are raised */
1831 else if (set_dtr(port, HIGH) < 0){ 1811 set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
1832 err("%s Error from DTR HIGH urb", __FUNCTION__);
1833 }
1834 else if (set_rts(port, HIGH) < 0){
1835 err("%s Error from RTS HIGH urb", __FUNCTION__);
1836 }
1837 } 1812 }
1838 1813
1839 /* Set flow control */ 1814 /* Set flow control */
@@ -1945,35 +1920,8 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
1945 1920
1946static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear) 1921static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear)
1947{ 1922{
1948 int ret;
1949
1950 dbg("%s TIOCMSET", __FUNCTION__); 1923 dbg("%s TIOCMSET", __FUNCTION__);
1951 if (set & TIOCM_DTR){ 1924 return update_mctrl(port, set, clear);
1952 if ((ret = set_dtr(port, HIGH)) < 0) {
1953 err("Urb to set DTR failed");
1954 return(ret);
1955 }
1956 }
1957 if (set & TIOCM_RTS) {
1958 if ((ret = set_rts(port, HIGH)) < 0){
1959 err("Urb to set RTS failed");
1960 return(ret);
1961 }
1962 }
1963
1964 if (clear & TIOCM_DTR){
1965 if ((ret = set_dtr(port, LOW)) < 0){
1966 err("Urb to unset DTR failed");
1967 return(ret);
1968 }
1969 }
1970 if (clear & TIOCM_RTS) {
1971 if ((ret = set_rts(port, LOW)) < 0){
1972 err("Urb to unset RTS failed");
1973 return(ret);
1974 }
1975 }
1976 return(0);
1977} 1925}
1978 1926
1979 1927