summaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/keyspan_pda.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/keyspan_pda.c')
-rw-r--r--drivers/usb/serial/keyspan_pda.c109
1 files changed, 51 insertions, 58 deletions
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 54a21a99c001..b3fb2ecefb31 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -44,7 +44,6 @@
struct keyspan_pda_private {
int tx_room;
- int tx_throttled;
struct work_struct unthrottle_work;
struct usb_serial *serial;
struct usb_serial_port *port;
@@ -138,9 +137,13 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work)
{
struct keyspan_pda_private *priv =
container_of(work, struct keyspan_pda_private, unthrottle_work);
+ struct usb_serial_port *port = priv->port;
struct usb_serial *serial = priv->serial;
+ unsigned long flags;
int result;
+ dev_dbg(&port->dev, "%s\n", __func__);
+
/* ask the device to tell us when the tx buffer becomes
sufficiently empty */
result = usb_control_msg(serial->dev,
@@ -156,8 +159,19 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work)
if (result < 0)
dev_dbg(&serial->dev->dev, "%s - error %d from usb_control_msg\n",
__func__, result);
-}
+ /*
+ * Need to check available space after requesting notification in case
+ * buffer is already empty so that no notification is sent.
+ */
+ result = keyspan_pda_get_write_room(priv);
+ if (result > KEYSPAN_TX_THRESHOLD) {
+ spin_lock_irqsave(&port->lock, flags);
+ priv->tx_room = max(priv->tx_room, result);
+ spin_unlock_irqrestore(&port->lock, flags);
+ usb_serial_port_softint(port);
+ }
+}
static void keyspan_pda_rx_interrupt(struct urb *urb)
{
@@ -212,7 +226,6 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
break;
case 2: /* tx unthrottle interrupt */
spin_lock_irqsave(&port->lock, flags);
- priv->tx_throttled = 0;
priv->tx_room = max(priv->tx_room, KEYSPAN_TX_THRESHOLD);
spin_unlock_irqrestore(&port->lock, flags);
/* queue up a wakeup at scheduler time */
@@ -472,35 +485,42 @@ static int keyspan_pda_tiocmset(struct tty_struct *tty,
static int keyspan_pda_write(struct tty_struct *tty,
struct usb_serial_port *port, const unsigned char *buf, int count)
{
- int request_unthrottle = 0;
- int rc = 0;
struct keyspan_pda_private *priv;
unsigned long flags;
+ int room;
+ int rc;
priv = usb_get_serial_port_data(port);
- /* guess how much room is left in the device's ring buffer, and if we
- want to send more than that, check first, updating our notion of
- what is left. If our write will result in no room left, ask the
- device to give us an interrupt when the room available rises above
- a threshold, and hold off all writers (eventually, those using
- select() or poll() too) until we receive that unthrottle interrupt.
- Block if we can't write anything at all, otherwise write as much as
- we can. */
+ /*
+ * Guess how much room is left in the device's ring buffer. If our
+ * write will result in no room left, ask the device to give us an
+ * interrupt when the room available rises above a threshold but also
+ * query how much room is currently available (in case our guess was
+ * too conservative and the buffer is already empty when the
+ * unthrottle work is scheduled).
+ */
if (count == 0) {
dev_dbg(&port->dev, "write request of 0 bytes\n");
return 0;
}
+ if (count > port->bulk_out_size)
+ count = port->bulk_out_size;
+
/* we might block because of:
the TX urb is in-flight (wait until it completes)
the device is full (wait until it says there is room)
*/
spin_lock_irqsave(&port->lock, flags);
- if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled) {
+ room = priv->tx_room;
+ if (!test_bit(0, &port->write_urbs_free) || room == 0) {
spin_unlock_irqrestore(&port->lock, flags);
return 0;
}
clear_bit(0, &port->write_urbs_free);
+ if (count > room)
+ count = room;
+ priv->tx_room -= count;
spin_unlock_irqrestore(&port->lock, flags);
/* At this point the URB is in our control, nobody else can submit it
@@ -508,58 +528,30 @@ static int keyspan_pda_write(struct tty_struct *tty,
finished). Also, the tx process is not throttled. So we are
ready to write. */
- count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+ dev_dbg(&port->dev, "%s - count = %d, txroom = %d\n", __func__, count, room);
- /* Check if we might overrun the Tx buffer. If so, ask the
- device how much room it really has. This is done only on
- scheduler time, since usb_control_msg() sleeps. */
- if (count > priv->tx_room && !in_interrupt()) {
- rc = keyspan_pda_get_write_room(priv);
- if (rc < 0)
- goto exit;
-
- priv->tx_room = rc;
- }
+ memcpy(port->write_urb->transfer_buffer, buf, count);
+ port->write_urb->transfer_buffer_length = count;
- if (count >= priv->tx_room) {
- /* we're about to completely fill the Tx buffer, so
- we'll be throttled afterwards. */
- count = priv->tx_room;
- request_unthrottle = 1;
- }
+ rc = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ if (rc) {
+ dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed\n");
- if (count) {
- /* now transfer data */
- memcpy(port->write_urb->transfer_buffer, buf, count);
- /* send the data out the bulk port */
- port->write_urb->transfer_buffer_length = count;
+ spin_lock_irqsave(&port->lock, flags);
+ priv->tx_room = max(priv->tx_room, room + count);
+ spin_unlock_irqrestore(&port->lock, flags);
- priv->tx_room -= count;
+ set_bit(0, &port->write_urbs_free);
- rc = usb_submit_urb(port->write_urb, GFP_ATOMIC);
- if (rc) {
- dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed\n");
- goto exit;
- }
- } else {
- /* There wasn't any room left, so we are throttled until
- the buffer empties a bit */
- request_unthrottle = 1;
+ return rc;
}
- if (request_unthrottle) {
- priv->tx_throttled = 1; /* block writers */
+ if (count == room)
schedule_work(&priv->unthrottle_work);
- }
- rc = count;
-exit:
- if (rc <= 0)
- set_bit(0, &port->write_urbs_free);
- return rc;
+ return count;
}
-
static void keyspan_pda_write_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
@@ -581,7 +573,7 @@ static int keyspan_pda_write_room(struct tty_struct *tty)
int room = 0;
spin_lock_irqsave(&port->lock, flags);
- if (test_bit(0, &port->write_urbs_free) && !priv->tx_throttled)
+ if (test_bit(0, &port->write_urbs_free))
room = priv->tx_room;
spin_unlock_irqrestore(&port->lock, flags);
@@ -601,7 +593,7 @@ static int keyspan_pda_chars_in_buffer(struct tty_struct *tty)
n_tty.c:normal_poll() ) that we're not writeable. */
spin_lock_irqsave(&port->lock, flags);
- if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled)
+ if (!test_bit(0, &port->write_urbs_free) || priv->tx_room == 0)
ret = 256;
spin_unlock_irqrestore(&port->lock, flags);
return ret;
@@ -630,8 +622,9 @@ static int keyspan_pda_open(struct tty_struct *tty,
if (rc < 0)
return rc;
+ spin_lock_irq(&port->lock);
priv->tx_room = rc;
- priv->tx_throttled = rc ? 0 : 1;
+ spin_unlock_irq(&port->lock);
/*Start reading from the device*/
rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);