summaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/option.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 5d3999e3ff6..b37d65fc875 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -38,6 +38,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
+#include <linux/bitops.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
@@ -240,6 +241,7 @@ struct option_port_private {
/* Output endpoints and buffer for this port */
struct urb *out_urbs[N_OUT_URB];
char out_buffer[N_OUT_URB][OUT_BUFLEN];
+ unsigned long out_busy; /* Bit vector of URBs in use */
/* Settings for the port */
int rts_state; /* Handshaking pins (outputs) */
@@ -370,7 +372,7 @@ static int option_write(struct usb_serial_port *port,
todo = OUT_BUFLEN;
this_urb = portdata->out_urbs[i];
- if (this_urb->status == -EINPROGRESS) {
+ if (test_and_set_bit(i, &portdata->out_busy)) {
if (time_before(jiffies,
portdata->tx_start_time[i] + 10 * HZ))
continue;
@@ -394,6 +396,7 @@ static int option_write(struct usb_serial_port *port,
dbg("usb_submit_urb %p (write bulk) failed "
"(%d, has %d)", this_urb,
err, this_urb->status);
+ clear_bit(i, &portdata->out_busy);
continue;
}
portdata->tx_start_time[i] = jiffies;
@@ -446,12 +449,23 @@ static void option_indat_callback(struct urb *urb)
static void option_outdat_callback(struct urb *urb)
{
struct usb_serial_port *port;
+ struct option_port_private *portdata;
+ int i;
dbg("%s", __FUNCTION__);
port = (struct usb_serial_port *) urb->context;
usb_serial_port_softint(port);
+
+ portdata = usb_get_serial_port_data(port);
+ for (i = 0; i < N_OUT_URB; ++i) {
+ if (portdata->out_urbs[i] == urb) {
+ smp_mb__before_clear_bit();
+ clear_bit(i, &portdata->out_busy);
+ break;
+ }
+ }
}
static void option_instat_callback(struct urb *urb)
@@ -518,7 +532,7 @@ static int option_write_room(struct usb_serial_port *port)
for (i=0; i < N_OUT_URB; i++) {
this_urb = portdata->out_urbs[i];
- if (this_urb && this_urb->status != -EINPROGRESS)
+ if (this_urb && !test_bit(i, &portdata->out_busy))
data_len += OUT_BUFLEN;
}
@@ -537,7 +551,7 @@ static int option_chars_in_buffer(struct usb_serial_port *port)
for (i=0; i < N_OUT_URB; i++) {
this_urb = portdata->out_urbs[i];
- if (this_urb && this_urb->status == -EINPROGRESS)
+ if (this_urb && test_bit(i, &portdata->out_busy))
data_len += this_urb->transfer_buffer_length;
}
dbg("%s: %d", __FUNCTION__, data_len);