diff options
author | Johan Hovold <jhovold@gmail.com> | 2010-03-17 18:05:56 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-20 16:21:34 -0400 |
commit | 0f3d5bae2bdacce6c6c1d116809d6b3d50338df7 (patch) | |
tree | f0bbd19801f576a26279ee485ff969234a9051b0 /drivers/usb/serial/generic.c | |
parent | 2db6c7698bbb37128959d3a207fc46e3f45bef3c (diff) |
USB: serial: clean up read processing in generic driver
Always process and flush read urb, but only resubmit when not throttled.
The new tty-layer supply plenty of slack so there is really no need to
cache and delay processing of a single urb while throttled.
Note that unthrottle now submits using GFP_KERNEL as we are not in
atomic context (so there is no need to save irq state either).
Note also that the process_read_urb function could be added to
usb_serial_driver should any driver need to do any device specific
processing.
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial/generic.c')
-rw-r--r-- | drivers/usb/serial/generic.c | 27 |
1 files changed, 11 insertions, 16 deletions
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index ffc2f163bb59..e16c0b234cc9 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c | |||
@@ -408,16 +408,16 @@ int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, | |||
408 | } | 408 | } |
409 | EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urb); | 409 | EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urb); |
410 | 410 | ||
411 | /* Push data to tty layer and resubmit the bulk read URB */ | 411 | static void usb_serial_generic_process_read_urb(struct urb *urb) |
412 | static void flush_and_resubmit_read_urb(struct usb_serial_port *port) | ||
413 | { | 412 | { |
414 | struct urb *urb = port->read_urb; | 413 | struct usb_serial_port *port = urb->context; |
415 | struct tty_struct *tty = tty_port_tty_get(&port->port); | 414 | struct tty_struct *tty; |
416 | char *ch = (char *)urb->transfer_buffer; | 415 | char *ch = (char *)urb->transfer_buffer; |
417 | int i; | 416 | int i; |
418 | 417 | ||
418 | tty = tty_port_tty_get(&port->port); | ||
419 | if (!tty) | 419 | if (!tty) |
420 | goto done; | 420 | return; |
421 | 421 | ||
422 | /* The per character mucking around with sysrq path it too slow for | 422 | /* The per character mucking around with sysrq path it too slow for |
423 | stuff like 3G modems, so shortcircuit it in the 99.9999999% of cases | 423 | stuff like 3G modems, so shortcircuit it in the 99.9999999% of cases |
@@ -425,7 +425,6 @@ static void flush_and_resubmit_read_urb(struct usb_serial_port *port) | |||
425 | if (!port->port.console || !port->sysrq) | 425 | if (!port->port.console || !port->sysrq) |
426 | tty_insert_flip_string(tty, ch, urb->actual_length); | 426 | tty_insert_flip_string(tty, ch, urb->actual_length); |
427 | else { | 427 | else { |
428 | /* Push data to tty */ | ||
429 | for (i = 0; i < urb->actual_length; i++, ch++) { | 428 | for (i = 0; i < urb->actual_length; i++, ch++) { |
430 | if (!usb_serial_handle_sysrq_char(tty, port, *ch)) | 429 | if (!usb_serial_handle_sysrq_char(tty, port, *ch)) |
431 | tty_insert_flip_char(tty, *ch, TTY_NORMAL); | 430 | tty_insert_flip_char(tty, *ch, TTY_NORMAL); |
@@ -433,8 +432,6 @@ static void flush_and_resubmit_read_urb(struct usb_serial_port *port) | |||
433 | } | 432 | } |
434 | tty_flip_buffer_push(tty); | 433 | tty_flip_buffer_push(tty); |
435 | tty_kref_put(tty); | 434 | tty_kref_put(tty); |
436 | done: | ||
437 | usb_serial_generic_submit_read_urb(port, GFP_ATOMIC); | ||
438 | } | 435 | } |
439 | 436 | ||
440 | void usb_serial_generic_read_bulk_callback(struct urb *urb) | 437 | void usb_serial_generic_read_bulk_callback(struct urb *urb) |
@@ -454,13 +451,14 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) | |||
454 | 451 | ||
455 | usb_serial_debug_data(debug, &port->dev, __func__, | 452 | usb_serial_debug_data(debug, &port->dev, __func__, |
456 | urb->actual_length, data); | 453 | urb->actual_length, data); |
454 | usb_serial_generic_process_read_urb(urb); | ||
457 | 455 | ||
458 | /* Throttle the device if requested by tty */ | 456 | /* Throttle the device if requested by tty */ |
459 | spin_lock_irqsave(&port->lock, flags); | 457 | spin_lock_irqsave(&port->lock, flags); |
460 | port->throttled = port->throttle_req; | 458 | port->throttled = port->throttle_req; |
461 | if (!port->throttled) { | 459 | if (!port->throttled) { |
462 | spin_unlock_irqrestore(&port->lock, flags); | 460 | spin_unlock_irqrestore(&port->lock, flags); |
463 | flush_and_resubmit_read_urb(port); | 461 | usb_serial_generic_submit_read_urb(port, GFP_ATOMIC); |
464 | } else | 462 | } else |
465 | spin_unlock_irqrestore(&port->lock, flags); | 463 | spin_unlock_irqrestore(&port->lock, flags); |
466 | } | 464 | } |
@@ -523,20 +521,17 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty) | |||
523 | { | 521 | { |
524 | struct usb_serial_port *port = tty->driver_data; | 522 | struct usb_serial_port *port = tty->driver_data; |
525 | int was_throttled; | 523 | int was_throttled; |
526 | unsigned long flags; | ||
527 | 524 | ||
528 | dbg("%s - port %d", __func__, port->number); | 525 | dbg("%s - port %d", __func__, port->number); |
529 | 526 | ||
530 | /* Clear the throttle flags */ | 527 | /* Clear the throttle flags */ |
531 | spin_lock_irqsave(&port->lock, flags); | 528 | spin_lock_irq(&port->lock); |
532 | was_throttled = port->throttled; | 529 | was_throttled = port->throttled; |
533 | port->throttled = port->throttle_req = 0; | 530 | port->throttled = port->throttle_req = 0; |
534 | spin_unlock_irqrestore(&port->lock, flags); | 531 | spin_unlock_irq(&port->lock); |
535 | 532 | ||
536 | if (was_throttled) { | 533 | if (was_throttled) |
537 | /* Resume reading from device */ | 534 | usb_serial_generic_submit_read_urb(port, GFP_KERNEL); |
538 | flush_and_resubmit_read_urb(port); | ||
539 | } | ||
540 | } | 535 | } |
541 | 536 | ||
542 | #ifdef CONFIG_MAGIC_SYSRQ | 537 | #ifdef CONFIG_MAGIC_SYSRQ |