aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorBjørn Mork <bjorn@mork.no>2015-11-16 07:15:46 -0500
committerJohan Hovold <johan@kernel.org>2015-11-16 12:29:07 -0500
commit59536da34513c594af2a6fd35ba65ea45b6960a1 (patch)
tree1a440447e5f06059cc50bf16a310f6d5e34c9b0c /drivers/usb
parent1bcb49e663f88bccee35b8688e6a3da2bea31fd4 (diff)
USB: qcserial: Fix support for HP lt4112 LTE/HSPA+ Gobi 4G Modem
The DEVICE_HWI type was added under the faulty assumption that Huawei devices based on Qualcomm chipsets and firmware use the static USB interface numbering known from Gobi devices. But this model does not apply to Huawei devices like the HP branded lt4112 (Huawei me906e). Huawei firmwares will dynamically assign interface numbers. Functions are renumbered when the firmware is reconfigured. Fix by changing the DEVICE_HWI type to use a simplified version of Huawei's subclass + protocol scheme: Blacklisting known network interface combinations and assuming the rest are serial. Reported-and-tested-by: Muri Nicanor <muri+libqmi@immerda.ch> Tested-by: Martin Hauke <mardnh@gmx.de> Cc: <stable@vger.kernel.org> Fixes: e7181d005e84 ("USB: qcserial: Add support for HP lt4112 LTE/HSPA+ Gobi 4G Modem") Signed-off-by: Bjørn Mork <bjorn@mork.no> Signed-off-by: Johan Hovold <johan@kernel.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/serial/qcserial.c54
1 files changed, 34 insertions, 20 deletions
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 0e46af0d0cb4..9919d2a9faf2 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -215,6 +215,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
215 int altsetting = -1; 215 int altsetting = -1;
216 bool sendsetup = false; 216 bool sendsetup = false;
217 217
218 /* we only support vendor specific functions */
219 if (intf->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
220 goto done;
221
218 nintf = serial->dev->actconfig->desc.bNumInterfaces; 222 nintf = serial->dev->actconfig->desc.bNumInterfaces;
219 dev_dbg(dev, "Num Interfaces = %d\n", nintf); 223 dev_dbg(dev, "Num Interfaces = %d\n", nintf);
220 ifnum = intf->desc.bInterfaceNumber; 224 ifnum = intf->desc.bInterfaceNumber;
@@ -341,29 +345,39 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
341 break; 345 break;
342 case QCSERIAL_HWI: 346 case QCSERIAL_HWI:
343 /* 347 /*
344 * Huawei layout: 348 * Huawei devices map functions by subclass + protocol
345 * 0: AT-capable modem port 349 * instead of interface numbers. The protocol identify
346 * 1: DM/DIAG 350 * a specific function, while the subclass indicate a
347 * 2: AT-capable modem port 351 * specific firmware source
348 * 3: CCID-compatible PCSC interface 352 *
349 * 4: QMI/net 353 * This is a blacklist of functions known to be
350 * 5: NMEA 354 * non-serial. The rest are assumed to be serial and
355 * will be handled by this driver
351 */ 356 */
352 switch (ifnum) { 357 switch (intf->desc.bInterfaceProtocol) {
353 case 0: 358 /* QMI combined (qmi_wwan) */
354 case 2: 359 case 0x07:
355 dev_dbg(dev, "Modem port found\n"); 360 case 0x37:
356 break; 361 case 0x67:
357 case 1: 362 /* QMI data (qmi_wwan) */
358 dev_dbg(dev, "DM/DIAG interface found\n"); 363 case 0x08:
359 break; 364 case 0x38:
360 case 5: 365 case 0x68:
361 dev_dbg(dev, "NMEA GPS interface found\n"); 366 /* QMI control (qmi_wwan) */
362 break; 367 case 0x09:
363 default: 368 case 0x39:
364 /* don't claim any unsupported interface */ 369 case 0x69:
370 /* NCM like (huawei_cdc_ncm) */
371 case 0x16:
372 case 0x46:
373 case 0x76:
365 altsetting = -1; 374 altsetting = -1;
366 break; 375 break;
376 default:
377 dev_dbg(dev, "Huawei type serial port found (%02x/%02x/%02x)\n",
378 intf->desc.bInterfaceClass,
379 intf->desc.bInterfaceSubClass,
380 intf->desc.bInterfaceProtocol);
367 } 381 }
368 break; 382 break;
369 default: 383 default: