diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5d3999e3ff614663dd8dab01f1c794b7c5b7a2d6..b37d65fc875257178580b567492ef90adea88db2 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -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);