linux/drivers/net/usb/qmi_wwan.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2012  Bjørn Mork <bjorn@mork.no>
   3 *
   4 * The probing code is heavily inspired by cdc_ether, which is:
   5 * Copyright (C) 2003-2005 by David Brownell
   6 * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License
  10 * version 2 as published by the Free Software Foundation.
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/netdevice.h>
  15#include <linux/ethtool.h>
  16#include <linux/etherdevice.h>
  17#include <linux/mii.h>
  18#include <linux/usb.h>
  19#include <linux/usb/cdc.h>
  20#include <linux/usb/usbnet.h>
  21#include <linux/usb/cdc-wdm.h>
  22
  23/* This driver supports wwan (3G/LTE/?) devices using a vendor
  24 * specific management protocol called Qualcomm MSM Interface (QMI) -
  25 * in addition to the more common AT commands over serial interface
  26 * management
  27 *
  28 * QMI is wrapped in CDC, using CDC encapsulated commands on the
  29 * control ("master") interface of a two-interface CDC Union
  30 * resembling standard CDC ECM.  The devices do not use the control
  31 * interface for any other CDC messages.  Most likely because the
  32 * management protocol is used in place of the standard CDC
  33 * notifications NOTIFY_NETWORK_CONNECTION and NOTIFY_SPEED_CHANGE
  34 *
  35 * Alternatively, control and data functions can be combined in a
  36 * single USB interface.
  37 *
  38 * Handling a protocol like QMI is out of the scope for any driver.
  39 * It is exported as a character device using the cdc-wdm driver as
  40 * a subdriver, enabling userspace applications ("modem managers") to
  41 * handle it.
  42 *
  43 * These devices may alternatively/additionally be configured using AT
  44 * commands on a serial interface
  45 */
  46
  47/* driver specific data */
  48struct qmi_wwan_state {
  49        struct usb_driver *subdriver;
  50        atomic_t pmcount;
  51        unsigned long unused;
  52        struct usb_interface *control;
  53        struct usb_interface *data;
  54};
  55
  56/* default ethernet address used by the modem */
  57static const u8 default_modem_addr[ETH_ALEN] = {0x02, 0x50, 0xf3};
  58
  59/* Make up an ethernet header if the packet doesn't have one.
  60 *
  61 * A firmware bug common among several devices cause them to send raw
  62 * IP packets under some circumstances.  There is no way for the
  63 * driver/host to know when this will happen.  And even when the bug
  64 * hits, some packets will still arrive with an intact header.
  65 *
  66 * The supported devices are only capably of sending IPv4, IPv6 and
  67 * ARP packets on a point-to-point link. Any packet with an ethernet
  68 * header will have either our address or a broadcast/multicast
  69 * address as destination.  ARP packets will always have a header.
  70 *
  71 * This means that this function will reliably add the appropriate
  72 * header iff necessary, provided our hardware address does not start
  73 * with 4 or 6.
  74 *
  75 * Another common firmware bug results in all packets being addressed
  76 * to 00:a0:c6:00:00:00 despite the host address being different.
  77 * This function will also fixup such packets.
  78 */
  79static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
  80{
  81        __be16 proto;
  82
  83        /* usbnet rx_complete guarantees that skb->len is at least
  84         * hard_header_len, so we can inspect the dest address without
  85         * checking skb->len
  86         */
  87        switch (skb->data[0] & 0xf0) {
  88        case 0x40:
  89                proto = htons(ETH_P_IP);
  90                break;
  91        case 0x60:
  92                proto = htons(ETH_P_IPV6);
  93                break;
  94        case 0x00:
  95                if (is_multicast_ether_addr(skb->data))
  96                        return 1;
  97                /* possibly bogus destination - rewrite just in case */
  98                skb_reset_mac_header(skb);
  99                goto fix_dest;
 100        default:
 101                /* pass along other packets without modifications */
 102                return 1;
 103        }
 104        if (skb_headroom(skb) < ETH_HLEN)
 105                return 0;
 106        skb_push(skb, ETH_HLEN);
 107        skb_reset_mac_header(skb);
 108        eth_hdr(skb)->h_proto = proto;
 109        memset(eth_hdr(skb)->h_source, 0, ETH_ALEN);
 110fix_dest:
 111        memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN);
 112        return 1;
 113}
 114
 115/* very simplistic detection of IPv4 or IPv6 headers */
 116static bool possibly_iphdr(const char *data)
 117{
 118        return (data[0] & 0xd0) == 0x40;
 119}
 120
 121/* disallow addresses which may be confused with IP headers */
 122static int qmi_wwan_mac_addr(struct net_device *dev, void *p)
 123{
 124        int ret;
 125        struct sockaddr *addr = p;
 126
 127        ret = eth_prepare_mac_addr_change(dev, p);
 128        if (ret < 0)
 129                return ret;
 130        if (possibly_iphdr(addr->sa_data))
 131                return -EADDRNOTAVAIL;
 132        eth_commit_mac_addr_change(dev, p);
 133        return 0;
 134}
 135
 136static const struct net_device_ops qmi_wwan_netdev_ops = {
 137        .ndo_open               = usbnet_open,
 138        .ndo_stop               = usbnet_stop,
 139        .ndo_start_xmit         = usbnet_start_xmit,
 140        .ndo_tx_timeout         = usbnet_tx_timeout,
 141        .ndo_change_mtu         = usbnet_change_mtu,
 142        .ndo_set_mac_address    = qmi_wwan_mac_addr,
 143        .ndo_validate_addr      = eth_validate_addr,
 144};
 145
 146/* using a counter to merge subdriver requests with our own into a
 147 * combined state
 148 */
 149static int qmi_wwan_manage_power(struct usbnet *dev, int on)
 150{
 151        struct qmi_wwan_state *info = (void *)&dev->data;
 152        int rv;
 153
 154        dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__,
 155                atomic_read(&info->pmcount), on);
 156
 157        if ((on && atomic_add_return(1, &info->pmcount) == 1) ||
 158            (!on && atomic_dec_and_test(&info->pmcount))) {
 159                /* need autopm_get/put here to ensure the usbcore sees
 160                 * the new value
 161                 */
 162                rv = usb_autopm_get_interface(dev->intf);
 163                dev->intf->needs_remote_wakeup = on;
 164                if (!rv)
 165                        usb_autopm_put_interface(dev->intf);
 166        }
 167        return 0;
 168}
 169
 170static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on)
 171{
 172        struct usbnet *dev = usb_get_intfdata(intf);
 173
 174        /* can be called while disconnecting */
 175        if (!dev)
 176                return 0;
 177        return qmi_wwan_manage_power(dev, on);
 178}
 179
 180/* collect all three endpoints and register subdriver */
 181static int qmi_wwan_register_subdriver(struct usbnet *dev)
 182{
 183        int rv;
 184        struct usb_driver *subdriver = NULL;
 185        struct qmi_wwan_state *info = (void *)&dev->data;
 186
 187        /* collect bulk endpoints */
 188        rv = usbnet_get_endpoints(dev, info->data);
 189        if (rv < 0)
 190                goto err;
 191
 192        /* update status endpoint if separate control interface */
 193        if (info->control != info->data)
 194                dev->status = &info->control->cur_altsetting->endpoint[0];
 195
 196        /* require interrupt endpoint for subdriver */
 197        if (!dev->status) {
 198                rv = -EINVAL;
 199                goto err;
 200        }
 201
 202        /* for subdriver power management */
 203        atomic_set(&info->pmcount, 0);
 204
 205        /* register subdriver */
 206        subdriver = usb_cdc_wdm_register(info->control, &dev->status->desc,
 207                                         4096, &qmi_wwan_cdc_wdm_manage_power);
 208        if (IS_ERR(subdriver)) {
 209                dev_err(&info->control->dev, "subdriver registration failed\n");
 210                rv = PTR_ERR(subdriver);
 211                goto err;
 212        }
 213
 214        /* prevent usbnet from using status endpoint */
 215        dev->status = NULL;
 216
 217        /* save subdriver struct for suspend/resume wrappers */
 218        info->subdriver = subdriver;
 219
 220err:
 221        return rv;
 222}
 223
 224static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
 225{
 226        int status = -1;
 227        u8 *buf = intf->cur_altsetting->extra;
 228        int len = intf->cur_altsetting->extralen;
 229        struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc;
 230        struct usb_cdc_union_desc *cdc_union = NULL;
 231        struct usb_cdc_ether_desc *cdc_ether = NULL;
 232        u32 found = 0;
 233        struct usb_driver *driver = driver_of(intf);
 234        struct qmi_wwan_state *info = (void *)&dev->data;
 235
 236        BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) <
 237                      sizeof(struct qmi_wwan_state)));
 238
 239        /* set up initial state */
 240        info->control = intf;
 241        info->data = intf;
 242
 243        /* and a number of CDC descriptors */
 244        while (len > 3) {
 245                struct usb_descriptor_header *h = (void *)buf;
 246
 247                /* ignore any misplaced descriptors */
 248                if (h->bDescriptorType != USB_DT_CS_INTERFACE)
 249                        goto next_desc;
 250
 251                /* buf[2] is CDC descriptor subtype */
 252                switch (buf[2]) {
 253                case USB_CDC_HEADER_TYPE:
 254                        if (found & 1 << USB_CDC_HEADER_TYPE) {
 255                                dev_dbg(&intf->dev, "extra CDC header\n");
 256                                goto err;
 257                        }
 258                        if (h->bLength != sizeof(struct usb_cdc_header_desc)) {
 259                                dev_dbg(&intf->dev, "CDC header len %u\n",
 260                                        h->bLength);
 261                                goto err;
 262                        }
 263                        break;
 264                case USB_CDC_UNION_TYPE:
 265                        if (found & 1 << USB_CDC_UNION_TYPE) {
 266                                dev_dbg(&intf->dev, "extra CDC union\n");
 267                                goto err;
 268                        }
 269                        if (h->bLength != sizeof(struct usb_cdc_union_desc)) {
 270                                dev_dbg(&intf->dev, "CDC union len %u\n",
 271                                        h->bLength);
 272                                goto err;
 273                        }
 274                        cdc_union = (struct usb_cdc_union_desc *)buf;
 275                        break;
 276                case USB_CDC_ETHERNET_TYPE:
 277                        if (found & 1 << USB_CDC_ETHERNET_TYPE) {
 278                                dev_dbg(&intf->dev, "extra CDC ether\n");
 279                                goto err;
 280                        }
 281                        if (h->bLength != sizeof(struct usb_cdc_ether_desc)) {
 282                                dev_dbg(&intf->dev, "CDC ether len %u\n",
 283                                        h->bLength);
 284                                goto err;
 285                        }
 286                        cdc_ether = (struct usb_cdc_ether_desc *)buf;
 287                        break;
 288                }
 289
 290                /* Remember which CDC functional descriptors we've seen.  Works
 291                 * for all types we care about, of which USB_CDC_ETHERNET_TYPE
 292                 * (0x0f) is the highest numbered
 293                 */
 294                if (buf[2] < 32)
 295                        found |= 1 << buf[2];
 296
 297next_desc:
 298                len -= h->bLength;
 299                buf += h->bLength;
 300        }
 301
 302        /* Use separate control and data interfaces if we found a CDC Union */
 303        if (cdc_union) {
 304                info->data = usb_ifnum_to_if(dev->udev,
 305                                             cdc_union->bSlaveInterface0);
 306                if (desc->bInterfaceNumber != cdc_union->bMasterInterface0 ||
 307                    !info->data) {
 308                        dev_err(&intf->dev,
 309                                "bogus CDC Union: master=%u, slave=%u\n",
 310                                cdc_union->bMasterInterface0,
 311                                cdc_union->bSlaveInterface0);
 312                        goto err;
 313                }
 314        }
 315
 316        /* errors aren't fatal - we can live with the dynamic address */
 317        if (cdc_ether) {
 318                dev->hard_mtu = le16_to_cpu(cdc_ether->wMaxSegmentSize);
 319                usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress);
 320        }
 321
 322        /* claim data interface and set it up */
 323        if (info->control != info->data) {
 324                status = usb_driver_claim_interface(driver, info->data, dev);
 325                if (status < 0)
 326                        goto err;
 327        }
 328
 329        status = qmi_wwan_register_subdriver(dev);
 330        if (status < 0 && info->control != info->data) {
 331                usb_set_intfdata(info->data, NULL);
 332                usb_driver_release_interface(driver, info->data);
 333        }
 334
 335        /* Never use the same address on both ends of the link, even
 336         * if the buggy firmware told us to.
 337         */
 338        if (ether_addr_equal(dev->net->dev_addr, default_modem_addr))
 339                eth_hw_addr_random(dev->net);
 340
 341        /* make MAC addr easily distinguishable from an IP header */
 342        if (possibly_iphdr(dev->net->dev_addr)) {
 343                dev->net->dev_addr[0] |= 0x02;  /* set local assignment bit */
 344                dev->net->dev_addr[0] &= 0xbf;  /* clear "IP" bit */
 345        }
 346        dev->net->netdev_ops = &qmi_wwan_netdev_ops;
 347err:
 348        return status;
 349}
 350
 351static void qmi_wwan_unbind(struct usbnet *dev, struct usb_interface *intf)
 352{
 353        struct qmi_wwan_state *info = (void *)&dev->data;
 354        struct usb_driver *driver = driver_of(intf);
 355        struct usb_interface *other;
 356
 357        if (info->subdriver && info->subdriver->disconnect)
 358                info->subdriver->disconnect(info->control);
 359
 360        /* allow user to unbind using either control or data */
 361        if (intf == info->control)
 362                other = info->data;
 363        else
 364                other = info->control;
 365
 366        /* only if not shared */
 367        if (other && intf != other) {
 368                usb_set_intfdata(other, NULL);
 369                usb_driver_release_interface(driver, other);
 370        }
 371
 372        info->subdriver = NULL;
 373        info->data = NULL;
 374        info->control = NULL;
 375}
 376
 377/* suspend/resume wrappers calling both usbnet and the cdc-wdm
 378 * subdriver if present.
 379 *
 380 * NOTE: cdc-wdm also supports pre/post_reset, but we cannot provide
 381 * wrappers for those without adding usbnet reset support first.
 382 */
 383static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message)
 384{
 385        struct usbnet *dev = usb_get_intfdata(intf);
 386        struct qmi_wwan_state *info = (void *)&dev->data;
 387        int ret;
 388
 389        /* Both usbnet_suspend() and subdriver->suspend() MUST return 0
 390         * in system sleep context, otherwise, the resume callback has
 391         * to recover device from previous suspend failure.
 392         */
 393        ret = usbnet_suspend(intf, message);
 394        if (ret < 0)
 395                goto err;
 396
 397        if (intf == info->control && info->subdriver &&
 398            info->subdriver->suspend)
 399                ret = info->subdriver->suspend(intf, message);
 400        if (ret < 0)
 401                usbnet_resume(intf);
 402err:
 403        return ret;
 404}
 405
 406static int qmi_wwan_resume(struct usb_interface *intf)
 407{
 408        struct usbnet *dev = usb_get_intfdata(intf);
 409        struct qmi_wwan_state *info = (void *)&dev->data;
 410        int ret = 0;
 411        bool callsub = (intf == info->control && info->subdriver &&
 412                        info->subdriver->resume);
 413
 414        if (callsub)
 415                ret = info->subdriver->resume(intf);
 416        if (ret < 0)
 417                goto err;
 418        ret = usbnet_resume(intf);
 419        if (ret < 0 && callsub)
 420                info->subdriver->suspend(intf, PMSG_SUSPEND);
 421err:
 422        return ret;
 423}
 424
 425static const struct driver_info qmi_wwan_info = {
 426        .description    = "WWAN/QMI device",
 427        .flags          = FLAG_WWAN,
 428        .bind           = qmi_wwan_bind,
 429        .unbind         = qmi_wwan_unbind,
 430        .manage_power   = qmi_wwan_manage_power,
 431        .rx_fixup       = qmi_wwan_rx_fixup,
 432};
 433
 434#define HUAWEI_VENDOR_ID        0x12D1
 435
 436/* map QMI/wwan function by a fixed interface number */
 437#define QMI_FIXED_INTF(vend, prod, num) \
 438        USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \
 439        .driver_info = (unsigned long)&qmi_wwan_info
 440
 441/* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */
 442#define QMI_GOBI1K_DEVICE(vend, prod) \
 443        QMI_FIXED_INTF(vend, prod, 3)
 444
 445/* Gobi 2000/3000 QMI/wwan interface number is 0 according to qcserial */
 446#define QMI_GOBI_DEVICE(vend, prod) \
 447        QMI_FIXED_INTF(vend, prod, 0)
 448
 449static const struct usb_device_id products[] = {
 450        /* 1. CDC ECM like devices match on the control interface */
 451        {       /* Huawei E392, E398 and possibly others sharing both device id and more... */
 452                USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 9),
 453                .driver_info        = (unsigned long)&qmi_wwan_info,
 454        },
 455        {       /* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */
 456                USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 57),
 457                .driver_info        = (unsigned long)&qmi_wwan_info,
 458        },
 459        {       /* HUAWEI_INTERFACE_NDIS_CONTROL_QUALCOMM */
 460                USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 0x01, 0x69),
 461                .driver_info        = (unsigned long)&qmi_wwan_info,
 462        },
 463
 464        /* 2. Combined interface devices matching on class+protocol */
 465        {       /* Huawei E367 and possibly others in "Windows mode" */
 466                USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 7),
 467                .driver_info        = (unsigned long)&qmi_wwan_info,
 468        },
 469        {       /* Huawei E392, E398 and possibly others in "Windows mode" */
 470                USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 17),
 471                .driver_info        = (unsigned long)&qmi_wwan_info,
 472        },
 473        {       /* HUAWEI_NDIS_SINGLE_INTERFACE_VDF */
 474                USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 0x01, 0x37),
 475                .driver_info        = (unsigned long)&qmi_wwan_info,
 476        },
 477        {       /* HUAWEI_INTERFACE_NDIS_HW_QUALCOMM */
 478                USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 0x01, 0x67),
 479                .driver_info        = (unsigned long)&qmi_wwan_info,
 480        },
 481        {       /* Pantech UML290, P4200 and more */
 482                USB_VENDOR_AND_INTERFACE_INFO(0x106c, USB_CLASS_VENDOR_SPEC, 0xf0, 0xff),
 483                .driver_info        = (unsigned long)&qmi_wwan_info,
 484        },
 485        {       /* Pantech UML290 - newer firmware */
 486                USB_VENDOR_AND_INTERFACE_INFO(0x106c, USB_CLASS_VENDOR_SPEC, 0xf1, 0xff),
 487                .driver_info        = (unsigned long)&qmi_wwan_info,
 488        },
 489        {       /* Novatel USB551L and MC551 */
 490                USB_DEVICE_AND_INTERFACE_INFO(0x1410, 0xb001,
 491                                              USB_CLASS_COMM,
 492                                              USB_CDC_SUBCLASS_ETHERNET,
 493                                              USB_CDC_PROTO_NONE),
 494                .driver_info        = (unsigned long)&qmi_wwan_info,
 495        },
 496        {       /* Novatel E362 */
 497                USB_DEVICE_AND_INTERFACE_INFO(0x1410, 0x9010,
 498                                              USB_CLASS_COMM,
 499                                              USB_CDC_SUBCLASS_ETHERNET,
 500                                              USB_CDC_PROTO_NONE),
 501                .driver_info        = (unsigned long)&qmi_wwan_info,
 502        },
 503        {       /* Dell Wireless 5800 (Novatel E362) */
 504                USB_DEVICE_AND_INTERFACE_INFO(0x413C, 0x8195,
 505                                              USB_CLASS_COMM,
 506                                              USB_CDC_SUBCLASS_ETHERNET,
 507                                              USB_CDC_PROTO_NONE),
 508                .driver_info        = (unsigned long)&qmi_wwan_info,
 509        },
 510        {       /* Dell Wireless 5800 V2 (Novatel E362) */
 511                USB_DEVICE_AND_INTERFACE_INFO(0x413C, 0x8196,
 512                                              USB_CLASS_COMM,
 513                                              USB_CDC_SUBCLASS_ETHERNET,
 514                                              USB_CDC_PROTO_NONE),
 515                .driver_info        = (unsigned long)&qmi_wwan_info,
 516        },
 517        {       /* Dell Wireless 5804 (Novatel E371) */
 518                USB_DEVICE_AND_INTERFACE_INFO(0x413C, 0x819b,
 519                                              USB_CLASS_COMM,
 520                                              USB_CDC_SUBCLASS_ETHERNET,
 521                                              USB_CDC_PROTO_NONE),
 522                .driver_info        = (unsigned long)&qmi_wwan_info,
 523        },
 524        {       /* ADU960S */
 525                USB_DEVICE_AND_INTERFACE_INFO(0x16d5, 0x650a,
 526                                              USB_CLASS_COMM,
 527                                              USB_CDC_SUBCLASS_ETHERNET,
 528                                              USB_CDC_PROTO_NONE),
 529                .driver_info        = (unsigned long)&qmi_wwan_info,
 530        },
 531
 532        /* 3. Combined interface devices matching on interface number */
 533        {QMI_FIXED_INTF(0x0408, 0xea42, 4)},    /* Yota / Megafon M100-1 */
 534        {QMI_FIXED_INTF(0x05c6, 0x7000, 0)},
 535        {QMI_FIXED_INTF(0x05c6, 0x7001, 1)},
 536        {QMI_FIXED_INTF(0x05c6, 0x7002, 1)},
 537        {QMI_FIXED_INTF(0x05c6, 0x7101, 1)},
 538        {QMI_FIXED_INTF(0x05c6, 0x7101, 2)},
 539        {QMI_FIXED_INTF(0x05c6, 0x7101, 3)},
 540        {QMI_FIXED_INTF(0x05c6, 0x7102, 1)},
 541        {QMI_FIXED_INTF(0x05c6, 0x7102, 2)},
 542        {QMI_FIXED_INTF(0x05c6, 0x7102, 3)},
 543        {QMI_FIXED_INTF(0x05c6, 0x8000, 7)},
 544        {QMI_FIXED_INTF(0x05c6, 0x8001, 6)},
 545        {QMI_FIXED_INTF(0x05c6, 0x9000, 4)},
 546        {QMI_FIXED_INTF(0x05c6, 0x9003, 4)},
 547        {QMI_FIXED_INTF(0x05c6, 0x9005, 2)},
 548        {QMI_FIXED_INTF(0x05c6, 0x900a, 4)},
 549        {QMI_FIXED_INTF(0x05c6, 0x900b, 2)},
 550        {QMI_FIXED_INTF(0x05c6, 0x900c, 4)},
 551        {QMI_FIXED_INTF(0x05c6, 0x900c, 5)},
 552        {QMI_FIXED_INTF(0x05c6, 0x900c, 6)},
 553        {QMI_FIXED_INTF(0x05c6, 0x900d, 5)},
 554        {QMI_FIXED_INTF(0x05c6, 0x900f, 3)},
 555        {QMI_FIXED_INTF(0x05c6, 0x900f, 4)},
 556        {QMI_FIXED_INTF(0x05c6, 0x900f, 5)},
 557        {QMI_FIXED_INTF(0x05c6, 0x9010, 4)},
 558        {QMI_FIXED_INTF(0x05c6, 0x9010, 5)},
 559        {QMI_FIXED_INTF(0x05c6, 0x9011, 3)},
 560        {QMI_FIXED_INTF(0x05c6, 0x9011, 4)},
 561        {QMI_FIXED_INTF(0x05c6, 0x9021, 1)},
 562        {QMI_FIXED_INTF(0x05c6, 0x9022, 2)},
 563        {QMI_FIXED_INTF(0x05c6, 0x9025, 4)},    /* Alcatel-sbell ASB TL131 TDD LTE  (China Mobile) */
 564        {QMI_FIXED_INTF(0x05c6, 0x9026, 3)},
 565        {QMI_FIXED_INTF(0x05c6, 0x902e, 5)},
 566        {QMI_FIXED_INTF(0x05c6, 0x9031, 5)},
 567        {QMI_FIXED_INTF(0x05c6, 0x9032, 4)},
 568        {QMI_FIXED_INTF(0x05c6, 0x9033, 3)},
 569        {QMI_FIXED_INTF(0x05c6, 0x9033, 4)},
 570        {QMI_FIXED_INTF(0x05c6, 0x9033, 5)},
 571        {QMI_FIXED_INTF(0x05c6, 0x9033, 6)},
 572        {QMI_FIXED_INTF(0x05c6, 0x9034, 3)},
 573        {QMI_FIXED_INTF(0x05c6, 0x9034, 4)},
 574        {QMI_FIXED_INTF(0x05c6, 0x9034, 5)},
 575        {QMI_FIXED_INTF(0x05c6, 0x9034, 6)},
 576        {QMI_FIXED_INTF(0x05c6, 0x9034, 7)},
 577        {QMI_FIXED_INTF(0x05c6, 0x9035, 4)},
 578        {QMI_FIXED_INTF(0x05c6, 0x9036, 3)},
 579        {QMI_FIXED_INTF(0x05c6, 0x9037, 5)},
 580        {QMI_FIXED_INTF(0x05c6, 0x9038, 4)},
 581        {QMI_FIXED_INTF(0x05c6, 0x903b, 7)},
 582        {QMI_FIXED_INTF(0x05c6, 0x903c, 6)},
 583        {QMI_FIXED_INTF(0x05c6, 0x903d, 6)},
 584        {QMI_FIXED_INTF(0x05c6, 0x903e, 5)},
 585        {QMI_FIXED_INTF(0x05c6, 0x9043, 3)},
 586        {QMI_FIXED_INTF(0x05c6, 0x9046, 3)},
 587        {QMI_FIXED_INTF(0x05c6, 0x9046, 4)},
 588        {QMI_FIXED_INTF(0x05c6, 0x9046, 5)},
 589        {QMI_FIXED_INTF(0x05c6, 0x9047, 2)},
 590        {QMI_FIXED_INTF(0x05c6, 0x9047, 3)},
 591        {QMI_FIXED_INTF(0x05c6, 0x9047, 4)},
 592        {QMI_FIXED_INTF(0x05c6, 0x9048, 4)},
 593        {QMI_FIXED_INTF(0x05c6, 0x9048, 5)},
 594        {QMI_FIXED_INTF(0x05c6, 0x9048, 6)},
 595        {QMI_FIXED_INTF(0x05c6, 0x9048, 7)},
 596        {QMI_FIXED_INTF(0x05c6, 0x9048, 8)},
 597        {QMI_FIXED_INTF(0x05c6, 0x904c, 5)},
 598        {QMI_FIXED_INTF(0x05c6, 0x904c, 6)},
 599        {QMI_FIXED_INTF(0x05c6, 0x904c, 7)},
 600        {QMI_FIXED_INTF(0x05c6, 0x904c, 8)},
 601        {QMI_FIXED_INTF(0x05c6, 0x9050, 3)},
 602        {QMI_FIXED_INTF(0x05c6, 0x9052, 4)},
 603        {QMI_FIXED_INTF(0x05c6, 0x9053, 6)},
 604        {QMI_FIXED_INTF(0x05c6, 0x9053, 7)},
 605        {QMI_FIXED_INTF(0x05c6, 0x9054, 5)},
 606        {QMI_FIXED_INTF(0x05c6, 0x9054, 6)},
 607        {QMI_FIXED_INTF(0x05c6, 0x9055, 3)},
 608        {QMI_FIXED_INTF(0x05c6, 0x9055, 4)},
 609        {QMI_FIXED_INTF(0x05c6, 0x9055, 5)},
 610        {QMI_FIXED_INTF(0x05c6, 0x9055, 6)},
 611        {QMI_FIXED_INTF(0x05c6, 0x9055, 7)},
 612        {QMI_FIXED_INTF(0x05c6, 0x9056, 3)},
 613        {QMI_FIXED_INTF(0x05c6, 0x9062, 2)},
 614        {QMI_FIXED_INTF(0x05c6, 0x9062, 3)},
 615        {QMI_FIXED_INTF(0x05c6, 0x9062, 4)},
 616        {QMI_FIXED_INTF(0x05c6, 0x9062, 5)},
 617        {QMI_FIXED_INTF(0x05c6, 0x9062, 6)},
 618        {QMI_FIXED_INTF(0x05c6, 0x9062, 7)},
 619        {QMI_FIXED_INTF(0x05c6, 0x9062, 8)},
 620        {QMI_FIXED_INTF(0x05c6, 0x9062, 9)},
 621        {QMI_FIXED_INTF(0x05c6, 0x9064, 3)},
 622        {QMI_FIXED_INTF(0x05c6, 0x9065, 6)},
 623        {QMI_FIXED_INTF(0x05c6, 0x9065, 7)},
 624        {QMI_FIXED_INTF(0x05c6, 0x9066, 5)},
 625        {QMI_FIXED_INTF(0x05c6, 0x9066, 6)},
 626        {QMI_FIXED_INTF(0x05c6, 0x9067, 1)},
 627        {QMI_FIXED_INTF(0x05c6, 0x9068, 2)},
 628        {QMI_FIXED_INTF(0x05c6, 0x9068, 3)},
 629        {QMI_FIXED_INTF(0x05c6, 0x9068, 4)},
 630        {QMI_FIXED_INTF(0x05c6, 0x9068, 5)},
 631        {QMI_FIXED_INTF(0x05c6, 0x9068, 6)},
 632        {QMI_FIXED_INTF(0x05c6, 0x9068, 7)},
 633        {QMI_FIXED_INTF(0x05c6, 0x9069, 5)},
 634        {QMI_FIXED_INTF(0x05c6, 0x9069, 6)},
 635        {QMI_FIXED_INTF(0x05c6, 0x9069, 7)},
 636        {QMI_FIXED_INTF(0x05c6, 0x9069, 8)},
 637        {QMI_FIXED_INTF(0x05c6, 0x9070, 4)},
 638        {QMI_FIXED_INTF(0x05c6, 0x9070, 5)},
 639        {QMI_FIXED_INTF(0x05c6, 0x9075, 5)},
 640        {QMI_FIXED_INTF(0x05c6, 0x9076, 4)},
 641        {QMI_FIXED_INTF(0x05c6, 0x9076, 5)},
 642        {QMI_FIXED_INTF(0x05c6, 0x9076, 6)},
 643        {QMI_FIXED_INTF(0x05c6, 0x9076, 7)},
 644        {QMI_FIXED_INTF(0x05c6, 0x9076, 8)},
 645        {QMI_FIXED_INTF(0x05c6, 0x9077, 3)},
 646        {QMI_FIXED_INTF(0x05c6, 0x9077, 4)},
 647        {QMI_FIXED_INTF(0x05c6, 0x9077, 5)},
 648        {QMI_FIXED_INTF(0x05c6, 0x9077, 6)},
 649        {QMI_FIXED_INTF(0x05c6, 0x9078, 3)},
 650        {QMI_FIXED_INTF(0x05c6, 0x9079, 4)},
 651        {QMI_FIXED_INTF(0x05c6, 0x9079, 5)},
 652        {QMI_FIXED_INTF(0x05c6, 0x9079, 6)},
 653        {QMI_FIXED_INTF(0x05c6, 0x9079, 7)},
 654        {QMI_FIXED_INTF(0x05c6, 0x9079, 8)},
 655        {QMI_FIXED_INTF(0x05c6, 0x9080, 5)},
 656        {QMI_FIXED_INTF(0x05c6, 0x9080, 6)},
 657        {QMI_FIXED_INTF(0x05c6, 0x9080, 7)},
 658        {QMI_FIXED_INTF(0x05c6, 0x9080, 8)},
 659        {QMI_FIXED_INTF(0x05c6, 0x9083, 3)},
 660        {QMI_FIXED_INTF(0x05c6, 0x9084, 4)},
 661        {QMI_FIXED_INTF(0x05c6, 0x920d, 0)},
 662        {QMI_FIXED_INTF(0x05c6, 0x920d, 5)},
 663        {QMI_FIXED_INTF(0x12d1, 0x140c, 1)},    /* Huawei E173 */
 664        {QMI_FIXED_INTF(0x12d1, 0x14ac, 1)},    /* Huawei E1820 */
 665        {QMI_FIXED_INTF(0x19d2, 0x0002, 1)},
 666        {QMI_FIXED_INTF(0x19d2, 0x0012, 1)},
 667        {QMI_FIXED_INTF(0x19d2, 0x0017, 3)},
 668        {QMI_FIXED_INTF(0x19d2, 0x0019, 3)},    /* ONDA MT689DC */
 669        {QMI_FIXED_INTF(0x19d2, 0x0021, 4)},
 670        {QMI_FIXED_INTF(0x19d2, 0x0025, 1)},
 671        {QMI_FIXED_INTF(0x19d2, 0x0031, 4)},
 672        {QMI_FIXED_INTF(0x19d2, 0x0042, 4)},
 673        {QMI_FIXED_INTF(0x19d2, 0x0049, 5)},
 674        {QMI_FIXED_INTF(0x19d2, 0x0052, 4)},
 675        {QMI_FIXED_INTF(0x19d2, 0x0055, 1)},    /* ZTE (Vodafone) K3520-Z */
 676        {QMI_FIXED_INTF(0x19d2, 0x0058, 4)},
 677        {QMI_FIXED_INTF(0x19d2, 0x0063, 4)},    /* ZTE (Vodafone) K3565-Z */
 678        {QMI_FIXED_INTF(0x19d2, 0x0104, 4)},    /* ZTE (Vodafone) K4505-Z */
 679        {QMI_FIXED_INTF(0x19d2, 0x0113, 5)},
 680        {QMI_FIXED_INTF(0x19d2, 0x0118, 5)},
 681        {QMI_FIXED_INTF(0x19d2, 0x0121, 5)},
 682        {QMI_FIXED_INTF(0x19d2, 0x0123, 4)},
 683        {QMI_FIXED_INTF(0x19d2, 0x0124, 5)},
 684        {QMI_FIXED_INTF(0x19d2, 0x0125, 6)},
 685        {QMI_FIXED_INTF(0x19d2, 0x0126, 5)},
 686        {QMI_FIXED_INTF(0x19d2, 0x0130, 1)},
 687        {QMI_FIXED_INTF(0x19d2, 0x0133, 3)},
 688        {QMI_FIXED_INTF(0x19d2, 0x0141, 5)},
 689        {QMI_FIXED_INTF(0x19d2, 0x0157, 5)},    /* ZTE MF683 */
 690        {QMI_FIXED_INTF(0x19d2, 0x0158, 3)},
 691        {QMI_FIXED_INTF(0x19d2, 0x0167, 4)},    /* ZTE MF820D */
 692        {QMI_FIXED_INTF(0x19d2, 0x0168, 4)},
 693        {QMI_FIXED_INTF(0x19d2, 0x0176, 3)},
 694        {QMI_FIXED_INTF(0x19d2, 0x0178, 3)},
 695        {QMI_FIXED_INTF(0x19d2, 0x0191, 4)},    /* ZTE EuFi890 */
 696        {QMI_FIXED_INTF(0x19d2, 0x0199, 1)},    /* ZTE MF820S */
 697        {QMI_FIXED_INTF(0x19d2, 0x0200, 1)},
 698        {QMI_FIXED_INTF(0x19d2, 0x0257, 3)},    /* ZTE MF821 */
 699        {QMI_FIXED_INTF(0x19d2, 0x0265, 4)},    /* ONDA MT8205 4G LTE */
 700        {QMI_FIXED_INTF(0x19d2, 0x0284, 4)},    /* ZTE MF880 */
 701        {QMI_FIXED_INTF(0x19d2, 0x0326, 4)},    /* ZTE MF821D */
 702        {QMI_FIXED_INTF(0x19d2, 0x0412, 4)},    /* Telewell TW-LTE 4G */
 703        {QMI_FIXED_INTF(0x19d2, 0x1008, 4)},    /* ZTE (Vodafone) K3570-Z */
 704        {QMI_FIXED_INTF(0x19d2, 0x1010, 4)},    /* ZTE (Vodafone) K3571-Z */
 705        {QMI_FIXED_INTF(0x19d2, 0x1012, 4)},
 706        {QMI_FIXED_INTF(0x19d2, 0x1018, 3)},    /* ZTE (Vodafone) K5006-Z */
 707        {QMI_FIXED_INTF(0x19d2, 0x1021, 2)},
 708        {QMI_FIXED_INTF(0x19d2, 0x1245, 4)},
 709        {QMI_FIXED_INTF(0x19d2, 0x1247, 4)},
 710        {QMI_FIXED_INTF(0x19d2, 0x1252, 4)},
 711        {QMI_FIXED_INTF(0x19d2, 0x1254, 4)},
 712        {QMI_FIXED_INTF(0x19d2, 0x1255, 3)},
 713        {QMI_FIXED_INTF(0x19d2, 0x1255, 4)},
 714        {QMI_FIXED_INTF(0x19d2, 0x1256, 4)},
 715        {QMI_FIXED_INTF(0x19d2, 0x1401, 2)},
 716        {QMI_FIXED_INTF(0x19d2, 0x1402, 2)},    /* ZTE MF60 */
 717        {QMI_FIXED_INTF(0x19d2, 0x1424, 2)},
 718        {QMI_FIXED_INTF(0x19d2, 0x1425, 2)},
 719        {QMI_FIXED_INTF(0x19d2, 0x1426, 2)},    /* ZTE MF91 */
 720        {QMI_FIXED_INTF(0x19d2, 0x2002, 4)},    /* ZTE (Vodafone) K3765-Z */
 721        {QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)},    /* Sierra Wireless MC7700 */
 722        {QMI_FIXED_INTF(0x114f, 0x68a2, 8)},    /* Sierra Wireless MC7750 */
 723        {QMI_FIXED_INTF(0x1199, 0x68a2, 8)},    /* Sierra Wireless MC7710 in QMI mode */
 724        {QMI_FIXED_INTF(0x1199, 0x68a2, 19)},   /* Sierra Wireless MC7710 in QMI mode */
 725        {QMI_FIXED_INTF(0x1199, 0x901c, 8)},    /* Sierra Wireless EM7700 */
 726        {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)},    /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */
 727        {QMI_FIXED_INTF(0x2357, 0x0201, 4)},    /* TP-LINK HSUPA Modem MA180 */
 728        {QMI_FIXED_INTF(0x2357, 0x9000, 4)},    /* TP-LINK MA260 */
 729        {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)},    /* Telit LE920 */
 730        {QMI_FIXED_INTF(0x1bc7, 0x1201, 2)},    /* Telit LE920 */
 731        {QMI_FIXED_INTF(0x0b3c, 0xc005, 6)},    /* Olivetti Olicard 200 */
 732        {QMI_FIXED_INTF(0x1e2d, 0x0060, 4)},    /* Cinterion PLxx */
 733
 734        /* 4. Gobi 1000 devices */
 735        {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},    /* Acer Gobi Modem Device */
 736        {QMI_GOBI1K_DEVICE(0x03f0, 0x1f1d)},    /* HP un2400 Gobi Modem Device */
 737        {QMI_GOBI1K_DEVICE(0x04da, 0x250d)},    /* Panasonic Gobi Modem device */
 738        {QMI_GOBI1K_DEVICE(0x413c, 0x8172)},    /* Dell Gobi Modem device */
 739        {QMI_GOBI1K_DEVICE(0x1410, 0xa001)},    /* Novatel/Verizon USB-1000 */
 740        {QMI_GOBI1K_DEVICE(0x1410, 0xa002)},    /* Novatel Gobi Modem device */
 741        {QMI_GOBI1K_DEVICE(0x1410, 0xa003)},    /* Novatel Gobi Modem device */
 742        {QMI_GOBI1K_DEVICE(0x1410, 0xa004)},    /* Novatel Gobi Modem device */
 743        {QMI_GOBI1K_DEVICE(0x1410, 0xa005)},    /* Novatel Gobi Modem device */
 744        {QMI_GOBI1K_DEVICE(0x1410, 0xa006)},    /* Novatel Gobi Modem device */
 745        {QMI_GOBI1K_DEVICE(0x1410, 0xa007)},    /* Novatel Gobi Modem device */
 746        {QMI_GOBI1K_DEVICE(0x0b05, 0x1776)},    /* Asus Gobi Modem device */
 747        {QMI_GOBI1K_DEVICE(0x19d2, 0xfff3)},    /* ONDA Gobi Modem device */
 748        {QMI_GOBI1K_DEVICE(0x05c6, 0x9001)},    /* Generic Gobi Modem device */
 749        {QMI_GOBI1K_DEVICE(0x05c6, 0x9002)},    /* Generic Gobi Modem device */
 750        {QMI_GOBI1K_DEVICE(0x05c6, 0x9202)},    /* Generic Gobi Modem device */
 751        {QMI_GOBI1K_DEVICE(0x05c6, 0x9203)},    /* Generic Gobi Modem device */
 752        {QMI_GOBI1K_DEVICE(0x05c6, 0x9222)},    /* Generic Gobi Modem device */
 753        {QMI_GOBI1K_DEVICE(0x05c6, 0x9009)},    /* Generic Gobi Modem device */
 754
 755        /* 5. Gobi 2000 and 3000 devices */
 756        {QMI_GOBI_DEVICE(0x413c, 0x8186)},      /* Dell Gobi 2000 Modem device (N0218, VU936) */
 757        {QMI_GOBI_DEVICE(0x413c, 0x8194)},      /* Dell Gobi 3000 Composite */
 758        {QMI_GOBI_DEVICE(0x05c6, 0x920b)},      /* Generic Gobi 2000 Modem device */
 759        {QMI_GOBI_DEVICE(0x05c6, 0x9225)},      /* Sony Gobi 2000 Modem device (N0279, VU730) */
 760        {QMI_GOBI_DEVICE(0x05c6, 0x9245)},      /* Samsung Gobi 2000 Modem device (VL176) */
 761        {QMI_GOBI_DEVICE(0x03f0, 0x251d)},      /* HP Gobi 2000 Modem device (VP412) */
 762        {QMI_GOBI_DEVICE(0x05c6, 0x9215)},      /* Acer Gobi 2000 Modem device (VP413) */
 763        {QMI_GOBI_DEVICE(0x05c6, 0x9265)},      /* Asus Gobi 2000 Modem device (VR305) */
 764        {QMI_GOBI_DEVICE(0x05c6, 0x9235)},      /* Top Global Gobi 2000 Modem device (VR306) */
 765        {QMI_GOBI_DEVICE(0x05c6, 0x9275)},      /* iRex Technologies Gobi 2000 Modem device (VR307) */
 766        {QMI_GOBI_DEVICE(0x0af0, 0x8120)},      /* Option GTM681W */
 767        {QMI_GOBI_DEVICE(0x1199, 0x68a5)},      /* Sierra Wireless Modem */
 768        {QMI_GOBI_DEVICE(0x1199, 0x68a9)},      /* Sierra Wireless Modem */
 769        {QMI_GOBI_DEVICE(0x1199, 0x9001)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
 770        {QMI_GOBI_DEVICE(0x1199, 0x9002)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
 771        {QMI_GOBI_DEVICE(0x1199, 0x9003)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
 772        {QMI_GOBI_DEVICE(0x1199, 0x9004)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
 773        {QMI_GOBI_DEVICE(0x1199, 0x9005)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
 774        {QMI_GOBI_DEVICE(0x1199, 0x9006)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
 775        {QMI_GOBI_DEVICE(0x1199, 0x9007)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
 776        {QMI_GOBI_DEVICE(0x1199, 0x9008)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
 777        {QMI_GOBI_DEVICE(0x1199, 0x9009)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
 778        {QMI_GOBI_DEVICE(0x1199, 0x900a)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
 779        {QMI_GOBI_DEVICE(0x1199, 0x9011)},      /* Sierra Wireless Gobi 2000 Modem device (MC8305) */
 780        {QMI_GOBI_DEVICE(0x16d8, 0x8002)},      /* CMDTech Gobi 2000 Modem device (VU922) */
 781        {QMI_GOBI_DEVICE(0x05c6, 0x9205)},      /* Gobi 2000 Modem device */
 782        {QMI_GOBI_DEVICE(0x1199, 0x9013)},      /* Sierra Wireless Gobi 3000 Modem device (MC8355) */
 783        {QMI_GOBI_DEVICE(0x03f0, 0x371d)},      /* HP un2430 Mobile Broadband Module */
 784        {QMI_GOBI_DEVICE(0x1199, 0x9015)},      /* Sierra Wireless Gobi 3000 Modem device */
 785        {QMI_GOBI_DEVICE(0x1199, 0x9019)},      /* Sierra Wireless Gobi 3000 Modem device */
 786        {QMI_GOBI_DEVICE(0x1199, 0x901b)},      /* Sierra Wireless MC7770 */
 787        {QMI_GOBI_DEVICE(0x12d1, 0x14f1)},      /* Sony Gobi 3000 Composite */
 788        {QMI_GOBI_DEVICE(0x1410, 0xa021)},      /* Foxconn Gobi 3000 Modem device (Novatel E396) */
 789
 790        { }                                     /* END */
 791};
 792MODULE_DEVICE_TABLE(usb, products);
 793
 794static int qmi_wwan_probe(struct usb_interface *intf,
 795                          const struct usb_device_id *prod)
 796{
 797        struct usb_device_id *id = (struct usb_device_id *)prod;
 798
 799        /* Workaround to enable dynamic IDs.  This disables usbnet
 800         * blacklisting functionality.  Which, if required, can be
 801         * reimplemented here by using a magic "blacklist" value
 802         * instead of 0 in the static device id table
 803         */
 804        if (!id->driver_info) {
 805                dev_dbg(&intf->dev, "setting defaults for dynamic device id\n");
 806                id->driver_info = (unsigned long)&qmi_wwan_info;
 807        }
 808
 809        return usbnet_probe(intf, id);
 810}
 811
 812static struct usb_driver qmi_wwan_driver = {
 813        .name                 = "qmi_wwan",
 814        .id_table             = products,
 815        .probe                = qmi_wwan_probe,
 816        .disconnect           = usbnet_disconnect,
 817        .suspend              = qmi_wwan_suspend,
 818        .resume               = qmi_wwan_resume,
 819        .reset_resume         = qmi_wwan_resume,
 820        .supports_autosuspend = 1,
 821        .disable_hub_initiated_lpm = 1,
 822};
 823
 824module_usb_driver(qmi_wwan_driver);
 825
 826MODULE_AUTHOR("Bjørn Mork <bjorn@mork.no>");
 827MODULE_DESCRIPTION("Qualcomm MSM Interface (QMI) WWAN driver");
 828MODULE_LICENSE("GPL");
 829