|
|
@@ -223,6 +223,20 @@ err:
|
|
|
return rv;
|
|
|
}
|
|
|
|
|
|
+/* Send CDC SetControlLineState request, setting or clearing the DTR.
|
|
|
+ * "Required for Autoconnect and 9x30 to wake up" according to the
|
|
|
+ * GobiNet driver. The requirement has been verified on an MDM9230
|
|
|
+ * based Sierra Wireless MC7455
|
|
|
+ */
|
|
|
+static int qmi_wwan_change_dtr(struct usbnet *dev, bool on)
|
|
|
+{
|
|
|
+ u8 intf = dev->intf->cur_altsetting->desc.bInterfaceNumber;
|
|
|
+
|
|
|
+ return usbnet_write_cmd(dev, USB_CDC_REQ_SET_CONTROL_LINE_STATE,
|
|
|
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
|
|
+ on ? 0x01 : 0x00, intf, NULL, 0);
|
|
|
+}
|
|
|
+
|
|
|
static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
|
|
|
{
|
|
|
int status = -1;
|
|
|
@@ -280,6 +294,24 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
|
|
|
usb_driver_release_interface(driver, info->data);
|
|
|
}
|
|
|
|
|
|
+ /* disabling remote wakeup on MDM9x30 devices has the same
|
|
|
+ * effect as clearing DTR. The device will not respond to QMI
|
|
|
+ * requests until we set DTR again. This is similar to a
|
|
|
+ * QMI_CTL SYNC request, clearing a lot of firmware state
|
|
|
+ * including the client ID allocations.
|
|
|
+ *
|
|
|
+ * Our usage model allows a session to span multiple
|
|
|
+ * open/close events, so we must prevent the firmware from
|
|
|
+ * clearing out state the clients might need.
|
|
|
+ *
|
|
|
+ * MDM9x30 is the first QMI chipset with USB3 support. Abuse
|
|
|
+ * this fact to enable the quirk.
|
|
|
+ */
|
|
|
+ if (le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) {
|
|
|
+ qmi_wwan_manage_power(dev, 1);
|
|
|
+ qmi_wwan_change_dtr(dev, true);
|
|
|
+ }
|
|
|
+
|
|
|
/* Never use the same address on both ends of the link, even if the
|
|
|
* buggy firmware told us to. Or, if device is assigned the well-known
|
|
|
* buggy firmware MAC address, replace it with a random address,
|
|
|
@@ -307,6 +339,12 @@ static void qmi_wwan_unbind(struct usbnet *dev, struct usb_interface *intf)
|
|
|
if (info->subdriver && info->subdriver->disconnect)
|
|
|
info->subdriver->disconnect(info->control);
|
|
|
|
|
|
+ /* disable MDM9x30 quirk */
|
|
|
+ if (le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) {
|
|
|
+ qmi_wwan_change_dtr(dev, false);
|
|
|
+ qmi_wwan_manage_power(dev, 0);
|
|
|
+ }
|
|
|
+
|
|
|
/* allow user to unbind using either control or data */
|
|
|
if (intf == info->control)
|
|
|
other = info->data;
|