Received: by 2002:a25:ab43:0:0:0:0:0 with SMTP id u61csp271327ybi; Wed, 29 May 2019 21:05:49 -0700 (PDT) X-Google-Smtp-Source: APXvYqwyhsrj30fzfx7O55cp+QVErLXMpRJmQ5fOtaS6oK0bwrOjjseCvmvA4CozCQh9qCjReEUB X-Received: by 2002:a62:1ec3:: with SMTP id e186mr1651217pfe.197.1559189148903; Wed, 29 May 2019 21:05:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1559189148; cv=none; d=google.com; s=arc-20160816; b=IYXx0AnK9iQCouFsAig7x0DQtJyaV7Mw6thZI2DyGG44jFGLC6bdV+8Ljb44mDdaM0 UVmLmISXHXUceYX88vSMTFCzfoJeFRwRUnb7IGn82QLboH2eczrZnuv+1HBM8HIfOV+p zzmbUAtJL+JU1DjPRavgKgmQGx+XJSA/jT3bcWgMT+IMcjErXSO/XWik22ntFktpyKCK nYWsgGDq2xlEXzfl5ZvI7JKsLU4mMvP7s5XOJe92cvnsdISib69eIzd34TgkI33um1yz J+C3+kAY20Ouq4mdlWCjXP/JzMPgIRN4cMBqG2JfdLF6ArwnNP5m6Op8jy9VFXQMByUs I9ng== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=llAbDhgLo0DQVOPhvozwx0bIYbzmS2YscyCoeb9Tj6c=; b=JqNEw4sRP++K0RsdKRfsnzBnyC7Ub8OSZ6Y5+El7n97PveWAKaHxDFNrLWnmjD1A52 nJ8CR6k6sTMCTceIT6qRwvwhD81N9hs4xl6NvUdotOL12Goy1CMH/+U1vgsf7mBaJuZS Yl1anDiZ1R4Z74hRZNnssHCjOJlITfuZL1gPgDmoKDt68rxMuBw+VHjEj+gKGYBby65r bA2czg6vFXITn7BU/eC1QjGz5qQ97wH4kv0xHVvzolGxsk7hPwFV1FbwP0BA1lBjwsO9 6rlPMKVsHkLUDvUCPkhvhsqjVGP4jEG+AWahUyJrJpw/G0XxgBr2Hvw5JccMigOf7wPt U21w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=hZvtfaBV; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id cg12si2094727plb.19.2019.05.29.21.05.33; Wed, 29 May 2019 21:05:48 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=hZvtfaBV; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731731AbfE3EDO (ORCPT + 99 others); Thu, 30 May 2019 00:03:14 -0400 Received: from mail.kernel.org ([198.145.29.99]:49208 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731354AbfE3DR6 (ORCPT ); Wed, 29 May 2019 23:17:58 -0400 Received: from localhost (ip67-88-213-2.z213-88-67.customer.algx.net [67.88.213.2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 356302472D; Thu, 30 May 2019 03:17:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1559186277; bh=pgrKVLsh0b+AWDDmrQVRBK0DwAU3bC6pO8ssl/MfGN8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hZvtfaBV94paiT05SFCzxk9Z07Tzo5ziWhmmay2wj6uMQGCfHsyFTsjlHAhYdKlIN JA8YqnBeGMJDhzAkYnV6PmjahL8X8J9pt8ogAOqQl/ote6BaiL3Q+3RnjklRM8cBLY uyG6sRt/EZw7XGanTj408ZIIOdmxnQQLwsUSO1e0= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Kristian Evensen , =?UTF-8?q?Bj=C3=B8rn=20Mork?= , "David S. Miller" , Sasha Levin Subject: [PATCH 4.19 178/276] qmi_wwan: Add quirk for Quectel dynamic config Date: Wed, 29 May 2019 20:05:36 -0700 Message-Id: <20190530030536.437036166@linuxfoundation.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190530030523.133519668@linuxfoundation.org> References: <20190530030523.133519668@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org [ Upstream commit e4bf63482c309287ca84d91770ffa7dcc18e37eb ] Most, if not all, Quectel devices use dynamic interface numbers, and users are able to change the USB configuration at will. Matching on for example interface number is therefore not possible. Instead, the QMI device can be identified by looking at the interface class, subclass and protocol (all 0xff), as well as the number of endpoints. The reason we need to look at the number of endpoints, is that the diagnostic port interface has the same class, subclass and protocol as QMI. However, the diagnostic port only has two endpoints, while QMI has three. Until now, we have identified the QMI device by combining a match on class, subclass and protocol, with a call to the function quectel_diag_detect(). In quectel_diag_detect(), we check if the number of endpoints matches for known Quectel vendor/product ids. Adding new vendor/product ids to quectel_diag_detect() is not a good long-term solution. This commit replaces the function with a quirk, and applies the quirk to affected Quectel devices that I have been able to test the change with (EP06, EM12 and EC25). If the quirk is set and the number of endpoints equal two, we return from qmi_wwan_probe() with -ENODEV. Signed-off-by: Kristian Evensen Acked-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/usb/qmi_wwan.c | 65 ++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 366217263d704..d9a6699abe592 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -63,6 +63,7 @@ enum qmi_wwan_flags { enum qmi_wwan_quirks { QMI_WWAN_QUIRK_DTR = 1 << 0, /* needs "set DTR" request */ + QMI_WWAN_QUIRK_QUECTEL_DYNCFG = 1 << 1, /* check num. endpoints */ }; struct qmimux_hdr { @@ -845,6 +846,16 @@ static const struct driver_info qmi_wwan_info_quirk_dtr = { .data = QMI_WWAN_QUIRK_DTR, }; +static const struct driver_info qmi_wwan_info_quirk_quectel_dyncfg = { + .description = "WWAN/QMI device", + .flags = FLAG_WWAN | FLAG_SEND_ZLP, + .bind = qmi_wwan_bind, + .unbind = qmi_wwan_unbind, + .manage_power = qmi_wwan_manage_power, + .rx_fixup = qmi_wwan_rx_fixup, + .data = QMI_WWAN_QUIRK_DTR | QMI_WWAN_QUIRK_QUECTEL_DYNCFG, +}; + #define HUAWEI_VENDOR_ID 0x12D1 /* map QMI/wwan function by a fixed interface number */ @@ -865,6 +876,15 @@ static const struct driver_info qmi_wwan_info_quirk_dtr = { #define QMI_GOBI_DEVICE(vend, prod) \ QMI_FIXED_INTF(vend, prod, 0) +/* Quectel does not use fixed interface numbers on at least some of their + * devices. We need to check the number of endpoints to ensure that we bind to + * the correct interface. + */ +#define QMI_QUIRK_QUECTEL_DYNCFG(vend, prod) \ + USB_DEVICE_AND_INTERFACE_INFO(vend, prod, USB_CLASS_VENDOR_SPEC, \ + USB_SUBCLASS_VENDOR_SPEC, 0xff), \ + .driver_info = (unsigned long)&qmi_wwan_info_quirk_quectel_dyncfg + static const struct usb_device_id products[] = { /* 1. CDC ECM like devices match on the control interface */ { /* Huawei E392, E398 and possibly others sharing both device id and more... */ @@ -969,20 +989,9 @@ static const struct usb_device_id products[] = { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7), .driver_info = (unsigned long)&qmi_wwan_info, }, - { /* Quectel EP06/EG06/EM06 */ - USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x0306, - USB_CLASS_VENDOR_SPEC, - USB_SUBCLASS_VENDOR_SPEC, - 0xff), - .driver_info = (unsigned long)&qmi_wwan_info_quirk_dtr, - }, - { /* Quectel EG12/EM12 */ - USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x0512, - USB_CLASS_VENDOR_SPEC, - USB_SUBCLASS_VENDOR_SPEC, - 0xff), - .driver_info = (unsigned long)&qmi_wwan_info_quirk_dtr, - }, + {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ + {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */ + {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */ /* 3. Combined interface devices matching on interface number */ {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */ @@ -1283,7 +1292,6 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)}, /* HP lt4120 Snapdragon X5 LTE */ {QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */ {QMI_QUIRK_SET_DTR(0x1e0e, 0x9001, 5)}, /* SIMCom 7100E, 7230E, 7600E ++ */ - {QMI_QUIRK_SET_DTR(0x2c7c, 0x0125, 4)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ {QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)}, /* Quectel EC21 Mini PCIe */ {QMI_QUIRK_SET_DTR(0x2c7c, 0x0191, 4)}, /* Quectel EG91 */ {QMI_FIXED_INTF(0x2c7c, 0x0296, 4)}, /* Quectel BG96 */ @@ -1363,27 +1371,12 @@ static bool quectel_ec20_detected(struct usb_interface *intf) return false; } -static bool quectel_diag_detected(struct usb_interface *intf) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct usb_interface_descriptor intf_desc = intf->cur_altsetting->desc; - u16 id_vendor = le16_to_cpu(dev->descriptor.idVendor); - u16 id_product = le16_to_cpu(dev->descriptor.idProduct); - - if (id_vendor != 0x2c7c || intf_desc.bNumEndpoints != 2) - return false; - - if (id_product == 0x0306 || id_product == 0x0512) - return true; - else - return false; -} - static int qmi_wwan_probe(struct usb_interface *intf, const struct usb_device_id *prod) { struct usb_device_id *id = (struct usb_device_id *)prod; struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc; + const struct driver_info *info; /* Workaround to enable dynamic IDs. This disables usbnet * blacklisting functionality. Which, if required, can be @@ -1417,10 +1410,14 @@ static int qmi_wwan_probe(struct usb_interface *intf, * we need to match on class/subclass/protocol. These values are * identical for the diagnostic- and QMI-interface, but bNumEndpoints is * different. Ignore the current interface if the number of endpoints - * the number for the diag interface (two). + * equals the number for the diag interface (two). */ - if (quectel_diag_detected(intf)) - return -ENODEV; + info = (void *)&id->driver_info; + + if (info->data & QMI_WWAN_QUIRK_QUECTEL_DYNCFG) { + if (desc->bNumEndpoints == 2) + return -ENODEV; + } return usbnet_probe(intf, id); } -- 2.20.1