USB: cdc-acm: clean up open error handling
[cascardo/linux.git] / drivers / usb / class / cdc-acm.c
index e057e53..f239e3b 100644 (file)
  *
  * Sponsored by SuSE
  *
- * ChangeLog:
- *     v0.9  - thorough cleaning, URBification, almost a rewrite
- *     v0.10 - some more cleanups
- *     v0.11 - fixed flow control, read error doesn't stop reads
- *     v0.12 - added TIOCM ioctls, added break handling, made struct acm
- *             kmalloced
- *     v0.13 - added termios, added hangup
- *     v0.14 - sized down struct acm
- *     v0.15 - fixed flow control again - characters could be lost
- *     v0.16 - added code for modems with swapped data and control interfaces
- *     v0.17 - added new style probing
- *     v0.18 - fixed new style probing for devices with more configurations
- *     v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan)
- *     v0.20 - switched to probing on interface (rather than device) class
- *     v0.21 - revert to probing on device for devices with multiple configs
- *     v0.22 - probe only the control interface. if usbcore doesn't choose the
- *             config we want, sysadmin changes bConfigurationValue in sysfs.
- *     v0.23 - use softirq for rx processing, as needed by tty layer
- *     v0.24 - change probe method to evaluate CDC union descriptor
- *     v0.25 - downstream tasks paralelized to maximize throughput
- *     v0.26 - multiple write urbs, writesize increased
- */
-
-/*
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
 #include "cdc-acm.h"
 
 
-#define ACM_CLOSE_TIMEOUT      15      /* seconds to let writes drain */
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v0.26"
 #define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek"
 #define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
 
@@ -94,12 +64,6 @@ static DEFINE_MUTEX(open_mutex);
 static const struct tty_port_operations acm_port_ops = {
 };
 
-#ifdef VERBOSE_DEBUG
-#define verbose        1
-#else
-#define verbose        0
-#endif
-
 /*
  * Functions for ACM control messages.
  */
@@ -111,8 +75,9 @@ static int acm_ctrl_msg(struct acm *acm, int request, int value,
                request, USB_RT_ACM, value,
                acm->control->altsetting[0].desc.bInterfaceNumber,
                buf, len, 5000);
-       dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d",
-                                               request, value, len, retval);
+       dev_dbg(&acm->control->dev,
+                       "%s - rq 0x%02x, val %#x, len %#x, result %d\n",
+                       __func__, request, value, len, retval);
        return retval < 0 ? retval : 0;
 }
 
@@ -192,7 +157,9 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
 
        rc = usb_submit_urb(wb->urb, GFP_ATOMIC);
        if (rc < 0) {
-               dbg("usb_submit_urb(write bulk) failed: %d", rc);
+               dev_err(&acm->data->dev,
+                       "%s - usb_submit_urb(write bulk) failed: %d\n",
+                       __func__, rc);
                acm_write_done(acm, wb);
        }
        return rc;
@@ -211,7 +178,8 @@ static int acm_write_start(struct acm *acm, int wbn)
                return -ENODEV;
        }
 
-       dbg("%s susp_count: %d", __func__, acm->susp_count);
+       dev_vdbg(&acm->data->dev, "%s - susp_count %d\n", __func__,
+                                                       acm->susp_count);
        usb_autopm_get_interface_async(acm->control);
        if (acm->susp_count) {
                if (!acm->delayed_wb)
@@ -287,10 +255,14 @@ static void acm_ctrl_irq(struct urb *urb)
        case -ENOENT:
        case -ESHUTDOWN:
                /* this urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d", __func__, status);
+               dev_dbg(&acm->control->dev,
+                               "%s - urb shutting down with status: %d\n",
+                               __func__, status);
                return;
        default:
-               dbg("%s - nonzero urb status received: %d", __func__, status);
+               dev_dbg(&acm->control->dev,
+                               "%s - nonzero urb status received: %d\n",
+                               __func__, status);
                goto exit;
        }
 
@@ -302,8 +274,8 @@ static void acm_ctrl_irq(struct urb *urb)
        data = (unsigned char *)(dr + 1);
        switch (dr->bNotificationType) {
        case USB_CDC_NOTIFY_NETWORK_CONNECTION:
-               dbg("%s network", dr->wValue ?
-                                       "connected to" : "disconnected from");
+               dev_dbg(&acm->control->dev, "%s - network connection: %d\n",
+                                                       __func__, dr->wValue);
                break;
 
        case USB_CDC_NOTIFY_SERIAL_STATE:
@@ -313,7 +285,8 @@ static void acm_ctrl_irq(struct urb *urb)
                if (tty) {
                        if (!acm->clocal &&
                                (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
-                               dbg("calling hangup");
+                               dev_dbg(&acm->control->dev,
+                                       "%s - calling hangup\n", __func__);
                                tty_hangup(tty);
                        }
                        tty_kref_put(tty);
@@ -321,7 +294,10 @@ static void acm_ctrl_irq(struct urb *urb)
 
                acm->ctrlin = newctrl;
 
-               dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
+               dev_dbg(&acm->control->dev,
+                       "%s - input control lines: dcd%c dsr%c break%c "
+                       "ring%c framing%c parity%c overrun%c\n",
+                       __func__,
                        acm->ctrlin & ACM_CTRL_DCD ? '+' : '-',
                        acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
                        acm->ctrlin & ACM_CTRL_BRK ? '+' : '-',
@@ -332,7 +308,10 @@ static void acm_ctrl_irq(struct urb *urb)
                        break;
 
        default:
-               dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
+               dev_dbg(&acm->control->dev,
+                       "%s - unknown notification %d received: index %d "
+                       "len %d data0 %d data1 %d\n",
+                       __func__,
                        dr->bNotificationType, dr->wIndex,
                        dr->wLength, data[0], data[1]);
                break;
@@ -340,8 +319,8 @@ static void acm_ctrl_irq(struct urb *urb)
 exit:
        retval = usb_submit_urb(urb, GFP_ATOMIC);
        if (retval)
-               dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with "
-                       "result %d", __func__, retval);
+               dev_err(&acm->control->dev, "%s - usb_submit_urb failed: %d\n",
+                                                       __func__, retval);
 }
 
 /* data interface returns incoming bytes, or we got unthrottled */
@@ -352,16 +331,17 @@ static void acm_read_bulk(struct urb *urb)
        struct acm *acm = rcv->instance;
        int status = urb->status;
 
-       dbg("Entering acm_read_bulk with status %d", status);
+       dev_vdbg(&acm->data->dev, "%s - status %d\n", __func__, status);
 
        if (!ACM_READY(acm)) {
-               dev_dbg(&acm->data->dev, "Aborting, acm not ready");
+               dev_dbg(&acm->data->dev, "%s - acm not ready\n", __func__);
                return;
        }
        usb_mark_last_busy(acm->dev);
 
        if (status)
-               dev_dbg(&acm->data->dev, "bulk rx status %d\n", status);
+               dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n",
+                                                       __func__, status);
 
        buf = rcv->buffer;
        buf->size = urb->actual_length;
@@ -394,10 +374,10 @@ static void acm_rx_tasklet(unsigned long _acm)
        unsigned long flags;
        unsigned char throttled;
 
-       dbg("Entering acm_rx_tasklet");
+       dev_vdbg(&acm->data->dev, "%s\n", __func__);
 
        if (!ACM_READY(acm)) {
-               dbg("acm_rx_tasklet: ACM not ready");
+               dev_dbg(&acm->data->dev, "%s - acm not ready\n", __func__);
                return;
        }
 
@@ -405,7 +385,7 @@ static void acm_rx_tasklet(unsigned long _acm)
        throttled = acm->throttle;
        spin_unlock_irqrestore(&acm->throttle_lock, flags);
        if (throttled) {
-               dbg("acm_rx_tasklet: throttled");
+               dev_dbg(&acm->data->dev, "%s - throttled\n", __func__);
                return;
        }
 
@@ -422,8 +402,8 @@ next_buffer:
        list_del(&buf->list);
        spin_unlock_irqrestore(&acm->read_lock, flags);
 
-       dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
-
+       dev_vdbg(&acm->data->dev, "%s - processing buf 0x%p, size = %d\n",
+                                               __func__, buf, buf->size);
        if (tty) {
                spin_lock_irqsave(&acm->throttle_lock, flags);
                throttled = acm->throttle;
@@ -433,7 +413,8 @@ next_buffer:
                        tty_flip_buffer_push(tty);
                } else {
                        tty_kref_put(tty);
-                       dbg("Throttling noticed");
+                       dev_dbg(&acm->data->dev, "%s - throttling noticed\n",
+                                                               __func__);
                        spin_lock_irqsave(&acm->read_lock, flags);
                        list_add(&buf->list, &acm->filled_read_bufs);
                        spin_unlock_irqrestore(&acm->read_lock, flags);
@@ -494,7 +475,9 @@ urbs:
                        return;
                } else {
                        spin_unlock_irqrestore(&acm->read_lock, flags);
-                       dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf);
+                       dev_vdbg(&acm->data->dev,
+                               "%s - sending urb 0x%p, rcv 0x%p, buf 0x%p\n",
+                               __func__, rcv->urb, rcv, buf);
                }
        }
        spin_lock_irqsave(&acm->read_lock, flags);
@@ -509,9 +492,9 @@ static void acm_write_bulk(struct urb *urb)
        struct acm *acm = wb->instance;
        unsigned long flags;
 
-       if (verbose || urb->status
-                       || (urb->actual_length != urb->transfer_buffer_length))
-               dev_dbg(&acm->data->dev, "tx %d/%d bytes -- > %d\n",
+       if (urb->status || (urb->actual_length != urb->transfer_buffer_length))
+               dev_vdbg(&acm->data->dev, "%s - len %d/%d, status %d\n",
+                       __func__,
                        urb->actual_length,
                        urb->transfer_buffer_length,
                        urb->status);
@@ -521,8 +504,6 @@ static void acm_write_bulk(struct urb *urb)
        spin_unlock_irqrestore(&acm->write_lock, flags);
        if (ACM_READY(acm))
                schedule_work(&acm->work);
-       else
-               wake_up_interruptible(&acm->drain_wait);
 }
 
 static void acm_softint(struct work_struct *work)
@@ -530,7 +511,8 @@ static void acm_softint(struct work_struct *work)
        struct acm *acm = container_of(work, struct acm, work);
        struct tty_struct *tty;
 
-       dev_vdbg(&acm->data->dev, "tx work\n");
+       dev_vdbg(&acm->data->dev, "%s\n", __func__);
+
        if (!ACM_READY(acm))
                return;
        tty = tty_port_tty_get(&acm->port);
@@ -549,7 +531,6 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
        struct acm *acm;
        int rv = -ENODEV;
        int i;
-       dbg("Entering acm_tty_open.");
 
        mutex_lock(&open_mutex);
 
@@ -559,6 +540,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
        else
                rv = 0;
 
+       dev_dbg(&acm->control->dev, "%s\n", __func__);
+
        set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
 
        tty->driver_data = acm;
@@ -578,13 +561,14 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
 
        acm->ctrlurb->dev = acm->dev;
        if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
-               dbg("usb_submit_urb(ctrl irq) failed");
+               dev_err(&acm->control->dev,
+                       "%s - usb_submit_urb(ctrl irq) failed\n", __func__);
                goto bail_out;
        }
 
        if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
            (acm->ctrl_caps & USB_CDC_CAP_LINE))
-               goto full_bailout;
+               goto bail_out;
 
        usb_autopm_put_interface(acm->control);
 
@@ -608,8 +592,6 @@ out:
        mutex_unlock(&open_mutex);
        return rv;
 
-full_bailout:
-       usb_kill_urb(acm->ctrlurb);
 bail_out:
        acm->port.count--;
        mutex_unlock(&acm->mutex);
@@ -622,26 +604,24 @@ early_bail:
 
 static void acm_tty_unregister(struct acm *acm)
 {
-       int i, nr;
+       int i;
 
-       nr = acm->rx_buflimit;
        tty_unregister_device(acm_tty_driver, acm->minor);
        usb_put_intf(acm->control);
        acm_table[acm->minor] = NULL;
        usb_free_urb(acm->ctrlurb);
        for (i = 0; i < ACM_NW; i++)
                usb_free_urb(acm->wb[i].urb);
-       for (i = 0; i < nr; i++)
+       for (i = 0; i < acm->rx_buflimit; i++)
                usb_free_urb(acm->ru[i].urb);
        kfree(acm->country_codes);
        kfree(acm);
 }
 
-static int acm_tty_chars_in_buffer(struct tty_struct *tty);
-
 static void acm_port_down(struct acm *acm)
 {
-       int i, nr = acm->rx_buflimit;
+       int i;
+
        mutex_lock(&open_mutex);
        if (acm->dev) {
                usb_autopm_get_interface(acm->control);
@@ -650,7 +630,7 @@ static void acm_port_down(struct acm *acm)
                for (i = 0; i < ACM_NW; i++)
                        usb_kill_urb(acm->wb[i].urb);
                tasklet_disable(&acm->urb_task);
-               for (i = 0; i < nr; i++)
+               for (i = 0; i < acm->rx_buflimit; i++)
                        usb_kill_urb(acm->ru[i].urb);
                tasklet_enable(&acm->urb_task);
                acm->control->needs_remote_wakeup = 0;
@@ -698,13 +678,13 @@ static int acm_tty_write(struct tty_struct *tty,
        int wbn;
        struct acm_wb *wb;
 
-       dbg("Entering acm_tty_write to write %d bytes,", count);
-
        if (!ACM_READY(acm))
                return -EINVAL;
        if (!count)
                return 0;
 
+       dev_vdbg(&acm->data->dev, "%s - count %d\n", __func__, count);
+
        spin_lock_irqsave(&acm->write_lock, flags);
        wbn = acm_wb_alloc(acm);
        if (wbn < 0) {
@@ -714,7 +694,7 @@ static int acm_tty_write(struct tty_struct *tty,
        wb = &acm->wb[wbn];
 
        count = (count > acm->writesize) ? acm->writesize : count;
-       dbg("Get %d bytes...", count);
+       dev_vdbg(&acm->data->dev, "%s - write %d\n", __func__, count);
        memcpy(wb->buf, buf, count);
        wb->len = count;
        spin_unlock_irqrestore(&acm->write_lock, flags);
@@ -777,7 +757,8 @@ static int acm_tty_break_ctl(struct tty_struct *tty, int state)
                return -EINVAL;
        retval = acm_send_break(acm, state ? 0xffff : 0);
        if (retval < 0)
-               dbg("send break failed");
+               dev_dbg(&acm->control->dev, "%s - send break failed\n",
+                                                               __func__);
        return retval;
 }
 
@@ -872,7 +853,9 @@ static void acm_tty_set_termios(struct tty_struct *tty,
 
        if (memcmp(&acm->line, &newline, sizeof newline)) {
                memcpy(&acm->line, &newline, sizeof newline);
-               dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),
+               dev_dbg(&acm->control->dev, "%s - set line: %d %d %d %d\n",
+                       __func__,
+                       le32_to_cpu(newline.dwDTERate),
                        newline.bCharFormat, newline.bParityType,
                        newline.bDataBits);
                acm_set_line(acm, &acm->line);
@@ -897,9 +880,9 @@ static void acm_write_buffers_free(struct acm *acm)
 static void acm_read_buffers_free(struct acm *acm)
 {
        struct usb_device *usb_dev = interface_to_usbdev(acm->control);
-       int i, n = acm->rx_buflimit;
+       int i;
 
-       for (i = 0; i < n; i++)
+       for (i = 0; i < acm->rx_buflimit; i++)
                usb_free_coherent(usb_dev, acm->readsize,
                                  acm->rb[i].base, acm->rb[i].dma);
 }
@@ -1133,7 +1116,7 @@ skip_normal_probe:
                epwrite = t;
        }
 made_compressed_probe:
-       dbg("interfaces are valid");
+       dev_dbg(&intf->dev, "interfaces are valid\n");
        for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
 
        if (minor == ACM_TTY_MINORS) {
@@ -1143,7 +1126,7 @@ made_compressed_probe:
 
        acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
        if (acm == NULL) {
-               dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
+               dev_err(&intf->dev, "out of memory (acm kzalloc)\n");
                goto alloc_fail;
        }
 
@@ -1165,7 +1148,6 @@ made_compressed_probe:
        acm->urb_task.func = acm_rx_tasklet;
        acm->urb_task.data = (unsigned long) acm;
        INIT_WORK(&acm->work, acm_softint);
-       init_waitqueue_head(&acm->drain_wait);
        spin_lock_init(&acm->throttle_lock);
        spin_lock_init(&acm->write_lock);
        spin_lock_init(&acm->read_lock);
@@ -1179,19 +1161,19 @@ made_compressed_probe:
 
        buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
        if (!buf) {
-               dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
+               dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n");
                goto alloc_fail2;
        }
        acm->ctrl_buffer = buf;
 
        if (acm_write_buffers_alloc(acm) < 0) {
-               dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
+               dev_err(&intf->dev, "out of memory (write buffer alloc)\n");
                goto alloc_fail4;
        }
 
        acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
        if (!acm->ctrlurb) {
-               dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
+               dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
                goto alloc_fail5;
        }
        for (i = 0; i < num_rx_buf; i++) {
@@ -1199,7 +1181,7 @@ made_compressed_probe:
 
                rcv->urb = usb_alloc_urb(0, GFP_KERNEL);
                if (rcv->urb == NULL) {
-                       dev_dbg(&intf->dev,
+                       dev_err(&intf->dev,
                                "out of memory (read urbs usb_alloc_urb)\n");
                        goto alloc_fail6;
                }
@@ -1213,7 +1195,7 @@ made_compressed_probe:
                rb->base = usb_alloc_coherent(acm->dev, readsize,
                                GFP_KERNEL, &rb->dma);
                if (!rb->base) {
-                       dev_dbg(&intf->dev,
+                       dev_err(&intf->dev,
                                "out of memory (read bufs usb_alloc_coherent)\n");
                        goto alloc_fail7;
                }
@@ -1223,8 +1205,8 @@ made_compressed_probe:
 
                snd->urb = usb_alloc_urb(0, GFP_KERNEL);
                if (snd->urb == NULL) {
-                       dev_dbg(&intf->dev,
-                               "out of memory (write urbs usb_alloc_urb)");
+                       dev_err(&intf->dev,
+                               "out of memory (write urbs usb_alloc_urb)\n");
                        goto alloc_fail8;
                }
 
@@ -1318,7 +1300,8 @@ alloc_fail:
 static void stop_data_traffic(struct acm *acm)
 {
        int i;
-       dbg("Entering stop_data_traffic");
+
+       dev_dbg(&acm->control->dev, "%s\n", __func__);
 
        tasklet_disable(&acm->urb_task);
 
@@ -1716,8 +1699,7 @@ static int __init acm_init(void)
                return retval;
        }
 
-       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-              DRIVER_DESC "\n");
+       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
 
        return 0;
 }