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 | struct usb_driver *subdriver = NULL; | 214 | struct usb_driver *subdriver = NULL; |
| 215 | atomic_t *pmcount = (void *)&dev->data[1]; | 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 | atomic_set(pmcount, 0); | 231 | atomic_set(pmcount, 0); |
| 218 | 232 | ||
| 219 | /* collect all three endpoints */ | 233 | /* collect all three endpoints */ |
| @@ -341,6 +355,17 @@ static const struct driver_info qmi_wwan_gobi = { · 121 unmodified lines | |||
| 341 | .manage_power = qmi_wwan_manage_power, | 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 | #define HUAWEI_VENDOR_ID 0x12D1 | 369 | #define HUAWEI_VENDOR_ID 0x12D1 |
| 345 | #define QMI_GOBI_DEVICE(vend, prod) \ | 370 | #define QMI_GOBI_DEVICE(vend, prod) \ |
| 346 | USB_DEVICE(vend, prod), \ | 371 | USB_DEVICE(vend, prod), \ |
| @@ -375,6 +400,15 @@ static const struct usb_device_id products[] = { · 28 unmodified lines | |||
| 375 | .bInterfaceProtocol = 0xff, | 400 | .bInterfaceProtocol = 0xff, |
| 376 | .driver_info = (unsigned long)&qmi_wwan_shared, | 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 | {QMI_GOBI_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ | 412 | {QMI_GOBI_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ |
| 379 | {QMI_GOBI_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ | 413 | {QMI_GOBI_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ |
| 380 | {QMI_GOBI_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ | 414 | {QMI_GOBI_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ |