diff options
author | Johan Hovold <jhovold@gmail.com> | 2009-10-07 14:05:07 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-10-09 16:52:05 -0400 |
commit | cc01f17d5cb8ac604108515735aeca72e17944c1 (patch) | |
tree | 88f2dd91bf41f9a4b8881264ba0efdd2d64b9631 /drivers/usb/serial/ftdi_sio.c | |
parent | e63e278b4d2d867893962d3c7cd13a3a24ceb3f1 (diff) |
USB: ftdi_sio: re-implement read processing
- Re-structure read processing.
- Kill obsolete work queue and always push to tty in completion handler.
- Use tty_insert_flip_string instead of per character push when
possible.
- Fix stalled-read regression in 2.6.31 by using urb status to
determine when port is closed rather than port count.
- Fix race with open/close by checking ASYNCB_INITIALIZED in
unthrottle.
- Kill private rx_flag and lock and use throttle flags in
usb_serial_port instead.
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial/ftdi_sio.c')
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 383 |
1 files changed, 131 insertions, 252 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 75c84d9b080d..9c60d6d4908a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -76,12 +76,7 @@ struct ftdi_private { | |||
76 | unsigned long last_dtr_rts; /* saved modem control outputs */ | 76 | unsigned long last_dtr_rts; /* saved modem control outputs */ |
77 | wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ | 77 | wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ |
78 | char prev_status, diff_status; /* Used for TIOCMIWAIT */ | 78 | char prev_status, diff_status; /* Used for TIOCMIWAIT */ |
79 | __u8 rx_flags; /* receive state flags (throttling) */ | ||
80 | spinlock_t rx_lock; /* spinlock for receive state */ | ||
81 | struct delayed_work rx_work; | ||
82 | struct usb_serial_port *port; | 79 | struct usb_serial_port *port; |
83 | int rx_processed; | ||
84 | |||
85 | __u16 interface; /* FT2232C, FT2232H or FT4232H port interface | 80 | __u16 interface; /* FT2232C, FT2232H or FT4232H port interface |
86 | (0 for FT232/245) */ | 81 | (0 for FT232/245) */ |
87 | 82 | ||
@@ -736,10 +731,6 @@ static const char *ftdi_chip_name[] = { | |||
736 | /* Constants for read urb and write urb */ | 731 | /* Constants for read urb and write urb */ |
737 | #define BUFSZ 512 | 732 | #define BUFSZ 512 |
738 | 733 | ||
739 | /* rx_flags */ | ||
740 | #define THROTTLED 0x01 | ||
741 | #define ACTUALLY_THROTTLED 0x02 | ||
742 | |||
743 | /* Used for TIOCMIWAIT */ | 734 | /* Used for TIOCMIWAIT */ |
744 | #define FTDI_STATUS_B0_MASK (FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD) | 735 | #define FTDI_STATUS_B0_MASK (FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD) |
745 | #define FTDI_STATUS_B1_MASK (FTDI_RS_BI) | 736 | #define FTDI_STATUS_B1_MASK (FTDI_RS_BI) |
@@ -762,7 +753,7 @@ static int ftdi_write_room(struct tty_struct *tty); | |||
762 | static int ftdi_chars_in_buffer(struct tty_struct *tty); | 753 | static int ftdi_chars_in_buffer(struct tty_struct *tty); |
763 | static void ftdi_write_bulk_callback(struct urb *urb); | 754 | static void ftdi_write_bulk_callback(struct urb *urb); |
764 | static void ftdi_read_bulk_callback(struct urb *urb); | 755 | static void ftdi_read_bulk_callback(struct urb *urb); |
765 | static void ftdi_process_read(struct work_struct *work); | 756 | static void ftdi_process_read(struct usb_serial_port *port); |
766 | static void ftdi_set_termios(struct tty_struct *tty, | 757 | static void ftdi_set_termios(struct tty_struct *tty, |
767 | struct usb_serial_port *port, struct ktermios *old); | 758 | struct usb_serial_port *port, struct ktermios *old); |
768 | static int ftdi_tiocmget(struct tty_struct *tty, struct file *file); | 759 | static int ftdi_tiocmget(struct tty_struct *tty, struct file *file); |
@@ -1525,7 +1516,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) | |||
1525 | } | 1516 | } |
1526 | 1517 | ||
1527 | kref_init(&priv->kref); | 1518 | kref_init(&priv->kref); |
1528 | spin_lock_init(&priv->rx_lock); | ||
1529 | spin_lock_init(&priv->tx_lock); | 1519 | spin_lock_init(&priv->tx_lock); |
1530 | init_waitqueue_head(&priv->delta_msr_wait); | 1520 | init_waitqueue_head(&priv->delta_msr_wait); |
1531 | /* This will push the characters through immediately rather | 1521 | /* This will push the characters through immediately rather |
@@ -1547,7 +1537,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) | |||
1547 | port->read_urb->transfer_buffer_length = BUFSZ; | 1537 | port->read_urb->transfer_buffer_length = BUFSZ; |
1548 | } | 1538 | } |
1549 | 1539 | ||
1550 | INIT_DELAYED_WORK(&priv->rx_work, ftdi_process_read); | ||
1551 | priv->port = port; | 1540 | priv->port = port; |
1552 | 1541 | ||
1553 | /* Free port's existing write urb and transfer buffer. */ | 1542 | /* Free port's existing write urb and transfer buffer. */ |
@@ -1684,6 +1673,26 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port) | |||
1684 | return 0; | 1673 | return 0; |
1685 | } | 1674 | } |
1686 | 1675 | ||
1676 | static int ftdi_submit_read_urb(struct usb_serial_port *port, gfp_t mem_flags) | ||
1677 | { | ||
1678 | struct urb *urb = port->read_urb; | ||
1679 | struct usb_serial *serial = port->serial; | ||
1680 | int result; | ||
1681 | |||
1682 | usb_fill_bulk_urb(urb, serial->dev, | ||
1683 | usb_rcvbulkpipe(serial->dev, | ||
1684 | port->bulk_in_endpointAddress), | ||
1685 | urb->transfer_buffer, | ||
1686 | urb->transfer_buffer_length, | ||
1687 | ftdi_read_bulk_callback, port); | ||
1688 | result = usb_submit_urb(urb, mem_flags); | ||
1689 | if (result) | ||
1690 | dev_err(&port->dev, | ||
1691 | "%s - failed submitting read urb, error %d\n", | ||
1692 | __func__, result); | ||
1693 | return result; | ||
1694 | } | ||
1695 | |||
1687 | static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) | 1696 | static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) |
1688 | { /* ftdi_open */ | 1697 | { /* ftdi_open */ |
1689 | struct usb_device *dev = port->serial->dev; | 1698 | struct usb_device *dev = port->serial->dev; |
@@ -1717,23 +1726,14 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
1717 | ftdi_set_termios(tty, port, tty->termios); | 1726 | ftdi_set_termios(tty, port, tty->termios); |
1718 | 1727 | ||
1719 | /* Not throttled */ | 1728 | /* Not throttled */ |
1720 | spin_lock_irqsave(&priv->rx_lock, flags); | 1729 | spin_lock_irqsave(&port->lock, flags); |
1721 | priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED); | 1730 | port->throttled = 0; |
1722 | spin_unlock_irqrestore(&priv->rx_lock, flags); | 1731 | port->throttle_req = 0; |
1732 | spin_unlock_irqrestore(&port->lock, flags); | ||
1723 | 1733 | ||
1724 | /* Start reading from the device */ | 1734 | /* Start reading from the device */ |
1725 | priv->rx_processed = 0; | 1735 | result = ftdi_submit_read_urb(port, GFP_KERNEL); |
1726 | usb_fill_bulk_urb(port->read_urb, dev, | 1736 | if (!result) |
1727 | usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress), | ||
1728 | port->read_urb->transfer_buffer, | ||
1729 | port->read_urb->transfer_buffer_length, | ||
1730 | ftdi_read_bulk_callback, port); | ||
1731 | result = usb_submit_urb(port->read_urb, GFP_KERNEL); | ||
1732 | if (result) | ||
1733 | dev_err(&port->dev, | ||
1734 | "%s - failed submitting read urb, error %d\n", | ||
1735 | __func__, result); | ||
1736 | else | ||
1737 | kref_get(&priv->kref); | 1737 | kref_get(&priv->kref); |
1738 | 1738 | ||
1739 | return result; | 1739 | return result; |
@@ -1779,10 +1779,6 @@ static void ftdi_close(struct usb_serial_port *port) | |||
1779 | 1779 | ||
1780 | dbg("%s", __func__); | 1780 | dbg("%s", __func__); |
1781 | 1781 | ||
1782 | |||
1783 | /* cancel any scheduled reading */ | ||
1784 | cancel_delayed_work_sync(&priv->rx_work); | ||
1785 | |||
1786 | /* shutdown our bulk read */ | 1782 | /* shutdown our bulk read */ |
1787 | usb_kill_urb(port->read_urb); | 1783 | usb_kill_urb(port->read_urb); |
1788 | kref_put(&priv->kref, ftdi_sio_priv_release); | 1784 | kref_put(&priv->kref, ftdi_sio_priv_release); |
@@ -2005,236 +2001,121 @@ static int ftdi_chars_in_buffer(struct tty_struct *tty) | |||
2005 | return buffered; | 2001 | return buffered; |
2006 | } | 2002 | } |
2007 | 2003 | ||
2008 | static void ftdi_read_bulk_callback(struct urb *urb) | 2004 | static int ftdi_process_packet(struct tty_struct *tty, |
2005 | struct usb_serial_port *port, struct ftdi_private *priv, | ||
2006 | char *packet, int len) | ||
2009 | { | 2007 | { |
2010 | struct usb_serial_port *port = urb->context; | ||
2011 | struct ftdi_private *priv; | ||
2012 | int status = urb->status; | ||
2013 | |||
2014 | dbg("%s - port %d", __func__, port->number); | ||
2015 | |||
2016 | if (port->port.count <= 0) | ||
2017 | return; | ||
2018 | |||
2019 | if (status) { | ||
2020 | /* This will happen at close every time so it is a dbg not an | ||
2021 | err */ | ||
2022 | dbg("(this is ok on close) nonzero read bulk status received: %d", status); | ||
2023 | goto out; | ||
2024 | } | ||
2025 | |||
2026 | priv = usb_get_serial_port_data(port); | ||
2027 | ftdi_process_read(&priv->rx_work.work); | ||
2028 | } /* ftdi_read_bulk_callback */ | ||
2029 | |||
2030 | |||
2031 | static void ftdi_process_read(struct work_struct *work) | ||
2032 | { /* ftdi_process_read */ | ||
2033 | struct ftdi_private *priv = | ||
2034 | container_of(work, struct ftdi_private, rx_work.work); | ||
2035 | struct usb_serial_port *port = priv->port; | ||
2036 | struct urb *urb; | ||
2037 | struct tty_struct *tty; | ||
2038 | char error_flag; | ||
2039 | unsigned char *data; | ||
2040 | |||
2041 | int i; | 2008 | int i; |
2042 | int result; | 2009 | char status; |
2043 | int need_flip; | 2010 | char flag; |
2044 | int packet_offset; | 2011 | char *ch; |
2045 | unsigned long flags; | ||
2046 | 2012 | ||
2047 | dbg("%s - port %d", __func__, port->number); | 2013 | dbg("%s - port %d", __func__, port->number); |
2048 | 2014 | ||
2049 | if (port->port.count <= 0) | 2015 | if (len < 2) { |
2050 | return; | 2016 | dbg("malformed packet"); |
2051 | 2017 | return 0; | |
2052 | tty = tty_port_tty_get(&port->port); | ||
2053 | if (!tty) { | ||
2054 | dbg("%s - bad tty pointer - exiting", __func__); | ||
2055 | return; | ||
2056 | } | 2018 | } |
2057 | 2019 | ||
2058 | priv = usb_get_serial_port_data(port); | 2020 | /* Compare new line status to the old one, signal if different/ |
2059 | if (!priv) { | 2021 | N.B. packet may be processed more than once, but differences |
2060 | dbg("%s - bad port private data pointer - exiting", __func__); | 2022 | are only processed once. */ |
2061 | goto out; | 2023 | status = packet[0] & FTDI_STATUS_B0_MASK; |
2024 | if (status != priv->prev_status) { | ||
2025 | priv->diff_status |= status ^ priv->prev_status; | ||
2026 | wake_up_interruptible(&priv->delta_msr_wait); | ||
2027 | priv->prev_status = status; | ||
2062 | } | 2028 | } |
2063 | 2029 | ||
2064 | urb = port->read_urb; | 2030 | /* |
2065 | if (!urb) { | 2031 | * Although the device uses a bitmask and hence can have multiple |
2066 | dbg("%s - bad read_urb pointer - exiting", __func__); | 2032 | * errors on a packet - the order here sets the priority the error is |
2067 | goto out; | 2033 | * returned to the tty layer. |
2034 | */ | ||
2035 | flag = TTY_NORMAL; | ||
2036 | if (packet[1] & FTDI_RS_OE) { | ||
2037 | flag = TTY_OVERRUN; | ||
2038 | dbg("OVERRRUN error"); | ||
2068 | } | 2039 | } |
2069 | 2040 | if (packet[1] & FTDI_RS_BI) { | |
2070 | data = urb->transfer_buffer; | 2041 | flag = TTY_BREAK; |
2071 | 2042 | dbg("BREAK received"); | |
2072 | if (priv->rx_processed) { | 2043 | usb_serial_handle_break(port); |
2073 | dbg("%s - already processed: %d bytes, %d remain", __func__, | 2044 | } |
2074 | priv->rx_processed, | 2045 | if (packet[1] & FTDI_RS_PE) { |
2075 | urb->actual_length - priv->rx_processed); | 2046 | flag = TTY_PARITY; |
2076 | } else { | 2047 | dbg("PARITY error"); |
2077 | /* The first two bytes of every read packet are status */ | 2048 | } |
2078 | if (urb->actual_length > 2) | 2049 | if (packet[1] & FTDI_RS_FE) { |
2079 | usb_serial_debug_data(debug, &port->dev, __func__, | 2050 | flag = TTY_FRAME; |
2080 | urb->actual_length, data); | 2051 | dbg("FRAMING error"); |
2081 | else | ||
2082 | dbg("Status only: %03oo %03oo", data[0], data[1]); | ||
2083 | } | 2052 | } |
2084 | 2053 | ||
2085 | 2054 | len -= 2; | |
2086 | /* TO DO -- check for hung up line and handle appropriately: */ | 2055 | if (!len) |
2087 | /* send hangup */ | 2056 | return 0; /* status only */ |
2088 | /* See acm.c - you do a tty_hangup - eg tty_hangup(tty) */ | 2057 | ch = packet + 2; |
2089 | /* if CD is dropped and the line is not CLOCAL then we should hangup */ | 2058 | |
2090 | 2059 | if (!(port->console && port->sysrq) && flag == TTY_NORMAL) | |
2091 | need_flip = 0; | 2060 | tty_insert_flip_string(tty, ch, len); |
2092 | for (packet_offset = priv->rx_processed; | 2061 | else { |
2093 | packet_offset < urb->actual_length; packet_offset += priv->max_packet_size) { | 2062 | for (i = 0; i < len; i++, ch++) { |
2094 | int length; | 2063 | if (!usb_serial_handle_sysrq_char(tty, port, *ch)) |
2095 | 2064 | tty_insert_flip_char(tty, *ch, flag); | |
2096 | /* Compare new line status to the old one, signal if different/ | ||
2097 | N.B. packet may be processed more than once, but differences | ||
2098 | are only processed once. */ | ||
2099 | char new_status = data[packet_offset + 0] & | ||
2100 | FTDI_STATUS_B0_MASK; | ||
2101 | if (new_status != priv->prev_status) { | ||
2102 | priv->diff_status |= | ||
2103 | new_status ^ priv->prev_status; | ||
2104 | wake_up_interruptible(&priv->delta_msr_wait); | ||
2105 | priv->prev_status = new_status; | ||
2106 | } | ||
2107 | |||
2108 | length = min_t(u32, priv->max_packet_size, urb->actual_length-packet_offset)-2; | ||
2109 | if (length < 0) { | ||
2110 | dev_err(&port->dev, "%s - bad packet length: %d\n", | ||
2111 | __func__, length+2); | ||
2112 | length = 0; | ||
2113 | } | ||
2114 | |||
2115 | if (priv->rx_flags & THROTTLED) { | ||
2116 | dbg("%s - throttled", __func__); | ||
2117 | break; | ||
2118 | } | ||
2119 | if (tty_buffer_request_room(tty, length) < length) { | ||
2120 | /* break out & wait for throttling/unthrottling to | ||
2121 | happen */ | ||
2122 | dbg("%s - receive room low", __func__); | ||
2123 | break; | ||
2124 | } | 2065 | } |
2066 | } | ||
2067 | return len; | ||
2068 | } | ||
2125 | 2069 | ||
2126 | /* Handle errors and break */ | 2070 | static void ftdi_process_read(struct usb_serial_port *port) |
2127 | error_flag = TTY_NORMAL; | 2071 | { |
2128 | /* Although the device uses a bitmask and hence can have | 2072 | struct urb *urb = port->read_urb; |
2129 | multiple errors on a packet - the order here sets the | 2073 | struct tty_struct *tty; |
2130 | priority the error is returned to the tty layer */ | 2074 | struct ftdi_private *priv = usb_get_serial_port_data(port); |
2075 | char *data = (char *)urb->transfer_buffer; | ||
2076 | int i; | ||
2077 | int len; | ||
2078 | int count = 0; | ||
2131 | 2079 | ||
2132 | if (data[packet_offset+1] & FTDI_RS_OE) { | 2080 | tty = tty_port_tty_get(&port->port); |
2133 | error_flag = TTY_OVERRUN; | 2081 | if (!tty) |
2134 | dbg("OVERRRUN error"); | 2082 | return; |
2135 | } | ||
2136 | if (data[packet_offset+1] & FTDI_RS_BI) { | ||
2137 | error_flag = TTY_BREAK; | ||
2138 | dbg("BREAK received"); | ||
2139 | usb_serial_handle_break(port); | ||
2140 | } | ||
2141 | if (data[packet_offset+1] & FTDI_RS_PE) { | ||
2142 | error_flag = TTY_PARITY; | ||
2143 | dbg("PARITY error"); | ||
2144 | } | ||
2145 | if (data[packet_offset+1] & FTDI_RS_FE) { | ||
2146 | error_flag = TTY_FRAME; | ||
2147 | dbg("FRAMING error"); | ||
2148 | } | ||
2149 | if (length > 0) { | ||
2150 | for (i = 2; i < length+2; i++) { | ||
2151 | /* Note that the error flag is duplicated for | ||
2152 | every character received since we don't know | ||
2153 | which character it applied to */ | ||
2154 | if (!usb_serial_handle_sysrq_char(tty, port, | ||
2155 | data[packet_offset + i])) | ||
2156 | tty_insert_flip_char(tty, | ||
2157 | data[packet_offset + i], | ||
2158 | error_flag); | ||
2159 | } | ||
2160 | need_flip = 1; | ||
2161 | } | ||
2162 | 2083 | ||
2163 | #ifdef NOT_CORRECT_BUT_KEEPING_IT_FOR_NOW | 2084 | for (i = 0; i < urb->actual_length; i += priv->max_packet_size) { |
2164 | /* if a parity error is detected you get status packets forever | 2085 | len = min_t(int, urb->actual_length - i, priv->max_packet_size); |
2165 | until a character is sent without a parity error. | 2086 | count += ftdi_process_packet(tty, port, priv, &data[i], len); |
2166 | This doesn't work well since the application receives a | 2087 | } |
2167 | never ending stream of bad data - even though new data | ||
2168 | hasn't been sent. Therefore I (bill) have taken this out. | ||
2169 | However - this might make sense for framing errors and so on | ||
2170 | so I am leaving the code in for now. | ||
2171 | */ | ||
2172 | else { | ||
2173 | if (error_flag != TTY_NORMAL) { | ||
2174 | dbg("error_flag is not normal"); | ||
2175 | /* In this case it is just status - if that is | ||
2176 | an error send a bad character */ | ||
2177 | if (tty->flip.count >= TTY_FLIPBUF_SIZE) | ||
2178 | tty_flip_buffer_push(tty); | ||
2179 | tty_insert_flip_char(tty, 0xff, error_flag); | ||
2180 | need_flip = 1; | ||
2181 | } | ||
2182 | } | ||
2183 | #endif | ||
2184 | } /* "for(packet_offset=0..." */ | ||
2185 | 2088 | ||
2186 | /* Low latency */ | 2089 | if (count) |
2187 | if (need_flip) | ||
2188 | tty_flip_buffer_push(tty); | 2090 | tty_flip_buffer_push(tty); |
2091 | tty_kref_put(tty); | ||
2092 | } | ||
2189 | 2093 | ||
2190 | if (packet_offset < urb->actual_length) { | 2094 | static void ftdi_read_bulk_callback(struct urb *urb) |
2191 | /* not completely processed - record progress */ | 2095 | { |
2192 | priv->rx_processed = packet_offset; | 2096 | struct usb_serial_port *port = urb->context; |
2193 | dbg("%s - incomplete, %d bytes processed, %d remain", | 2097 | unsigned long flags; |
2194 | __func__, packet_offset, | ||
2195 | urb->actual_length - packet_offset); | ||
2196 | /* check if we were throttled while processing */ | ||
2197 | spin_lock_irqsave(&priv->rx_lock, flags); | ||
2198 | if (priv->rx_flags & THROTTLED) { | ||
2199 | priv->rx_flags |= ACTUALLY_THROTTLED; | ||
2200 | spin_unlock_irqrestore(&priv->rx_lock, flags); | ||
2201 | dbg("%s - deferring remainder until unthrottled", | ||
2202 | __func__); | ||
2203 | goto out; | ||
2204 | } | ||
2205 | spin_unlock_irqrestore(&priv->rx_lock, flags); | ||
2206 | /* if the port is closed stop trying to read */ | ||
2207 | if (port->port.count > 0) | ||
2208 | /* delay processing of remainder */ | ||
2209 | schedule_delayed_work(&priv->rx_work, 1); | ||
2210 | else | ||
2211 | dbg("%s - port is closed", __func__); | ||
2212 | goto out; | ||
2213 | } | ||
2214 | |||
2215 | /* urb is completely processed */ | ||
2216 | priv->rx_processed = 0; | ||
2217 | 2098 | ||
2218 | /* if the port is closed stop trying to read */ | 2099 | dbg("%s - port %d", __func__, port->number); |
2219 | if (port->port.count > 0) { | ||
2220 | /* Continue trying to always read */ | ||
2221 | usb_fill_bulk_urb(port->read_urb, port->serial->dev, | ||
2222 | usb_rcvbulkpipe(port->serial->dev, | ||
2223 | port->bulk_in_endpointAddress), | ||
2224 | port->read_urb->transfer_buffer, | ||
2225 | port->read_urb->transfer_buffer_length, | ||
2226 | ftdi_read_bulk_callback, port); | ||
2227 | 2100 | ||
2228 | result = usb_submit_urb(port->read_urb, GFP_ATOMIC); | 2101 | if (urb->status) { |
2229 | if (result) | 2102 | dbg("%s - nonzero read bulk status received: %d", |
2230 | dev_err(&port->dev, | 2103 | __func__, urb->status); |
2231 | "%s - failed resubmitting read urb, error %d\n", | 2104 | return; |
2232 | __func__, result); | ||
2233 | } | 2105 | } |
2234 | out: | ||
2235 | tty_kref_put(tty); | ||
2236 | } /* ftdi_process_read */ | ||
2237 | 2106 | ||
2107 | usb_serial_debug_data(debug, &port->dev, __func__, | ||
2108 | urb->actual_length, urb->transfer_buffer); | ||
2109 | ftdi_process_read(port); | ||
2110 | |||
2111 | spin_lock_irqsave(&port->lock, flags); | ||
2112 | port->throttled = port->throttle_req; | ||
2113 | if (!port->throttled) { | ||
2114 | spin_unlock_irqrestore(&port->lock, flags); | ||
2115 | ftdi_submit_read_urb(port, GFP_ATOMIC); | ||
2116 | } else | ||
2117 | spin_unlock_irqrestore(&port->lock, flags); | ||
2118 | } | ||
2238 | 2119 | ||
2239 | static void ftdi_break_ctl(struct tty_struct *tty, int break_state) | 2120 | static void ftdi_break_ctl(struct tty_struct *tty, int break_state) |
2240 | { | 2121 | { |
@@ -2566,33 +2447,31 @@ static int ftdi_ioctl(struct tty_struct *tty, struct file *file, | |||
2566 | static void ftdi_throttle(struct tty_struct *tty) | 2447 | static void ftdi_throttle(struct tty_struct *tty) |
2567 | { | 2448 | { |
2568 | struct usb_serial_port *port = tty->driver_data; | 2449 | struct usb_serial_port *port = tty->driver_data; |
2569 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
2570 | unsigned long flags; | 2450 | unsigned long flags; |
2571 | 2451 | ||
2572 | dbg("%s - port %d", __func__, port->number); | 2452 | dbg("%s - port %d", __func__, port->number); |
2573 | 2453 | ||
2574 | spin_lock_irqsave(&priv->rx_lock, flags); | 2454 | spin_lock_irqsave(&port->lock, flags); |
2575 | priv->rx_flags |= THROTTLED; | 2455 | port->throttle_req = 1; |
2576 | spin_unlock_irqrestore(&priv->rx_lock, flags); | 2456 | spin_unlock_irqrestore(&port->lock, flags); |
2577 | } | 2457 | } |
2578 | 2458 | ||
2579 | 2459 | void ftdi_unthrottle(struct tty_struct *tty) | |
2580 | static void ftdi_unthrottle(struct tty_struct *tty) | ||
2581 | { | 2460 | { |
2582 | struct usb_serial_port *port = tty->driver_data; | 2461 | struct usb_serial_port *port = tty->driver_data; |
2583 | struct ftdi_private *priv = usb_get_serial_port_data(port); | 2462 | int was_throttled; |
2584 | int actually_throttled; | ||
2585 | unsigned long flags; | 2463 | unsigned long flags; |
2586 | 2464 | ||
2587 | dbg("%s - port %d", __func__, port->number); | 2465 | dbg("%s - port %d", __func__, port->number); |
2588 | 2466 | ||
2589 | spin_lock_irqsave(&priv->rx_lock, flags); | 2467 | spin_lock_irqsave(&port->lock, flags); |
2590 | actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED; | 2468 | was_throttled = port->throttled; |
2591 | priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED); | 2469 | port->throttled = port->throttle_req = 0; |
2592 | spin_unlock_irqrestore(&priv->rx_lock, flags); | 2470 | spin_unlock_irqrestore(&port->lock, flags); |
2593 | 2471 | ||
2594 | if (actually_throttled) | 2472 | /* Resubmit urb if throttled and open. */ |
2595 | schedule_delayed_work(&priv->rx_work, 0); | 2473 | if (was_throttled && test_bit(ASYNCB_INITIALIZED, &port->port.flags)) |
2474 | ftdi_submit_read_urb(port, GFP_KERNEL); | ||
2596 | } | 2475 | } |
2597 | 2476 | ||
2598 | static int __init ftdi_init(void) | 2477 | static int __init ftdi_init(void) |