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