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