linux/drivers/usb/gadget/f_loopback.c
<<
>>
Prefs
   1/*
   2 * f_loopback.c - USB peripheral loopback configuration driver
   3 *
   4 * Copyright (C) 2003-2008 David Brownell
   5 * Copyright (C) 2008 by Nokia Corporation
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 */
  12
  13/* #define VERBOSE_DEBUG */
  14
  15#include <linux/slab.h>
  16#include <linux/kernel.h>
  17#include <linux/device.h>
  18#include <linux/module.h>
  19#include <linux/err.h>
  20#include <linux/usb/composite.h>
  21
  22#include "g_zero.h"
  23
  24/*
  25 * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals,
  26 *
  27 * This takes messages of various sizes written OUT to a device, and loops
  28 * them back so they can be read IN from it.  It has been used by certain
  29 * test applications.  It supports limited testing of data queueing logic.
  30 *
  31 *
  32 * This is currently packaged as a configuration driver, which can't be
  33 * combined with other functions to make composite devices.  However, it
  34 * can be combined with other independent configurations.
  35 */
  36struct f_loopback {
  37        struct usb_function     function;
  38
  39        struct usb_ep           *in_ep;
  40        struct usb_ep           *out_ep;
  41};
  42
  43static inline struct f_loopback *func_to_loop(struct usb_function *f)
  44{
  45        return container_of(f, struct f_loopback, function);
  46}
  47
  48static unsigned qlen;
  49static unsigned buflen;
  50
  51/*-------------------------------------------------------------------------*/
  52
  53static struct usb_interface_descriptor loopback_intf = {
  54        .bLength =              sizeof loopback_intf,
  55        .bDescriptorType =      USB_DT_INTERFACE,
  56
  57        .bNumEndpoints =        2,
  58        .bInterfaceClass =      USB_CLASS_VENDOR_SPEC,
  59        /* .iInterface = DYNAMIC */
  60};
  61
  62/* full speed support: */
  63
  64static struct usb_endpoint_descriptor fs_loop_source_desc = {
  65        .bLength =              USB_DT_ENDPOINT_SIZE,
  66        .bDescriptorType =      USB_DT_ENDPOINT,
  67
  68        .bEndpointAddress =     USB_DIR_IN,
  69        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
  70};
  71
  72static struct usb_endpoint_descriptor fs_loop_sink_desc = {
  73        .bLength =              USB_DT_ENDPOINT_SIZE,
  74        .bDescriptorType =      USB_DT_ENDPOINT,
  75
  76        .bEndpointAddress =     USB_DIR_OUT,
  77        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
  78};
  79
  80static struct usb_descriptor_header *fs_loopback_descs[] = {
  81        (struct usb_descriptor_header *) &loopback_intf,
  82        (struct usb_descriptor_header *) &fs_loop_sink_desc,
  83        (struct usb_descriptor_header *) &fs_loop_source_desc,
  84        NULL,
  85};
  86
  87/* high speed support: */
  88
  89static struct usb_endpoint_descriptor hs_loop_source_desc = {
  90        .bLength =              USB_DT_ENDPOINT_SIZE,
  91        .bDescriptorType =      USB_DT_ENDPOINT,
  92
  93        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
  94        .wMaxPacketSize =       cpu_to_le16(512),
  95};
  96
  97static struct usb_endpoint_descriptor hs_loop_sink_desc = {
  98        .bLength =              USB_DT_ENDPOINT_SIZE,
  99        .bDescriptorType =      USB_DT_ENDPOINT,
 100
 101        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
 102        .wMaxPacketSize =       cpu_to_le16(512),
 103};
 104
 105static struct usb_descriptor_header *hs_loopback_descs[] = {
 106        (struct usb_descriptor_header *) &loopback_intf,
 107        (struct usb_descriptor_header *) &hs_loop_source_desc,
 108        (struct usb_descriptor_header *) &hs_loop_sink_desc,
 109        NULL,
 110};
 111
 112/* super speed support: */
 113
 114static struct usb_endpoint_descriptor ss_loop_source_desc = {
 115        .bLength =              USB_DT_ENDPOINT_SIZE,
 116        .bDescriptorType =      USB_DT_ENDPOINT,
 117
 118        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
 119        .wMaxPacketSize =       cpu_to_le16(1024),
 120};
 121
 122struct usb_ss_ep_comp_descriptor ss_loop_source_comp_desc = {
 123        .bLength =              USB_DT_SS_EP_COMP_SIZE,
 124        .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
 125        .bMaxBurst =            0,
 126        .bmAttributes =         0,
 127        .wBytesPerInterval =    0,
 128};
 129
 130static struct usb_endpoint_descriptor ss_loop_sink_desc = {
 131        .bLength =              USB_DT_ENDPOINT_SIZE,
 132        .bDescriptorType =      USB_DT_ENDPOINT,
 133
 134        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
 135        .wMaxPacketSize =       cpu_to_le16(1024),
 136};
 137
 138struct usb_ss_ep_comp_descriptor ss_loop_sink_comp_desc = {
 139        .bLength =              USB_DT_SS_EP_COMP_SIZE,
 140        .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
 141        .bMaxBurst =            0,
 142        .bmAttributes =         0,
 143        .wBytesPerInterval =    0,
 144};
 145
 146static struct usb_descriptor_header *ss_loopback_descs[] = {
 147        (struct usb_descriptor_header *) &loopback_intf,
 148        (struct usb_descriptor_header *) &ss_loop_source_desc,
 149        (struct usb_descriptor_header *) &ss_loop_source_comp_desc,
 150        (struct usb_descriptor_header *) &ss_loop_sink_desc,
 151        (struct usb_descriptor_header *) &ss_loop_sink_comp_desc,
 152        NULL,
 153};
 154
 155/* function-specific strings: */
 156
 157static struct usb_string strings_loopback[] = {
 158        [0].s = "loop input to output",
 159        {  }                    /* end of list */
 160};
 161
 162static struct usb_gadget_strings stringtab_loop = {
 163        .language       = 0x0409,       /* en-us */
 164        .strings        = strings_loopback,
 165};
 166
 167static struct usb_gadget_strings *loopback_strings[] = {
 168        &stringtab_loop,
 169        NULL,
 170};
 171
 172/*-------------------------------------------------------------------------*/
 173
 174static int loopback_bind(struct usb_configuration *c, struct usb_function *f)
 175{
 176        struct usb_composite_dev *cdev = c->cdev;
 177        struct f_loopback       *loop = func_to_loop(f);
 178        int                     id;
 179        int ret;
 180
 181        /* allocate interface ID(s) */
 182        id = usb_interface_id(c, f);
 183        if (id < 0)
 184                return id;
 185        loopback_intf.bInterfaceNumber = id;
 186
 187        id = usb_string_id(cdev);
 188        if (id < 0)
 189                return id;
 190        strings_loopback[0].id = id;
 191        loopback_intf.iInterface = id;
 192
 193        /* allocate endpoints */
 194
 195        loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc);
 196        if (!loop->in_ep) {
 197autoconf_fail:
 198                ERROR(cdev, "%s: can't autoconfigure on %s\n",
 199                        f->name, cdev->gadget->name);
 200                return -ENODEV;
 201        }
 202        loop->in_ep->driver_data = cdev;        /* claim */
 203
 204        loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_sink_desc);
 205        if (!loop->out_ep)
 206                goto autoconf_fail;
 207        loop->out_ep->driver_data = cdev;       /* claim */
 208
 209        /* support high speed hardware */
 210        hs_loop_source_desc.bEndpointAddress =
 211                fs_loop_source_desc.bEndpointAddress;
 212        hs_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress;
 213
 214        /* support super speed hardware */
 215        ss_loop_source_desc.bEndpointAddress =
 216                fs_loop_source_desc.bEndpointAddress;
 217        ss_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress;
 218
 219        ret = usb_assign_descriptors(f, fs_loopback_descs, hs_loopback_descs,
 220                        ss_loopback_descs);
 221        if (ret)
 222                return ret;
 223
 224        DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
 225            (gadget_is_superspeed(c->cdev->gadget) ? "super" :
 226             (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
 227                        f->name, loop->in_ep->name, loop->out_ep->name);
 228        return 0;
 229}
 230
 231static void lb_free_func(struct usb_function *f)
 232{
 233        usb_free_all_descriptors(f);
 234        kfree(func_to_loop(f));
 235}
 236
 237static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
 238{
 239        struct f_loopback       *loop = ep->driver_data;
 240        struct usb_composite_dev *cdev = loop->function.config->cdev;
 241        int                     status = req->status;
 242
 243        switch (status) {
 244
 245        case 0:                         /* normal completion? */
 246                if (ep == loop->out_ep) {
 247                        /* loop this OUT packet back IN to the host */
 248                        req->zero = (req->actual < req->length);
 249                        req->length = req->actual;
 250                        status = usb_ep_queue(loop->in_ep, req, GFP_ATOMIC);
 251                        if (status == 0)
 252                                return;
 253
 254                        /* "should never get here" */
 255                        ERROR(cdev, "can't loop %s to %s: %d\n",
 256                                ep->name, loop->in_ep->name,
 257                                status);
 258                }
 259
 260                /* queue the buffer for some later OUT packet */
 261                req->length = buflen;
 262                status = usb_ep_queue(loop->out_ep, req, GFP_ATOMIC);
 263                if (status == 0)
 264                        return;
 265
 266                /* "should never get here" */
 267                /* FALLTHROUGH */
 268
 269        default:
 270                ERROR(cdev, "%s loop complete --> %d, %d/%d\n", ep->name,
 271                                status, req->actual, req->length);
 272                /* FALLTHROUGH */
 273
 274        /* NOTE:  since this driver doesn't maintain an explicit record
 275         * of requests it submitted (just maintains qlen count), we
 276         * rely on the hardware driver to clean up on disconnect or
 277         * endpoint disable.
 278         */
 279        case -ECONNABORTED:             /* hardware forced ep reset */
 280        case -ECONNRESET:               /* request dequeued */
 281        case -ESHUTDOWN:                /* disconnect from host */
 282                free_ep_req(ep, req);
 283                return;
 284        }
 285}
 286
 287static void disable_loopback(struct f_loopback *loop)
 288{
 289        struct usb_composite_dev        *cdev;
 290
 291        cdev = loop->function.config->cdev;
 292        disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL);
 293        VDBG(cdev, "%s disabled\n", loop->function.name);
 294}
 295
 296static int
 297enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
 298{
 299        int                                     result = 0;
 300        struct usb_ep                           *ep;
 301        struct usb_request                      *req;
 302        unsigned                                i;
 303
 304        /* one endpoint writes data back IN to the host */
 305        ep = loop->in_ep;
 306        result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
 307        if (result)
 308                return result;
 309        result = usb_ep_enable(ep);
 310        if (result < 0)
 311                return result;
 312        ep->driver_data = loop;
 313
 314        /* one endpoint just reads OUT packets */
 315        ep = loop->out_ep;
 316        result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
 317        if (result)
 318                goto fail0;
 319
 320        result = usb_ep_enable(ep);
 321        if (result < 0) {
 322fail0:
 323                ep = loop->in_ep;
 324                usb_ep_disable(ep);
 325                ep->driver_data = NULL;
 326                return result;
 327        }
 328        ep->driver_data = loop;
 329
 330        /* allocate a bunch of read buffers and queue them all at once.
 331         * we buffer at most 'qlen' transfers; fewer if any need more
 332         * than 'buflen' bytes each.
 333         */
 334        for (i = 0; i < qlen && result == 0; i++) {
 335                req = alloc_ep_req(ep, 0);
 336                if (req) {
 337                        req->complete = loopback_complete;
 338                        result = usb_ep_queue(ep, req, GFP_ATOMIC);
 339                        if (result)
 340                                ERROR(cdev, "%s queue req --> %d\n",
 341                                                ep->name, result);
 342                } else {
 343                        usb_ep_disable(ep);
 344                        ep->driver_data = NULL;
 345                        result = -ENOMEM;
 346                        goto fail0;
 347                }
 348        }
 349
 350        DBG(cdev, "%s enabled\n", loop->function.name);
 351        return result;
 352}
 353
 354static int loopback_set_alt(struct usb_function *f,
 355                unsigned intf, unsigned alt)
 356{
 357        struct f_loopback       *loop = func_to_loop(f);
 358        struct usb_composite_dev *cdev = f->config->cdev;
 359
 360        /* we know alt is zero */
 361        if (loop->in_ep->driver_data)
 362                disable_loopback(loop);
 363        return enable_loopback(cdev, loop);
 364}
 365
 366static void loopback_disable(struct usb_function *f)
 367{
 368        struct f_loopback       *loop = func_to_loop(f);
 369
 370        disable_loopback(loop);
 371}
 372
 373static struct usb_function *loopback_alloc(struct usb_function_instance *fi)
 374{
 375        struct f_loopback       *loop;
 376        struct f_lb_opts        *lb_opts;
 377
 378        loop = kzalloc(sizeof *loop, GFP_KERNEL);
 379        if (!loop)
 380                return ERR_PTR(-ENOMEM);
 381
 382        lb_opts = container_of(fi, struct f_lb_opts, func_inst);
 383        buflen = lb_opts->bulk_buflen;
 384        qlen = lb_opts->qlen;
 385        if (!qlen)
 386                qlen = 32;
 387
 388        loop->function.name = "loopback";
 389        loop->function.bind = loopback_bind;
 390        loop->function.set_alt = loopback_set_alt;
 391        loop->function.disable = loopback_disable;
 392        loop->function.strings = loopback_strings;
 393
 394        loop->function.free_func = lb_free_func;
 395
 396        return &loop->function;
 397}
 398
 399static void lb_free_instance(struct usb_function_instance *fi)
 400{
 401        struct f_lb_opts *lb_opts;
 402
 403        lb_opts = container_of(fi, struct f_lb_opts, func_inst);
 404        kfree(lb_opts);
 405}
 406
 407static struct usb_function_instance *loopback_alloc_instance(void)
 408{
 409        struct f_lb_opts *lb_opts;
 410
 411        lb_opts = kzalloc(sizeof(*lb_opts), GFP_KERNEL);
 412        if (!lb_opts)
 413                return ERR_PTR(-ENOMEM);
 414        lb_opts->func_inst.free_func_inst = lb_free_instance;
 415        return  &lb_opts->func_inst;
 416}
 417DECLARE_USB_FUNCTION(Loopback, loopback_alloc_instance, loopback_alloc);
 418
 419int __init lb_modinit(void)
 420{
 421        int ret;
 422
 423        ret = usb_function_register(&Loopbackusb_func);
 424        if (ret)
 425                return ret;
 426        return ret;
 427}
 428void __exit lb_modexit(void)
 429{
 430        usb_function_unregister(&Loopbackusb_func);
 431}
 432
 433MODULE_LICENSE("GPL");
 434