diag: Add functionality to close SDIO channel.
DIAG driver pulls MDM9k traffic onto MSM using the SDIO bridge.
This patch adds capability to close this channel under special
circumstances.
Signed-off-by: Shalabh Jain <shalabhj@codeaurora.org>
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 6041954..5c685c3 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -213,6 +213,7 @@
struct workqueue_struct *diag_sdio_wq;
struct work_struct diag_read_sdio_work;
struct work_struct diag_remove_sdio_work;
+ struct work_struct diag_close_sdio_work;
struct diag_request *usb_read_mdm_ptr;
struct diag_request *write_ptr_mdm;
#endif
diff --git a/drivers/char/diag/diagfwd_sdio.c b/drivers/char/diag/diagfwd_sdio.c
index 8d43286..8be9f46 100644
--- a/drivers/char/diag/diagfwd_sdio.c
+++ b/drivers/char/diag/diagfwd_sdio.c
@@ -40,11 +40,11 @@
if (r > IN_BUF_SIZE) {
if (r < MAX_IN_BUF_SIZE) {
pr_err("diag: SDIO sending"
- " in packets more than %d bytes", r);
+ " packets more than %d bytes\n", r);
buf = krealloc(buf, r, GFP_KERNEL);
} else {
pr_err("diag: SDIO sending"
- " in packets more than %d bytes", MAX_IN_BUF_SIZE);
+ " in packets more than %d bytes\n", MAX_IN_BUF_SIZE);
return;
}
}
@@ -69,6 +69,31 @@
__diag_sdio_send_req();
}
+static void diag_sdio_notify(void *ctxt, unsigned event)
+{
+ if (event == SDIO_EVENT_DATA_READ_AVAIL)
+ queue_work(driver->diag_sdio_wq,
+ &(driver->diag_read_sdio_work));
+
+ if (event == SDIO_EVENT_DATA_WRITE_AVAIL)
+ wake_up_interruptible(&driver->wait_q);
+}
+
+static int diag_sdio_close(void)
+{
+ queue_work(driver->diag_sdio_wq, &(driver->diag_close_sdio_work));
+ return 0;
+}
+
+static void diag_close_sdio_work_fn(struct work_struct *work)
+{
+ pr_debug("diag: sdio close called\n");
+ if (sdio_close(driver->sdio_ch))
+ pr_err("diag: could not close SDIO channel\n");
+ else
+ driver->sdio_ch = NULL; /* channel successfully closed */
+}
+
int diagfwd_connect_sdio(void)
{
int err;
@@ -76,9 +101,19 @@
err = usb_diag_alloc_req(driver->mdm_ch, N_MDM_WRITE,
N_MDM_READ);
if (err)
- printk(KERN_ERR "diag: unable to alloc USB req on mdm ch");
+ pr_err("diag: unable to alloc USB req on mdm ch\n");
driver->in_busy_sdio = 0;
+ if (!driver->sdio_ch) {
+ err = sdio_open("SDIO_DIAG", &driver->sdio_ch, driver,
+ diag_sdio_notify);
+ if (err)
+ pr_info("diag: could not open SDIO channel\n");
+ else
+ pr_info("diag: opened SDIO channel\n");
+ } else {
+ pr_info("diag: SDIO channel already open\n");
+ }
/* Poll USB channel to check for data*/
queue_work(driver->diag_sdio_wq, &(driver->diag_read_mdm_work));
@@ -91,6 +126,8 @@
{
driver->in_busy_sdio = 1;
usb_diag_free_req(driver->mdm_ch);
+ if (driver->sdio_ch && (driver->logging_mode == USB_MODE))
+ diag_sdio_close();
return 0;
}
@@ -125,16 +162,6 @@
}
}
-static void diag_sdio_notify(void *ctxt, unsigned event)
-{
- if (event == SDIO_EVENT_DATA_READ_AVAIL)
- queue_work(driver->diag_sdio_wq,
- &(driver->diag_read_sdio_work));
-
- if (event == SDIO_EVENT_DATA_WRITE_AVAIL)
- wake_up_interruptible(&driver->wait_q);
-}
-
static int diag_sdio_probe(struct platform_device *pdev)
{
int err;
@@ -159,7 +186,7 @@
static void diag_remove_sdio_work_fn(struct work_struct *work)
{
- pr_debug("\n diag: sdio remove called");
+ pr_debug("diag: sdio remove called\n");
/*Disable SDIO channel to prevent further read/write */
driver->sdio_ch = NULL;
}
@@ -226,6 +253,7 @@
#endif
INIT_WORK(&(driver->diag_read_sdio_work), diag_read_sdio_work_fn);
INIT_WORK(&(driver->diag_remove_sdio_work), diag_remove_sdio_work_fn);
+ INIT_WORK(&(driver->diag_close_sdio_work), diag_close_sdio_work_fn);
ret = platform_driver_register(&msm_sdio_ch_driver);
if (ret)
printk(KERN_INFO "DIAG could not register SDIO device");