Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7c5cca35 authored by Kristian Evensen's avatar Kristian Evensen Committed by David S. Miller
Browse files

qmi_wwan: Support dynamic config on Quectel EP06



Quectel EP06 (and EM06/EG06) supports dynamic configuration of USB
interfaces, without the device changing VID/PID or configuration number.
When the configuration is updated and interfaces are added/removed, the
interface numbers change. This means that the current code for matching
EP06 does not work.

This patch removes the current EP06 interface number match, and replaces
it with a match on class, subclass and protocol. Unfortunately, matching
on those three alone is not enough, as the diag interface exports the
same values as QMI. The other serial interfaces + adb export different
values and do not match.

The diag interface only has two endpoints, while the QMI interface has
three. I have therefore added a check for number of interfaces, and we
ignore the interface if the number of endpoints equals two.

Signed-off-by: default avatarKristian Evensen <kristian.evensen@gmail.com>
Acked-by: default avatarBjørn Mork <bjorn@mork.no>
Acked-by: default avatarDan Williams <dcbw@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3ebb1744
Loading
Loading
Loading
Loading
+29 −1
Original line number Original line Diff line number Diff line
@@ -967,6 +967,13 @@ static const struct usb_device_id products[] = {
		USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7),
		USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7),
		.driver_info = (unsigned long)&qmi_wwan_info,
		.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,
	},


	/* 3. Combined interface devices matching on interface number */
	/* 3. Combined interface devices matching on interface number */
	{QMI_FIXED_INTF(0x0408, 0xea42, 4)},	/* Yota / Megafon M100-1 */
	{QMI_FIXED_INTF(0x0408, 0xea42, 4)},	/* Yota / Megafon M100-1 */
@@ -1255,7 +1262,6 @@ static const struct usb_device_id products[] = {
	{QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)},	/* Quectel EC21 Mini PCIe */
	{QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)},	/* Quectel EC21 Mini PCIe */
	{QMI_QUIRK_SET_DTR(0x2c7c, 0x0191, 4)},	/* Quectel EG91 */
	{QMI_QUIRK_SET_DTR(0x2c7c, 0x0191, 4)},	/* Quectel EG91 */
	{QMI_FIXED_INTF(0x2c7c, 0x0296, 4)},	/* Quectel BG96 */
	{QMI_FIXED_INTF(0x2c7c, 0x0296, 4)},	/* Quectel BG96 */
	{QMI_QUIRK_SET_DTR(0x2c7c, 0x0306, 4)},	/* Quectel EP06 Mini PCIe */


	/* 4. Gobi 1000 devices */
	/* 4. Gobi 1000 devices */
	{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},	/* Acer Gobi Modem Device */
	{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},	/* Acer Gobi Modem Device */
@@ -1331,6 +1337,19 @@ static bool quectel_ec20_detected(struct usb_interface *intf)
	return false;
	return false;
}
}


static bool quectel_ep06_diag_detected(struct usb_interface *intf)
{
	struct usb_device *dev = interface_to_usbdev(intf);
	struct usb_interface_descriptor intf_desc = intf->cur_altsetting->desc;

	if (le16_to_cpu(dev->descriptor.idVendor) == 0x2c7c &&
	    le16_to_cpu(dev->descriptor.idProduct) == 0x0306 &&
	    intf_desc.bNumEndpoints == 2)
		return true;

	return false;
}

static int qmi_wwan_probe(struct usb_interface *intf,
static int qmi_wwan_probe(struct usb_interface *intf,
			  const struct usb_device_id *prod)
			  const struct usb_device_id *prod)
{
{
@@ -1365,6 +1384,15 @@ static int qmi_wwan_probe(struct usb_interface *intf,
		return -ENODEV;
		return -ENODEV;
	}
	}


	/* Quectel EP06/EM06/EG06 supports dynamic interface configuration, so
	 * 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).
	 */
	if (quectel_ep06_diag_detected(intf))
		return -ENODEV;

	return usbnet_probe(intf, id);
	return usbnet_probe(intf, id);
}
}