usb: smd: Always call smd_close upon cable disconnect
During subsystem restart, SMD_EVENT_CLOSE is sent via callback,
which the DUN and RMNET control modules mistakenly interpret as the
channel being closed automatically. This causes a problem when the
modem comes back online and notifies via SMD_EVENT_OPEN: the gadget
driver now has a handle to an open SMD channel even without a USB
connection. Then when the USB cable is reconnected, due to disconnect
being called first, it accidentally closes the re-opened channel,
causing the following smd_open() to fail because it is busy being
closed.
Instead, simply always call smd_close() on actual disconnect,
so that the subsequent connect will successfully be able to open the
channel.
CRs-fixed: 327710
Change-Id: Ia7b3e52638f9bdc96c083cb16e0231e7af7ff884
Signed-off-by: Jack Pham <jackp@codeaurora.org>
diff --git a/drivers/usb/gadget/u_smd.c b/drivers/usb/gadget/u_smd.c
index caccade..93a96be 100644
--- a/drivers/usb/gadget/u_smd.c
+++ b/drivers/usb/gadget/u_smd.c
@@ -711,17 +711,18 @@
port->n_read = 0;
spin_unlock_irqrestore(&port->port_lock, flags);
- if (!test_bit(CH_OPENED, &port->pi->flags))
- return;
+ if (test_and_clear_bit(CH_OPENED, &port->pi->flags)) {
+ /* lower the dtr */
+ port->cbits_to_modem = 0;
+ smd_tiocmset(port->pi->ch,
+ port->cbits_to_modem,
+ ~port->cbits_to_modem);
+ }
- /* lower the dtr */
- port->cbits_to_modem = 0;
- smd_tiocmset(port->pi->ch,
- port->cbits_to_modem,
- ~port->cbits_to_modem);
-
- smd_close(port->pi->ch);
- clear_bit(CH_OPENED, &port->pi->flags);
+ if (port->pi->ch) {
+ smd_close(port->pi->ch);
+ port->pi->ch = NULL;
+ }
}
#define SMD_CH_MAX_LEN 20
@@ -765,7 +766,10 @@
if (!strncmp(pi->name, pdev->name, SMD_CH_MAX_LEN)) {
clear_bit(CH_READY, &pi->flags);
clear_bit(CH_OPENED, &pi->flags);
- smd_close(pi->ch);
+ if (pi->ch) {
+ smd_close(pi->ch);
+ pi->ch = NULL;
+ }
break;
}
}
@@ -821,6 +825,7 @@
size_t count, loff_t *ppos)
{
struct gsmd_port *port;
+ struct smd_port_info *pi;
char *buf;
unsigned long flags;
int temp = 0;
@@ -833,6 +838,7 @@
for (i = 0; i < n_smd_ports; i++) {
port = smd_ports[i].port;
+ pi = port->pi;
spin_lock_irqsave(&port->port_lock, flags);
temp += scnprintf(buf + temp, 512 - temp,
"###PORT:%d###\n"
@@ -848,10 +854,10 @@
i, port->nbytes_tolaptop, port->nbytes_tomodem,
port->cbits_to_modem, port->cbits_to_laptop,
port->n_read,
- smd_read_avail(port->pi->ch),
- smd_write_avail(port->pi->ch),
- test_bit(CH_OPENED, &port->pi->flags),
- test_bit(CH_READY, &port->pi->flags));
+ pi->ch ? smd_read_avail(pi->ch) : 0,
+ pi->ch ? smd_write_avail(pi->ch) : 0,
+ test_bit(CH_OPENED, &pi->flags),
+ test_bit(CH_READY, &pi->flags));
spin_unlock_irqrestore(&port->port_lock, flags);
}