usb: gsmd: Add platform driver corresponding to smd channel
USB shared memory DUN(dial up networking) driver re-tries multiple times
to open smd channel, due to delay in smd driver initialization and modem
load during boot up. Instead, register a platform driver with smd channel
name. Whenever specific SMD channel is opened by modem, a corresponding
platform device would be added resulting in probe of platform driver being
called. In the probe function, DUN driver opens up SMD channel
Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
diff --git a/drivers/usb/gadget/u_smd.c b/drivers/usb/gadget/u_smd.c
index c0a20b0..3c91a47 100644
--- a/drivers/usb/gadget/u_smd.c
+++ b/drivers/usb/gadget/u_smd.c
@@ -40,6 +40,7 @@
#define SMD_N_PORTS 2
#define CH_OPENED 0
+#define CH_READY 1
struct smd_port_info {
struct smd_channel *ch;
char *name;
@@ -96,6 +97,7 @@
static struct smd_portmaster {
struct mutex lock;
struct gsmd_port *port;
+ struct platform_driver pdrv;
} smd_ports[SMD_N_PORTS];
static unsigned n_smd_ports;
@@ -514,36 +516,23 @@
}
}
-#define MAX_SMD_RETRY_CNT 20
static void gsmd_connect_work(struct work_struct *w)
{
struct gsmd_port *port;
struct smd_port_info *pi;
int ret;
- int retry_cnt = 0;
+ unsigned long flags;
port = container_of(w, struct gsmd_port, connect_work);
pi = port->pi;
pr_debug("%s: port:%p port#%d\n", __func__, port, port->port_num);
- /* SMD driver comes online gets initialized and loads modem
- * 10 seconds after boot up. If USB cable is connected at boot-up,
- * this might result smd open failure. To work-around, retry
- * opening multiple times.
- */
- do {
- if (!port->port_usb)
- return;
+ if (!test_bit(CH_READY, &pi->flags))
+ return;
- ret = smd_named_open_on_edge(pi->name, SMD_APPS_MODEM,
- &pi->ch, port, gsmd_notify);
- if (!ret)
- break;
-
- retry_cnt++;
- msleep(1000);
- } while (retry_cnt < MAX_SMD_RETRY_CNT);
+ ret = smd_named_open_on_edge(pi->name, SMD_APPS_MODEM,
+ &pi->ch, port, gsmd_notify);
if (ret) {
pr_err("%s: unable to open smd port:%s err:%d\n",
@@ -551,19 +540,15 @@
return;
}
- pr_debug("%s: SMD port open successful retrycnt:%d\n",
- __func__, retry_cnt);
-
wait_event(pi->wait, test_bit(CH_OPENED, &pi->flags));
- if (!port->port_usb)
- return;
-
+ spin_lock_irqsave(&port->port_lock, flags);
/* update usb control signals to modem */
- if (port->cbits_to_modem)
+ if (port->port_usb && port->cbits_to_modem)
smd_tiocmset(port->pi->ch,
port->cbits_to_modem,
~port->cbits_to_modem);
+ spin_unlock_irqrestore(&port->port_lock, flags);
gsmd_start_io(port);
}
@@ -709,7 +694,55 @@
~port->cbits_to_modem);
smd_close(port->pi->ch);
- port->pi->flags = 0;
+ clear_bit(CH_OPENED, &port->pi->flags);
+}
+
+#define SMD_CH_MAX_LEN 20
+static int gsmd_ch_probe(struct platform_device *pdev)
+{
+ struct gsmd_port *port;
+ struct smd_port_info *pi;
+ int i;
+ unsigned long flags;
+
+ pr_debug("%s: name:%s\n", __func__, pdev->name);
+
+ for (i = 0; i < n_smd_ports; i++) {
+ port = smd_ports[i].port;
+ pi = port->pi;
+
+ if (!strncmp(pi->name, pdev->name, SMD_CH_MAX_LEN)) {
+ set_bit(CH_READY, &pi->flags);
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (port->port_usb)
+ queue_work(gsmd_wq, &port->connect_work);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ break;
+ }
+ }
+ return 0;
+}
+
+static int gsmd_ch_remove(struct platform_device *pdev)
+{
+ struct gsmd_port *port;
+ struct smd_port_info *pi;
+ int i;
+
+ pr_debug("%s: name:%s\n", __func__, pdev->name);
+
+ for (i = 0; i < n_smd_ports; i++) {
+ port = smd_ports[i].port;
+ pi = port->pi;
+
+ 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);
+ break;
+ }
+ }
+ return 0;
}
static void gsmd_port_free(int portno)
@@ -723,6 +756,7 @@
static int gsmd_port_alloc(int portno, struct usb_cdc_line_coding *coding)
{
struct gsmd_port *port;
+ struct platform_driver *pdrv;
port = kzalloc(sizeof(struct gsmd_port), GFP_KERNEL);
if (!port)
@@ -744,6 +778,12 @@
init_waitqueue_head(&port->pi->wait);
smd_ports[portno].port = port;
+ pdrv = &smd_ports[portno].pdrv;
+ pdrv->probe = gsmd_ch_probe;
+ pdrv->remove = gsmd_ch_remove;
+ pdrv->driver.name = port->pi->name;
+ pdrv->driver.owner = THIS_MODULE;
+ platform_driver_register(pdrv);
pr_debug("%s: port:%p portno:%d\n", __func__, port, portno);
@@ -774,10 +814,14 @@
"nbytes_tomodem: %lu\n"
"cbits_to_modem: %u\n"
"cbits_to_laptop: %u\n"
- "n_read: %u\n",
+ "n_read: %u\n"
+ "CH_OPENED: %d\n"
+ "CH_READY: %d\n",
i, port->nbytes_tolaptop, port->nbytes_tomodem,
port->cbits_to_modem, port->cbits_to_laptop,
- port->n_read);
+ port->n_read,
+ test_bit(CH_OPENED, &port->pi->flags),
+ test_bit(CH_READY, &port->pi->flags));
spin_unlock_irqrestore(&port->port_lock, flags);
}