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
  39static inline struct f_loopback *func_to_loop(struct usb_function *f)
  40{
  41        return container_of(f, struct f_loopback, function);
  42}
  43
  44static unsigned qlen;
  45static unsigned buflen;
  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        loop->in_ep->driver_data = cdev;        /* claim */
 199
 200        loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_sink_desc);
 201        if (!loop->out_ep)
 202                goto autoconf_fail;
 203        loop->out_ep->driver_data = cdev;       /* claim */
 204
 205        /* support high speed hardware */
 206        hs_loop_source_desc.bEndpointAddress =
 207                fs_loop_source_desc.bEndpointAddress;
 208        hs_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress;
 209
 210        /* support super speed hardware */
 211        ss_loop_source_desc.bEndpointAddress =
 212                fs_loop_source_desc.bEndpointAddress;
 213        ss_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress;
 214
 215        ret = usb_assign_descriptors(f, fs_loopback_descs, hs_loopback_descs,
 216                        ss_loopback_descs);
 217        if (ret)
 218                return ret;
 219
 220        DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
 221            (gadget_is_superspeed(c->cdev->gadget) ? "super" :
 222             (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
 223                        f->name, loop->in_ep->name, loop->out_ep->name);
 224        return 0;
 225}
 226
 227static void lb_free_func(struct usb_function *f)
 228{
 229        struct f_lb_opts *opts;
 230
 231        opts = container_of(f->fi, struct f_lb_opts, func_inst);
 232
 233        mutex_lock(&opts->lock);
 234        opts->refcnt--;
 235        mutex_unlock(&opts->lock);
 236
 237        usb_free_all_descriptors(f);
 238        kfree(func_to_loop(f));
 239}
 240
 241static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
 242{
 243        struct f_loopback       *loop = ep->driver_data;
 244        struct usb_composite_dev *cdev = loop->function.config->cdev;
 245        int                     status = req->status;
 246
 247        switch (status) {
 248
 249        case 0:                         /* normal completion? */
 250                if (ep == loop->out_ep) {
 251                        req->zero = (req->actual < req->length);
 252                        req->length = req->actual;
 253                }
 254
 255                /* queue the buffer for some later OUT packet */
 256                req->length = buflen;
 257                status = usb_ep_queue(ep, req, GFP_ATOMIC);
 258                if (status == 0)
 259                        return;
 260
 261                /* "should never get here" */
 262                /* FALLTHROUGH */
 263
 264        default:
 265                ERROR(cdev, "%s loop complete --> %d, %d/%d\n", ep->name,
 266                                status, req->actual, req->length);
 267                /* FALLTHROUGH */
 268
 269        /* NOTE:  since this driver doesn't maintain an explicit record
 270         * of requests it submitted (just maintains qlen count), we
 271         * rely on the hardware driver to clean up on disconnect or
 272         * endpoint disable.
 273         */
 274        case -ECONNABORTED:             /* hardware forced ep reset */
 275        case -ECONNRESET:               /* request dequeued */
 276        case -ESHUTDOWN:                /* disconnect from host */
 277                free_ep_req(ep, req);
 278                return;
 279        }
 280}
 281
 282static void disable_loopback(struct f_loopback *loop)
 283{
 284        struct usb_composite_dev        *cdev;
 285
 286        cdev = loop->function.config->cdev;
 287        disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL);
 288        VDBG(cdev, "%s disabled\n", loop->function.name);
 289}
 290
 291static inline struct usb_request *lb_alloc_ep_req(struct usb_ep *ep, int len)
 292{
 293        return alloc_ep_req(ep, len, buflen);
 294}
 295
 296static int enable_endpoint(struct usb_composite_dev *cdev, struct f_loopback *loop,
 297                struct usb_ep *ep)
 298{
 299        struct usb_request                      *req;
 300        unsigned                                i;
 301        int                                     result;
 302
 303        /*
 304         * one endpoint writes data back IN to the host while another endpoint
 305         * just reads OUT packets
 306         */
 307        result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
 308        if (result)
 309                goto fail0;
 310        result = usb_ep_enable(ep);
 311        if (result < 0)
 312                goto fail0;
 313        ep->driver_data = loop;
 314
 315        /*
 316         * allocate a bunch of read buffers and queue them all at once.
 317         * we buffer at most 'qlen' transfers; fewer if any need more
 318         * than 'buflen' bytes each.
 319         */
 320        for (i = 0; i < qlen && result == 0; i++) {
 321                req = lb_alloc_ep_req(ep, 0);
 322                if (!req)
 323                        goto fail1;
 324
 325                req->complete = loopback_complete;
 326                result = usb_ep_queue(ep, req, GFP_ATOMIC);
 327                if (result) {
 328                        ERROR(cdev, "%s queue req --> %d\n",
 329                                        ep->name, result);
 330                        goto fail1;
 331                }
 332        }
 333
 334        return 0;
 335
 336fail1:
 337        usb_ep_disable(ep);
 338
 339fail0:
 340        return result;
 341}
 342
 343static int
 344enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
 345{
 346        int                                     result = 0;
 347
 348        result = enable_endpoint(cdev, loop, loop->in_ep);
 349        if (result)
 350                return result;
 351
 352        result = enable_endpoint(cdev, loop, loop->out_ep);
 353        if (result)
 354                return result;
 355
 356        DBG(cdev, "%s enabled\n", loop->function.name);
 357        return result;
 358}
 359
 360static int loopback_set_alt(struct usb_function *f,
 361                unsigned intf, unsigned alt)
 362{
 363        struct f_loopback       *loop = func_to_loop(f);
 364        struct usb_composite_dev *cdev = f->config->cdev;
 365
 366        /* we know alt is zero */
 367        if (loop->in_ep->driver_data)
 368                disable_loopback(loop);
 369        return enable_loopback(cdev, loop);
 370}
 371
 372static void loopback_disable(struct usb_function *f)
 373{
 374        struct f_loopback       *loop = func_to_loop(f);
 375
 376        disable_loopback(loop);
 377}
 378
 379static struct usb_function *loopback_alloc(struct usb_function_instance *fi)
 380{
 381        struct f_loopback       *loop;
 382        struct f_lb_opts        *lb_opts;
 383
 384        loop = kzalloc(sizeof *loop, GFP_KERNEL);
 385        if (!loop)
 386                return ERR_PTR(-ENOMEM);
 387
 388        lb_opts = container_of(fi, struct f_lb_opts, func_inst);
 389
 390        mutex_lock(&lb_opts->lock);
 391        lb_opts->refcnt++;
 392        mutex_unlock(&lb_opts->lock);
 393
 394        buflen = lb_opts->bulk_buflen;
 395        qlen = lb_opts->qlen;
 396        if (!qlen)
 397                qlen = 32;
 398
 399        loop->function.name = "loopback";
 400        loop->function.bind = loopback_bind;
 401        loop->function.set_alt = loopback_set_alt;
 402        loop->function.disable = loopback_disable;
 403        loop->function.strings = loopback_strings;
 404
 405        loop->function.free_func = lb_free_func;
 406
 407        return &loop->function;
 408}
 409
 410static inline struct f_lb_opts *to_f_lb_opts(struct config_item *item)
 411{
 412        return container_of(to_config_group(item), struct f_lb_opts,
 413                            func_inst.group);
 414}
 415
 416CONFIGFS_ATTR_STRUCT(f_lb_opts);
 417CONFIGFS_ATTR_OPS(f_lb_opts);
 418
 419static void lb_attr_release(struct config_item *item)
 420{
 421        struct f_lb_opts *lb_opts = to_f_lb_opts(item);
 422
 423        usb_put_function_instance(&lb_opts->func_inst);
 424}
 425
 426static struct configfs_item_operations lb_item_ops = {
 427        .release                = lb_attr_release,
 428        .show_attribute         = f_lb_opts_attr_show,
 429        .store_attribute        = f_lb_opts_attr_store,
 430};
 431
 432static ssize_t f_lb_opts_qlen_show(struct f_lb_opts *opts, char *page)
 433{
 434        int result;
 435
 436        mutex_lock(&opts->lock);
 437        result = sprintf(page, "%d", opts->qlen);
 438        mutex_unlock(&opts->lock);
 439
 440        return result;
 441}
 442
 443static ssize_t f_lb_opts_qlen_store(struct f_lb_opts *opts,
 444                                    const char *page, size_t len)
 445{
 446        int ret;
 447        u32 num;
 448
 449        mutex_lock(&opts->lock);
 450        if (opts->refcnt) {
 451                ret = -EBUSY;
 452                goto end;
 453        }
 454
 455        ret = kstrtou32(page, 0, &num);
 456        if (ret)
 457                goto end;
 458
 459        opts->qlen = num;
 460        ret = len;
 461end:
 462        mutex_unlock(&opts->lock);
 463        return ret;
 464}
 465
 466static struct f_lb_opts_attribute f_lb_opts_qlen =
 467        __CONFIGFS_ATTR(qlen, S_IRUGO | S_IWUSR,
 468                        f_lb_opts_qlen_show,
 469                        f_lb_opts_qlen_store);
 470
 471static ssize_t f_lb_opts_bulk_buflen_show(struct f_lb_opts *opts, char *page)
 472{
 473        int result;
 474
 475        mutex_lock(&opts->lock);
 476        result = sprintf(page, "%d", opts->bulk_buflen);
 477        mutex_unlock(&opts->lock);
 478
 479        return result;
 480}
 481
 482static ssize_t f_lb_opts_bulk_buflen_store(struct f_lb_opts *opts,
 483                                    const char *page, size_t len)
 484{
 485        int ret;
 486        u32 num;
 487
 488        mutex_lock(&opts->lock);
 489        if (opts->refcnt) {
 490                ret = -EBUSY;
 491                goto end;
 492        }
 493
 494        ret = kstrtou32(page, 0, &num);
 495        if (ret)
 496                goto end;
 497
 498        opts->bulk_buflen = num;
 499        ret = len;
 500end:
 501        mutex_unlock(&opts->lock);
 502        return ret;
 503}
 504
 505static struct f_lb_opts_attribute f_lb_opts_bulk_buflen =
 506        __CONFIGFS_ATTR(buflen, S_IRUGO | S_IWUSR,
 507                        f_lb_opts_bulk_buflen_show,
 508                        f_lb_opts_bulk_buflen_store);
 509
 510static struct configfs_attribute *lb_attrs[] = {
 511        &f_lb_opts_qlen.attr,
 512        &f_lb_opts_bulk_buflen.attr,
 513        NULL,
 514};
 515
 516static struct config_item_type lb_func_type = {
 517        .ct_item_ops    = &lb_item_ops,
 518        .ct_attrs       = lb_attrs,
 519        .ct_owner       = THIS_MODULE,
 520};
 521
 522static void lb_free_instance(struct usb_function_instance *fi)
 523{
 524        struct f_lb_opts *lb_opts;
 525
 526        lb_opts = container_of(fi, struct f_lb_opts, func_inst);
 527        kfree(lb_opts);
 528}
 529
 530static struct usb_function_instance *loopback_alloc_instance(void)
 531{
 532        struct f_lb_opts *lb_opts;
 533
 534        lb_opts = kzalloc(sizeof(*lb_opts), GFP_KERNEL);
 535        if (!lb_opts)
 536                return ERR_PTR(-ENOMEM);
 537        mutex_init(&lb_opts->lock);
 538        lb_opts->func_inst.free_func_inst = lb_free_instance;
 539        lb_opts->bulk_buflen = GZERO_BULK_BUFLEN;
 540        lb_opts->qlen = GZERO_QLEN;
 541
 542        config_group_init_type_name(&lb_opts->func_inst.group, "",
 543                                    &lb_func_type);
 544
 545        return  &lb_opts->func_inst;
 546}
 547DECLARE_USB_FUNCTION(Loopback, loopback_alloc_instance, loopback_alloc);
 548
 549int __init lb_modinit(void)
 550{
 551        int ret;
 552
 553        ret = usb_function_register(&Loopbackusb_func);
 554        if (ret)
 555                return ret;
 556        return ret;
 557}
 558void __exit lb_modexit(void)
 559{
 560        usb_function_unregister(&Loopbackusb_func);
 561}
 562
 563MODULE_LICENSE("GPL");
 564