linux/drivers/usb/gadget/f_eem.c
<<
>>
Prefs
   1/*
   2 * f_eem.c -- USB CDC Ethernet (EEM) link function driver
   3 *
   4 * Copyright (C) 2003-2005,2008 David Brownell
   5 * Copyright (C) 2008 Nokia Corporation
   6 * Copyright (C) 2009 EF Johnson Technologies
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21 */
  22
  23#include <linux/kernel.h>
  24#include <linux/device.h>
  25#include <linux/etherdevice.h>
  26#include <linux/crc32.h>
  27
  28#include "u_ether.h"
  29
  30#define EEM_HLEN 2
  31
  32/*
  33 * This function is a "CDC Ethernet Emulation Model" (CDC EEM)
  34 * Ethernet link.
  35 */
  36
  37struct eem_ep_descs {
  38        struct usb_endpoint_descriptor  *in;
  39        struct usb_endpoint_descriptor  *out;
  40};
  41
  42struct f_eem {
  43        struct gether                   port;
  44        u8                              ctrl_id;
  45
  46        struct eem_ep_descs             fs;
  47        struct eem_ep_descs             hs;
  48};
  49
  50static inline struct f_eem *func_to_eem(struct usb_function *f)
  51{
  52        return container_of(f, struct f_eem, port.func);
  53}
  54
  55/*-------------------------------------------------------------------------*/
  56
  57/* interface descriptor: */
  58
  59static struct usb_interface_descriptor eem_intf __initdata = {
  60        .bLength =              sizeof eem_intf,
  61        .bDescriptorType =      USB_DT_INTERFACE,
  62
  63        /* .bInterfaceNumber = DYNAMIC */
  64        .bNumEndpoints =        2,
  65        .bInterfaceClass =      USB_CLASS_COMM,
  66        .bInterfaceSubClass =   USB_CDC_SUBCLASS_EEM,
  67        .bInterfaceProtocol =   USB_CDC_PROTO_EEM,
  68        /* .iInterface = DYNAMIC */
  69};
  70
  71/* full speed support: */
  72
  73static struct usb_endpoint_descriptor eem_fs_in_desc __initdata = {
  74        .bLength =              USB_DT_ENDPOINT_SIZE,
  75        .bDescriptorType =      USB_DT_ENDPOINT,
  76
  77        .bEndpointAddress =     USB_DIR_IN,
  78        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
  79};
  80
  81static struct usb_endpoint_descriptor eem_fs_out_desc __initdata = {
  82        .bLength =              USB_DT_ENDPOINT_SIZE,
  83        .bDescriptorType =      USB_DT_ENDPOINT,
  84
  85        .bEndpointAddress =     USB_DIR_OUT,
  86        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
  87};
  88
  89static struct usb_descriptor_header *eem_fs_function[] __initdata = {
  90        /* CDC EEM control descriptors */
  91        (struct usb_descriptor_header *) &eem_intf,
  92        (struct usb_descriptor_header *) &eem_fs_in_desc,
  93        (struct usb_descriptor_header *) &eem_fs_out_desc,
  94        NULL,
  95};
  96
  97/* high speed support: */
  98
  99static struct usb_endpoint_descriptor eem_hs_in_desc __initdata = {
 100        .bLength =              USB_DT_ENDPOINT_SIZE,
 101        .bDescriptorType =      USB_DT_ENDPOINT,
 102
 103        .bEndpointAddress =     USB_DIR_IN,
 104        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
 105        .wMaxPacketSize =       cpu_to_le16(512),
 106};
 107
 108static struct usb_endpoint_descriptor eem_hs_out_desc __initdata = {
 109        .bLength =              USB_DT_ENDPOINT_SIZE,
 110        .bDescriptorType =      USB_DT_ENDPOINT,
 111
 112        .bEndpointAddress =     USB_DIR_OUT,
 113        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
 114        .wMaxPacketSize =       cpu_to_le16(512),
 115};
 116
 117static struct usb_descriptor_header *eem_hs_function[] __initdata = {
 118        /* CDC EEM control descriptors */
 119        (struct usb_descriptor_header *) &eem_intf,
 120        (struct usb_descriptor_header *) &eem_hs_in_desc,
 121        (struct usb_descriptor_header *) &eem_hs_out_desc,
 122        NULL,
 123};
 124
 125/* string descriptors: */
 126
 127static struct usb_string eem_string_defs[] = {
 128        [0].s = "CDC Ethernet Emulation Model (EEM)",
 129        {  } /* end of list */
 130};
 131
 132static struct usb_gadget_strings eem_string_table = {
 133        .language =             0x0409, /* en-us */
 134        .strings =              eem_string_defs,
 135};
 136
 137static struct usb_gadget_strings *eem_strings[] = {
 138        &eem_string_table,
 139        NULL,
 140};
 141
 142/*-------------------------------------------------------------------------*/
 143
 144static int eem_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
 145{
 146        struct usb_composite_dev *cdev = f->config->cdev;
 147        int                     value = -EOPNOTSUPP;
 148        u16                     w_index = le16_to_cpu(ctrl->wIndex);
 149        u16                     w_value = le16_to_cpu(ctrl->wValue);
 150        u16                     w_length = le16_to_cpu(ctrl->wLength);
 151
 152        DBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
 153                ctrl->bRequestType, ctrl->bRequest,
 154                w_value, w_index, w_length);
 155
 156        /* device either stalls (value < 0) or reports success */
 157        return value;
 158}
 159
 160
 161static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 162{
 163        struct f_eem            *eem = func_to_eem(f);
 164        struct usb_composite_dev *cdev = f->config->cdev;
 165        struct net_device       *net;
 166
 167        /* we know alt == 0, so this is an activation or a reset */
 168        if (alt != 0)
 169                goto fail;
 170
 171        if (intf == eem->ctrl_id) {
 172
 173                if (eem->port.in_ep->driver_data) {
 174                        DBG(cdev, "reset eem\n");
 175                        gether_disconnect(&eem->port);
 176                }
 177
 178                if (!eem->port.in) {
 179                        DBG(cdev, "init eem\n");
 180                        eem->port.in = ep_choose(cdev->gadget,
 181                                        eem->hs.in, eem->fs.in);
 182                        eem->port.out = ep_choose(cdev->gadget,
 183                                        eem->hs.out, eem->fs.out);
 184                }
 185
 186                /* zlps should not occur because zero-length EEM packets
 187                 * will be inserted in those cases where they would occur
 188                 */
 189                eem->port.is_zlp_ok = 1;
 190                eem->port.cdc_filter = DEFAULT_FILTER;
 191                DBG(cdev, "activate eem\n");
 192                net = gether_connect(&eem->port);
 193                if (IS_ERR(net))
 194                        return PTR_ERR(net);
 195        } else
 196                goto fail;
 197
 198        return 0;
 199fail:
 200        return -EINVAL;
 201}
 202
 203static void eem_disable(struct usb_function *f)
 204{
 205        struct f_eem            *eem = func_to_eem(f);
 206        struct usb_composite_dev *cdev = f->config->cdev;
 207
 208        DBG(cdev, "eem deactivated\n");
 209
 210        if (eem->port.in_ep->driver_data)
 211                gether_disconnect(&eem->port);
 212}
 213
 214/*-------------------------------------------------------------------------*/
 215
 216/* EEM function driver setup/binding */
 217
 218static int __init
 219eem_bind(struct usb_configuration *c, struct usb_function *f)
 220{
 221        struct usb_composite_dev *cdev = c->cdev;
 222        struct f_eem            *eem = func_to_eem(f);
 223        int                     status;
 224        struct usb_ep           *ep;
 225
 226        /* allocate instance-specific interface IDs */
 227        status = usb_interface_id(c, f);
 228        if (status < 0)
 229                goto fail;
 230        eem->ctrl_id = status;
 231        eem_intf.bInterfaceNumber = status;
 232
 233        status = -ENODEV;
 234
 235        /* allocate instance-specific endpoints */
 236        ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_in_desc);
 237        if (!ep)
 238                goto fail;
 239        eem->port.in_ep = ep;
 240        ep->driver_data = cdev; /* claim */
 241
 242        ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_out_desc);
 243        if (!ep)
 244                goto fail;
 245        eem->port.out_ep = ep;
 246        ep->driver_data = cdev; /* claim */
 247
 248        status = -ENOMEM;
 249
 250        /* copy descriptors, and track endpoint copies */
 251        f->descriptors = usb_copy_descriptors(eem_fs_function);
 252        if (!f->descriptors)
 253                goto fail;
 254
 255        eem->fs.in = usb_find_endpoint(eem_fs_function,
 256                        f->descriptors, &eem_fs_in_desc);
 257        eem->fs.out = usb_find_endpoint(eem_fs_function,
 258                        f->descriptors, &eem_fs_out_desc);
 259
 260        /* support all relevant hardware speeds... we expect that when
 261         * hardware is dual speed, all bulk-capable endpoints work at
 262         * both speeds
 263         */
 264        if (gadget_is_dualspeed(c->cdev->gadget)) {
 265                eem_hs_in_desc.bEndpointAddress =
 266                                eem_fs_in_desc.bEndpointAddress;
 267                eem_hs_out_desc.bEndpointAddress =
 268                                eem_fs_out_desc.bEndpointAddress;
 269
 270                /* copy descriptors, and track endpoint copies */
 271                f->hs_descriptors = usb_copy_descriptors(eem_hs_function);
 272                if (!f->hs_descriptors)
 273                        goto fail;
 274
 275                eem->hs.in = usb_find_endpoint(eem_hs_function,
 276                                f->hs_descriptors, &eem_hs_in_desc);
 277                eem->hs.out = usb_find_endpoint(eem_hs_function,
 278                                f->hs_descriptors, &eem_hs_out_desc);
 279        }
 280
 281        DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n",
 282                        gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
 283                        eem->port.in_ep->name, eem->port.out_ep->name);
 284        return 0;
 285
 286fail:
 287        if (f->descriptors)
 288                usb_free_descriptors(f->descriptors);
 289
 290        /* we might as well release our claims on endpoints */
 291        if (eem->port.out)
 292                eem->port.out_ep->driver_data = NULL;
 293        if (eem->port.in)
 294                eem->port.in_ep->driver_data = NULL;
 295
 296        ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
 297
 298        return status;
 299}
 300
 301static void
 302eem_unbind(struct usb_configuration *c, struct usb_function *f)
 303{
 304        struct f_eem    *eem = func_to_eem(f);
 305
 306        DBG(c->cdev, "eem unbind\n");
 307
 308        if (gadget_is_dualspeed(c->cdev->gadget))
 309                usb_free_descriptors(f->hs_descriptors);
 310        usb_free_descriptors(f->descriptors);
 311        kfree(eem);
 312}
 313
 314static void eem_cmd_complete(struct usb_ep *ep, struct usb_request *req)
 315{
 316}
 317
 318/*
 319 * Add the EEM header and ethernet checksum.
 320 * We currently do not attempt to put multiple ethernet frames
 321 * into a single USB transfer
 322 */
 323static struct sk_buff *eem_wrap(struct gether *port, struct sk_buff *skb)
 324{
 325        struct sk_buff  *skb2 = NULL;
 326        struct usb_ep   *in = port->in_ep;
 327        int             padlen = 0;
 328        u16             len = skb->len;
 329
 330        if (!skb_cloned(skb)) {
 331                int headroom = skb_headroom(skb);
 332                int tailroom = skb_tailroom(skb);
 333
 334                /* When (len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) is 0,
 335                 * stick two bytes of zero-length EEM packet on the end.
 336                 */
 337                if (((len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) == 0)
 338                        padlen += 2;
 339
 340                if ((tailroom >= (ETH_FCS_LEN + padlen)) &&
 341                                (headroom >= EEM_HLEN))
 342                        goto done;
 343        }
 344
 345        skb2 = skb_copy_expand(skb, EEM_HLEN, ETH_FCS_LEN + padlen, GFP_ATOMIC);
 346        dev_kfree_skb_any(skb);
 347        skb = skb2;
 348        if (!skb)
 349                return skb;
 350
 351done:
 352        /* use the "no CRC" option */
 353        put_unaligned_be32(0xdeadbeef, skb_put(skb, 4));
 354
 355        /* EEM packet header format:
 356         * b0..13:      length of ethernet frame
 357         * b14:         bmCRC (0 == sentinel CRC)
 358         * b15:         bmType (0 == data)
 359         */
 360        len = skb->len;
 361        put_unaligned_le16((len & 0x3FFF) | BIT(14), skb_push(skb, 2));
 362
 363        /* add a zero-length EEM packet, if needed */
 364        if (padlen)
 365                put_unaligned_le16(0, skb_put(skb, 2));
 366
 367        return skb;
 368}
 369
 370/*
 371 * Remove the EEM header.  Note that there can be many EEM packets in a single
 372 * USB transfer, so we need to break them out and handle them independently.
 373 */
 374static int eem_unwrap(struct gether *port,
 375                        struct sk_buff *skb,
 376                        struct sk_buff_head *list)
 377{
 378        struct usb_composite_dev        *cdev = port->func.config->cdev;
 379        int                             status = 0;
 380
 381        do {
 382                struct sk_buff  *skb2;
 383                u16             header;
 384                u16             len = 0;
 385
 386                if (skb->len < EEM_HLEN) {
 387                        status = -EINVAL;
 388                        DBG(cdev, "invalid EEM header\n");
 389                        goto error;
 390                }
 391
 392                /* remove the EEM header */
 393                header = get_unaligned_le16(skb->data);
 394                skb_pull(skb, EEM_HLEN);
 395
 396                /* EEM packet header format:
 397                 * b0..14:      EEM type dependent (data or command)
 398                 * b15:         bmType (0 == data, 1 == command)
 399                 */
 400                if (header & BIT(15)) {
 401                        struct usb_request      *req = cdev->req;
 402                        u16                     bmEEMCmd;
 403
 404                        /* EEM command packet format:
 405                         * b0..10:      bmEEMCmdParam
 406                         * b11..13:     bmEEMCmd
 407                         * b14:         reserved (must be zero)
 408                         * b15:         bmType (1 == command)
 409                         */
 410                        if (header & BIT(14))
 411                                continue;
 412
 413                        bmEEMCmd = (header >> 11) & 0x7;
 414                        switch (bmEEMCmd) {
 415                        case 0: /* echo */
 416                                len = header & 0x7FF;
 417                                if (skb->len < len) {
 418                                        status = -EOVERFLOW;
 419                                        goto error;
 420                                }
 421
 422                                skb2 = skb_clone(skb, GFP_ATOMIC);
 423                                if (unlikely(!skb2)) {
 424                                        DBG(cdev, "EEM echo response error\n");
 425                                        goto next;
 426                                }
 427                                skb_trim(skb2, len);
 428                                put_unaligned_le16(BIT(15) | BIT(11) | len,
 429                                                        skb_push(skb2, 2));
 430                                skb_copy_bits(skb, 0, req->buf, skb->len);
 431                                req->length = skb->len;
 432                                req->complete = eem_cmd_complete;
 433                                req->zero = 1;
 434                                if (usb_ep_queue(port->in_ep, req, GFP_ATOMIC))
 435                                        DBG(cdev, "echo response queue fail\n");
 436                                break;
 437
 438                        case 1:  /* echo response */
 439                        case 2:  /* suspend hint */
 440                        case 3:  /* response hint */
 441                        case 4:  /* response complete hint */
 442                        case 5:  /* tickle */
 443                        default: /* reserved */
 444                                continue;
 445                        }
 446                } else {
 447                        u32             crc, crc2;
 448                        struct sk_buff  *skb3;
 449
 450                        /* check for zero-length EEM packet */
 451                        if (header == 0)
 452                                continue;
 453
 454                        /* EEM data packet format:
 455                         * b0..13:      length of ethernet frame
 456                         * b14:         bmCRC (0 == sentinel, 1 == calculated)
 457                         * b15:         bmType (0 == data)
 458                         */
 459                        len = header & 0x3FFF;
 460                        if ((skb->len < len)
 461                                        || (len < (ETH_HLEN + ETH_FCS_LEN))) {
 462                                status = -EINVAL;
 463                                goto error;
 464                        }
 465
 466                        /* validate CRC */
 467                        crc = get_unaligned_le32(skb->data + len - ETH_FCS_LEN);
 468                        if (header & BIT(14)) {
 469                                crc = get_unaligned_le32(skb->data + len
 470                                                        - ETH_FCS_LEN);
 471                                crc2 = ~crc32_le(~0,
 472                                                skb->data,
 473                                                skb->len - ETH_FCS_LEN);
 474                        } else {
 475                                crc = get_unaligned_be32(skb->data + len
 476                                                        - ETH_FCS_LEN);
 477                                crc2 = 0xdeadbeef;
 478                        }
 479                        if (crc != crc2) {
 480                                DBG(cdev, "invalid EEM CRC\n");
 481                                goto next;
 482                        }
 483
 484                        skb2 = skb_clone(skb, GFP_ATOMIC);
 485                        if (unlikely(!skb2)) {
 486                                DBG(cdev, "unable to unframe EEM packet\n");
 487                                continue;
 488                        }
 489                        skb_trim(skb2, len - ETH_FCS_LEN);
 490
 491                        skb3 = skb_copy_expand(skb2,
 492                                                NET_IP_ALIGN,
 493                                                0,
 494                                                GFP_ATOMIC);
 495                        if (unlikely(!skb3)) {
 496                                DBG(cdev, "unable to realign EEM packet\n");
 497                                dev_kfree_skb_any(skb2);
 498                                continue;
 499                        }
 500                        dev_kfree_skb_any(skb2);
 501                        skb_queue_tail(list, skb3);
 502                }
 503next:
 504                skb_pull(skb, len);
 505        } while (skb->len);
 506
 507error:
 508        dev_kfree_skb_any(skb);
 509        return status;
 510}
 511
 512/**
 513 * eem_bind_config - add CDC Ethernet (EEM) network link to a configuration
 514 * @c: the configuration to support the network link
 515 * Context: single threaded during gadget setup
 516 *
 517 * Returns zero on success, else negative errno.
 518 *
 519 * Caller must have called @gether_setup().  Caller is also responsible
 520 * for calling @gether_cleanup() before module unload.
 521 */
 522int __init eem_bind_config(struct usb_configuration *c)
 523{
 524        struct f_eem    *eem;
 525        int             status;
 526
 527        /* maybe allocate device-global string IDs */
 528        if (eem_string_defs[0].id == 0) {
 529
 530                /* control interface label */
 531                status = usb_string_id(c->cdev);
 532                if (status < 0)
 533                        return status;
 534                eem_string_defs[0].id = status;
 535                eem_intf.iInterface = status;
 536        }
 537
 538        /* allocate and initialize one new instance */
 539        eem = kzalloc(sizeof *eem, GFP_KERNEL);
 540        if (!eem)
 541                return -ENOMEM;
 542
 543        eem->port.cdc_filter = DEFAULT_FILTER;
 544
 545        eem->port.func.name = "cdc_eem";
 546        eem->port.func.strings = eem_strings;
 547        /* descriptors are per-instance copies */
 548        eem->port.func.bind = eem_bind;
 549        eem->port.func.unbind = eem_unbind;
 550        eem->port.func.set_alt = eem_set_alt;
 551        eem->port.func.setup = eem_setup;
 552        eem->port.func.disable = eem_disable;
 553        eem->port.wrap = eem_wrap;
 554        eem->port.unwrap = eem_unwrap;
 555        eem->port.header_len = EEM_HLEN;
 556
 557        status = usb_add_function(c, &eem->port.func);
 558        if (status)
 559                kfree(eem);
 560        return status;
 561}
 562
 563