Hello!

I have ZyXEL UNO modem which has usb acm interface. Starting with kernel
version 2.6.8 the driver cdc-acm began to hand when the modem connection
was dropped due to being idle. After the hang, no data could be read from
the device /dev/usb/ttyACM0, but writting was ok. The led "data" was lit
on the modem all the time after the disconnect (which indicates that modem
has data to be read).

I tracked down the problem to this: acm_read_bulk was called from
usb_submit_urb(acm->readurb), _inside_ acm_tty_open, and that time acm->used
was 0 which led to acm_rx_tasklet being not called, and acm_read_bulk was
never called again.

The problem was caused by patch in 2.6.8, which moved incrementing of
acm->used to bottom of acm_tty_open. My patch to fix it is attached.

When debugging the problem I noticed that debug messages sometimes have
double \n and the second one is not KERN_DEBUG level, which causes it to
be emitted to display. A second patch to normalize newlines in debug
output is attached.

-- 
   Alexander.
--- cdc-acm.c.1 2005-02-19 00:46:04.498452192 +0300
+++ cdc-acm.c   2005-02-19 00:48:09.313477424 +0300
@@ -272,7 +272,7 @@
 
         down(&open_sem);
 
-       if (acm->used) {
+       if (acm->used++) {
                goto done;
         }
 
@@ -296,7 +296,6 @@
        tty->low_latency = 1;
 
 done:
-       acm->used++;
        up(&open_sem);
        return 0;
 
@@ -305,6 +304,7 @@
 bail_out_and_unlink:
        usb_kill_urb(acm->ctrlurb);
 bail_out:
+       acm->used--;
        up(&open_sem);
        return -EIO;
 }
--- cdc-acm.c.2 2005-02-19 00:48:48.222562344 +0300
+++ cdc-acm.c   2005-02-19 00:53:42.616807616 +0300
@@ -175,7 +175,7 @@
 static void acm_read_bulk(struct urb *urb, struct pt_regs *regs)
 {
        struct acm *acm = urb->context;
-       dbg("Entering acm_read_bulk with status %d\n", urb->status);
+       dbg("Entering acm_read_bulk with status %d", urb->status);
 
        if (!ACM_READY(acm))
                return;
@@ -232,7 +232,7 @@
 static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
 {
        struct acm *acm = (struct acm *)urb->context;
-       dbg("Entering acm_write_bulk with status %d\n", urb->status);
+       dbg("Entering acm_write_bulk with status %d", urb->status);
 
        if (!ACM_READY(acm))
                goto out;
@@ -248,7 +248,7 @@
 static void acm_softint(void *private)
 {
        struct acm *acm = private;
-       dbg("Entering acm_softint.\n");
+       dbg("Entering acm_softint.");
        
        if (!ACM_READY(acm))
                return;
@@ -262,7 +262,7 @@
 static int acm_tty_open(struct tty_struct *tty, struct file *filp)
 {
        struct acm *acm = acm_table[tty->index];
-       dbg("Entering acm_tty_open.\n");
+       dbg("Entering acm_tty_open.");
 
        if (!acm || !acm->dev)
                return -EINVAL;
@@ -339,7 +339,7 @@
 {
        struct acm *acm = tty->driver_data;
        int stat;
-       dbg("Entering acm_tty_write to write %d bytes,\n", count);
+       dbg("Entering acm_tty_write to write %d bytes,", count);
 
        if (!ACM_READY(acm))
                return -EINVAL;
@@ -352,7 +352,7 @@
 
        dbg("Get %d bytes...", count);
        memcpy(acm->write_buffer, buf, count);
-       dbg("  Successfully copied.\n");
+       dbg("  Successfully copied.");
 
        acm->writeurb->transfer_buffer_length = count;
        acm->writeurb->dev = acm->dev;
@@ -540,7 +540,7 @@
 
        if (!buflen) {
                if (intf->cur_altsetting->endpoint->extralen && 
intf->cur_altsetting->endpoint->extra) {
-                       dev_dbg(&intf->dev,"Seeking extra descriptors on 
endpoint");
+                       dev_dbg(&intf->dev,"Seeking extra descriptors on 
endpoint\n");
                        buflen = intf->cur_altsetting->endpoint->extralen;
                        buffer = intf->cur_altsetting->endpoint->extra;
                } else {

Reply via email to