diff options
Diffstat (limited to 'drivers/usb/serial/ftdi_sio.c')
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 146 |
1 files changed, 49 insertions, 97 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 0b03ddab53d9..d1964a0c4168 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -429,6 +429,9 @@ static struct usb_device_id id_table_combined [] = { | |||
429 | { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, | 429 | { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, |
430 | { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, | 430 | { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, |
431 | { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) }, | 431 | { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) }, |
432 | { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) }, | ||
433 | { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) }, | ||
434 | { USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) }, | ||
432 | { } /* Terminating entry */ | 435 | { } /* Terminating entry */ |
433 | }; | 436 | }; |
434 | 437 | ||
@@ -545,6 +548,7 @@ static struct usb_serial_device_type ftdi_sio_device = { | |||
545 | 548 | ||
546 | 549 | ||
547 | #define WDR_TIMEOUT 5000 /* default urb timeout */ | 550 | #define WDR_TIMEOUT 5000 /* default urb timeout */ |
551 | #define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */ | ||
548 | 552 | ||
549 | /* High and low are for DTR, RTS etc etc */ | 553 | /* High and low are for DTR, RTS etc etc */ |
550 | #define HIGH 1 | 554 | #define HIGH 1 |
@@ -593,62 +597,59 @@ static __u32 ftdi_232bm_baud_to_divisor(int baud) | |||
593 | return(ftdi_232bm_baud_base_to_divisor(baud, 48000000)); | 597 | return(ftdi_232bm_baud_base_to_divisor(baud, 48000000)); |
594 | } | 598 | } |
595 | 599 | ||
596 | static int set_rts(struct usb_serial_port *port, int high_or_low) | 600 | #define set_mctrl(port, set) update_mctrl((port), (set), 0) |
601 | #define clear_mctrl(port, clear) update_mctrl((port), 0, (clear)) | ||
602 | |||
603 | static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned int clear) | ||
597 | { | 604 | { |
598 | struct ftdi_private *priv = usb_get_serial_port_data(port); | 605 | struct ftdi_private *priv = usb_get_serial_port_data(port); |
599 | char *buf; | 606 | char *buf; |
600 | unsigned ftdi_high_or_low; | 607 | unsigned urb_value; |
601 | int rv; | 608 | int rv; |
602 | |||
603 | buf = kmalloc(1, GFP_NOIO); | ||
604 | if (!buf) | ||
605 | return -ENOMEM; | ||
606 | |||
607 | if (high_or_low) { | ||
608 | ftdi_high_or_low = FTDI_SIO_SET_RTS_HIGH; | ||
609 | priv->last_dtr_rts |= TIOCM_RTS; | ||
610 | } else { | ||
611 | ftdi_high_or_low = FTDI_SIO_SET_RTS_LOW; | ||
612 | priv->last_dtr_rts &= ~TIOCM_RTS; | ||
613 | } | ||
614 | rv = usb_control_msg(port->serial->dev, | ||
615 | usb_sndctrlpipe(port->serial->dev, 0), | ||
616 | FTDI_SIO_SET_MODEM_CTRL_REQUEST, | ||
617 | FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, | ||
618 | ftdi_high_or_low, priv->interface, | ||
619 | buf, 0, WDR_TIMEOUT); | ||
620 | |||
621 | kfree(buf); | ||
622 | return rv; | ||
623 | } | ||
624 | 609 | ||
610 | if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) { | ||
611 | dbg("%s - DTR|RTS not being set|cleared", __FUNCTION__); | ||
612 | return 0; /* no change */ | ||
613 | } | ||
625 | 614 | ||
626 | static int set_dtr(struct usb_serial_port *port, int high_or_low) | ||
627 | { | ||
628 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
629 | char *buf; | ||
630 | unsigned ftdi_high_or_low; | ||
631 | int rv; | ||
632 | |||
633 | buf = kmalloc(1, GFP_NOIO); | 615 | buf = kmalloc(1, GFP_NOIO); |
634 | if (!buf) | 616 | if (!buf) { |
635 | return -ENOMEM; | 617 | return -ENOMEM; |
636 | |||
637 | if (high_or_low) { | ||
638 | ftdi_high_or_low = FTDI_SIO_SET_DTR_HIGH; | ||
639 | priv->last_dtr_rts |= TIOCM_DTR; | ||
640 | } else { | ||
641 | ftdi_high_or_low = FTDI_SIO_SET_DTR_LOW; | ||
642 | priv->last_dtr_rts &= ~TIOCM_DTR; | ||
643 | } | 618 | } |
619 | |||
620 | clear &= ~set; /* 'set' takes precedence over 'clear' */ | ||
621 | urb_value = 0; | ||
622 | if (clear & TIOCM_DTR) | ||
623 | urb_value |= FTDI_SIO_SET_DTR_LOW; | ||
624 | if (clear & TIOCM_RTS) | ||
625 | urb_value |= FTDI_SIO_SET_RTS_LOW; | ||
626 | if (set & TIOCM_DTR) | ||
627 | urb_value |= FTDI_SIO_SET_DTR_HIGH; | ||
628 | if (set & TIOCM_RTS) | ||
629 | urb_value |= FTDI_SIO_SET_RTS_HIGH; | ||
644 | rv = usb_control_msg(port->serial->dev, | 630 | rv = usb_control_msg(port->serial->dev, |
645 | usb_sndctrlpipe(port->serial->dev, 0), | 631 | usb_sndctrlpipe(port->serial->dev, 0), |
646 | FTDI_SIO_SET_MODEM_CTRL_REQUEST, | 632 | FTDI_SIO_SET_MODEM_CTRL_REQUEST, |
647 | FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, | 633 | FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, |
648 | ftdi_high_or_low, priv->interface, | 634 | urb_value, priv->interface, |
649 | buf, 0, WDR_TIMEOUT); | 635 | buf, 0, WDR_TIMEOUT); |
650 | 636 | ||
651 | kfree(buf); | 637 | kfree(buf); |
638 | if (rv < 0) { | ||
639 | err("%s Error from MODEM_CTRL urb: DTR %s, RTS %s", | ||
640 | __FUNCTION__, | ||
641 | (set & TIOCM_DTR) ? "HIGH" : | ||
642 | (clear & TIOCM_DTR) ? "LOW" : "unchanged", | ||
643 | (set & TIOCM_RTS) ? "HIGH" : | ||
644 | (clear & TIOCM_RTS) ? "LOW" : "unchanged"); | ||
645 | } else { | ||
646 | dbg("%s - DTR %s, RTS %s", __FUNCTION__, | ||
647 | (set & TIOCM_DTR) ? "HIGH" : | ||
648 | (clear & TIOCM_DTR) ? "LOW" : "unchanged", | ||
649 | (set & TIOCM_RTS) ? "HIGH" : | ||
650 | (clear & TIOCM_RTS) ? "LOW" : "unchanged"); | ||
651 | priv->last_dtr_rts = (priv->last_dtr_rts & ~clear) | set; | ||
652 | } | ||
652 | return rv; | 653 | return rv; |
653 | } | 654 | } |
654 | 655 | ||
@@ -681,7 +682,7 @@ static int change_speed(struct usb_serial_port *port) | |||
681 | FTDI_SIO_SET_BAUDRATE_REQUEST, | 682 | FTDI_SIO_SET_BAUDRATE_REQUEST, |
682 | FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, | 683 | FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, |
683 | urb_value, urb_index, | 684 | urb_value, urb_index, |
684 | buf, 0, 100); | 685 | buf, 0, WDR_SHORT_TIMEOUT); |
685 | 686 | ||
686 | kfree(buf); | 687 | kfree(buf); |
687 | return rv; | 688 | return rv; |
@@ -1219,12 +1220,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) | |||
1219 | /* FIXME: Flow control might be enabled, so it should be checked - | 1220 | /* FIXME: Flow control might be enabled, so it should be checked - |
1220 | we have no control of defaults! */ | 1221 | we have no control of defaults! */ |
1221 | /* Turn on RTS and DTR since we are not flow controlling by default */ | 1222 | /* Turn on RTS and DTR since we are not flow controlling by default */ |
1222 | if (set_dtr(port, HIGH) < 0) { | 1223 | set_mctrl(port, TIOCM_DTR | TIOCM_RTS); |
1223 | err("%s Error from DTR HIGH urb", __FUNCTION__); | ||
1224 | } | ||
1225 | if (set_rts(port, HIGH) < 0){ | ||
1226 | err("%s Error from RTS HIGH urb", __FUNCTION__); | ||
1227 | } | ||
1228 | 1224 | ||
1229 | /* Not throttled */ | 1225 | /* Not throttled */ |
1230 | spin_lock_irqsave(&priv->rx_lock, flags); | 1226 | spin_lock_irqsave(&priv->rx_lock, flags); |
@@ -1274,14 +1270,8 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) | |||
1274 | err("error from flowcontrol urb"); | 1270 | err("error from flowcontrol urb"); |
1275 | } | 1271 | } |
1276 | 1272 | ||
1277 | /* drop DTR */ | 1273 | /* drop RTS and DTR */ |
1278 | if (set_dtr(port, LOW) < 0){ | 1274 | clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); |
1279 | err("Error from DTR LOW urb"); | ||
1280 | } | ||
1281 | /* drop RTS */ | ||
1282 | if (set_rts(port, LOW) < 0) { | ||
1283 | err("Error from RTS LOW urb"); | ||
1284 | } | ||
1285 | } /* Note change no line if hupcl is off */ | 1275 | } /* Note change no line if hupcl is off */ |
1286 | 1276 | ||
1287 | /* cancel any scheduled reading */ | 1277 | /* cancel any scheduled reading */ |
@@ -1797,7 +1787,7 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ | |||
1797 | FTDI_SIO_SET_DATA_REQUEST, | 1787 | FTDI_SIO_SET_DATA_REQUEST, |
1798 | FTDI_SIO_SET_DATA_REQUEST_TYPE, | 1788 | FTDI_SIO_SET_DATA_REQUEST_TYPE, |
1799 | urb_value , priv->interface, | 1789 | urb_value , priv->interface, |
1800 | buf, 0, 100) < 0) { | 1790 | buf, 0, WDR_SHORT_TIMEOUT) < 0) { |
1801 | err("%s FAILED to set databits/stopbits/parity", __FUNCTION__); | 1791 | err("%s FAILED to set databits/stopbits/parity", __FUNCTION__); |
1802 | } | 1792 | } |
1803 | 1793 | ||
@@ -1812,25 +1802,14 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ | |||
1812 | err("%s error from disable flowcontrol urb", __FUNCTION__); | 1802 | err("%s error from disable flowcontrol urb", __FUNCTION__); |
1813 | } | 1803 | } |
1814 | /* Drop RTS and DTR */ | 1804 | /* Drop RTS and DTR */ |
1815 | if (set_dtr(port, LOW) < 0){ | 1805 | clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); |
1816 | err("%s Error from DTR LOW urb", __FUNCTION__); | ||
1817 | } | ||
1818 | if (set_rts(port, LOW) < 0){ | ||
1819 | err("%s Error from RTS LOW urb", __FUNCTION__); | ||
1820 | } | ||
1821 | |||
1822 | } else { | 1806 | } else { |
1823 | /* set the baudrate determined before */ | 1807 | /* set the baudrate determined before */ |
1824 | if (change_speed(port)) { | 1808 | if (change_speed(port)) { |
1825 | err("%s urb failed to set baurdrate", __FUNCTION__); | 1809 | err("%s urb failed to set baurdrate", __FUNCTION__); |
1826 | } | 1810 | } |
1827 | /* Ensure RTS and DTR are raised */ | 1811 | /* Ensure RTS and DTR are raised */ |
1828 | else if (set_dtr(port, HIGH) < 0){ | 1812 | set_mctrl(port, TIOCM_DTR | TIOCM_RTS); |
1829 | err("%s Error from DTR HIGH urb", __FUNCTION__); | ||
1830 | } | ||
1831 | else if (set_rts(port, HIGH) < 0){ | ||
1832 | err("%s Error from RTS HIGH urb", __FUNCTION__); | ||
1833 | } | ||
1834 | } | 1813 | } |
1835 | 1814 | ||
1836 | /* Set flow control */ | 1815 | /* Set flow control */ |
@@ -1942,35 +1921,8 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) | |||
1942 | 1921 | ||
1943 | static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear) | 1922 | static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear) |
1944 | { | 1923 | { |
1945 | int ret; | ||
1946 | |||
1947 | dbg("%s TIOCMSET", __FUNCTION__); | 1924 | dbg("%s TIOCMSET", __FUNCTION__); |
1948 | if (set & TIOCM_DTR){ | 1925 | return update_mctrl(port, set, clear); |
1949 | if ((ret = set_dtr(port, HIGH)) < 0) { | ||
1950 | err("Urb to set DTR failed"); | ||
1951 | return(ret); | ||
1952 | } | ||
1953 | } | ||
1954 | if (set & TIOCM_RTS) { | ||
1955 | if ((ret = set_rts(port, HIGH)) < 0){ | ||
1956 | err("Urb to set RTS failed"); | ||
1957 | return(ret); | ||
1958 | } | ||
1959 | } | ||
1960 | |||
1961 | if (clear & TIOCM_DTR){ | ||
1962 | if ((ret = set_dtr(port, LOW)) < 0){ | ||
1963 | err("Urb to unset DTR failed"); | ||
1964 | return(ret); | ||
1965 | } | ||
1966 | } | ||
1967 | if (clear & TIOCM_RTS) { | ||
1968 | if ((ret = set_rts(port, LOW)) < 0){ | ||
1969 | err("Urb to unset RTS failed"); | ||
1970 | return(ret); | ||
1971 | } | ||
1972 | } | ||
1973 | return(0); | ||
1974 | } | 1926 | } |
1975 | 1927 | ||
1976 | 1928 | ||