ZTE have yet to discover the magic of USB descriptors. These devices use ff/ff/ff for class/subclass/protocol regardless of function, except for usb-storage. Use an interface number whitelist to force the driver to bind only to the QMI/wwan interface.
Unified · Split
| @@ -214,6 +214,20 @@ static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf) · 213 unmodified lines | ||
| 214 | 214 | struct usb_driver *subdriver = NULL; |
| 215 | 215 | atomic_t *pmcount = (void *)&dev->data[1]; |
| 216 | 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 | + | |
| 217 | 231 | atomic_set(pmcount, 0); |
| 218 | 232 | |
| 219 | 233 | /* collect all three endpoints */ |
| @@ -341,6 +355,17 @@ static const struct driver_info qmi_wwan_gobi = { · 121 unmodified lines | ||
| 341 | 355 | .manage_power = qmi_wwan_manage_power, |
| 342 | 356 | }; |
| 343 | 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 | + | |
| 344 | 369 | #define HUAWEI_VENDOR_ID 0x12D1 |
| 345 | 370 | #define QMI_GOBI_DEVICE(vend, prod) \ |
| 346 | 371 | USB_DEVICE(vend, prod), \ |
| @@ -375,6 +400,15 @@ static const struct usb_device_id products[] = { · 28 unmodified lines | ||
| 375 | 400 | .bInterfaceProtocol = 0xff, |
| 376 | 401 | .driver_info = (unsigned long)&qmi_wwan_shared, |
| 377 | 402 | }, |
| 403 | + { /* ZTE MF820D */ | |
| 404 | + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, | |
| 405 | + .idVendor = 0x19d2, | |
| 406 | + .idProduct = 0x0167, | |
| 407 | + .bInterfaceClass = 0xff, | |
| 408 | + .bInterfaceSubClass = 0xff, | |
| 409 | + .bInterfaceProtocol = 0xff, | |
| 410 | + .driver_info = (unsigned long)&qmi_wwan_force_int4, | |
| 411 | + }, | |
| 378 | 412 | {QMI_GOBI_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ |
| 379 | 413 | {QMI_GOBI_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ |
| 380 | 414 | {QMI_GOBI_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ |