USB: f_rmnet: Drop DTR on host suspend

Some Windows hosts are not dropping DTR during suspend, but are
setting DTR as part of resume. Hence, send DTR set to zero to
the Modem when the rmnet interface is suspended.

Change-Id: I9137021e2c4074c71e9142e7dbac2042311b3c4d
Signed-off-by: Chiranjeevi Velempati <cvelempa@codeaurora.org>
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 177176e..86f8a25 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -426,6 +426,23 @@
 	kfree(f->name);
 }
 
+static void frmnet_suspend(struct usb_function *f)
+{
+	struct f_rmnet *dev = func_to_rmnet(f);
+	unsigned port_num;
+
+	if (!atomic_read(&dev->online))
+		return;
+	/* This is a workaround for a bug in Windows 7/XP hosts in which
+	 * the DTR bit is not set low when going into suspend. Hence force it
+	 * low here when this function driver is suspended.
+	 */
+	if (dev->port.notify_modem) {
+		port_num = rmnet_ports[dev->port_num].ctrl_xport_num;
+		dev->port.notify_modem(&dev->port, port_num, ~ACM_CTRL_DTR);
+	}
+}
+
 static void frmnet_disable(struct usb_function *f)
 {
 	struct f_rmnet *dev = func_to_rmnet(f);
@@ -937,6 +954,7 @@
 	f->disable = frmnet_disable;
 	f->set_alt = frmnet_set_alt;
 	f->setup = frmnet_setup;
+	f->suspend = frmnet_suspend;
 	dev->port.send_cpkt_response = frmnet_send_cpkt_response;
 	dev->port.disconnect = frmnet_disconnect;
 	dev->port.connect = frmnet_connect;