]> Git Repo - linux.git/blobdiff - drivers/usb/class/cdc-acm.c
memsw: remove noswapaccount kernel parameter
[linux.git] / drivers / usb / class / cdc-acm.c
index e057e5381465b1a12c03e550f3ff6b2f9d4d24e0..395a347f2ebbea52d86b20cb97bec70548b6a34a 100644 (file)
@@ -7,35 +7,12 @@
  * Copyright (c) 2000 Vojtech Pavlik   <[email protected]>
  * Copyright (c) 2004 Oliver Neukum    <[email protected]>
  * Copyright (c) 2005 David Kubicek    <[email protected]>
+ * Copyright (c) 2011 Johan Hovold     <[email protected]>
  *
  * USB Abstract Control Model driver for USB modems and ISDN adapters
  *
  * 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_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek, Johan Hovold"
 #define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
 
 static struct usb_driver acm_driver;
@@ -94,12 +65,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 +76,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 +158,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 +179,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 +256,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 +275,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 +286,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 +295,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 +309,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,166 +320,96 @@ 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 */
-static void acm_read_bulk(struct urb *urb)
+static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags)
 {
-       struct acm_rb *buf;
-       struct acm_ru *rcv = urb->context;
-       struct acm *acm = rcv->instance;
-       int status = urb->status;
+       int res;
+
+       if (!test_and_clear_bit(index, &acm->read_urbs_free))
+               return 0;
 
-       dbg("Entering acm_read_bulk with status %d", status);
+       dev_vdbg(&acm->data->dev, "%s - urb %d\n", __func__, index);
 
-       if (!ACM_READY(acm)) {
-               dev_dbg(&acm->data->dev, "Aborting, acm not ready");
-               return;
+       res = usb_submit_urb(acm->read_urbs[index], mem_flags);
+       if (res) {
+               if (res != -EPERM) {
+                       dev_err(&acm->data->dev,
+                                       "%s - usb_submit_urb failed: %d\n",
+                                       __func__, res);
+               }
+               set_bit(index, &acm->read_urbs_free);
+               return res;
        }
-       usb_mark_last_busy(acm->dev);
 
-       if (status)
-               dev_dbg(&acm->data->dev, "bulk rx status %d\n", status);
+       return 0;
+}
 
-       buf = rcv->buffer;
-       buf->size = urb->actual_length;
+static int acm_submit_read_urbs(struct acm *acm, gfp_t mem_flags)
+{
+       int res;
+       int i;
 
-       if (likely(status == 0)) {
-               spin_lock(&acm->read_lock);
-               acm->processing++;
-               list_add_tail(&rcv->list, &acm->spare_read_urbs);
-               list_add_tail(&buf->list, &acm->filled_read_bufs);
-               spin_unlock(&acm->read_lock);
-       } else {
-               /* we drop the buffer due to an error */
-               spin_lock(&acm->read_lock);
-               list_add_tail(&rcv->list, &acm->spare_read_urbs);
-               list_add(&buf->list, &acm->spare_read_bufs);
-               spin_unlock(&acm->read_lock);
-               /* nevertheless the tasklet must be kicked unconditionally
-               so the queue cannot dry up */
+       for (i = 0; i < acm->rx_buflimit; ++i) {
+               res = acm_submit_read_urb(acm, i, mem_flags);
+               if (res)
+                       return res;
        }
-       if (likely(!acm->susp_count))
-               tasklet_schedule(&acm->urb_task);
+
+       return 0;
 }
 
-static void acm_rx_tasklet(unsigned long _acm)
+static void acm_process_read_urb(struct acm *acm, struct urb *urb)
 {
-       struct acm *acm = (void *)_acm;
-       struct acm_rb *buf;
        struct tty_struct *tty;
-       struct acm_ru *rcv;
-       unsigned long flags;
-       unsigned char throttled;
 
-       dbg("Entering acm_rx_tasklet");
-
-       if (!ACM_READY(acm)) {
-               dbg("acm_rx_tasklet: ACM not ready");
+       if (!urb->actual_length)
                return;
-       }
-
-       spin_lock_irqsave(&acm->throttle_lock, flags);
-       throttled = acm->throttle;
-       spin_unlock_irqrestore(&acm->throttle_lock, flags);
-       if (throttled) {
-               dbg("acm_rx_tasklet: throttled");
-               return;
-       }
 
        tty = tty_port_tty_get(&acm->port);
+       if (!tty)
+               return;
 
-next_buffer:
-       spin_lock_irqsave(&acm->read_lock, flags);
-       if (list_empty(&acm->filled_read_bufs)) {
-               spin_unlock_irqrestore(&acm->read_lock, flags);
-               goto urbs;
-       }
-       buf = list_entry(acm->filled_read_bufs.next,
-                        struct acm_rb, list);
-       list_del(&buf->list);
-       spin_unlock_irqrestore(&acm->read_lock, flags);
-
-       dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
-
-       if (tty) {
-               spin_lock_irqsave(&acm->throttle_lock, flags);
-               throttled = acm->throttle;
-               spin_unlock_irqrestore(&acm->throttle_lock, flags);
-               if (!throttled) {
-                       tty_insert_flip_string(tty, buf->base, buf->size);
-                       tty_flip_buffer_push(tty);
-               } else {
-                       tty_kref_put(tty);
-                       dbg("Throttling noticed");
-                       spin_lock_irqsave(&acm->read_lock, flags);
-                       list_add(&buf->list, &acm->filled_read_bufs);
-                       spin_unlock_irqrestore(&acm->read_lock, flags);
-                       return;
-               }
-       }
-
-       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;
+       tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length);
+       tty_flip_buffer_push(tty);
 
-urbs:
        tty_kref_put(tty);
+}
 
-       while (!list_empty(&acm->spare_read_bufs)) {
-               spin_lock_irqsave(&acm->read_lock, flags);
-               if (list_empty(&acm->spare_read_urbs)) {
-                       acm->processing = 0;
-                       spin_unlock_irqrestore(&acm->read_lock, flags);
-                       return;
-               }
-               rcv = list_entry(acm->spare_read_urbs.next,
-                                struct acm_ru, list);
-               list_del(&rcv->list);
-               spin_unlock_irqrestore(&acm->read_lock, flags);
+static void acm_read_bulk_callback(struct urb *urb)
+{
+       struct acm_rb *rb = urb->context;
+       struct acm *acm = rb->instance;
+       unsigned long flags;
 
-               buf = list_entry(acm->spare_read_bufs.next,
-                                struct acm_rb, list);
-               list_del(&buf->list);
+       dev_vdbg(&acm->data->dev, "%s - urb %d, len %d\n", __func__,
+                                       rb->index, urb->actual_length);
+       set_bit(rb->index, &acm->read_urbs_free);
 
-               rcv->buffer = buf;
+       if (!acm->dev) {
+               dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__);
+               return;
+       }
+       usb_mark_last_busy(acm->dev);
 
-               if (acm->is_int_ep)
-                       usb_fill_int_urb(rcv->urb, acm->dev,
-                                        acm->rx_endpoint,
-                                        buf->base,
-                                        acm->readsize,
-                                        acm_read_bulk, rcv, acm->bInterval);
-               else
-                       usb_fill_bulk_urb(rcv->urb, acm->dev,
-                                         acm->rx_endpoint,
-                                         buf->base,
-                                         acm->readsize,
-                                         acm_read_bulk, rcv);
-               rcv->urb->transfer_dma = buf->dma;
-               rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-               /* This shouldn't kill the driver as unsuccessful URBs are
-                  returned to the free-urbs-pool and resubmited ASAP */
-               spin_lock_irqsave(&acm->read_lock, flags);
-               if (acm->susp_count ||
-                               usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
-                       list_add(&buf->list, &acm->spare_read_bufs);
-                       list_add(&rcv->list, &acm->spare_read_urbs);
-                       acm->processing = 0;
-                       spin_unlock_irqrestore(&acm->read_lock, flags);
-                       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);
-               }
+       if (urb->status) {
+               dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n",
+                                                       __func__, urb->status);
+               return;
        }
+       acm_process_read_urb(acm, urb);
+
+       /* throttle device if requested by tty */
        spin_lock_irqsave(&acm->read_lock, flags);
-       acm->processing = 0;
-       spin_unlock_irqrestore(&acm->read_lock, flags);
+       acm->throttled = acm->throttle_req;
+       if (!acm->throttled && !acm->susp_count) {
+               spin_unlock_irqrestore(&acm->read_lock, flags);
+               acm_submit_read_urb(acm, rb->index, GFP_ATOMIC);
+       } else {
+               spin_unlock_irqrestore(&acm->read_lock, flags);
+       }
 }
 
 /* data interface wrote those outgoing bytes */
@@ -509,9 +419,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 +431,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 +438,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);
@@ -548,8 +457,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 +466,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,38 +487,28 @@ 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);
 
-       INIT_LIST_HEAD(&acm->spare_read_urbs);
-       INIT_LIST_HEAD(&acm->spare_read_bufs);
-       INIT_LIST_HEAD(&acm->filled_read_bufs);
-
-       for (i = 0; i < acm->rx_buflimit; i++)
-               list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
-       for (i = 0; i < acm->rx_buflimit; i++)
-               list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
-
-       acm->throttle = 0;
+       if (acm_submit_read_urbs(acm, GFP_KERNEL))
+               goto bail_out;
 
        set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
        rv = tty_port_block_til_ready(&acm->port, tty, filp);
-       tasklet_schedule(&acm->urb_task);
 
        mutex_unlock(&acm->mutex);
 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 +521,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++)
-               usb_free_urb(acm->ru[i].urb);
+       for (i = 0; i < acm->rx_buflimit; i++)
+               usb_free_urb(acm->read_urbs[i]);
        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);
@@ -649,10 +546,8 @@ static void acm_port_down(struct acm *acm)
                usb_kill_urb(acm->ctrlurb);
                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++)
-                       usb_kill_urb(acm->ru[i].urb);
-               tasklet_enable(&acm->urb_task);
+               for (i = 0; i < acm->rx_buflimit; i++)
+                       usb_kill_urb(acm->read_urbs[i]);
                acm->control->needs_remote_wakeup = 0;
                usb_autopm_put_interface(acm->control);
        }
@@ -698,13 +593,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 +609,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);
@@ -751,22 +646,31 @@ static int acm_tty_chars_in_buffer(struct tty_struct *tty)
 static void acm_tty_throttle(struct tty_struct *tty)
 {
        struct acm *acm = tty->driver_data;
+
        if (!ACM_READY(acm))
                return;
-       spin_lock_bh(&acm->throttle_lock);
-       acm->throttle = 1;
-       spin_unlock_bh(&acm->throttle_lock);
+
+       spin_lock_irq(&acm->read_lock);
+       acm->throttle_req = 1;
+       spin_unlock_irq(&acm->read_lock);
 }
 
 static void acm_tty_unthrottle(struct tty_struct *tty)
 {
        struct acm *acm = tty->driver_data;
+       unsigned int was_throttled;
+
        if (!ACM_READY(acm))
                return;
-       spin_lock_bh(&acm->throttle_lock);
-       acm->throttle = 0;
-       spin_unlock_bh(&acm->throttle_lock);
-       tasklet_schedule(&acm->urb_task);
+
+       spin_lock_irq(&acm->read_lock);
+       was_throttled = acm->throttled;
+       acm->throttled = 0;
+       acm->throttle_req = 0;
+       spin_unlock_irq(&acm->read_lock);
+
+       if (was_throttled)
+               acm_submit_read_urbs(acm, GFP_KERNEL);
 }
 
 static int acm_tty_break_ctl(struct tty_struct *tty, int state)
@@ -777,7 +681,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 +777,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,11 +804,11 @@ 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);
+                         acm->read_buffers[i].base, acm->read_buffers[i].dma);
 }
 
 /* Little helper: write buffers allocate */
@@ -946,7 +853,7 @@ static int acm_probe(struct usb_interface *intf,
        u8 ac_management_function = 0;
        u8 call_management_function = 0;
        int call_interface_num = -1;
-       int data_interface_num;
+       int data_interface_num = -1;
        unsigned long quirks;
        int num_rx_buf;
        int i;
@@ -1030,7 +937,11 @@ next_desc:
        if (!union_header) {
                if (call_interface_num > 0) {
                        dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n");
-                       data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
+                       /* quirks for Droids MuIn LCD */
+                       if (quirks & NO_DATA_INTERFACE)
+                               data_interface = usb_ifnum_to_if(usb_dev, 0);
+                       else
+                               data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
                        control_interface = intf;
                } else {
                        if (intf->cur_altsetting->desc.bNumEndpoints != 3) {
@@ -1133,7 +1044,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 +1054,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;
        }
 
@@ -1162,11 +1073,7 @@ made_compressed_probe:
        acm->ctrlsize = ctrlsize;
        acm->readsize = readsize;
        acm->rx_buflimit = num_rx_buf;
-       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);
        mutex_init(&acm->mutex);
@@ -1179,53 +1086,69 @@ 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++) {
-               struct acm_ru *rcv = &(acm->ru[i]);
+               struct acm_rb *rb = &(acm->read_buffers[i]);
+               struct urb *urb;
 
-               rcv->urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (rcv->urb == NULL) {
-                       dev_dbg(&intf->dev,
-                               "out of memory (read urbs usb_alloc_urb)\n");
+               rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
+                                                               &rb->dma);
+               if (!rb->base) {
+                       dev_err(&intf->dev, "out of memory "
+                                       "(read bufs usb_alloc_coherent)\n");
                        goto alloc_fail6;
                }
+               rb->index = i;
+               rb->instance = acm;
 
-               rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-               rcv->instance = acm;
-       }
-       for (i = 0; i < num_rx_buf; i++) {
-               struct acm_rb *rb = &(acm->rb[i]);
-
-               rb->base = usb_alloc_coherent(acm->dev, readsize,
-                               GFP_KERNEL, &rb->dma);
-               if (!rb->base) {
-                       dev_dbg(&intf->dev,
-                               "out of memory (read bufs usb_alloc_coherent)\n");
-                       goto alloc_fail7;
+               urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!urb) {
+                       dev_err(&intf->dev,
+                               "out of memory (read urbs usb_alloc_urb)\n");
+                       goto alloc_fail6;
+               }
+               urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+               urb->transfer_dma = rb->dma;
+               if (acm->is_int_ep) {
+                       usb_fill_int_urb(urb, acm->dev,
+                                        acm->rx_endpoint,
+                                        rb->base,
+                                        acm->readsize,
+                                        acm_read_bulk_callback, rb,
+                                        acm->bInterval);
+               } else {
+                       usb_fill_bulk_urb(urb, acm->dev,
+                                         acm->rx_endpoint,
+                                         rb->base,
+                                         acm->readsize,
+                                         acm_read_bulk_callback, rb);
                }
+
+               acm->read_urbs[i] = urb;
+               __set_bit(i, &acm->read_urbs_free);
        }
        for (i = 0; i < ACM_NW; i++) {
                struct acm_wb *snd = &(acm->wb[i]);
 
                snd->urb = usb_alloc_urb(0, GFP_KERNEL);
                if (snd->urb == NULL) {
-                       dev_dbg(&intf->dev,
-                               "out of memory (write urbs usb_alloc_urb)");
-                       goto alloc_fail8;
+                       dev_err(&intf->dev,
+                               "out of memory (write urbs usb_alloc_urb)\n");
+                       goto alloc_fail7;
                }
 
                if (usb_endpoint_xfer_int(epwrite))
@@ -1244,7 +1167,7 @@ made_compressed_probe:
 
        i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
        if (i < 0)
-               goto alloc_fail8;
+               goto alloc_fail7;
 
        if (cfd) { /* export the country data */
                acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
@@ -1296,14 +1219,13 @@ skip_countries:
        acm_table[minor] = acm;
 
        return 0;
-alloc_fail8:
+alloc_fail7:
        for (i = 0; i < ACM_NW; i++)
                usb_free_urb(acm->wb[i].urb);
-alloc_fail7:
-       acm_read_buffers_free(acm);
 alloc_fail6:
        for (i = 0; i < num_rx_buf; i++)
-               usb_free_urb(acm->ru[i].urb);
+               usb_free_urb(acm->read_urbs[i]);
+       acm_read_buffers_free(acm);
        usb_free_urb(acm->ctrlurb);
 alloc_fail5:
        acm_write_buffers_free(acm);
@@ -1318,17 +1240,14 @@ alloc_fail:
 static void stop_data_traffic(struct acm *acm)
 {
        int i;
-       dbg("Entering stop_data_traffic");
 
-       tasklet_disable(&acm->urb_task);
+       dev_dbg(&acm->control->dev, "%s\n", __func__);
 
        usb_kill_urb(acm->ctrlurb);
        for (i = 0; i < ACM_NW; i++)
                usb_kill_urb(acm->wb[i].urb);
        for (i = 0; i < acm->rx_buflimit; i++)
-               usb_kill_urb(acm->ru[i].urb);
-
-       tasklet_enable(&acm->urb_task);
+               usb_kill_urb(acm->read_urbs[i]);
 
        cancel_work_sync(&acm->work);
 }
@@ -1389,11 +1308,9 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
        if (message.event & PM_EVENT_AUTO) {
                int b;
 
-               spin_lock_irq(&acm->read_lock);
-               spin_lock(&acm->write_lock);
-               b = acm->processing + acm->transmitting;
-               spin_unlock(&acm->write_lock);
-               spin_unlock_irq(&acm->read_lock);
+               spin_lock_irq(&acm->write_lock);
+               b = acm->transmitting;
+               spin_unlock_irq(&acm->write_lock);
                if (b)
                        return -EBUSY;
        }
@@ -1455,7 +1372,7 @@ static int acm_resume(struct usb_interface *intf)
                if (rv < 0)
                        goto err_out;
 
-               tasklet_schedule(&acm->urb_task);
+               rv = acm_submit_read_urbs(acm, GFP_NOIO);
        }
 
 err_out:
@@ -1622,6 +1539,11 @@ static const struct usb_device_id acm_ids[] = {
        .driver_info = NOT_A_MODEM,
        },
 
+       /* Support for Droids MuIn LCD */
+       { USB_DEVICE(0x04d8, 0x000b),
+       .driver_info = NO_DATA_INTERFACE,
+       },
+
        /* control interfaces without any protocol set */
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
                USB_CDC_PROTO_NONE) },
@@ -1716,8 +1638,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;
 }
This page took 0.061481 seconds and 4 git commands to generate.