*
* 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"
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.
*/
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;
}
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;
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)
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;
}
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:
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);
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 ? '+' : '-',
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;
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 */
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;
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;
}
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;
}
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;
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);
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);
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);
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)
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);
struct acm *acm;
int rv = -ENODEV;
int i;
- dbg("Entering acm_tty_open.");
mutex_lock(&open_mutex);
else
rv = 0;
+ dev_dbg(&acm->control->dev, "%s\n", __func__);
+
set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
tty->driver_data = acm;
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);
mutex_unlock(&open_mutex);
return rv;
-full_bailout:
- usb_kill_urb(acm->ctrlurb);
bail_out:
acm->port.count--;
mutex_unlock(&acm->mutex);
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);
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;
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) {
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);
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;
}
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);
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);
}
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) {
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;
}
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);
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++) {
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;
}
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;
}
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;
}
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);
return retval;
}
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
return 0;
}