USB: serial: add generic wait_until_sent implementation

Add generic wait_until_sent implementation which polls for empty
hardware buffers using the new port-operation tx_empty.

The generic implementation will be used for all sub-drivers that
implement tx_empty but does not define wait_until_sent.

Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Johan Hovold 2013-05-08 17:51:43 +02:00 committed by Greg Kroah-Hartman
parent 0693196fe7
commit dcf0105039
3 changed files with 36 additions and 0 deletions

View file

@ -253,6 +253,37 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
}
EXPORT_SYMBOL_GPL(usb_serial_generic_chars_in_buffer);
void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout)
{
struct usb_serial_port *port = tty->driver_data;
unsigned int bps;
unsigned long period;
unsigned long expire;
bps = tty_get_baud_rate(tty);
if (!bps)
bps = 9600; /* B0 */
/*
* Use a poll-period of roughly the time it takes to send one
* character or at least one jiffy.
*/
period = max_t(unsigned long, (10 * HZ / bps), 1);
period = min_t(unsigned long, period, timeout);
dev_dbg(&port->dev, "%s - timeout = %u ms, period = %u ms\n",
__func__, jiffies_to_msecs(timeout),
jiffies_to_msecs(period));
expire = jiffies + timeout;
while (!port->serial->type->tx_empty(port)) {
schedule_timeout_interruptible(period);
if (signal_pending(current))
break;
if (time_after(jiffies, expire))
break;
}
}
EXPORT_SYMBOL_GPL(usb_serial_generic_wait_until_sent);
static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
int index, gfp_t mem_flags)
{

View file

@ -1333,6 +1333,8 @@ static void usb_serial_operations_init(struct usb_serial_driver *device)
set_to_generic_if_null(device, close);
set_to_generic_if_null(device, write_room);
set_to_generic_if_null(device, chars_in_buffer);
if (device->tx_empty)
set_to_generic_if_null(device, wait_until_sent);
set_to_generic_if_null(device, read_bulk_callback);
set_to_generic_if_null(device, write_bulk_callback);
set_to_generic_if_null(device, process_read_urb);

View file

@ -269,6 +269,7 @@ struct usb_serial_driver {
void (*break_ctl)(struct tty_struct *tty, int break_state);
int (*chars_in_buffer)(struct tty_struct *tty);
void (*wait_until_sent)(struct tty_struct *tty, long timeout);
bool (*tx_empty)(struct usb_serial_port *port);
void (*throttle)(struct tty_struct *tty);
void (*unthrottle)(struct tty_struct *tty);
int (*tiocmget)(struct tty_struct *tty);
@ -328,6 +329,8 @@ extern void usb_serial_generic_close(struct usb_serial_port *port);
extern int usb_serial_generic_resume(struct usb_serial *serial);
extern int usb_serial_generic_write_room(struct tty_struct *tty);
extern int usb_serial_generic_chars_in_buffer(struct tty_struct *tty);
extern void usb_serial_generic_wait_until_sent(struct tty_struct *tty,
long timeout);
extern void usb_serial_generic_read_bulk_callback(struct urb *urb);
extern void usb_serial_generic_write_bulk_callback(struct urb *urb);
extern void usb_serial_generic_throttle(struct tty_struct *tty);