summaryrefslogtreecommitdiffstats
path: root/drivers/net/usb
diff options
context:
space:
mode:
authorKristian Evensen <kristian.evensen@gmail.com>2019-04-07 09:39:09 -0400
committerDavid S. Miller <davem@davemloft.net>2019-04-08 19:25:56 -0400
commite4bf63482c309287ca84d91770ffa7dcc18e37eb (patch)
treefc8a39f41c20dc14a9ce1eb813fd677a7f8c93a0 /drivers/net/usb
parent22b56e827093dd1af2379d294aba7d629b3f3436 (diff)
qmi_wwan: Add quirk for Quectel dynamic config
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 <kristian.evensen@gmail.com> Acked-by: Bjørn Mork <bjorn@mork.no> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb')
-rw-r--r--drivers/net/usb/qmi_wwan.c65
1 files changed, 31 insertions, 34 deletions
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 9195f3476b1d..18c4e5d17b05 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -63,6 +63,7 @@ enum qmi_wwan_flags {
63 63
64enum qmi_wwan_quirks { 64enum qmi_wwan_quirks {
65 QMI_WWAN_QUIRK_DTR = 1 << 0, /* needs "set DTR" request */ 65 QMI_WWAN_QUIRK_DTR = 1 << 0, /* needs "set DTR" request */
66 QMI_WWAN_QUIRK_QUECTEL_DYNCFG = 1 << 1, /* check num. endpoints */
66}; 67};
67 68
68struct qmimux_hdr { 69struct qmimux_hdr {
@@ -845,6 +846,16 @@ static const struct driver_info qmi_wwan_info_quirk_dtr = {
845 .data = QMI_WWAN_QUIRK_DTR, 846 .data = QMI_WWAN_QUIRK_DTR,
846}; 847};
847 848
849static const struct driver_info qmi_wwan_info_quirk_quectel_dyncfg = {
850 .description = "WWAN/QMI device",
851 .flags = FLAG_WWAN | FLAG_SEND_ZLP,
852 .bind = qmi_wwan_bind,
853 .unbind = qmi_wwan_unbind,
854 .manage_power = qmi_wwan_manage_power,
855 .rx_fixup = qmi_wwan_rx_fixup,
856 .data = QMI_WWAN_QUIRK_DTR | QMI_WWAN_QUIRK_QUECTEL_DYNCFG,
857};
858
848#define HUAWEI_VENDOR_ID 0x12D1 859#define HUAWEI_VENDOR_ID 0x12D1
849 860
850/* map QMI/wwan function by a fixed interface number */ 861/* map QMI/wwan function by a fixed interface number */
@@ -865,6 +876,15 @@ static const struct driver_info qmi_wwan_info_quirk_dtr = {
865#define QMI_GOBI_DEVICE(vend, prod) \ 876#define QMI_GOBI_DEVICE(vend, prod) \
866 QMI_FIXED_INTF(vend, prod, 0) 877 QMI_FIXED_INTF(vend, prod, 0)
867 878
879/* Quectel does not use fixed interface numbers on at least some of their
880 * devices. We need to check the number of endpoints to ensure that we bind to
881 * the correct interface.
882 */
883#define QMI_QUIRK_QUECTEL_DYNCFG(vend, prod) \
884 USB_DEVICE_AND_INTERFACE_INFO(vend, prod, USB_CLASS_VENDOR_SPEC, \
885 USB_SUBCLASS_VENDOR_SPEC, 0xff), \
886 .driver_info = (unsigned long)&qmi_wwan_info_quirk_quectel_dyncfg
887
868static const struct usb_device_id products[] = { 888static const struct usb_device_id products[] = {
869 /* 1. CDC ECM like devices match on the control interface */ 889 /* 1. CDC ECM like devices match on the control interface */
870 { /* Huawei E392, E398 and possibly others sharing both device id and more... */ 890 { /* Huawei E392, E398 and possibly others sharing both device id and more... */
@@ -969,20 +989,9 @@ static const struct usb_device_id products[] = {
969 USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7), 989 USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7),
970 .driver_info = (unsigned long)&qmi_wwan_info, 990 .driver_info = (unsigned long)&qmi_wwan_info,
971 }, 991 },
972 { /* Quectel EP06/EG06/EM06 */ 992 {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */
973 USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x0306, 993 {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */
974 USB_CLASS_VENDOR_SPEC, 994 {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */
975 USB_SUBCLASS_VENDOR_SPEC,
976 0xff),
977 .driver_info = (unsigned long)&qmi_wwan_info_quirk_dtr,
978 },
979 { /* Quectel EG12/EM12 */
980 USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x0512,
981 USB_CLASS_VENDOR_SPEC,
982 USB_SUBCLASS_VENDOR_SPEC,
983 0xff),
984 .driver_info = (unsigned long)&qmi_wwan_info_quirk_dtr,
985 },
986 995
987 /* 3. Combined interface devices matching on interface number */ 996 /* 3. Combined interface devices matching on interface number */
988 {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */ 997 {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */
@@ -1271,7 +1280,6 @@ static const struct usb_device_id products[] = {
1271 {QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)}, /* HP lt4120 Snapdragon X5 LTE */ 1280 {QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)}, /* HP lt4120 Snapdragon X5 LTE */
1272 {QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */ 1281 {QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */
1273 {QMI_QUIRK_SET_DTR(0x1e0e, 0x9001, 5)}, /* SIMCom 7100E, 7230E, 7600E ++ */ 1282 {QMI_QUIRK_SET_DTR(0x1e0e, 0x9001, 5)}, /* SIMCom 7100E, 7230E, 7600E ++ */
1274 {QMI_QUIRK_SET_DTR(0x2c7c, 0x0125, 4)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */
1275 {QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)}, /* Quectel EC21 Mini PCIe */ 1283 {QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)}, /* Quectel EC21 Mini PCIe */
1276 {QMI_QUIRK_SET_DTR(0x2c7c, 0x0191, 4)}, /* Quectel EG91 */ 1284 {QMI_QUIRK_SET_DTR(0x2c7c, 0x0191, 4)}, /* Quectel EG91 */
1277 {QMI_FIXED_INTF(0x2c7c, 0x0296, 4)}, /* Quectel BG96 */ 1285 {QMI_FIXED_INTF(0x2c7c, 0x0296, 4)}, /* Quectel BG96 */
@@ -1351,27 +1359,12 @@ static bool quectel_ec20_detected(struct usb_interface *intf)
1351 return false; 1359 return false;
1352} 1360}
1353 1361
1354static bool quectel_diag_detected(struct usb_interface *intf)
1355{
1356 struct usb_device *dev = interface_to_usbdev(intf);
1357 struct usb_interface_descriptor intf_desc = intf->cur_altsetting->desc;
1358 u16 id_vendor = le16_to_cpu(dev->descriptor.idVendor);
1359 u16 id_product = le16_to_cpu(dev->descriptor.idProduct);
1360
1361 if (id_vendor != 0x2c7c || intf_desc.bNumEndpoints != 2)
1362 return false;
1363
1364 if (id_product == 0x0306 || id_product == 0x0512)
1365 return true;
1366 else
1367 return false;
1368}
1369
1370static int qmi_wwan_probe(struct usb_interface *intf, 1362static int qmi_wwan_probe(struct usb_interface *intf,
1371 const struct usb_device_id *prod) 1363 const struct usb_device_id *prod)
1372{ 1364{
1373 struct usb_device_id *id = (struct usb_device_id *)prod; 1365 struct usb_device_id *id = (struct usb_device_id *)prod;
1374 struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc; 1366 struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc;
1367 const struct driver_info *info;
1375 1368
1376 /* Workaround to enable dynamic IDs. This disables usbnet 1369 /* Workaround to enable dynamic IDs. This disables usbnet
1377 * blacklisting functionality. Which, if required, can be 1370 * blacklisting functionality. Which, if required, can be
@@ -1405,10 +1398,14 @@ static int qmi_wwan_probe(struct usb_interface *intf,
1405 * we need to match on class/subclass/protocol. These values are 1398 * we need to match on class/subclass/protocol. These values are
1406 * identical for the diagnostic- and QMI-interface, but bNumEndpoints is 1399 * identical for the diagnostic- and QMI-interface, but bNumEndpoints is
1407 * different. Ignore the current interface if the number of endpoints 1400 * different. Ignore the current interface if the number of endpoints
1408 * the number for the diag interface (two). 1401 * equals the number for the diag interface (two).
1409 */ 1402 */
1410 if (quectel_diag_detected(intf)) 1403 info = (void *)&id->driver_info;
1411 return -ENODEV; 1404
1405 if (info->data & QMI_WWAN_QUIRK_QUECTEL_DYNCFG) {
1406 if (desc->bNumEndpoints == 2)
1407 return -ENODEV;
1408 }
1412 1409
1413 return usbnet_probe(intf, id); 1410 return usbnet_probe(intf, id);
1414} 1411}