CTC++ Coverage Report - Execution Profile    #619/1532

Files Summary | Functions Summary | Execution Profile | Index | No Index
First | Previous | Next | Last


File: drivers/usb/class/cdc-acm.c
Instrumentation mode: function-decision-multicondition
TER: 0 % ( 0/704)

Start/ End/    
True False - Line Source

  1 /*
  2  * cdc-acm.c
  3  *
  4  * Copyright (c) 1999 Armin Fuerst   <fuerst@in.tum.de>
  5  * Copyright (c) 1999 Pavel Machek   <pavel@suse.cz>
  6  * Copyright (c) 1999 Johannes Erdfelt   <johannes@erdfelt.com>
  7  * Copyright (c) 2000 Vojtech Pavlik   <vojtech@suse.cz>
  8  * Copyright (c) 2004 Oliver Neukum   <oliver@neukum.name>
  9  * Copyright (c) 2005 David Kubicek   <dave@awk.cz>
  10  *
  11  * USB Abstract Control Model driver for USB modems and ISDN adapters
  12  *
  13  * Sponsored by SuSE
  14  *
  15  * ChangeLog:
  16  *   v0.9  - thorough cleaning, URBification, almost a rewrite
  17  *   v0.10 - some more cleanups
  18  *   v0.11 - fixed flow control, read error doesn't stop reads
  19  *   v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced
  20  *   v0.13 - added termios, added hangup
  21  *   v0.14 - sized down struct acm
  22  *   v0.15 - fixed flow control again - characters could be lost
  23  *   v0.16 - added code for modems with swapped data and control interfaces
  24  *   v0.17 - added new style probing
  25  *   v0.18 - fixed new style probing for devices with more configurations
  26  *   v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan)
  27  *   v0.20 - switched to probing on interface (rather than device) class
  28  *   v0.21 - revert to probing on device for devices with multiple configs
  29  *   v0.22 - probe only the control interface. if usbcore doesn't choose the
  30  *      config we want, sysadmin changes bConfigurationValue in sysfs.
  31  *   v0.23 - use softirq for rx processing, as needed by tty layer
  32  *   v0.24 - change probe method to evaluate CDC union descriptor
  33  *   v0.25 - downstream tasks paralelized to maximize throughput
  34  */
  35 
  36 /*
  37  * This program is free software; you can redistribute it and/or modify
  38  * it under the terms of the GNU General Public License as published by
  39  * the Free Software Foundation; either version 2 of the License, or
  40  * (at your option) any later version.
  41  *
  42  * This program is distributed in the hope that it will be useful,
  43  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  44  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  45  * GNU General Public License for more details.
  46  *
  47  * You should have received a copy of the GNU General Public License
  48  * along with this program; if not, write to the Free Software
  49  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  50  */
  51 
  52 #undef DEBUG
  53 
  54 #include <linux/kernel.h>
  55 #include <linux/errno.h>
  56 #include <linux/init.h>
  57 #include <linux/slab.h>
  58 #include <linux/tty.h>
  59 #include <linux/tty_driver.h>
  60 #include <linux/tty_flip.h>
  61 #include <linux/module.h>
  62 #include <linux/smp_lock.h>
  63 #include <asm/uaccess.h>
  64 #include <linux/usb.h>
  65 #include <linux/usb_cdc.h>
  66 #include <asm/byteorder.h>
  67 #include <asm/unaligned.h>
  68 #include <linux/list.h>
  69 
  70 #include "cdc-acm.h"
  71 
  72 /*
  73  * Version Information
  74  */
  75 #define DRIVER_VERSION "v0.25"
  76 #define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek"
  77 #define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
  78 
  79 static struct usb_driver acm_driver;
  80 static struct tty_driver *acm_tty_driver;
  81 static struct acm *acm_table[ACM_TTY_MINORS];
  82 
  83 static DECLARE_MUTEX(open_sem);
  84 
  85 #define ACM_READY(acm)   (acm && acm->dev && acm->used)
  86 
  87 /*
  88  * Functions for ACM control messages.
  89  */
  90 
 
- 91 static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len)
  92 {
  93    int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
  94       request, USB_RT_ACM, value,
  95       acm->control->altsetting[0].desc.bInterfaceNumber,
  96       buf, len, 5000);
    97    dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
- 97 do-while (0)
    98    return retval < 0 ? retval : 0;
- 98 ternary-?: retval < 0
 - 98 return retval < 0 ? retval : 0
  99 }
  100 
  101 /* devices aren't required to support these requests.
  102  * the cdc acm descriptor tells whether they do...
  103  */
  104 #define acm_set_control(acm, control) \
  105    acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0)
  106 #define acm_set_line(acm, line) \
  107    acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line))
  108 #define acm_send_break(acm, ms) \
  109    acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
  110 
  111 /*
  112  * Write buffer management.
  113  * All of these assume proper locks taken by the caller.
  114  */
  115 
 
- 116 static int acm_wb_alloc(struct acm *acm)
  117 {
  118    int i, wbn;
  119    struct acm_wb *wb;
  120 
  121    wbn = acm->write_current;
  122    i = 0;
- 123    for (;;) {
  124       wb = &acm->wb[wbn];
- 125       if (!wb->use) {
  126          wb->use = 1;
 - 127          return wbn;
  128       }
  129       wbn = (wbn + 1) % ACM_NWB;
- 130       if (++i >= ACM_NWB)
 - 131          return -1;
  132    }
  133 }
  134 
 
- 135 static void acm_wb_free(struct acm *acm, int wbn)
  136 {
  137    acm->wb[wbn].use = 0;
  138 }
  139 
 
- 140 static int acm_wb_is_avail(struct acm *acm)
  141 {
  142    int i, n;
  143 
  144    n = 0;
- 145    for (i = 0; i < ACM_NWB; i++) {
- 146       if (!acm->wb[i].use)
  147          n++;
  148    }
 - 149    return n;
  150 }
  151 
 
- 152 static inline int acm_wb_is_used(struct acm *acm, int wbn)
  153 {
 - 154    return acm->wb[wbn].use;
  155 }
  156 
  157 /*
  158  * Finish write.
  159  */
 
- 160 static void acm_write_done(struct acm *acm)
  161 {
  162    unsigned long flags;
  163    int wbn;
  164 
    165    spin_lock_irqsave(&acm->write_lock, flags);
    165   do
    165     do
- 165     do-while (0)
- 165   do-while (0)
    165   do
    165     do
- 165     do-while (0)
- 165   do-while (0)
- 165 do-while (0)
  166    acm->write_ready = 1;
  167    wbn = acm->write_current;
  168    acm_wb_free(acm, wbn);
  169    acm->write_current = (wbn + 1) % ACM_NWB;
    170    spin_unlock_irqrestore(&acm->write_lock, flags);
    170   do
    170     do
- 170     do-while (0)
- 170   do-while (0)
- 170 do-while (0)
  171 }
  172 
  173 /*
  174  * Poke write.
  175  */
 
- 176 static int acm_write_start(struct acm *acm)
  177 {
  178    unsigned long flags;
  179    int wbn;
  180    struct acm_wb *wb;
  181    int rc;
  182 
    183    spin_lock_irqsave(&acm->write_lock, flags);
    183   do
    183     do
- 183     do-while (0)
- 183   do-while (0)
    183   do
    183     do
- 183     do-while (0)
- 183   do-while (0)
- 183 do-while (0)
- 184    if (!acm->dev) {
    185       spin_unlock_irqrestore(&acm->write_lock, flags);
    185     do
    185       do
- 185       do-while (0)
- 185     do-while (0)
- 185   do-while (0)
 - 186       return -ENODEV;
  187    }
  188 
- 189    if (!acm->write_ready) {
    190       spin_unlock_irqrestore(&acm->write_lock, flags);
    190     do
    190       do
- 190       do-while (0)
- 190     do-while (0)
- 190   do-while (0)
 - 191       return 0;   /* A white lie */
  192    }
  193 
  194    wbn = acm->write_current;
- 195    if (!acm_wb_is_used(acm, wbn)) {
    196       spin_unlock_irqrestore(&acm->write_lock, flags);
    196     do
    196       do
- 196       do-while (0)
- 196     do-while (0)
- 196   do-while (0)
 - 197       return 0;
  198    }
  199    wb = &acm->wb[wbn];
  200 
  201    acm->write_ready = 0;
    202    spin_unlock_irqrestore(&acm->write_lock, flags);
    202   do
    202     do
- 202     do-while (0)
- 202   do-while (0)
- 202 do-while (0)
  203 
  204    acm->writeurb->transfer_buffer = wb->buf;
  205    acm->writeurb->transfer_dma = wb->dmah;
  206    acm->writeurb->transfer_buffer_length = wb->len;
  207    acm->writeurb->dev = acm->dev;
  208 
- 209    if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) {
    210       dbg("usb_submit_urb(write bulk) failed: %d", rc);
- 210   do-while (0)
  211       acm_write_done(acm);
  212    }
 - 213    return rc;
  214 }
  215 
  216 /*
  217  * Interrupt handlers for various ACM device responses
  218  */
  219 
  220 /* control interface reports status changes with "interrupt" transfers */
 
- 221 static void acm_ctrl_irq(struct urb *urb, struct pt_regs *regs)
  222 {
  223    struct acm *acm = urb->context;
  224    struct usb_cdc_notification *dr = urb->transfer_buffer;
  225    unsigned char *data;
  226    int newctrl;
  227    int status;
  228 
    229    switch (urb->status) {
 - 230    case 0:
  231       /* success */
 - 232       break;
 - 233    case -ECONNRESET:
 - 234    case -ENOENT:
 - 235    case -ESHUTDOWN:
  236       /* this urb is terminated, clean up */
    237       dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
- 237   do-while (0)
 - 238       return;
 - 239    default:
    240       dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
- 240   do-while (0)
 - 241       goto exit;
  242    }
  243 
- 244    if (!ACM_READY(acm))
 - 244   !(T && T && F)
 - 244   !(T && F && _)
 - 244   !(F && _ && _)
 - 244   !(T && T && T)
 - 245       goto exit;
  246 
  247    data = (unsigned char *)(dr + 1);
    248    switch (dr->bNotificationType) {
  249 
 - 250       case USB_CDC_NOTIFY_NETWORK_CONNECTION:
  251 
    252          dbg("%s network", dr->wValue ? "connected to" : "disconnected from");
- 252   do-while (0)
 - 253          break;
  254 
 - 255       case USB_CDC_NOTIFY_SERIAL_STATE:
  256 
  257          newctrl = le16_to_cpu(get_unaligned((__le16 *) data));
  258 
- 259          if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
 - 259     T && T && (T)
 - 259     T && T && (F)
 - 259     T && F && (_)
 - 259     F && _ && (_)
    260             dbg("calling hangup");
- 260     do-while (0)
  261             tty_hangup(acm->tty);
  262          }
  263 
  264          acm->ctrlin = newctrl;
  265 
    266          dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
- 266   do-while (0)
  267             acm->ctrlin & ACM_CTRL_DCD ? '+' : '-',   acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
  268             acm->ctrlin & ACM_CTRL_BRK ? '+' : '-',   acm->ctrlin & ACM_CTRL_RI  ? '+' : '-',
  269             acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-',   acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
  270             acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
  271 
 - 272          break;
  273 
 - 274       default:
    275          dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
- 275   do-while (0)
  276             dr->bNotificationType, dr->wIndex,
  277             dr->wLength, data[0], data[1]);
 - 278          break;
  279    }
  280 exit:
  281    status = usb_submit_urb (urb, GFP_ATOMIC);
- 282    if (status)
  283       err ("%s - usb_submit_urb failed with result %d",
  284            __FUNCTION__, status);
  285 }
  286 
  287 /* data interface returns incoming bytes, or we got unthrottled */
 
- 288 static void acm_read_bulk(struct urb *urb, struct pt_regs *regs)
  289 {
  290    struct acm_rb *buf;
  291    struct acm_ru *rcv = urb->context;
  292    struct acm *acm = rcv->instance;
    293    dbg("Entering acm_read_bulk with status %d\n", urb->status);
- 293 do-while (0)
  294 
- 295    if (!ACM_READY(acm))
 - 295   !(T && T && F)
 - 295   !(T && F && _)
 - 295   !(F && _ && _)
 - 295   !(T && T && T)
 - 296       return;
  297 
- 298    if (urb->status)
    299       dev_dbg(&acm->data->dev, "bulk rx status %d\n", urb->status);
- 299   do-while (0)
  300 
  301    buf = rcv->buffer;
  302    buf->size = urb->actual_length;
  303 
    304    spin_lock(&acm->read_lock);
    304   do
- 304   do-while (0)
- 304 do-while (0)
  305    list_add_tail(&rcv->list, &acm->spare_read_urbs);
  306    list_add_tail(&buf->list, &acm->filled_read_bufs);
    307    spin_unlock(&acm->read_lock);
    307   do
- 307   do-while (0)
- 307 do-while (0)
  308 
  309    tasklet_schedule(&acm->urb_task);
  310 }
  311 
 
- 312 static void acm_rx_tasklet(unsigned long _acm)
  313 {
  314    struct acm *acm = (void *)_acm;
  315    struct acm_rb *buf;
  316    struct tty_struct *tty = acm->tty;
  317    struct acm_ru *rcv;
  318    //unsigned long flags;
  319    int i = 0;
    320    dbg("Entering acm_rx_tasklet");
- 320 do-while (0)
  321 
- 322    if (!ACM_READY(acm) || acm->throttle)
 - 322   !(T && T && T) || T
 - 322   !(T && T && F) || _
 - 322   !(T && F && _) || _
 - 322   !(F && _ && _) || _
 - 322   !(T && T && T) || F
 - 323       return;
  324 
  325 next_buffer:
    326    spin_lock(&acm->read_lock);
    326   do
- 326   do-while (0)
- 326 do-while (0)
- 327    if (list_empty(&acm->filled_read_bufs)) {
    328       spin_unlock(&acm->read_lock);
    328     do
- 328     do-while (0)
- 328   do-while (0)
 - 329       goto urbs;
  330    }
  331    buf = list_entry(acm->filled_read_bufs.next,
  332           struct acm_rb, list);
  333    list_del(&buf->list);
    334    spin_unlock(&acm->read_lock);
    334   do
- 334   do-while (0)
- 334 do-while (0)
  335 
    336    dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d\n", buf, buf->size);
- 336 do-while (0)
  337 
  338    tty_buffer_request_room(tty, buf->size);
- 339    if (!acm->throttle)
  340       tty_insert_flip_string(tty, buf->base, buf->size);
  341    tty_flip_buffer_push(tty);
  342 
    343    spin_lock(&acm->throttle_lock);
    343   do
- 343   do-while (0)
- 343 do-while (0)
- 344    if (acm->throttle) {
    345       dbg("Throtteling noticed");
- 345   do-while (0)
  346       memmove(buf->base, buf->base + i, buf->size - i);
  347       buf->size -= i;
    348       spin_unlock(&acm->throttle_lock);
    348     do
- 348     do-while (0)
- 348   do-while (0)
    349       spin_lock(&acm->read_lock);
    349     do
- 349     do-while (0)
- 349   do-while (0)
  350       list_add(&buf->list, &acm->filled_read_bufs);
    351       spin_unlock(&acm->read_lock);
    351     do
- 351     do-while (0)
- 351   do-while (0)
 - 352       return;
  353    }
    354    spin_unlock(&acm->throttle_lock);
    354   do
- 354   do-while (0)
- 354 do-while (0)
  355 
    356    spin_lock(&acm->read_lock);
    356   do
- 356   do-while (0)
- 356 do-while (0)
  357    list_add(&buf->list, &acm->spare_read_bufs);
    358    spin_unlock(&acm->read_lock);
    358   do
- 358   do-while (0)
- 358 do-while (0)
 - 359    goto next_buffer;
  360 
  361 urbs:
- 362    while (!list_empty(&acm->spare_read_bufs)) {
    363       spin_lock(&acm->read_lock);
    363     do
- 363     do-while (0)
- 363   do-while (0)
- 364       if (list_empty(&acm->spare_read_urbs)) {
    365          spin_unlock(&acm->read_lock);
    365       do
- 365       do-while (0)
- 365     do-while (0)
 - 366          return;
  367       }
  368       rcv = list_entry(acm->spare_read_urbs.next,
  369              struct acm_ru, list);
  370       list_del(&rcv->list);
    371       spin_unlock(&acm->read_lock);
    371     do
- 371     do-while (0)
- 371   do-while (0)
  372 
  373       buf = list_entry(acm->spare_read_bufs.next,
  374              struct acm_rb, list);
  375       list_del(&buf->list);
  376 
  377       rcv->buffer = buf;
  378 
  379       usb_fill_bulk_urb(rcv->urb, acm->dev,
  380               acm->rx_endpoint,
  381               buf->base,
  382               acm->readsize,
  383               acm_read_bulk, rcv);