Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

qmi_wwan: unconditionally reject 2 ep interfaces

We have been using the fact that the QMI and DIAG functions
usually are the only ones with class/subclass/protocol being
ff/ff/ff on Quectel modems. This has allowed us to match the
QMI function without knowing the exact interface number,
which can vary depending on firmware configuration.

The ability to silently reject the DIAG function, which is
usually handled by the option driver, is important for this
method to work. This is done based on the knowledge that it
has exactly 2 bulk endpoints. QMI function control interfaces
will have either 3 or 1 endpoint. This rule is universal so
the quirk condition can be removed.

The fixed layouts known from the Gobi1k and Gobi2k modems
have been gradually replaced by more dynamic layouts, and
many vendors now use configurable layouts without changing
device IDs. Renaming the class/subclass/protocol matching
macro makes it more obvious that this is now not Quectel
specific anymore.

Cc: Kristian Evensen <kristian.evensen@gmail.com>
Cc: Aleksander Morgado <aleksander@aleksander.es>
Signed-off-by: Bjørn Mork <bjorn@mork.no>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Bjørn Mork and committed by
David S. Miller
00516d13 5d1fbdf2

+15 -27
+15 -27
drivers/net/usb/qmi_wwan.c
··· 61 61 62 62 enum qmi_wwan_quirks { 63 63 QMI_WWAN_QUIRK_DTR = 1 << 0, /* needs "set DTR" request */ 64 - QMI_WWAN_QUIRK_QUECTEL_DYNCFG = 1 << 1, /* check num. endpoints */ 65 64 }; 66 65 67 66 struct qmimux_hdr { ··· 915 916 .data = QMI_WWAN_QUIRK_DTR, 916 917 }; 917 918 918 - static const struct driver_info qmi_wwan_info_quirk_quectel_dyncfg = { 919 - .description = "WWAN/QMI device", 920 - .flags = FLAG_WWAN | FLAG_SEND_ZLP, 921 - .bind = qmi_wwan_bind, 922 - .unbind = qmi_wwan_unbind, 923 - .manage_power = qmi_wwan_manage_power, 924 - .rx_fixup = qmi_wwan_rx_fixup, 925 - .data = QMI_WWAN_QUIRK_DTR | QMI_WWAN_QUIRK_QUECTEL_DYNCFG, 926 - }; 927 - 928 919 #define HUAWEI_VENDOR_ID 0x12D1 929 920 930 921 /* map QMI/wwan function by a fixed interface number */ ··· 935 946 #define QMI_GOBI_DEVICE(vend, prod) \ 936 947 QMI_FIXED_INTF(vend, prod, 0) 937 948 938 - /* Quectel does not use fixed interface numbers on at least some of their 939 - * devices. We need to check the number of endpoints to ensure that we bind to 940 - * the correct interface. 949 + /* Many devices have QMI and DIAG functions which are distinguishable 950 + * from other vendor specific functions by class, subclass and 951 + * protocol all being 0xff. The DIAG function has exactly 2 endpoints 952 + * and is silently rejected when probed. 953 + * 954 + * This makes it possible to match dynamically numbered QMI functions 955 + * as seen on e.g. many Quectel modems. 941 956 */ 942 - #define QMI_QUIRK_QUECTEL_DYNCFG(vend, prod) \ 957 + #define QMI_MATCH_FF_FF_FF(vend, prod) \ 943 958 USB_DEVICE_AND_INTERFACE_INFO(vend, prod, USB_CLASS_VENDOR_SPEC, \ 944 959 USB_SUBCLASS_VENDOR_SPEC, 0xff), \ 945 - .driver_info = (unsigned long)&qmi_wwan_info_quirk_quectel_dyncfg 960 + .driver_info = (unsigned long)&qmi_wwan_info_quirk_dtr 946 961 947 962 static const struct usb_device_id products[] = { 948 963 /* 1. CDC ECM like devices match on the control interface */ ··· 1052 1059 USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7), 1053 1060 .driver_info = (unsigned long)&qmi_wwan_info, 1054 1061 }, 1055 - {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ 1056 - {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */ 1057 - {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */ 1058 - {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */ 1062 + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ 1063 + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */ 1064 + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */ 1065 + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */ 1059 1066 1060 1067 /* 3. Combined interface devices matching on interface number */ 1061 1068 {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */ ··· 1448 1455 { 1449 1456 struct usb_device_id *id = (struct usb_device_id *)prod; 1450 1457 struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc; 1451 - const struct driver_info *info; 1452 1458 1453 1459 /* Workaround to enable dynamic IDs. This disables usbnet 1454 1460 * blacklisting functionality. Which, if required, can be ··· 1483 1491 * different. Ignore the current interface if the number of endpoints 1484 1492 * equals the number for the diag interface (two). 1485 1493 */ 1486 - info = (void *)id->driver_info; 1487 - 1488 - if (info->data & QMI_WWAN_QUIRK_QUECTEL_DYNCFG) { 1489 - if (desc->bNumEndpoints == 2) 1490 - return -ENODEV; 1491 - } 1494 + if (desc->bNumEndpoints == 2) 1495 + return -ENODEV; 1492 1496 1493 1497 return usbnet_probe(intf, id); 1494 1498 }