diff options
-rw-r--r-- | drivers/usb/serial/option.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5d3999e3ff61..b37d65fc8752 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/tty.h> | 38 | #include <linux/tty.h> |
39 | #include <linux/tty_flip.h> | 39 | #include <linux/tty_flip.h> |
40 | #include <linux/module.h> | 40 | #include <linux/module.h> |
41 | #include <linux/bitops.h> | ||
41 | #include <linux/usb.h> | 42 | #include <linux/usb.h> |
42 | #include <linux/usb/serial.h> | 43 | #include <linux/usb/serial.h> |
43 | 44 | ||
@@ -240,6 +241,7 @@ struct option_port_private { | |||
240 | /* Output endpoints and buffer for this port */ | 241 | /* Output endpoints and buffer for this port */ |
241 | struct urb *out_urbs[N_OUT_URB]; | 242 | struct urb *out_urbs[N_OUT_URB]; |
242 | char out_buffer[N_OUT_URB][OUT_BUFLEN]; | 243 | char out_buffer[N_OUT_URB][OUT_BUFLEN]; |
244 | unsigned long out_busy; /* Bit vector of URBs in use */ | ||
243 | 245 | ||
244 | /* Settings for the port */ | 246 | /* Settings for the port */ |
245 | int rts_state; /* Handshaking pins (outputs) */ | 247 | int rts_state; /* Handshaking pins (outputs) */ |
@@ -370,7 +372,7 @@ static int option_write(struct usb_serial_port *port, | |||
370 | todo = OUT_BUFLEN; | 372 | todo = OUT_BUFLEN; |
371 | 373 | ||
372 | this_urb = portdata->out_urbs[i]; | 374 | this_urb = portdata->out_urbs[i]; |
373 | if (this_urb->status == -EINPROGRESS) { | 375 | if (test_and_set_bit(i, &portdata->out_busy)) { |
374 | if (time_before(jiffies, | 376 | if (time_before(jiffies, |
375 | portdata->tx_start_time[i] + 10 * HZ)) | 377 | portdata->tx_start_time[i] + 10 * HZ)) |
376 | continue; | 378 | continue; |
@@ -394,6 +396,7 @@ static int option_write(struct usb_serial_port *port, | |||
394 | dbg("usb_submit_urb %p (write bulk) failed " | 396 | dbg("usb_submit_urb %p (write bulk) failed " |
395 | "(%d, has %d)", this_urb, | 397 | "(%d, has %d)", this_urb, |
396 | err, this_urb->status); | 398 | err, this_urb->status); |
399 | clear_bit(i, &portdata->out_busy); | ||
397 | continue; | 400 | continue; |
398 | } | 401 | } |
399 | portdata->tx_start_time[i] = jiffies; | 402 | portdata->tx_start_time[i] = jiffies; |
@@ -446,12 +449,23 @@ static void option_indat_callback(struct urb *urb) | |||
446 | static void option_outdat_callback(struct urb *urb) | 449 | static void option_outdat_callback(struct urb *urb) |
447 | { | 450 | { |
448 | struct usb_serial_port *port; | 451 | struct usb_serial_port *port; |
452 | struct option_port_private *portdata; | ||
453 | int i; | ||
449 | 454 | ||
450 | dbg("%s", __FUNCTION__); | 455 | dbg("%s", __FUNCTION__); |
451 | 456 | ||
452 | port = (struct usb_serial_port *) urb->context; | 457 | port = (struct usb_serial_port *) urb->context; |
453 | 458 | ||
454 | usb_serial_port_softint(port); | 459 | usb_serial_port_softint(port); |
460 | |||
461 | portdata = usb_get_serial_port_data(port); | ||
462 | for (i = 0; i < N_OUT_URB; ++i) { | ||
463 | if (portdata->out_urbs[i] == urb) { | ||
464 | smp_mb__before_clear_bit(); | ||
465 | clear_bit(i, &portdata->out_busy); | ||
466 | break; | ||
467 | } | ||
468 | } | ||
455 | } | 469 | } |
456 | 470 | ||
457 | static void option_instat_callback(struct urb *urb) | 471 | static void option_instat_callback(struct urb *urb) |
@@ -518,7 +532,7 @@ static int option_write_room(struct usb_serial_port *port) | |||
518 | 532 | ||
519 | for (i=0; i < N_OUT_URB; i++) { | 533 | for (i=0; i < N_OUT_URB; i++) { |
520 | this_urb = portdata->out_urbs[i]; | 534 | this_urb = portdata->out_urbs[i]; |
521 | if (this_urb && this_urb->status != -EINPROGRESS) | 535 | if (this_urb && !test_bit(i, &portdata->out_busy)) |
522 | data_len += OUT_BUFLEN; | 536 | data_len += OUT_BUFLEN; |
523 | } | 537 | } |
524 | 538 | ||
@@ -537,7 +551,7 @@ static int option_chars_in_buffer(struct usb_serial_port *port) | |||
537 | 551 | ||
538 | for (i=0; i < N_OUT_URB; i++) { | 552 | for (i=0; i < N_OUT_URB; i++) { |
539 | this_urb = portdata->out_urbs[i]; | 553 | this_urb = portdata->out_urbs[i]; |
540 | if (this_urb && this_urb->status == -EINPROGRESS) | 554 | if (this_urb && test_bit(i, &portdata->out_busy)) |
541 | data_len += this_urb->transfer_buffer_length; | 555 | data_len += this_urb->transfer_buffer_length; |
542 | } | 556 | } |
543 | dbg("%s: %d", __FUNCTION__, data_len); | 557 | dbg("%s: %d", __FUNCTION__, data_len); |