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);
 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        struct f_loopback       *loop = ep->driver_data;
 312
 313        return alloc_ep_req(ep, len, loop->buflen);
 314}
 315
 316static int alloc_requests(struct usb_composite_dev *cdev,
 317                          struct f_loopback *loop)
 318{
 319        struct usb_request *in_req, *out_req;
 320        int i;
 321        int result = 0;
 322
 323        /*
 324         * allocate a bunch of read buffers and queue them all at once.
 325         * we buffer at most 'qlen' transfers; We allocate buffers only
 326         * for out transfer and reuse them in IN transfers to implement
 327         * our loopback functionality
 328         */
 329        for (i = 0; i < loop->qlen && result == 0; i++) {
 330                result = -ENOMEM;
 331
 332                in_req = usb_ep_alloc_request(loop->in_ep, GFP_ATOMIC);
 333                if (!in_req)
 334                        goto fail;
 335
 336                out_req = lb_alloc_ep_req(loop->out_ep, 0);
 337                if (!out_req)
 338                        goto fail_in;
 339
 340                in_req->complete = loopback_complete;
 341                out_req->complete = loopback_complete;
 342
 343                in_req->buf = out_req->buf;
 344                /* length will be set in complete routine */
 345                in_req->context = out_req;
 346                out_req->context = in_req;
 347
 348                result = usb_ep_queue(loop->out_ep, out_req, GFP_ATOMIC);
 349                if (result) {
 350                        ERROR(cdev, "%s queue req --> %d\n",
 351                                        loop->out_ep->name, result);
 352                        goto fail_out;
 353                }
 354        }
 355
 356        return 0;
 357
 358fail_out:
 359        free_ep_req(loop->out_ep, out_req);
 360fail_in:
 361        usb_ep_free_request(loop->in_ep, in_req);
 362fail:
 363        return result;
 364}
 365
 366static int enable_endpoint(struct usb_composite_dev *cdev,
 367                           struct f_loopback *loop, struct usb_ep *ep)
 368{
 369        int                                     result;
 370
 371        result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
 372        if (result)
 373                goto out;
 374
 375        result = usb_ep_enable(ep);
 376        if (result < 0)
 377                goto out;
 378        ep->driver_data = loop;
 379        result = 0;
 380
 381out:
 382        return result;
 383}
 384
 385static int
 386enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
 387{
 388        int                                     result = 0;
 389
 390        result = enable_endpoint(cdev, loop, loop->in_ep);
 391        if (result)
 392                goto out;
 393
 394        result = enable_endpoint(cdev, loop, loop->out_ep);
 395        if (result)
 396                goto disable_in;
 397
 398        result = alloc_requests(cdev, loop);
 399        if (result)
 400                goto disable_out;
 401
 402        DBG(cdev, "%s enabled\n", loop->function.name);
 403        return 0;
 404
 405disable_out:
 406        usb_ep_disable(loop->out_ep);
 407disable_in:
 408        usb_ep_disable(loop->in_ep);
 409out:
 410        return result;
 411}
 412
 413static int loopback_set_alt(struct usb_function *f,
 414                unsigned intf, unsigned alt)
 415{
 416        struct f_loopback       *loop = func_to_loop(f);
 417        struct usb_composite_dev *cdev = f->config->cdev;
 418
 419        /* we know alt is zero */
 420        disable_loopback(loop);
 421        return enable_loopback(cdev, loop);
 422}
 423
 424static void loopback_disable(struct usb_function *f)
 425{
 426        struct f_loopback       *loop = func_to_loop(f);
 427
 428        disable_loopback(loop);
 429}
 430
 431static struct usb_function *loopback_alloc(struct usb_function_instance *fi)
 432{
 433        struct f_loopback       *loop;
 434        struct f_lb_opts        *lb_opts;
 435
 436        loop = kzalloc(sizeof *loop, GFP_KERNEL);
 437        if (!loop)
 438                return ERR_PTR(-ENOMEM);
 439
 440        lb_opts = container_of(fi, struct f_lb_opts, func_inst);
 441
 442        mutex_lock(&lb_opts->lock);
 443        lb_opts->refcnt++;
 444        mutex_unlock(&lb_opts->lock);
 445
 446        loop->buflen = lb_opts->bulk_buflen;
 447        loop->qlen = lb_opts->qlen;
 448        if (!loop->qlen)
 449                loop->qlen = 32;
 450
 451        loop->function.name = "loopback";
 452        loop->function.bind = loopback_bind;
 453        loop->function.set_alt = loopback_set_alt;
 454        loop->function.disable = loopback_disable;
 455        loop->function.strings = loopback_strings;
 456
 457        loop->function.free_func = lb_free_func;
 458
 459        return &loop->function;
 460}
 461
 462static inline struct f_lb_opts *to_f_lb_opts(struct config_item *item)
 463{
 464        return container_of(to_config_group(item), struct f_lb_opts,
 465                            func_inst.group);
 466}
 467
 468static void lb_attr_release(struct config_item *item)
 469{
 470        struct f_lb_opts *lb_opts = to_f_lb_opts(item);
 471
 472        usb_put_function_instance(&lb_opts->func_inst);
 473}
 474
 475static struct configfs_item_operations lb_item_ops = {
 476        .release                = lb_attr_release,
 477};
 478
 479static ssize_t f_lb_opts_qlen_show(struct config_item *item, char *page)
 480{
 481        struct f_lb_opts *opts = to_f_lb_opts(item);
 482        int result;
 483
 484        mutex_lock(&opts->lock);
 485        result = sprintf(page, "%d\n", opts->qlen);
 486        mutex_unlock(&opts->lock);
 487
 488        return result;
 489}
 490
 491static ssize_t f_lb_opts_qlen_store(struct config_item *item,
 492                                    const char *page, size_t len)
 493{
 494        struct f_lb_opts *opts = to_f_lb_opts(item);
 495        int ret;
 496        u32 num;
 497
 498        mutex_lock(&opts->lock);
 499        if (opts->refcnt) {
 500                ret = -EBUSY;
 501                goto end;
 502        }
 503
 504        ret = kstrtou32(page, 0, &num);
 505        if (ret)
 506                goto end;
 507
 508        opts->qlen = num;
 509        ret = len;
 510end:
 511        mutex_unlock(&opts->lock);
 512        return ret;
 513}
 514
 515CONFIGFS_ATTR(f_lb_opts_, qlen);
 516
 517static ssize_t f_lb_opts_bulk_buflen_show(struct config_item *item, char *page)
 518{
 519        struct f_lb_opts *opts = to_f_lb_opts(item);
 520        int result;
 521
 522        mutex_lock(&opts->lock);
 523        result = sprintf(page, "%d\n", opts->bulk_buflen);
 524        mutex_unlock(&opts->lock);
 525
 526        return result;
 527}
 528
 529static ssize_t f_lb_opts_bulk_buflen_store(struct config_item *item,
 530                                    const char *page, size_t len)
 531{
 532        struct f_lb_opts *opts = to_f_lb_opts(item);
 533        int ret;
 534        u32 num;
 535
 536        mutex_lock(&opts->lock);
 537        if (opts->refcnt) {
 538                ret = -EBUSY;
 539                goto end;
 540        }
 541
 542        ret = kstrtou32(page, 0, &num);
 543        if (ret)
 544                goto end;
 545
 546        opts->bulk_buflen = num;
 547        ret = len;
 548end:
 549        mutex_unlock(&opts->lock);
 550        return ret;
 551}
 552
 553CONFIGFS_ATTR(f_lb_opts_, bulk_buflen);
 554
 555static struct configfs_attribute *lb_attrs[] = {
 556        &f_lb_opts_attr_qlen,
 557        &f_lb_opts_attr_bulk_buflen,
 558        NULL,
 559};
 560
 561static struct config_item_type lb_func_type = {
 562        .ct_item_ops    = &lb_item_ops,
 563        .ct_attrs       = lb_attrs,
 564        .ct_owner       = THIS_MODULE,
 565};
 566
 567static void lb_free_instance(struct usb_function_instance *fi)
 568{
 569        struct f_lb_opts *lb_opts;
 570
 571        lb_opts = container_of(fi, struct f_lb_opts, func_inst);
 572        kfree(lb_opts);
 573}
 574
 575static struct usb_function_instance *loopback_alloc_instance(void)
 576{
 577        struct f_lb_opts *lb_opts;
 578
 579        lb_opts = kzalloc(sizeof(*lb_opts), GFP_KERNEL);
 580        if (!lb_opts)
 581                return ERR_PTR(-ENOMEM);
 582        mutex_init(&lb_opts->lock);
 583        lb_opts->func_inst.free_func_inst = lb_free_instance;
 584        lb_opts->bulk_buflen = GZERO_BULK_BUFLEN;
 585        lb_opts->qlen = GZERO_QLEN;
 586
 587        config_group_init_type_name(&lb_opts->func_inst.group, "",
 588                                    &lb_func_type);
 589
 590        return  &lb_opts->func_inst;
 591}
 592DECLARE_USB_FUNCTION(Loopback, loopback_alloc_instance, loopback_alloc);
 593
 594int __init lb_modinit(void)
 595{
 596        int ret;
 597
 598        ret = usb_function_register(&Loopbackusb_func);
 599        if (ret)
 600                return ret;
 601        return ret;
 602}
 603void __exit lb_modexit(void)
 604{
 605        usb_function_unregister(&Loopbackusb_func);
 606}
 607
 608MODULE_LICENSE("GPL");
 609