[2.6.10] cdc-acm.c patches

From: Alexander V. Lukyanov
Date: Thu Feb 24 2005 - 07:12:05 EST


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.--- linux-2.6.10/drivers/usb/class/cdc-acm.c.orig Thu Feb 24 15:02:29 2005
+++ linux-2.6.10/drivers/usb/class/cdc-acm.c Thu Feb 24 15:02:36 2005
@@ -272,7 +272,7 @@ static int acm_tty_open(struct tty_struc

down(&open_sem);

- if (acm->used) {
+ if (acm->used++) {
goto done;
}

@@ -296,7 +296,6 @@ static int acm_tty_open(struct tty_struc
tty->low_latency = 1;

done:
- acm->used++;
up(&open_sem);
return 0;

@@ -305,6 +304,7 @@ full_bailout:
bail_out_and_unlink:
usb_kill_urb(acm->ctrlurb);
bail_out:
+ acm->used--;
up(&open_sem);
return -EIO;
}
--- linux-2.6.10/drivers/usb/class/cdc-acm.c.orig1 Thu Feb 24 15:02:41 2005
+++ linux-2.6.10/drivers/usb/class/cdc-acm.c Thu Feb 24 15:03:41 2005
@@ -175,7 +175,7 @@ exit:
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_rx_tasklet(unsigned long
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 @@ out:
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 void acm_softint(void *private)
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 @@ static int acm_tty_write(struct tty_stru
{
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 @@ static int acm_tty_write(struct tty_stru

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 @@ static int acm_probe (struct usb_interfa

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 {