linux/drivers/usb/gadget/function/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#include "u_f.h"
  24
  25/*
  26 * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals,
  27 *
  28 * This takes messages of various sizes written OUT to a device, and loops
  29 * them back so they can be read IN from it.  It has been used by certain
  30 * test applications.  It supports limited testing of data queueing logic.
  31 */
  32struct f_loopback {
  33        struct usb_function     function;
  34
  35        struct usb_ep           *in_ep;
  36        struct usb_ep           *out_ep;
  37
  38        unsigned                qlen;
  39        unsigned                buflen;
  40};
  41
  42static inline struct f_loopback *func_to_loop(struct usb_function *f)
  43{
  44        return container_of(f, struct f_loopback, function);
  45}
  46
  47/*-------------------------------------------------------------------------*/
  48
  49static struct usb_interface_descriptor loopback_intf = {
  50        .bLength =              sizeof(loopback_intf),
  51        .bDescriptorType =      USB_DT_INTERFACE,
  52
  53        .bNumEndpoints =        2,
  54        .bInterfaceClass =      USB_CLASS_VENDOR_SPEC,
  55        /* .iInterface = DYNAMIC */
  56};
  57
  58/* full speed support: */
  59
  60static struct usb_endpoint_descriptor fs_loop_source_desc = {
  61        .bLength =              USB_DT_ENDPOINT_SIZE,
  62        .bDescriptorType =      USB_DT_ENDPOINT,
  63
  64        .bEndpointAddress =     USB_DIR_IN,
  65        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
  66};
  67
  68static struct usb_endpoint_descriptor fs_loop_sink_desc = {
  69        .bLength =              USB_DT_ENDPOINT_SIZE,
  70        .bDescriptorType =      USB_DT_ENDPOINT,
  71
  72        .bEndpointAddress =     USB_DIR_OUT,
  73        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
  74};
  75
  76static struct usb_descriptor_header *fs_loopback_descs[] = {
  77        (struct usb_descriptor_header *) &loopback_intf,
  78        (struct usb_descriptor_header *) &fs_loop_sink_desc,
  79        (struct usb_descriptor_header *) &fs_loop_source_desc,
  80        NULL,
  81};
  82
  83/* high speed support: */
  84
  85static struct usb_endpoint_descriptor hs_loop_source_desc = {
  86        .bLength =              USB_DT_ENDPOINT_SIZE,
  87        .bDescriptorType =      USB_DT_ENDPOINT,
  88
  89        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
  90        .wMaxPacketSize =       cpu_to_le16(512),
  91};
  92
  93static struct usb_endpoint_descriptor hs_loop_sink_desc = {
  94        .bLength =              USB_DT_ENDPOINT_SIZE,
  95        .bDescriptorType =      USB_DT_ENDPOINT,
  96
  97        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
  98        .wMaxPacketSize =       cpu_to_le16(512),
  99};
 100
 101static struct usb_descriptor_header *hs_loopback_descs[] = {
 102        (struct usb_descriptor_header *) &loopback_intf,
 103        (struct usb_descriptor_header *) &hs_loop_source_desc,
 104        (struct usb_descriptor_header *) &hs_loop_sink_desc,
 105        NULL,
 106};
 107
 108/* super speed support: */
 109
 110static struct usb_endpoint_descriptor ss_loop_source_desc = {
 111        .bLength =              USB_DT_ENDPOINT_SIZE,
 112        .bDescriptorType =      USB_DT_ENDPOINT,
 113
 114        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
 115        .wMaxPacketSize =       cpu_to_le16(1024),
 116};
 117
 118static struct usb_ss_ep_comp_descriptor ss_loop_source_comp_desc = {
 119        .bLength =              USB_DT_SS_EP_COMP_SIZE,
 120        .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
 121        .bMaxBurst =            0,
 122        .bmAttributes =         0,
 123        .wBytesPerInterval =    0,
 124};
 125
 126static struct usb_endpoint_descriptor ss_loop_sink_desc = {
 127        .bLength =              USB_DT_ENDPOINT_SIZE,
 128        .bDescriptorType =      USB_DT_ENDPOINT,
 129
 130        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
 131        .wMaxPacketSize =       cpu_to_le16(1024),
 132};
 133
 134static struct usb_ss_ep_comp_descriptor ss_loop_sink_comp_desc = {
 135        .bLength =              USB_DT_SS_EP_COMP_SIZE,
 136        .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
 137        .bMaxBurst =            0,
 138        .bmAttributes =         0,
 139        .wBytesPerInterval =    0,
 140};
 141
 142static struct usb_descriptor_header *ss_loopback_descs[] = {
 143        (struct usb_descriptor_header *) &loopback_intf,
 144        (struct usb_descriptor_header *) &ss_loop_source_desc,
 145        (struct usb_descriptor_header *) &ss_loop_source_comp_desc,
 146        (struct usb_descriptor_header *) &ss_loop_sink_desc,
 147        (struct usb_descriptor_header *) &ss_loop_sink_comp_desc,
 148        NULL,
 149};
 150
 151/* function-specific strings: */
 152
 153static struct usb_string strings_loopback[] = {
 154        [0].s = "loop input to output",
 155        {  }                    /* end of list */
 156};
 157
 158static struct usb_gadget_strings stringtab_loop = {
 159        .language       = 0x0409,       /* en-us */
 160        .strings        = strings_loopback,
 161};
 162
 163static struct usb_gadget_strings *loopback_strings[] = {
 164        &stringtab_loop,
 165        NULL,
 166};
 167
 168/*-------------------------------------------------------------------------*/
 169
 170static int loopback_bind(struct usb_configuration *c, struct usb_function *f)
 171{
 172        struct usb_composite_dev *cdev = c->cdev;
 173        struct f_loopback       *loop = func_to_loop(f);
 174        int                     id;
 175        int ret;
 176
 177        /* allocate interface ID(s) */
 178        id = usb_interface_id(c, f);
 179        if (id < 0)
 180                return id;
 181        loopback_intf.bInterfaceNumber = id;
 182
 183        id = usb_string_id(cdev);
 184        if (id < 0)
 185                return id;
 186        strings_loopback[0].id = id;
 187        loopback_intf.iInterface = id;
 188
 189        /* allocate endpoints */
 190
 191        loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc);
 192        if (!loop->in_ep) {
 193autoconf_fail:
 194                ERROR(cdev, "%s: can't autoconfigure on %s\n",
 195                        f->name, cdev->gadget->name);
 196                return -ENODEV;
 197        }
 198
 199        loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_sink_desc);
 200        if (!loop->out_ep)
 201                goto autoconf_fail;
 202
 203        /* support high speed hardware */
 204        hs_loop_source_desc.bEndpointAddress =
 205                fs_loop_source_desc.bEndpointAddress;
 206        hs_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress;
 207
 208        /* support super speed hardware */
 209        ss_loop_source_desc.bEndpointAddress =
 210                fs_loop_source_desc.bEndpointAddress;
 211        ss_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress;
 212
 213        ret = usb_assign_descriptors(f, fs_loopback_descs, hs_loopback_descs,
 214                        ss_loopback_descs, NULL);
 215        if (ret)
 216                return ret;
 217
 218        DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
 219            (gadget_is_superspeed(c->cdev->gadget) ? "super" :
 220             (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
 221                        f->name, loop->in_ep->name, loop->out_ep->name);
 222        return 0;
 223}
 224
 225static void lb_free_func(struct usb_function *f)
 226{
 227        struct f_lb_opts *opts;
 228
 229        opts = container_of(f->fi, struct f_lb_opts, func_inst);
 230
 231        mutex_lock(&opts->lock);
 232        opts->refcnt--;
 233        mutex_unlock(&opts->lock);
 234
 235        usb_free_all_descriptors(f);
 236        kfree(func_to_loop(f));
 237}
 238
 239static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
 240{
 241        struct f_loopback       *loop = ep->driver_data;
 242        struct usb_composite_dev *cdev = loop->function.config->cdev;
 243        int                     status = req->status;
 244
 245        switch (status) {
 246        case 0:                         /* normal completion? */
 247                if (ep == loop->out_ep) {
 248                        /*
 249                         * We received some data from the host so let's
 250                         * queue it so host can read the from our in ep
 251                         */
 252                        struct usb_request *in_req = req->context;
 253
 254                        in_req->zero = (req->actual < req->length);
 255                        in_req->length = req->actual;
 256                        ep = loop->in_ep;
 257                        req = in_req;
 258                } else {
 259                        /*
 260                         * We have just looped back a bunch of data
 261                         * to host. Now let's wait for some more data.
 262                         */
 263                        req = req->context;
 264                        ep = loop->out_ep;
 265                }
 266
 267                /* queue the buffer back to host or for next bunch of data */
 268                status = usb_ep_queue(ep, req, GFP_ATOMIC);
 269                if (status == 0) {
 270                        return;
 271                } else {
 272                        ERROR(cdev, "Unable to loop back buffer to %s: %d\n",
 273                              ep->name, status);
 274                        goto free_req;
 275                }
 276
 277                /* "should never get here" */
 278        default:
 279                ERROR(cdev, "%s loop complete --> %d, %d/%d\n", ep->name,
 280                                status, req->actual, req->length);
 281                /* FALLTHROUGH */
 282
 283        /* NOTE:  since this driver doesn't maintain an explicit record
 284         * of requests it submitted (just maintains qlen count), we
 285         * rely on the hardware driver to clean up on disconnect or
 286         * endpoint disable.
 287         */
 288        case -ECONNABORTED:             /* hardware forced ep reset */
 289        case -ECONNRESET:               /* request dequeued */
 290        case -ESHUTDOWN:                /* disconnect from host */
 291free_req:
 292                usb_ep_free_request(ep == loop->in_ep ?
 293                                    loop->out_ep : loop->in_ep,
 294                                    req->context);
 295                free_ep_req(ep, req);
 296                return;
 297        }
 298}
 299
 300static void disable_loopback(struct f_loopback *loop)
 301{
 302        struct usb_composite_dev        *cdev;
 303
 304        cdev = loop->function.config->cdev;
 305        disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL);
 306        VDBG(cdev, "%s disabled\n", loop->function.name);
 307}
 308
 309static inline struct usb_request *lb_alloc_ep_req(struct usb_ep *ep, int len)
 310{
 311        return alloc_ep_req(ep, len);
 312}
 313
 314static int alloc_requests(struct usb_composite_dev *cdev,
 315                          struct f_loopback *loop)
 316{
 317        struct usb_request *in_req, *out_req;
 318        int i;
 319        int result = 0;
 320
 321        /*
 322         * allocate a bunch of read buffers and queue them all at once.
 323         * we buffer at most 'qlen' transfers; We allocate buffers only
 324         * for out transfer and reuse them in IN transfers to implement
 325         * our loopback functionality
 326         */
 327        for (i = 0; i < loop->qlen && result == 0; i++) {
 328                result = -ENOMEM;
 329
 330                in_req = usb_ep_alloc_request(loop->in_ep, GFP_ATOMIC);
 331                if (!in_req)
 332                        goto fail;
 333
 334                out_req = lb_alloc_ep_req(loop->out_ep, loop->buflen);
 335                if (!out_req)
 336                        goto fail_in;
 337
 338                in_req->complete = loopback_complete;
 339                out_req->complete = loopback_complete;
 340
 341                in_req->buf = out_req->buf;
 342                /* length will be set in complete routine */
 343                in_req->context = out_req;
 344                out_req->context = in_req;
 345
 346                result = usb_ep_queue(loop->out_ep, out_req, GFP_ATOMIC);
 347                if (result) {
 348                        ERROR(cdev, "%s queue req --> %d\n",
 349                                        loop->out_ep->name, result);
 350                        goto fail_out;
 351                }
 352        }
 353
 354        return 0;
 355
 356fail_out:
 357        free_ep_req(loop->out_ep, out_req);
 358fail_in:
 359        usb_ep_free_request(loop->in_ep, in_req);
 360fail:
 361        return result;
 362}
 363
 364static int enable_endpoint(struct usb_composite_dev *cdev,
 365                           struct f_loopback *loop, struct usb_ep *ep)
 366{
 367        int                                     result;
 368
 369        result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
 370        if (result)
 371                goto out;
 372
 373        result = usb_ep_enable(ep);
 374        if (result < 0)
 375                goto out;
 376        ep->driver_data = loop;
 377        result = 0;
 378
 379out:
 380        return result;
 381}
 382
 383static int
 384enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
 385{
 386        int                                     result = 0;
 387
 388        result = enable_endpoint(cdev, loop, loop->in_ep);
 389        if (result)
 390                goto out;
 391
 392        result = enable_endpoint(cdev, loop, loop->out_ep);
 393        if (result)
 394                goto disable_in;
 395
 396        result = alloc_requests(cdev, loop);
 397        if (result)
 398                goto disable_out;
 399
 400        DBG(cdev, "%s enabled\n", loop->function.name);
 401        return 0;
 402
 403disable_out:
 404        usb_ep_disable(loop->out_ep);
 405disable_in:
 406        usb_ep_disable(loop->in_ep);
 407out:
 408        return result;
 409}
 410
 411static int loopback_set_alt(struct usb_function *f,
 412                unsigned intf, unsigned alt)
 413{
 414        struct f_loopback       *loop = func_to_loop(f);
 415        struct usb_composite_dev *cdev = f->config->cdev;
 416
 417        /* we know alt is zero */
 418        disable_loopback(loop);
 419        return enable_loopback(cdev, loop);
 420}
 421
 422static void loopback_disable(struct usb_function *f)
 423{
 424        struct f_loopback       *loop = func_to_loop(f);
 425
 426        disable_loopback(loop);
 427}
 428
 429static struct usb_function *loopback_alloc(struct usb_function_instance *fi)
 430{
 431        struct f_loopback       *loop;
 432        struct f_lb_opts        *lb_opts;
 433
 434        loop = kzalloc(sizeof *loop, GFP_KERNEL);
 435        if (!loop)
 436                return ERR_PTR(-ENOMEM);
 437
 438        lb_opts = container_of(fi, struct f_lb_opts, func_inst);
 439
 440        mutex_lock(&lb_opts->lock);
 441        lb_opts->refcnt++;
 442        mutex_unlock(&lb_opts->lock);
 443
 444        loop->buflen = lb_opts->bulk_buflen;
 445        loop->qlen = lb_opts->qlen;
 446        if (!loop->qlen)
 447                loop->qlen = 32;
 448
 449        loop->function.name = "loopback";
 450        loop->function.bind = loopback_bind;
 451        loop->function.set_alt = loopback_set_alt;
 452        loop->function.disable = loopback_disable;
 453        loop->function.strings = loopback_strings;
 454
 455        loop->function.free_func = lb_free_func;
 456
 457        return &loop->function;
 458}
 459
 460static inline struct f_lb_opts *to_f_lb_opts(struct config_item *item)
 461{
 462        return container_of(to_config_group(item), struct f_lb_opts,
 463                            func_inst.group);
 464}
 465
 466static void lb_attr_release(struct config_item *item)
 467{
 468        struct f_lb_opts *lb_opts = to_f_lb_opts(item);
 469
 470        usb_put_function_instance(&lb_opts->func_inst);
 471}
 472
 473static struct configfs_item_operations lb_item_ops = {
 474        .release                = lb_attr_release,
 475};
 476
 477static ssize_t f_lb_opts_qlen_show(struct config_item *item, char *page)
 478{
 479        struct f_lb_opts *opts = to_f_lb_opts(item);
 480        int result;
 481
 482        mutex_lock(&opts->lock);
 483        result = sprintf(page, "%d\n", opts->qlen);
 484        mutex_unlock(&opts->lock);
 485
 486        return result;
 487}
 488
 489static ssize_t f_lb_opts_qlen_store(struct config_item *item,
 490                                    const char *page, size_t len)
 491{
 492        struct f_lb_opts *opts = to_f_lb_opts(item);
 493        int ret;
 494        u32 num;
 495
 496        mutex_lock(&opts->lock);
 497        if (opts->refcnt) {
 498                ret = -EBUSY;
 499                goto end;
 500        }
 501
 502        ret = kstrtou32(page, 0, &num);
 503        if (ret)
 504                goto end;
 505
 506        opts->qlen = num;
 507        ret = len;
 508end:
 509        mutex_unlock(&opts->lock);
 510        return ret;
 511}
 512
 513CONFIGFS_ATTR(f_lb_opts_, qlen);
 514
 515static ssize_t f_lb_opts_bulk_buflen_show(struct config_item *item, char *page)
 516{
 517        struct f_lb_opts *opts = to_f_lb_opts(item);
 518        int result;
 519
 520        mutex_lock(&opts->lock);
 521        result = sprintf(page, "%d\n", opts->bulk_buflen);
 522        mutex_unlock(&opts->lock);
 523
 524        return result;
 525}
 526
 527static ssize_t f_lb_opts_bulk_buflen_store(struct config_item *item,
 528                                    const char *page, size_t len)
 529{
 530        struct f_lb_opts *opts = to_f_lb_opts(item);
 531        int ret;
 532        u32 num;
 533
 534        mutex_lock(&opts->lock);
 535        if (opts->refcnt) {
 536                ret = -EBUSY;
 537                goto end;
 538        }
 539
 540        ret = kstrtou32(page, 0, &num);
 541        if (ret)
 542                goto end;
 543
 544        opts->bulk_buflen = num;
 545        ret = len;
 546end:
 547        mutex_unlock(&opts->lock);
 548        return ret;
 549}
 550
 551CONFIGFS_ATTR(f_lb_opts_, bulk_buflen);
 552
 553static struct configfs_attribute *lb_attrs[] = {
 554        &f_lb_opts_attr_qlen,
 555        &f_lb_opts_attr_bulk_buflen,
 556        NULL,
 557};
 558
 559static struct config_item_type lb_func_type = {
 560        .ct_item_ops    = &lb_item_ops,
 561        .ct_attrs       = lb_attrs,
 562        .ct_owner       = THIS_MODULE,
 563};
 564
 565static void lb_free_instance(struct usb_function_instance *fi)
 566{
 567        struct f_lb_opts *lb_opts;
 568
 569        lb_opts = container_of(fi, struct f_lb_opts, func_inst);
 570        kfree(lb_opts);
 571}
 572
 573static struct usb_function_instance *loopback_alloc_instance(void)
 574{
 575        struct f_lb_opts *lb_opts;
 576
 577        lb_opts = kzalloc(sizeof(*lb_opts), GFP_KERNEL);
 578        if (!lb_opts)
 579                return ERR_PTR(-ENOMEM);
 580        mutex_init(&lb_opts->lock);
 581        lb_opts->func_inst.free_func_inst = lb_free_instance;
 582        lb_opts->bulk_buflen = GZERO_BULK_BUFLEN;
 583        lb_opts->qlen = GZERO_QLEN;
 584
 585        config_group_init_type_name(&lb_opts->func_inst.group, "",
 586                                    &lb_func_type);
 587
 588        return  &lb_opts->func_inst;
 589}
 590DECLARE_USB_FUNCTION(Loopback, loopback_alloc_instance, loopback_alloc);
 591
 592int __init lb_modinit(void)
 593{
 594        return usb_function_register(&Loopbackusb_func);
 595}
 596
 597void __exit lb_modexit(void)
 598{
 599        usb_function_unregister(&Loopbackusb_func);
 600}
 601
 602MODULE_LICENSE("GPL");
 603