1 /* 2 * Copyright (c) 2012 Bjørn Mork <bjorn@mork.no> 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * version 2 as published by the Free Software Foundation. 7 */ 8 9 #include <linux/module.h> 10 #include <linux/netdevice.h> 11 #include <linux/ethtool.h> 12 #include <linux/mii.h> 13 #include <linux/usb.h> 14 #include <linux/usb/cdc.h> 15 #include <linux/usb/usbnet.h> 16 #include <linux/usb/cdc-wdm.h> 17 18 /* The name of the CDC Device Management driver */ 19 #define DM_DRIVER "cdc_wdm" 20 21 /* 22 * This driver supports wwan (3G/LTE/?) devices using a vendor 23 * specific management protocol called Qualcomm MSM Interface (QMI) - 24 * in addition to the more common AT commands over serial interface 25 * management 26 * 27 * QMI is wrapped in CDC, using CDC encapsulated commands on the 28 * control ("master") interface of a two-interface CDC Union 29 * resembling standard CDC ECM. The devices do not use the control 30 * interface for any other CDC messages. Most likely because the 31 * management protocol is used in place of the standard CDC 32 * notifications NOTIFY_NETWORK_CONNECTION and NOTIFY_SPEED_CHANGE 33 * 34 * Handling a protocol like QMI is out of the scope for any driver. 35 * It can be exported as a character device using the cdc-wdm driver, 36 * which will enable userspace applications ("modem managers") to 37 * handle it. This may be required to use the network interface 38 * provided by the driver. 39 * 40 * These devices may alternatively/additionally be configured using AT 41 * commands on any of the serial interfaces driven by the option driver 42 * 43 * This driver binds only to the data ("slave") interface to enable 44 * the cdc-wdm driver to bind to the control interface. It still 45 * parses the CDC functional descriptors on the control interface to 46 * a) verify that this is indeed a handled interface (CDC Union 47 * header lists it as slave) 48 * b) get MAC address and other ethernet config from the CDC Ethernet 49 * header 50 * c) enable user bind requests against the control interface, which 51 * is the common way to bind to CDC Ethernet Control Model type 52 * interfaces 53 * d) provide a hint to the user about which interface is the 54 * corresponding management interface 55 */ 56 57 static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) 58 { 59 int status = -1; 60 struct usb_interface *control = NULL; 61 u8 *buf = intf->cur_altsetting->extra; 62 int len = intf->cur_altsetting->extralen; 63 struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc; 64 struct usb_cdc_union_desc *cdc_union = NULL; 65 struct usb_cdc_ether_desc *cdc_ether = NULL; 66 u32 required = 1 << USB_CDC_HEADER_TYPE | 1 << USB_CDC_UNION_TYPE; 67 u32 found = 0; 68 atomic_t *pmcount = (void *)&dev->data[1]; 69 70 atomic_set(pmcount, 0); 71 72 /* 73 * assume a data interface has no additional descriptors and 74 * that the control and data interface are numbered 75 * consecutively - this holds for the Huawei device at least 76 */ 77 if (len == 0 && desc->bInterfaceNumber > 0) { 78 control = usb_ifnum_to_if(dev->udev, desc->bInterfaceNumber - 1); 79 if (!control) 80 goto err; 81 82 buf = control->cur_altsetting->extra; 83 len = control->cur_altsetting->extralen; 84 dev_dbg(&intf->dev, "guessing \"control\" => %s, \"data\" => this\n", 85 dev_name(&control->dev)); 86 } 87 88 while (len > 3) { 89 struct usb_descriptor_header *h = (void *)buf; 90 91 /* ignore any misplaced descriptors */ 92 if (h->bDescriptorType != USB_DT_CS_INTERFACE) 93 goto next_desc; 94 95 /* buf[2] is CDC descriptor subtype */ 96 switch (buf[2]) { 97 case USB_CDC_HEADER_TYPE: 98 if (found & 1 << USB_CDC_HEADER_TYPE) { 99 dev_dbg(&intf->dev, "extra CDC header\n"); 100 goto err; 101 } 102 if (h->bLength != sizeof(struct usb_cdc_header_desc)) { 103 dev_dbg(&intf->dev, "CDC header len %u\n", h->bLength); 104 goto err; 105 } 106 break; 107 case USB_CDC_UNION_TYPE: 108 if (found & 1 << USB_CDC_UNION_TYPE) { 109 dev_dbg(&intf->dev, "extra CDC union\n"); 110 goto err; 111 } 112 if (h->bLength != sizeof(struct usb_cdc_union_desc)) { 113 dev_dbg(&intf->dev, "CDC union len %u\n", h->bLength); 114 goto err; 115 } 116 cdc_union = (struct usb_cdc_union_desc *)buf; 117 break; 118 case USB_CDC_ETHERNET_TYPE: 119 if (found & 1 << USB_CDC_ETHERNET_TYPE) { 120 dev_dbg(&intf->dev, "extra CDC ether\n"); 121 goto err; 122 } 123 if (h->bLength != sizeof(struct usb_cdc_ether_desc)) { 124 dev_dbg(&intf->dev, "CDC ether len %u\n", h->bLength); 125 goto err; 126 } 127 cdc_ether = (struct usb_cdc_ether_desc *)buf; 128 break; 129 } 130 131 /* 132 * Remember which CDC functional descriptors we've seen. Works 133 * for all types we care about, of which USB_CDC_ETHERNET_TYPE 134 * (0x0f) is the highest numbered 135 */ 136 if (buf[2] < 32) 137 found |= 1 << buf[2]; 138 139 next_desc: 140 len -= h->bLength; 141 buf += h->bLength; 142 } 143 144 /* did we find all the required ones? */ 145 if ((found & required) != required) { 146 dev_err(&intf->dev, "CDC functional descriptors missing\n"); 147 goto err; 148 } 149 150 /* give the user a helpful hint if trying to bind to the wrong interface */ 151 if (cdc_union && desc->bInterfaceNumber == cdc_union->bMasterInterface0) { 152 dev_err(&intf->dev, "leaving \"control\" interface for " DM_DRIVER " - try binding to %s instead!\n", 153 dev_name(&usb_ifnum_to_if(dev->udev, cdc_union->bSlaveInterface0)->dev)); 154 goto err; 155 } 156 157 /* errors aren't fatal - we can live with the dynamic address */ 158 if (cdc_ether) { 159 dev->hard_mtu = le16_to_cpu(cdc_ether->wMaxSegmentSize); 160 usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress); 161 } 162 163 /* success! point the user to the management interface */ 164 if (control) 165 dev_info(&intf->dev, "Use \"" DM_DRIVER "\" for QMI interface %s\n", 166 dev_name(&control->dev)); 167 168 /* XXX: add a sysfs symlink somewhere to help management applications find it? */ 169 170 /* collect bulk endpoints now that we know intf == "data" interface */ 171 status = usbnet_get_endpoints(dev, intf); 172 173 err: 174 return status; 175 } 176 177 /* using a counter to merge subdriver requests with our own into a combined state */ 178 static int qmi_wwan_manage_power(struct usbnet *dev, int on) 179 { 180 atomic_t *pmcount = (void *)&dev->data[1]; 181 int rv = 0; 182 183 dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__, atomic_read(pmcount), on); 184 185 if ((on && atomic_add_return(1, pmcount) == 1) || (!on && atomic_dec_and_test(pmcount))) { 186 /* need autopm_get/put here to ensure the usbcore sees the new value */ 187 rv = usb_autopm_get_interface(dev->intf); 188 if (rv < 0) 189 goto err; 190 dev->intf->needs_remote_wakeup = on; 191 usb_autopm_put_interface(dev->intf); 192 } 193 err: 194 return rv; 195 } 196 197 static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on) 198 { 199 struct usbnet *dev = usb_get_intfdata(intf); 200 return qmi_wwan_manage_power(dev, on); 201 } 202 203 /* Some devices combine the "control" and "data" functions into a 204 * single interface with all three endpoints: interrupt + bulk in and 205 * out 206 * 207 * Setting up cdc-wdm as a subdriver owning the interrupt endpoint 208 * will let it provide userspace access to the encapsulated QMI 209 * protocol without interfering with the usbnet operations. 210 */ 211 static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf) 212 { 213 int rv; 214 struct usb_driver *subdriver = NULL; 215 atomic_t *pmcount = (void *)&dev->data[1]; 216 217 /* ZTE makes devices where the interface descriptors and endpoint 218 * configurations of two or more interfaces are identical, even 219 * though the functions are completely different. If set, then 220 * driver_info->data is a bitmap of acceptable interface numbers 221 * allowing us to bind to one such interface without binding to 222 * all of them 223 */ 224 if (dev->driver_info->data && 225 !test_bit(intf->cur_altsetting->desc.bInterfaceNumber, &dev->driver_info->data)) { 226 dev_info(&intf->dev, "not on our whitelist - ignored"); 227 rv = -ENODEV; 228 goto err; 229 } 230 231 atomic_set(pmcount, 0); 232 233 /* collect all three endpoints */ 234 rv = usbnet_get_endpoints(dev, intf); 235 if (rv < 0) 236 goto err; 237 238 /* require interrupt endpoint for subdriver */ 239 if (!dev->status) { 240 rv = -EINVAL; 241 goto err; 242 } 243 244 subdriver = usb_cdc_wdm_register(intf, &dev->status->desc, 512, &qmi_wwan_cdc_wdm_manage_power); 245 if (IS_ERR(subdriver)) { 246 rv = PTR_ERR(subdriver); 247 goto err; 248 } 249 250 /* can't let usbnet use the interrupt endpoint */ 251 dev->status = NULL; 252 253 /* save subdriver struct for suspend/resume wrappers */ 254 dev->data[0] = (unsigned long)subdriver; 255 256 err: 257 return rv; 258 } 259 260 /* Gobi devices uses identical class/protocol codes for all interfaces regardless 261 * of function. Some of these are CDC ACM like and have the exact same endpoints 262 * we are looking for. This leaves two possible strategies for identifying the 263 * correct interface: 264 * a) hardcoding interface number, or 265 * b) use the fact that the wwan interface is the only one lacking additional 266 * (CDC functional) descriptors 267 * 268 * Let's see if we can get away with the generic b) solution. 269 */ 270 static int qmi_wwan_bind_gobi(struct usbnet *dev, struct usb_interface *intf) 271 { 272 int rv = -EINVAL; 273 274 /* ignore any interface with additional descriptors */ 275 if (intf->cur_altsetting->extralen) 276 goto err; 277 278 rv = qmi_wwan_bind_shared(dev, intf); 279 err: 280 return rv; 281 } 282 283 static void qmi_wwan_unbind_shared(struct usbnet *dev, struct usb_interface *intf) 284 { 285 struct usb_driver *subdriver = (void *)dev->data[0]; 286 287 if (subdriver && subdriver->disconnect) 288 subdriver->disconnect(intf); 289 290 dev->data[0] = (unsigned long)NULL; 291 } 292 293 /* suspend/resume wrappers calling both usbnet and the cdc-wdm 294 * subdriver if present. 295 * 296 * NOTE: cdc-wdm also supports pre/post_reset, but we cannot provide 297 * wrappers for those without adding usbnet reset support first. 298 */ 299 static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message) 300 { 301 struct usbnet *dev = usb_get_intfdata(intf); 302 struct usb_driver *subdriver = (void *)dev->data[0]; 303 int ret; 304 305 ret = usbnet_suspend(intf, message); 306 if (ret < 0) 307 goto err; 308 309 if (subdriver && subdriver->suspend) 310 ret = subdriver->suspend(intf, message); 311 if (ret < 0) 312 usbnet_resume(intf); 313 err: 314 return ret; 315 } 316 317 static int qmi_wwan_resume(struct usb_interface *intf) 318 { 319 struct usbnet *dev = usb_get_intfdata(intf); 320 struct usb_driver *subdriver = (void *)dev->data[0]; 321 int ret = 0; 322 323 if (subdriver && subdriver->resume) 324 ret = subdriver->resume(intf); 325 if (ret < 0) 326 goto err; 327 ret = usbnet_resume(intf); 328 if (ret < 0 && subdriver && subdriver->resume && subdriver->suspend) 329 subdriver->suspend(intf, PMSG_SUSPEND); 330 err: 331 return ret; 332 } 333 334 335 static const struct driver_info qmi_wwan_info = { 336 .description = "QMI speaking wwan device", 337 .flags = FLAG_WWAN, 338 .bind = qmi_wwan_bind, 339 .manage_power = qmi_wwan_manage_power, 340 }; 341 342 static const struct driver_info qmi_wwan_shared = { 343 .description = "QMI speaking wwan device with combined interface", 344 .flags = FLAG_WWAN, 345 .bind = qmi_wwan_bind_shared, 346 .unbind = qmi_wwan_unbind_shared, 347 .manage_power = qmi_wwan_manage_power, 348 }; 349 350 static const struct driver_info qmi_wwan_gobi = { 351 .description = "Qualcomm Gobi wwan/QMI device", 352 .flags = FLAG_WWAN, 353 .bind = qmi_wwan_bind_gobi, 354 .unbind = qmi_wwan_unbind_shared, 355 .manage_power = qmi_wwan_manage_power, 356 }; 357 358 /* ZTE suck at making USB descriptors */ 359 static const struct driver_info qmi_wwan_force_int4 = { 360 .description = "Qualcomm Gobi wwan/QMI device", 361 .flags = FLAG_WWAN, 362 .bind = qmi_wwan_bind_gobi, 363 .unbind = qmi_wwan_unbind_shared, 364 .manage_power = qmi_wwan_manage_power, 365 .data = BIT(4), /* interface whitelist bitmap */ 366 }; 367 368 /* Sierra Wireless provide equally useless interface descriptors 369 * Devices in QMI mode can be switched between two different 370 * configurations: 371 * a) USB interface #8 is QMI/wwan 372 * b) USB interfaces #8, #19 and #20 are QMI/wwan 373 * 374 * Both configurations provide a number of other interfaces (serial++), 375 * some of which have the same endpoint configuration as we expect, so 376 * a whitelist or blacklist is necessary. 377 * 378 * FIXME: The below whitelist should include BIT(20). It does not 379 * because I cannot get it to work... 380 */ 381 static const struct driver_info qmi_wwan_sierra = { 382 .description = "Sierra Wireless wwan/QMI device", 383 .flags = FLAG_WWAN, 384 .bind = qmi_wwan_bind_gobi, 385 .unbind = qmi_wwan_unbind_shared, 386 .manage_power = qmi_wwan_manage_power, 387 .data = BIT(8) | BIT(19), /* interface whitelist bitmap */ 388 }; 389 390 #define HUAWEI_VENDOR_ID 0x12D1 391 #define QMI_GOBI_DEVICE(vend, prod) \ 392 USB_DEVICE(vend, prod), \ 393 .driver_info = (unsigned long)&qmi_wwan_gobi 394 395 static const struct usb_device_id products[] = { 396 { /* Huawei E392, E398 and possibly others sharing both device id and more... */ 397 .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, 398 .idVendor = HUAWEI_VENDOR_ID, 399 .bInterfaceClass = USB_CLASS_VENDOR_SPEC, 400 .bInterfaceSubClass = 1, 401 .bInterfaceProtocol = 8, /* NOTE: This is the *slave* interface of the CDC Union! */ 402 .driver_info = (unsigned long)&qmi_wwan_info, 403 }, 404 { /* Huawei E392, E398 and possibly others in "Windows mode" 405 * using a combined control and data interface without any CDC 406 * functional descriptors 407 */ 408 .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, 409 .idVendor = HUAWEI_VENDOR_ID, 410 .bInterfaceClass = USB_CLASS_VENDOR_SPEC, 411 .bInterfaceSubClass = 1, 412 .bInterfaceProtocol = 17, 413 .driver_info = (unsigned long)&qmi_wwan_shared, 414 }, 415 { /* Pantech UML290 */ 416 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, 417 .idVendor = 0x106c, 418 .idProduct = 0x3718, 419 .bInterfaceClass = 0xff, 420 .bInterfaceSubClass = 0xf0, 421 .bInterfaceProtocol = 0xff, 422 .driver_info = (unsigned long)&qmi_wwan_shared, 423 }, 424 { /* ZTE MF820D */ 425 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, 426 .idVendor = 0x19d2, 427 .idProduct = 0x0167, 428 .bInterfaceClass = 0xff, 429 .bInterfaceSubClass = 0xff, 430 .bInterfaceProtocol = 0xff, 431 .driver_info = (unsigned long)&qmi_wwan_force_int4, 432 }, 433 { /* ZTE (Vodafone) K3565-Z */ 434 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, 435 .idVendor = 0x19d2, 436 .idProduct = 0x0063, 437 .bInterfaceClass = 0xff, 438 .bInterfaceSubClass = 0xff, 439 .bInterfaceProtocol = 0xff, 440 .driver_info = (unsigned long)&qmi_wwan_force_int4, 441 }, 442 { /* ZTE (Vodafone) K3570-Z */ 443 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, 444 .idVendor = 0x19d2, 445 .idProduct = 0x1008, 446 .bInterfaceClass = 0xff, 447 .bInterfaceSubClass = 0xff, 448 .bInterfaceProtocol = 0xff, 449 .driver_info = (unsigned long)&qmi_wwan_force_int4, 450 }, 451 { /* ZTE (Vodafone) K3571-Z */ 452 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, 453 .idVendor = 0x19d2, 454 .idProduct = 0x1010, 455 .bInterfaceClass = 0xff, 456 .bInterfaceSubClass = 0xff, 457 .bInterfaceProtocol = 0xff, 458 .driver_info = (unsigned long)&qmi_wwan_force_int4, 459 }, 460 { /* ZTE (Vodafone) K4505-Z */ 461 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, 462 .idVendor = 0x19d2, 463 .idProduct = 0x0104, 464 .bInterfaceClass = 0xff, 465 .bInterfaceSubClass = 0xff, 466 .bInterfaceProtocol = 0xff, 467 .driver_info = (unsigned long)&qmi_wwan_force_int4, 468 }, 469 { /* Sierra Wireless MC77xx in QMI mode */ 470 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, 471 .idVendor = 0x1199, 472 .idProduct = 0x68a2, 473 .bInterfaceClass = 0xff, 474 .bInterfaceSubClass = 0xff, 475 .bInterfaceProtocol = 0xff, 476 .driver_info = (unsigned long)&qmi_wwan_sierra, 477 }, 478 {QMI_GOBI_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ 479 {QMI_GOBI_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ 480 {QMI_GOBI_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ 481 {QMI_GOBI_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ 482 {QMI_GOBI_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */ 483 {QMI_GOBI_DEVICE(0x1410, 0xa001)}, /* Novatel Gobi Modem device */ 484 {QMI_GOBI_DEVICE(0x0b05, 0x1776)}, /* Asus Gobi Modem device */ 485 {QMI_GOBI_DEVICE(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */ 486 {QMI_GOBI_DEVICE(0x05c6, 0x9001)}, /* Generic Gobi Modem device */ 487 {QMI_GOBI_DEVICE(0x05c6, 0x9002)}, /* Generic Gobi Modem device */ 488 {QMI_GOBI_DEVICE(0x05c6, 0x9202)}, /* Generic Gobi Modem device */ 489 {QMI_GOBI_DEVICE(0x05c6, 0x9203)}, /* Generic Gobi Modem device */ 490 {QMI_GOBI_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ 491 {QMI_GOBI_DEVICE(0x05c6, 0x9009)}, /* Generic Gobi Modem device */ 492 {QMI_GOBI_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */ 493 {QMI_GOBI_DEVICE(0x05c6, 0x920b)}, /* Generic Gobi 2000 Modem device */ 494 {QMI_GOBI_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */ 495 {QMI_GOBI_DEVICE(0x05c6, 0x9245)}, /* Samsung Gobi 2000 Modem device (VL176) */ 496 {QMI_GOBI_DEVICE(0x03f0, 0x251d)}, /* HP Gobi 2000 Modem device (VP412) */ 497 {QMI_GOBI_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */ 498 {QMI_GOBI_DEVICE(0x05c6, 0x9265)}, /* Asus Gobi 2000 Modem device (VR305) */ 499 {QMI_GOBI_DEVICE(0x05c6, 0x9235)}, /* Top Global Gobi 2000 Modem device (VR306) */ 500 {QMI_GOBI_DEVICE(0x05c6, 0x9275)}, /* iRex Technologies Gobi 2000 Modem device (VR307) */ 501 {QMI_GOBI_DEVICE(0x1199, 0x9001)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 502 {QMI_GOBI_DEVICE(0x1199, 0x9002)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 503 {QMI_GOBI_DEVICE(0x1199, 0x9003)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 504 {QMI_GOBI_DEVICE(0x1199, 0x9004)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 505 {QMI_GOBI_DEVICE(0x1199, 0x9005)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 506 {QMI_GOBI_DEVICE(0x1199, 0x9006)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 507 {QMI_GOBI_DEVICE(0x1199, 0x9007)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 508 {QMI_GOBI_DEVICE(0x1199, 0x9008)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 509 {QMI_GOBI_DEVICE(0x1199, 0x9009)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 510 {QMI_GOBI_DEVICE(0x1199, 0x900a)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 511 {QMI_GOBI_DEVICE(0x1199, 0x9011)}, /* Sierra Wireless Gobi 2000 Modem device (MC8305) */ 512 {QMI_GOBI_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ 513 {QMI_GOBI_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */ 514 {QMI_GOBI_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ 515 { } /* END */ 516 }; 517 MODULE_DEVICE_TABLE(usb, products); 518 519 static struct usb_driver qmi_wwan_driver = { 520 .name = "qmi_wwan", 521 .id_table = products, 522 .probe = usbnet_probe, 523 .disconnect = usbnet_disconnect, 524 .suspend = qmi_wwan_suspend, 525 .resume = qmi_wwan_resume, 526 .reset_resume = qmi_wwan_resume, 527 .supports_autosuspend = 1, 528 }; 529 530 static int __init qmi_wwan_init(void) 531 { 532 return usb_register(&qmi_wwan_driver); 533 } 534 module_init(qmi_wwan_init); 535 536 static void __exit qmi_wwan_exit(void) 537 { 538 usb_deregister(&qmi_wwan_driver); 539 } 540 module_exit(qmi_wwan_exit); 541 542 MODULE_AUTHOR("Bjørn Mork <bjorn@mork.no>"); 543 MODULE_DESCRIPTION("Qualcomm MSM Interface (QMI) WWAN driver"); 544 MODULE_LICENSE("GPL"); 545