|
@@ -1,7 +1,7 @@
|
|
|
/*
|
|
|
* USB Serial Converter Generic functions
|
|
|
*
|
|
|
- * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com)
|
|
|
+ * Copyright (C) 2010 - 2011 Johan Hovold (jhovold@gmail.com)
|
|
|
* Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
|
|
|
*
|
|
|
* This program is free software; you can redistribute it and/or
|
|
@@ -132,7 +132,7 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port
|
|
|
|
|
|
/* if we have a bulk endpoint, start reading from it */
|
|
|
if (port->bulk_in_size)
|
|
|
- result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL);
|
|
|
+ result = usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
|
|
|
|
|
|
return result;
|
|
|
}
|
|
@@ -157,8 +157,10 @@ static void generic_cleanup(struct usb_serial_port *port)
|
|
|
kfifo_reset_out(&port->write_fifo);
|
|
|
spin_unlock_irqrestore(&port->lock, flags);
|
|
|
}
|
|
|
- if (port->bulk_in_size)
|
|
|
- usb_kill_urb(port->read_urb);
|
|
|
+ if (port->bulk_in_size) {
|
|
|
+ for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
|
|
|
+ usb_kill_urb(port->read_urbs[i]);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -308,19 +310,52 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
|
|
|
return chars;
|
|
|
}
|
|
|
|
|
|
-int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
|
|
|
+static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
|
|
|
+ int index, gfp_t mem_flags)
|
|
|
+{
|
|
|
+ int res;
|
|
|
+
|
|
|
+ if (!test_and_clear_bit(index, &port->read_urbs_free))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ dbg("%s - port %d, urb %d\n", __func__, port->number, index);
|
|
|
+
|
|
|
+ res = usb_submit_urb(port->read_urbs[index], mem_flags);
|
|
|
+ if (res) {
|
|
|
+ if (res != -EPERM) {
|
|
|
+ dev_err(&port->dev,
|
|
|
+ "%s - usb_submit_urb failed: %d\n",
|
|
|
+ __func__, res);
|
|
|
+ }
|
|
|
+ set_bit(index, &port->read_urbs_free);
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port,
|
|
|
gfp_t mem_flags)
|
|
|
{
|
|
|
- int result;
|
|
|
+ int res;
|
|
|
+ int i;
|
|
|
|
|
|
- result = usb_submit_urb(port->read_urb, mem_flags);
|
|
|
- if (result && result != -EPERM) {
|
|
|
- dev_err(&port->dev, "%s - error submitting urb: %d\n",
|
|
|
- __func__, result);
|
|
|
+ dbg("%s - port %d", __func__, port->number);
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
|
|
|
+ res = usb_serial_generic_submit_read_urb(port, i, mem_flags);
|
|
|
+ if (res)
|
|
|
+ goto err;
|
|
|
}
|
|
|
- return result;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+err:
|
|
|
+ for (; i >= 0; --i)
|
|
|
+ usb_kill_urb(port->read_urbs[i]);
|
|
|
+
|
|
|
+ return res;
|
|
|
}
|
|
|
-EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urb);
|
|
|
+EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urbs);
|
|
|
|
|
|
void usb_serial_generic_process_read_urb(struct urb *urb)
|
|
|
{
|
|
@@ -356,14 +391,19 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
|
|
|
{
|
|
|
struct usb_serial_port *port = urb->context;
|
|
|
unsigned char *data = urb->transfer_buffer;
|
|
|
- int status = urb->status;
|
|
|
unsigned long flags;
|
|
|
+ int i;
|
|
|
|
|
|
- dbg("%s - port %d", __func__, port->number);
|
|
|
+ for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
|
|
|
+ if (urb == port->read_urbs[i])
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ set_bit(i, &port->read_urbs_free);
|
|
|
|
|
|
- if (unlikely(status != 0)) {
|
|
|
- dbg("%s - nonzero read bulk status received: %d",
|
|
|
- __func__, status);
|
|
|
+ dbg("%s - port %d, urb %d, len %d\n", __func__, port->number, i,
|
|
|
+ urb->actual_length);
|
|
|
+ if (urb->status) {
|
|
|
+ dbg("%s - non-zero urb status: %d\n", __func__, urb->status);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -376,7 +416,7 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
|
|
|
port->throttled = port->throttle_req;
|
|
|
if (!port->throttled) {
|
|
|
spin_unlock_irqrestore(&port->lock, flags);
|
|
|
- usb_serial_generic_submit_read_urb(port, GFP_ATOMIC);
|
|
|
+ usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC);
|
|
|
} else
|
|
|
spin_unlock_irqrestore(&port->lock, flags);
|
|
|
}
|
|
@@ -443,7 +483,7 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
|
|
|
spin_unlock_irq(&port->lock);
|
|
|
|
|
|
if (was_throttled)
|
|
|
- usb_serial_generic_submit_read_urb(port, GFP_KERNEL);
|
|
|
+ usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle);
|
|
|
|
|
@@ -509,8 +549,9 @@ int usb_serial_generic_resume(struct usb_serial *serial)
|
|
|
if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
|
|
|
continue;
|
|
|
|
|
|
- if (port->read_urb) {
|
|
|
- r = usb_submit_urb(port->read_urb, GFP_NOIO);
|
|
|
+ if (port->bulk_in_size) {
|
|
|
+ r = usb_serial_generic_submit_read_urbs(port,
|
|
|
+ GFP_NOIO);
|
|
|
if (r < 0)
|
|
|
c++;
|
|
|
}
|