On Sat, Feb 03, 2007 at 04:18:24PM +0100, Oliver Neukum wrote:
> 1. Why not simply take the lock earlier?

And call the tty layer under acm->throttle_lock? I think not.

We could of course read acm->throttle once under the lock and
store its value in a local variable. I can write it like that if
you prefer it, but I actually think that my solution is simpler since
it never needs to push buffers back on filled_read_bufs.

Greetings,
  Joris.

--

There seems to be a bug in the handling of device throttling in the
CDC-ACM driver. When the tty requests throttling, the same packet
is sometimes delivered to the tty and also pushed back on the list
of pending packets, resulting in delivery of duplicate data.

The proposed patch fixes the problem by unconditionally pushing the
packet to the tty and never pushing it back on the pending list.
It is reasonable to assume that the tty layer can store at least one
more packet after requesting throttling, since it does a fair amount
of internal buffering.

Signed-off-by: Joris van Rantwijk <[EMAIL PROTECTED]>

diff -urp -U5 linux-2.6.19.2-orig/drivers/usb/class/cdc-acm.c 
linux-2.6.19.2/drivers/usb/class/cdc-acm.c
--- linux-2.6.19.2-orig/drivers/usb/class/cdc-acm.c     2007-01-10 
20:10:37.000000000 +0100
+++ linux-2.6.19.2/drivers/usb/class/cdc-acm.c  2007-02-03 01:05:21.000000000 
+0100
@@ -324,11 +324,10 @@ static void acm_rx_tasklet(unsigned long
        struct acm *acm = (void *)_acm;
        struct acm_rb *buf;
        struct tty_struct *tty = acm->tty;
        struct acm_ru *rcv;
        unsigned long flags;
-       int i = 0;
        dbg("Entering acm_rx_tasklet");
 
        if (!ACM_READY(acm) || acm->throttle)
                return;
 
@@ -339,35 +338,27 @@ next_buffer:
                goto urbs;
        }
        buf = list_entry(acm->filled_read_bufs.next,
                         struct acm_rb, list);
        list_del(&buf->list);
+       list_add(&buf->list, &acm->spare_read_bufs);
        spin_unlock_irqrestore(&acm->read_lock, flags);
 
        dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
 
        tty_buffer_request_room(tty, buf->size);
-       if (!acm->throttle)
-               tty_insert_flip_string(tty, buf->base, buf->size);
+       tty_insert_flip_string(tty, buf->base, buf->size);
        tty_flip_buffer_push(tty);
 
        spin_lock(&acm->throttle_lock);
        if (acm->throttle) {
-               dbg("Throtteling noticed");
-               memmove(buf->base, buf->base + i, buf->size - i);
-               buf->size -= i;
+               dbg("Throttling noticed");
                spin_unlock(&acm->throttle_lock);
-               spin_lock_irqsave(&acm->read_lock, flags);
-               list_add(&buf->list, &acm->filled_read_bufs);
-               spin_unlock_irqrestore(&acm->read_lock, flags);
                return;
        }
        spin_unlock(&acm->throttle_lock);
 
-       spin_lock_irqsave(&acm->read_lock, flags);
-       list_add(&buf->list, &acm->spare_read_bufs);
-       spin_unlock_irqrestore(&acm->read_lock, flags);
        goto next_buffer;
 
 urbs:
        while (!list_empty(&acm->spare_read_bufs)) {
                spin_lock_irqsave(&acm->read_lock, flags);

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier.
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to