linux/drivers/net/usb/cdc_ether.c
<<
>>
Prefs
   1/*
   2 * CDC Ethernet based networking peripherals
   3 * Copyright (C) 2003-2005 by David Brownell
   4 * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, write to the Free Software
  18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19 */
  20
  21// #define      DEBUG                   // error path messages, extra info
  22// #define      VERBOSE                 // more; success messages
  23
  24#include <linux/module.h>
  25#include <linux/init.h>
  26#include <linux/netdevice.h>
  27#include <linux/etherdevice.h>
  28#include <linux/ethtool.h>
  29#include <linux/workqueue.h>
  30#include <linux/mii.h>
  31#include <linux/usb.h>
  32#include <linux/usb/cdc.h>
  33#include <linux/usb/usbnet.h>
  34
  35
  36#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
  37
  38static int is_rndis(struct usb_interface_descriptor *desc)
  39{
  40        return (desc->bInterfaceClass == USB_CLASS_COMM &&
  41                desc->bInterfaceSubClass == 2 &&
  42                desc->bInterfaceProtocol == 0xff);
  43}
  44
  45static int is_activesync(struct usb_interface_descriptor *desc)
  46{
  47        return (desc->bInterfaceClass == USB_CLASS_MISC &&
  48                desc->bInterfaceSubClass == 1 &&
  49                desc->bInterfaceProtocol == 1);
  50}
  51
  52static int is_wireless_rndis(struct usb_interface_descriptor *desc)
  53{
  54        return (desc->bInterfaceClass == USB_CLASS_WIRELESS_CONTROLLER &&
  55                desc->bInterfaceSubClass == 1 &&
  56                desc->bInterfaceProtocol == 3);
  57}
  58
  59#else
  60
  61#define is_rndis(desc)          0
  62#define is_activesync(desc)     0
  63#define is_wireless_rndis(desc) 0
  64
  65#endif
  66
  67static const u8 mbm_guid[16] = {
  68        0xa3, 0x17, 0xa8, 0x8b, 0x04, 0x5e, 0x4f, 0x01,
  69        0xa6, 0x07, 0xc0, 0xff, 0xcb, 0x7e, 0x39, 0x2a,
  70};
  71
  72/*
  73 * probes control interface, claims data interface, collects the bulk
  74 * endpoints, activates data interface (if needed), maybe sets MTU.
  75 * all pure cdc, except for certain firmware workarounds, and knowing
  76 * that rndis uses one different rule.
  77 */
  78int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
  79{
  80        u8                              *buf = intf->cur_altsetting->extra;
  81        int                             len = intf->cur_altsetting->extralen;
  82        struct usb_interface_descriptor *d;
  83        struct cdc_state                *info = (void *) &dev->data;
  84        int                             status;
  85        int                             rndis;
  86        struct usb_driver               *driver = driver_of(intf);
  87        struct usb_cdc_mdlm_desc        *desc = NULL;
  88        struct usb_cdc_mdlm_detail_desc *detail = NULL;
  89
  90        if (sizeof dev->data < sizeof *info)
  91                return -EDOM;
  92
  93        /* expect strict spec conformance for the descriptors, but
  94         * cope with firmware which stores them in the wrong place
  95         */
  96        if (len == 0 && dev->udev->actconfig->extralen) {
  97                /* Motorola SB4100 (and others: Brad Hards says it's
  98                 * from a Broadcom design) put CDC descriptors here
  99                 */
 100                buf = dev->udev->actconfig->extra;
 101                len = dev->udev->actconfig->extralen;
 102                dev_dbg(&intf->dev, "CDC descriptors on config\n");
 103        }
 104
 105        /* Maybe CDC descriptors are after the endpoint?  This bug has
 106         * been seen on some 2Wire Inc RNDIS-ish products.
 107         */
 108        if (len == 0) {
 109                struct usb_host_endpoint        *hep;
 110
 111                hep = intf->cur_altsetting->endpoint;
 112                if (hep) {
 113                        buf = hep->extra;
 114                        len = hep->extralen;
 115                }
 116                if (len)
 117                        dev_dbg(&intf->dev,
 118                                "CDC descriptors on endpoint\n");
 119        }
 120
 121        /* this assumes that if there's a non-RNDIS vendor variant
 122         * of cdc-acm, it'll fail RNDIS requests cleanly.
 123         */
 124        rndis = (is_rndis(&intf->cur_altsetting->desc) ||
 125                 is_activesync(&intf->cur_altsetting->desc) ||
 126                 is_wireless_rndis(&intf->cur_altsetting->desc));
 127
 128        memset(info, 0, sizeof *info);
 129        info->control = intf;
 130        while (len > 3) {
 131                if (buf [1] != USB_DT_CS_INTERFACE)
 132                        goto next_desc;
 133
 134                /* use bDescriptorSubType to identify the CDC descriptors.
 135                 * We expect devices with CDC header and union descriptors.
 136                 * For CDC Ethernet we need the ethernet descriptor.
 137                 * For RNDIS, ignore two (pointless) CDC modem descriptors
 138                 * in favor of a complicated OID-based RPC scheme doing what
 139                 * CDC Ethernet achieves with a simple descriptor.
 140                 */
 141                switch (buf [2]) {
 142                case USB_CDC_HEADER_TYPE:
 143                        if (info->header) {
 144                                dev_dbg(&intf->dev, "extra CDC header\n");
 145                                goto bad_desc;
 146                        }
 147                        info->header = (void *) buf;
 148                        if (info->header->bLength != sizeof *info->header) {
 149                                dev_dbg(&intf->dev, "CDC header len %u\n",
 150                                        info->header->bLength);
 151                                goto bad_desc;
 152                        }
 153                        break;
 154                case USB_CDC_ACM_TYPE:
 155                        /* paranoia:  disambiguate a "real" vendor-specific
 156                         * modem interface from an RNDIS non-modem.
 157                         */
 158                        if (rndis) {
 159                                struct usb_cdc_acm_descriptor *acm;
 160
 161                                acm = (void *) buf;
 162                                if (acm->bmCapabilities) {
 163                                        dev_dbg(&intf->dev,
 164                                                "ACM capabilities %02x, "
 165                                                "not really RNDIS?\n",
 166                                                acm->bmCapabilities);
 167                                        goto bad_desc;
 168                                }
 169                        }
 170                        break;
 171                case USB_CDC_UNION_TYPE:
 172                        if (info->u) {
 173                                dev_dbg(&intf->dev, "extra CDC union\n");
 174                                goto bad_desc;
 175                        }
 176                        info->u = (void *) buf;
 177                        if (info->u->bLength != sizeof *info->u) {
 178                                dev_dbg(&intf->dev, "CDC union len %u\n",
 179                                        info->u->bLength);
 180                                goto bad_desc;
 181                        }
 182
 183                        /* we need a master/control interface (what we're
 184                         * probed with) and a slave/data interface; union
 185                         * descriptors sort this all out.
 186                         */
 187                        info->control = usb_ifnum_to_if(dev->udev,
 188                                                info->u->bMasterInterface0);
 189                        info->data = usb_ifnum_to_if(dev->udev,
 190                                                info->u->bSlaveInterface0);
 191                        if (!info->control || !info->data) {
 192                                dev_dbg(&intf->dev,
 193                                        "master #%u/%p slave #%u/%p\n",
 194                                        info->u->bMasterInterface0,
 195                                        info->control,
 196                                        info->u->bSlaveInterface0,
 197                                        info->data);
 198                                goto bad_desc;
 199                        }
 200                        if (info->control != intf) {
 201                                dev_dbg(&intf->dev, "bogus CDC Union\n");
 202                                /* Ambit USB Cable Modem (and maybe others)
 203                                 * interchanges master and slave interface.
 204                                 */
 205                                if (info->data == intf) {
 206                                        info->data = info->control;
 207                                        info->control = intf;
 208                                } else
 209                                        goto bad_desc;
 210                        }
 211
 212                        /* a data interface altsetting does the real i/o */
 213                        d = &info->data->cur_altsetting->desc;
 214                        if (d->bInterfaceClass != USB_CLASS_CDC_DATA) {
 215                                dev_dbg(&intf->dev, "slave class %u\n",
 216                                        d->bInterfaceClass);
 217                                goto bad_desc;
 218                        }
 219                        break;
 220                case USB_CDC_ETHERNET_TYPE:
 221                        if (info->ether) {
 222                                dev_dbg(&intf->dev, "extra CDC ether\n");
 223                                goto bad_desc;
 224                        }
 225                        info->ether = (void *) buf;
 226                        if (info->ether->bLength != sizeof *info->ether) {
 227                                dev_dbg(&intf->dev, "CDC ether len %u\n",
 228                                        info->ether->bLength);
 229                                goto bad_desc;
 230                        }
 231                        dev->hard_mtu = le16_to_cpu(
 232                                                info->ether->wMaxSegmentSize);
 233                        /* because of Zaurus, we may be ignoring the host
 234                         * side link address we were given.
 235                         */
 236                        break;
 237                case USB_CDC_MDLM_TYPE:
 238                        if (desc) {
 239                                dev_dbg(&intf->dev, "extra MDLM descriptor\n");
 240                                goto bad_desc;
 241                        }
 242
 243                        desc = (void *)buf;
 244
 245                        if (desc->bLength != sizeof(*desc))
 246                                goto bad_desc;
 247
 248                        if (memcmp(&desc->bGUID, mbm_guid, 16))
 249                                goto bad_desc;
 250                        break;
 251                case USB_CDC_MDLM_DETAIL_TYPE:
 252                        if (detail) {
 253                                dev_dbg(&intf->dev, "extra MDLM detail descriptor\n");
 254                                goto bad_desc;
 255                        }
 256
 257                        detail = (void *)buf;
 258
 259                        if (detail->bGuidDescriptorType == 0) {
 260                                if (detail->bLength < (sizeof(*detail) + 1))
 261                                        goto bad_desc;
 262                        } else
 263                                goto bad_desc;
 264                        break;
 265                }
 266next_desc:
 267                len -= buf [0]; /* bLength */
 268                buf += buf [0];
 269        }
 270
 271        /* Microsoft ActiveSync based and some regular RNDIS devices lack the
 272         * CDC descriptors, so we'll hard-wire the interfaces and not check
 273         * for descriptors.
 274         */
 275        if (rndis && !info->u) {
 276                info->control = usb_ifnum_to_if(dev->udev, 0);
 277                info->data = usb_ifnum_to_if(dev->udev, 1);
 278                if (!info->control || !info->data) {
 279                        dev_dbg(&intf->dev,
 280                                "rndis: master #0/%p slave #1/%p\n",
 281                                info->control,
 282                                info->data);
 283                        goto bad_desc;
 284                }
 285
 286        } else if (!info->header || !info->u || (!rndis && !info->ether)) {
 287                dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
 288                        info->header ? "" : "header ",
 289                        info->u ? "" : "union ",
 290                        info->ether ? "" : "ether ");
 291                goto bad_desc;
 292        }
 293
 294        /* claim data interface and set it up ... with side effects.
 295         * network traffic can't flow until an altsetting is enabled.
 296         */
 297        status = usb_driver_claim_interface(driver, info->data, dev);
 298        if (status < 0)
 299                return status;
 300        status = usbnet_get_endpoints(dev, info->data);
 301        if (status < 0) {
 302                /* ensure immediate exit from usbnet_disconnect */
 303                usb_set_intfdata(info->data, NULL);
 304                usb_driver_release_interface(driver, info->data);
 305                return status;
 306        }
 307
 308        /* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */
 309        dev->status = NULL;
 310        if (info->control->cur_altsetting->desc.bNumEndpoints == 1) {
 311                struct usb_endpoint_descriptor  *desc;
 312
 313                dev->status = &info->control->cur_altsetting->endpoint [0];
 314                desc = &dev->status->desc;
 315                if (!usb_endpoint_is_int_in(desc) ||
 316                    (le16_to_cpu(desc->wMaxPacketSize)
 317                     < sizeof(struct usb_cdc_notification)) ||
 318                    !desc->bInterval) {
 319                        dev_dbg(&intf->dev, "bad notification endpoint\n");
 320                        dev->status = NULL;
 321                }
 322        }
 323        if (rndis && !dev->status) {
 324                dev_dbg(&intf->dev, "missing RNDIS status endpoint\n");
 325                usb_set_intfdata(info->data, NULL);
 326                usb_driver_release_interface(driver, info->data);
 327                return -ENODEV;
 328        }
 329        return 0;
 330
 331bad_desc:
 332        dev_info(&dev->udev->dev, "bad CDC descriptors\n");
 333        return -ENODEV;
 334}
 335EXPORT_SYMBOL_GPL(usbnet_generic_cdc_bind);
 336
 337void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf)
 338{
 339        struct cdc_state                *info = (void *) &dev->data;
 340        struct usb_driver               *driver = driver_of(intf);
 341
 342        /* disconnect master --> disconnect slave */
 343        if (intf == info->control && info->data) {
 344                /* ensure immediate exit from usbnet_disconnect */
 345                usb_set_intfdata(info->data, NULL);
 346                usb_driver_release_interface(driver, info->data);
 347                info->data = NULL;
 348        }
 349
 350        /* and vice versa (just in case) */
 351        else if (intf == info->data && info->control) {
 352                /* ensure immediate exit from usbnet_disconnect */
 353                usb_set_intfdata(info->control, NULL);
 354                usb_driver_release_interface(driver, info->control);
 355                info->control = NULL;
 356        }
 357}
 358EXPORT_SYMBOL_GPL(usbnet_cdc_unbind);
 359
 360/*-------------------------------------------------------------------------
 361 *
 362 * Communications Device Class, Ethernet Control model
 363 *
 364 * Takes two interfaces.  The DATA interface is inactive till an altsetting
 365 * is selected.  Configuration data includes class descriptors.  There's
 366 * an optional status endpoint on the control interface.
 367 *
 368 * This should interop with whatever the 2.4 "CDCEther.c" driver
 369 * (by Brad Hards) talked with, with more functionality.
 370 *
 371 *-------------------------------------------------------------------------*/
 372
 373static void dumpspeed(struct usbnet *dev, __le32 *speeds)
 374{
 375        netif_info(dev, timer, dev->net,
 376                   "link speeds: %u kbps up, %u kbps down\n",
 377                   __le32_to_cpu(speeds[0]) / 1000,
 378                   __le32_to_cpu(speeds[1]) / 1000);
 379}
 380
 381void usbnet_cdc_status(struct usbnet *dev, struct urb *urb)
 382{
 383        struct usb_cdc_notification     *event;
 384
 385        if (urb->actual_length < sizeof *event)
 386                return;
 387
 388        /* SPEED_CHANGE can get split into two 8-byte packets */
 389        if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) {
 390                dumpspeed(dev, (__le32 *) urb->transfer_buffer);
 391                return;
 392        }
 393
 394        event = urb->transfer_buffer;
 395        switch (event->bNotificationType) {
 396        case USB_CDC_NOTIFY_NETWORK_CONNECTION:
 397                netif_dbg(dev, timer, dev->net, "CDC: carrier %s\n",
 398                          event->wValue ? "on" : "off");
 399                if (event->wValue)
 400                        netif_carrier_on(dev->net);
 401                else
 402                        netif_carrier_off(dev->net);
 403                break;
 404        case USB_CDC_NOTIFY_SPEED_CHANGE:       /* tx/rx rates */
 405                netif_dbg(dev, timer, dev->net, "CDC: speed change (len %d)\n",
 406                          urb->actual_length);
 407                if (urb->actual_length != (sizeof *event + 8))
 408                        set_bit(EVENT_STS_SPLIT, &dev->flags);
 409                else
 410                        dumpspeed(dev, (__le32 *) &event[1]);
 411                break;
 412        /* USB_CDC_NOTIFY_RESPONSE_AVAILABLE can happen too (e.g. RNDIS),
 413         * but there are no standard formats for the response data.
 414         */
 415        default:
 416                netdev_err(dev->net, "CDC: unexpected notification %02x!\n",
 417                           event->bNotificationType);
 418                break;
 419        }
 420}
 421EXPORT_SYMBOL_GPL(usbnet_cdc_status);
 422
 423int usbnet_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
 424{
 425        int                             status;
 426        struct cdc_state                *info = (void *) &dev->data;
 427
 428        status = usbnet_generic_cdc_bind(dev, intf);
 429        if (status < 0)
 430                return status;
 431
 432        status = usbnet_get_ethernet_addr(dev, info->ether->iMACAddress);
 433        if (status < 0) {
 434                usb_set_intfdata(info->data, NULL);
 435                usb_driver_release_interface(driver_of(intf), info->data);
 436                return status;
 437        }
 438
 439        /* FIXME cdc-ether has some multicast code too, though it complains
 440         * in routine cases.  info->ether describes the multicast support.
 441         * Implement that here, manipulating the cdc filter as needed.
 442         */
 443        return 0;
 444}
 445EXPORT_SYMBOL_GPL(usbnet_cdc_bind);
 446
 447static int cdc_manage_power(struct usbnet *dev, int on)
 448{
 449        dev->intf->needs_remote_wakeup = on;
 450        return 0;
 451}
 452
 453static const struct driver_info cdc_info = {
 454        .description =  "CDC Ethernet Device",
 455        .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
 456        // .check_connect = cdc_check_connect,
 457        .bind =         usbnet_cdc_bind,
 458        .unbind =       usbnet_cdc_unbind,
 459        .status =       usbnet_cdc_status,
 460        .manage_power = cdc_manage_power,
 461};
 462
 463static const struct driver_info wwan_info = {
 464        .description =  "Mobile Broadband Network Device",
 465        .flags =        FLAG_WWAN,
 466        .bind =         usbnet_cdc_bind,
 467        .unbind =       usbnet_cdc_unbind,
 468        .status =       usbnet_cdc_status,
 469        .manage_power = cdc_manage_power,
 470};
 471
 472/*-------------------------------------------------------------------------*/
 473
 474#define HUAWEI_VENDOR_ID        0x12D1
 475
 476static const struct usb_device_id       products [] = {
 477/*
 478 * BLACKLIST !!
 479 *
 480 * First blacklist any products that are egregiously nonconformant
 481 * with the CDC Ethernet specs.  Minor braindamage we cope with; when
 482 * they're not even trying, needing a separate driver is only the first
 483 * of the differences to show up.
 484 */
 485
 486#define ZAURUS_MASTER_INTERFACE \
 487        .bInterfaceClass        = USB_CLASS_COMM, \
 488        .bInterfaceSubClass     = USB_CDC_SUBCLASS_ETHERNET, \
 489        .bInterfaceProtocol     = USB_CDC_PROTO_NONE
 490
 491/* SA-1100 based Sharp Zaurus ("collie"), or compatible;
 492 * wire-incompatible with true CDC Ethernet implementations.
 493 * (And, it seems, needlessly so...)
 494 */
 495{
 496        .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 497                          | USB_DEVICE_ID_MATCH_DEVICE,
 498        .idVendor               = 0x04DD,
 499        .idProduct              = 0x8004,
 500        ZAURUS_MASTER_INTERFACE,
 501        .driver_info            = 0,
 502},
 503
 504/* PXA-25x based Sharp Zaurii.  Note that it seems some of these
 505 * (later models especially) may have shipped only with firmware
 506 * advertising false "CDC MDLM" compatibility ... but we're not
 507 * clear which models did that, so for now let's assume the worst.
 508 */
 509{
 510        .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 511                          | USB_DEVICE_ID_MATCH_DEVICE,
 512        .idVendor               = 0x04DD,
 513        .idProduct              = 0x8005,       /* A-300 */
 514        ZAURUS_MASTER_INTERFACE,
 515        .driver_info            = 0,
 516}, {
 517        .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 518                          | USB_DEVICE_ID_MATCH_DEVICE,
 519        .idVendor               = 0x04DD,
 520        .idProduct              = 0x8006,       /* B-500/SL-5600 */
 521        ZAURUS_MASTER_INTERFACE,
 522        .driver_info            = 0,
 523}, {
 524        .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 525                  | USB_DEVICE_ID_MATCH_DEVICE,
 526        .idVendor               = 0x04DD,
 527        .idProduct              = 0x8007,       /* C-700 */
 528        ZAURUS_MASTER_INTERFACE,
 529        .driver_info            = 0,
 530}, {
 531        .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 532                 | USB_DEVICE_ID_MATCH_DEVICE,
 533        .idVendor               = 0x04DD,
 534        .idProduct              = 0x9031,       /* C-750 C-760 */
 535        ZAURUS_MASTER_INTERFACE,
 536        .driver_info            = 0,
 537}, {
 538        .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 539                 | USB_DEVICE_ID_MATCH_DEVICE,
 540        .idVendor               = 0x04DD,
 541        .idProduct              = 0x9032,       /* SL-6000 */
 542        ZAURUS_MASTER_INTERFACE,
 543        .driver_info            = 0,
 544}, {
 545        .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 546                 | USB_DEVICE_ID_MATCH_DEVICE,
 547        .idVendor               = 0x04DD,
 548        /* reported with some C860 units */
 549        .idProduct              = 0x9050,       /* C-860 */
 550        ZAURUS_MASTER_INTERFACE,
 551        .driver_info            = 0,
 552},
 553
 554/* Olympus has some models with a Zaurus-compatible option.
 555 * R-1000 uses a FreeScale i.MXL cpu (ARMv4T)
 556 */
 557{
 558        .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 559                 | USB_DEVICE_ID_MATCH_DEVICE,
 560        .idVendor               = 0x07B4,
 561        .idProduct              = 0x0F02,       /* R-1000 */
 562        ZAURUS_MASTER_INTERFACE,
 563        .driver_info            = 0,
 564},
 565
 566/* LG Electronics VL600 wants additional headers on every frame */
 567{
 568        USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM,
 569                        USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
 570        .driver_info = (unsigned long)&wwan_info,
 571},
 572
 573/*
 574 * WHITELIST!!!
 575 *
 576 * CDC Ether uses two interfaces, not necessarily consecutive.
 577 * We match the main interface, ignoring the optional device
 578 * class so we could handle devices that aren't exclusively
 579 * CDC ether.
 580 *
 581 * NOTE:  this match must come AFTER entries blacklisting devices
 582 * because of bugs/quirks in a given product (like Zaurus, above).
 583 */
 584{
 585        USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
 586                        USB_CDC_PROTO_NONE),
 587        .driver_info = (unsigned long) &cdc_info,
 588}, {
 589        USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM,
 590                        USB_CDC_PROTO_NONE),
 591        .driver_info = (unsigned long)&wwan_info,
 592
 593}, {
 594        /* Various Huawei modems with a network port like the UMG1831 */
 595        .match_flags    =   USB_DEVICE_ID_MATCH_VENDOR
 596                 | USB_DEVICE_ID_MATCH_INT_INFO,
 597        .idVendor               = HUAWEI_VENDOR_ID,
 598        .bInterfaceClass        = USB_CLASS_COMM,
 599        .bInterfaceSubClass     = USB_CDC_SUBCLASS_ETHERNET,
 600        .bInterfaceProtocol     = 255,
 601        .driver_info = (unsigned long)&wwan_info,
 602},
 603        { },            // END
 604};
 605MODULE_DEVICE_TABLE(usb, products);
 606
 607static struct usb_driver cdc_driver = {
 608        .name =         "cdc_ether",
 609        .id_table =     products,
 610        .probe =        usbnet_probe,
 611        .disconnect =   usbnet_disconnect,
 612        .suspend =      usbnet_suspend,
 613        .resume =       usbnet_resume,
 614        .reset_resume = usbnet_resume,
 615        .supports_autosuspend = 1,
 616};
 617
 618
 619static int __init cdc_init(void)
 620{
 621        BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data)
 622                        < sizeof(struct cdc_state)));
 623
 624        return usb_register(&cdc_driver);
 625}
 626module_init(cdc_init);
 627
 628static void __exit cdc_exit(void)
 629{
 630        usb_deregister(&cdc_driver);
 631}
 632module_exit(cdc_exit);
 633
 634MODULE_AUTHOR("David Brownell");
 635MODULE_DESCRIPTION("USB CDC Ethernet devices");
 636MODULE_LICENSE("GPL");
 637