diff options
author | Johan Hovold <jhovold@gmail.com> | 2010-03-17 23:05:56 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-20 13:21:34 -0700 |
commit | 0f3d5bae2bdacce6c6c1d116809d6b3d50338df7 (patch) | |
tree | f0bbd19801f576a26279ee485ff969234a9051b0 /drivers/usb/serial/generic.c | |
parent | 2db6c7698bbb37128959d3a207fc46e3f45bef3c (diff) | |
download | op-kernel-dev-0f3d5bae2bdacce6c6c1d116809d6b3d50338df7.zip op-kernel-dev-0f3d5bae2bdacce6c6c1d116809d6b3d50338df7.tar.gz |
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 ffc2f16..e16c0b2 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, } EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urb); -/* Push data to tty layer and resubmit the bulk read URB */ -static void flush_and_resubmit_read_urb(struct usb_serial_port *port) +static void usb_serial_generic_process_read_urb(struct urb *urb) { - struct urb *urb = port->read_urb; - struct tty_struct *tty = tty_port_tty_get(&port->port); + struct usb_serial_port *port = urb->context; + struct tty_struct *tty; char *ch = (char *)urb->transfer_buffer; int i; + tty = tty_port_tty_get(&port->port); if (!tty) - goto done; + return; /* The per character mucking around with sysrq path it too slow for 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) if (!port->port.console || !port->sysrq) tty_insert_flip_string(tty, ch, urb->actual_length); else { - /* Push data to tty */ for (i = 0; i < urb->actual_length; i++, ch++) { if (!usb_serial_handle_sysrq_char(tty, port, *ch)) tty_insert_flip_char(tty, *ch, TTY_NORMAL); @@ -433,8 +432,6 @@ static void flush_and_resubmit_read_urb(struct usb_serial_port *port) } tty_flip_buffer_push(tty); tty_kref_put(tty); -done: - usb_serial_generic_submit_read_urb(port, GFP_ATOMIC); } void usb_serial_generic_read_bulk_callback(struct urb *urb) @@ -454,13 +451,14 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); + usb_serial_generic_process_read_urb(urb); /* Throttle the device if requested by tty */ spin_lock_irqsave(&port->lock, flags); port->throttled = port->throttle_req; if (!port->throttled) { spin_unlock_irqrestore(&port->lock, flags); - flush_and_resubmit_read_urb(port); + usb_serial_generic_submit_read_urb(port, GFP_ATOMIC); } else spin_unlock_irqrestore(&port->lock, flags); } @@ -523,20 +521,17 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; int was_throttled; - unsigned long flags; dbg("%s - port %d", __func__, port->number); /* Clear the throttle flags */ - spin_lock_irqsave(&port->lock, flags); + spin_lock_irq(&port->lock); was_throttled = port->throttled; port->throttled = port->throttle_req = 0; - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irq(&port->lock); - if (was_throttled) { - /* Resume reading from device */ - flush_and_resubmit_read_urb(port); - } + if (was_throttled) + usb_serial_generic_submit_read_urb(port, GFP_KERNEL); } #ifdef CONFIG_MAGIC_SYSRQ |