linux/drivers/usb/gadget/legacy/dbgp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * dbgp.c -- EHCI Debug Port device gadget
   4 *
   5 * Copyright (C) 2010 Stephane Duverger
   6 *
   7 * Released under the GPLv2.
   8 */
   9
  10/* verbose messages */
  11#include <linux/kernel.h>
  12#include <linux/device.h>
  13#include <linux/module.h>
  14#include <linux/usb/ch9.h>
  15#include <linux/usb/gadget.h>
  16
  17#include "u_serial.h"
  18
  19#define DRIVER_VENDOR_ID        0x0525 /* NetChip */
  20#define DRIVER_PRODUCT_ID       0xc0de /* undefined */
  21
  22#define USB_DEBUG_MAX_PACKET_SIZE     8
  23#define DBGP_REQ_EP0_LEN              128
  24#define DBGP_REQ_LEN                  512
  25
  26static struct dbgp {
  27        struct usb_gadget  *gadget;
  28        struct usb_request *req;
  29        struct usb_ep      *i_ep;
  30        struct usb_ep      *o_ep;
  31#ifdef CONFIG_USB_G_DBGP_SERIAL
  32        struct gserial     *serial;
  33#endif
  34} dbgp;
  35
  36static struct usb_device_descriptor device_desc = {
  37        .bLength = sizeof device_desc,
  38        .bDescriptorType = USB_DT_DEVICE,
  39        .bcdUSB = cpu_to_le16(0x0200),
  40        .bDeviceClass = USB_CLASS_VENDOR_SPEC,
  41        .idVendor = cpu_to_le16(DRIVER_VENDOR_ID),
  42        .idProduct = cpu_to_le16(DRIVER_PRODUCT_ID),
  43        .bNumConfigurations = 1,
  44};
  45
  46static struct usb_debug_descriptor dbg_desc = {
  47        .bLength = sizeof dbg_desc,
  48        .bDescriptorType = USB_DT_DEBUG,
  49};
  50
  51static struct usb_endpoint_descriptor i_desc = {
  52        .bLength = USB_DT_ENDPOINT_SIZE,
  53        .bDescriptorType = USB_DT_ENDPOINT,
  54        .bmAttributes = USB_ENDPOINT_XFER_BULK,
  55        .bEndpointAddress = USB_DIR_IN,
  56};
  57
  58static struct usb_endpoint_descriptor o_desc = {
  59        .bLength = USB_DT_ENDPOINT_SIZE,
  60        .bDescriptorType = USB_DT_ENDPOINT,
  61        .bmAttributes = USB_ENDPOINT_XFER_BULK,
  62        .bEndpointAddress = USB_DIR_OUT,
  63};
  64
  65#ifdef CONFIG_USB_G_DBGP_PRINTK
  66static int dbgp_consume(char *buf, unsigned len)
  67{
  68        char c;
  69
  70        if (!len)
  71                return 0;
  72
  73        c = buf[len-1];
  74        if (c != 0)
  75                buf[len-1] = 0;
  76
  77        printk(KERN_NOTICE "%s%c", buf, c);
  78        return 0;
  79}
  80
  81static void __disable_ep(struct usb_ep *ep)
  82{
  83        usb_ep_disable(ep);
  84}
  85
  86static void dbgp_disable_ep(void)
  87{
  88        __disable_ep(dbgp.i_ep);
  89        __disable_ep(dbgp.o_ep);
  90}
  91
  92static void dbgp_complete(struct usb_ep *ep, struct usb_request *req)
  93{
  94        int stp;
  95        int err = 0;
  96        int status = req->status;
  97
  98        if (ep == dbgp.i_ep) {
  99                stp = 1;
 100                goto fail;
 101        }
 102
 103        if (status != 0) {
 104                stp = 2;
 105                goto release_req;
 106        }
 107
 108        dbgp_consume(req->buf, req->actual);
 109
 110        req->length = DBGP_REQ_LEN;
 111        err = usb_ep_queue(ep, req, GFP_ATOMIC);
 112        if (err < 0) {
 113                stp = 3;
 114                goto release_req;
 115        }
 116
 117        return;
 118
 119release_req:
 120        kfree(req->buf);
 121        usb_ep_free_request(dbgp.o_ep, req);
 122        dbgp_disable_ep();
 123fail:
 124        dev_dbg(&dbgp.gadget->dev,
 125                "complete: failure (%d:%d) ==> %d\n", stp, err, status);
 126}
 127
 128static int dbgp_enable_ep_req(struct usb_ep *ep)
 129{
 130        int err, stp;
 131        struct usb_request *req;
 132
 133        req = usb_ep_alloc_request(ep, GFP_KERNEL);
 134        if (!req) {
 135                err = -ENOMEM;
 136                stp = 1;
 137                goto fail_1;
 138        }
 139
 140        req->buf = kmalloc(DBGP_REQ_LEN, GFP_KERNEL);
 141        if (!req->buf) {
 142                err = -ENOMEM;
 143                stp = 2;
 144                goto fail_2;
 145        }
 146
 147        req->complete = dbgp_complete;
 148        req->length = DBGP_REQ_LEN;
 149        err = usb_ep_queue(ep, req, GFP_ATOMIC);
 150        if (err < 0) {
 151                stp = 3;
 152                goto fail_3;
 153        }
 154
 155        return 0;
 156
 157fail_3:
 158        kfree(req->buf);
 159fail_2:
 160        usb_ep_free_request(dbgp.o_ep, req);
 161fail_1:
 162        dev_dbg(&dbgp.gadget->dev,
 163                "enable ep req: failure (%d:%d)\n", stp, err);
 164        return err;
 165}
 166
 167static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc)
 168{
 169        int err;
 170        ep->desc = desc;
 171        err = usb_ep_enable(ep);
 172        return err;
 173}
 174
 175static int dbgp_enable_ep(void)
 176{
 177        int err, stp;
 178
 179        err = __enable_ep(dbgp.i_ep, &i_desc);
 180        if (err < 0) {
 181                stp = 1;
 182                goto fail_1;
 183        }
 184
 185        err = __enable_ep(dbgp.o_ep, &o_desc);
 186        if (err < 0) {
 187                stp = 2;
 188                goto fail_2;
 189        }
 190
 191        err = dbgp_enable_ep_req(dbgp.o_ep);
 192        if (err < 0) {
 193                stp = 3;
 194                goto fail_3;
 195        }
 196
 197        return 0;
 198
 199fail_3:
 200        __disable_ep(dbgp.o_ep);
 201fail_2:
 202        __disable_ep(dbgp.i_ep);
 203fail_1:
 204        dev_dbg(&dbgp.gadget->dev, "enable ep: failure (%d:%d)\n", stp, err);
 205        return err;
 206}
 207#endif
 208
 209static void dbgp_disconnect(struct usb_gadget *gadget)
 210{
 211#ifdef CONFIG_USB_G_DBGP_PRINTK
 212        dbgp_disable_ep();
 213#else
 214        gserial_disconnect(dbgp.serial);
 215#endif
 216}
 217
 218static void dbgp_unbind(struct usb_gadget *gadget)
 219{
 220#ifdef CONFIG_USB_G_DBGP_SERIAL
 221        kfree(dbgp.serial);
 222        dbgp.serial = NULL;
 223#endif
 224        if (dbgp.req) {
 225                kfree(dbgp.req->buf);
 226                usb_ep_free_request(gadget->ep0, dbgp.req);
 227                dbgp.req = NULL;
 228        }
 229}
 230
 231#ifdef CONFIG_USB_G_DBGP_SERIAL
 232static unsigned char tty_line;
 233#endif
 234
 235static int dbgp_configure_endpoints(struct usb_gadget *gadget)
 236{
 237        int stp;
 238
 239        usb_ep_autoconfig_reset(gadget);
 240
 241        dbgp.i_ep = usb_ep_autoconfig(gadget, &i_desc);
 242        if (!dbgp.i_ep) {
 243                stp = 1;
 244                goto fail_1;
 245        }
 246
 247        i_desc.wMaxPacketSize =
 248                cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
 249
 250        dbgp.o_ep = usb_ep_autoconfig(gadget, &o_desc);
 251        if (!dbgp.o_ep) {
 252                stp = 2;
 253                goto fail_1;
 254        }
 255
 256        o_desc.wMaxPacketSize =
 257                cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
 258
 259        dbg_desc.bDebugInEndpoint = i_desc.bEndpointAddress;
 260        dbg_desc.bDebugOutEndpoint = o_desc.bEndpointAddress;
 261
 262#ifdef CONFIG_USB_G_DBGP_SERIAL
 263        dbgp.serial->in = dbgp.i_ep;
 264        dbgp.serial->out = dbgp.o_ep;
 265
 266        dbgp.serial->in->desc = &i_desc;
 267        dbgp.serial->out->desc = &o_desc;
 268#endif
 269
 270        return 0;
 271
 272fail_1:
 273        dev_dbg(&dbgp.gadget->dev, "ep config: failure (%d)\n", stp);
 274        return -ENODEV;
 275}
 276
 277static int dbgp_bind(struct usb_gadget *gadget,
 278                struct usb_gadget_driver *driver)
 279{
 280        int err, stp;
 281
 282        dbgp.gadget = gadget;
 283
 284        dbgp.req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
 285        if (!dbgp.req) {
 286                err = -ENOMEM;
 287                stp = 1;
 288                goto fail;
 289        }
 290
 291        dbgp.req->buf = kmalloc(DBGP_REQ_EP0_LEN, GFP_KERNEL);
 292        if (!dbgp.req->buf) {
 293                err = -ENOMEM;
 294                stp = 2;
 295                goto fail;
 296        }
 297
 298        dbgp.req->length = DBGP_REQ_EP0_LEN;
 299
 300#ifdef CONFIG_USB_G_DBGP_SERIAL
 301        dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL);
 302        if (!dbgp.serial) {
 303                stp = 3;
 304                err = -ENOMEM;
 305                goto fail;
 306        }
 307
 308        if (gserial_alloc_line(&tty_line)) {
 309                stp = 4;
 310                err = -ENODEV;
 311                goto fail;
 312        }
 313#endif
 314
 315        err = dbgp_configure_endpoints(gadget);
 316        if (err < 0) {
 317                stp = 5;
 318                goto fail;
 319        }
 320
 321        dev_dbg(&dbgp.gadget->dev, "bind: success\n");
 322        return 0;
 323
 324fail:
 325        dev_dbg(&gadget->dev, "bind: failure (%d:%d)\n", stp, err);
 326        dbgp_unbind(gadget);
 327        return err;
 328}
 329
 330static void dbgp_setup_complete(struct usb_ep *ep,
 331                                struct usb_request *req)
 332{
 333        dev_dbg(&dbgp.gadget->dev, "setup complete: %d, %d/%d\n",
 334                req->status, req->actual, req->length);
 335}
 336
 337static int dbgp_setup(struct usb_gadget *gadget,
 338                      const struct usb_ctrlrequest *ctrl)
 339{
 340        struct usb_request *req = dbgp.req;
 341        u8 request = ctrl->bRequest;
 342        u16 value = le16_to_cpu(ctrl->wValue);
 343        u16 length = le16_to_cpu(ctrl->wLength);
 344        int err = -EOPNOTSUPP;
 345        void *data = NULL;
 346        u16 len = 0;
 347
 348        if (request == USB_REQ_GET_DESCRIPTOR) {
 349                switch (value>>8) {
 350                case USB_DT_DEVICE:
 351                        dev_dbg(&dbgp.gadget->dev, "setup: desc device\n");
 352                        len = sizeof device_desc;
 353                        data = &device_desc;
 354                        device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 355                        break;
 356                case USB_DT_DEBUG:
 357                        dev_dbg(&dbgp.gadget->dev, "setup: desc debug\n");
 358                        len = sizeof dbg_desc;
 359                        data = &dbg_desc;
 360                        break;
 361                default:
 362                        goto fail;
 363                }
 364                err = 0;
 365        } else if (request == USB_REQ_SET_FEATURE &&
 366                   value == USB_DEVICE_DEBUG_MODE) {
 367                dev_dbg(&dbgp.gadget->dev, "setup: feat debug\n");
 368#ifdef CONFIG_USB_G_DBGP_PRINTK
 369                err = dbgp_enable_ep();
 370#else
 371                err = dbgp_configure_endpoints(gadget);
 372                if (err < 0) {
 373                        goto fail;
 374                }
 375                err = gserial_connect(dbgp.serial, tty_line);
 376#endif
 377                if (err < 0)
 378                        goto fail;
 379        } else
 380                goto fail;
 381
 382        req->length = min(length, len);
 383        req->zero = len < req->length;
 384        if (data && req->length)
 385                memcpy(req->buf, data, req->length);
 386
 387        req->complete = dbgp_setup_complete;
 388        return usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
 389
 390fail:
 391        dev_dbg(&dbgp.gadget->dev,
 392                "setup: failure req %x v %x\n", request, value);
 393        return err;
 394}
 395
 396static struct usb_gadget_driver dbgp_driver = {
 397        .function = "dbgp",
 398        .max_speed = USB_SPEED_HIGH,
 399        .bind = dbgp_bind,
 400        .unbind = dbgp_unbind,
 401        .setup = dbgp_setup,
 402        .reset = dbgp_disconnect,
 403        .disconnect = dbgp_disconnect,
 404        .driver = {
 405                .owner = THIS_MODULE,
 406                .name = "dbgp"
 407        },
 408};
 409
 410static int __init dbgp_init(void)
 411{
 412        return usb_gadget_probe_driver(&dbgp_driver);
 413}
 414
 415static void __exit dbgp_exit(void)
 416{
 417        usb_gadget_unregister_driver(&dbgp_driver);
 418#ifdef CONFIG_USB_G_DBGP_SERIAL
 419        gserial_free_line(tty_line);
 420#endif
 421}
 422
 423MODULE_AUTHOR("Stephane Duverger");
 424MODULE_LICENSE("GPL");
 425module_init(dbgp_init);
 426module_exit(dbgp_exit);
 427