diag: Add notification for DCI
Until now, DIAG user space clients were unaware of smd
channel state in kernel. This change will add a notification
mechanism for DCI clients. This will notify the client if any
DCI smd channel comes up.
Change-Id: I043ab15505b40a23ba0e6ac6488ddfa8d80ae4a7
Signed-off-by: Shalabh Jain <shalabhj@codeaurora.org>
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 5cbf888..2860055 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -16,6 +16,7 @@
#include <linux/diagchar.h>
#include <linux/sched.h>
#include <linux/err.h>
+#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
@@ -115,6 +116,23 @@
queue_work(driver->diag_wq, &(driver->diag_read_smd_dci_work));
}
+void diag_dci_notify_client(int peripheral_mask)
+{
+ int i, stat;
+
+ /* Notify the DCI process that the peripheral DCI Channel is up */
+ for (i = 0; i < MAX_DCI_CLIENT; i++) {
+ if (driver->dci_notify_tbl[i].list & peripheral_mask) {
+ pr_debug("diag: sending signal now\n");
+ stat = send_sig(driver->dci_notify_tbl[i].signal_type,
+ driver->dci_notify_tbl[i].client, 0);
+ if (stat)
+ pr_err("diag: Err send sig stat: %d\n", stat);
+ break;
+ }
+ } /* end of loop for all DCI clients */
+}
+
static int diag_dci_probe(struct platform_device *pdev)
{
int err = 0;
@@ -125,6 +143,8 @@
if (err)
pr_err("diag: cannot open DCI port, Id = %d, err ="
" %d\n", pdev->id, err);
+ else
+ diag_dci_notify_client(DIAG_CON_MPSS);
}
return err;
}
@@ -302,6 +322,12 @@
if (driver->dci_tbl == NULL)
goto err;
}
+ if (driver->dci_notify_tbl == NULL) {
+ driver->dci_notify_tbl = kzalloc(MAX_DCI_CLIENT *
+ sizeof(struct dci_notification_tbl), GFP_KERNEL);
+ if (driver->dci_notify_tbl == NULL)
+ goto err;
+ }
if (driver->apps_dci_buf == NULL) {
driver->apps_dci_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
if (driver->apps_dci_buf == NULL)
@@ -316,6 +342,7 @@
err:
pr_err("diag: Could not initialize diag DCI buffers");
kfree(driver->dci_tbl);
+ kfree(driver->dci_notify_tbl);
kfree(driver->apps_dci_buf);
kfree(driver->buf_in_dci);
kfree(driver->write_ptr_dci);
@@ -328,6 +355,7 @@
driver->ch_dci = 0;
platform_driver_unregister(&msm_diag_dci_driver);
kfree(driver->dci_tbl);
+ kfree(driver->dci_notify_tbl);
kfree(driver->apps_dci_buf);
kfree(driver->buf_in_dci);
kfree(driver->write_ptr_dci);
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index cc6e0cf..c0b82df 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -22,6 +22,12 @@
int tag;
};
+struct dci_notification_tbl {
+ struct task_struct *client;
+ uint16_t list; /* bit mask */
+ int signal_type;
+};
+
#define DIAG_CON_APSS (0x0001) /* Bit mask for APSS */
#define DIAG_CON_MPSS (0x0002) /* Bit mask for MPSS */
#define DIAG_CON_LPASS (0x0004) /* Bit mask for LPASS */
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 7e7b514..6a7b931 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -18,6 +18,7 @@
#include <linux/mempool.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
+#include <linux/sched.h>
#include <mach/msm_smd.h>
#include <asm/atomic.h>
#include <asm/mach-types.h>
@@ -139,6 +140,7 @@
int use_device_tree;
/* DCI related variables */
struct diag_dci_tbl *dci_tbl;
+ struct dci_notification_tbl *dci_notify_tbl;
int dci_tag;
int dci_client_id;
struct mutex dci_mutex;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index d6a6e66..547f42f 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -343,6 +343,7 @@
int success = -1;
void *temp_buf;
uint16_t support_list = 0;
+ struct dci_notification_tbl *notify_params;
if (iocmd == DIAG_IOCTL_COMMAND_REG) {
struct bindpkt_params_per_process *pkt_params =
@@ -413,13 +414,23 @@
} else if (iocmd == DIAG_IOCTL_DCI_REG) {
if (driver->dci_state == DIAG_DCI_NO_REG)
return DIAG_DCI_NO_REG;
- /* use the 'list' later on to notify user space */
if (driver->num_dci_client >= MAX_DCI_CLIENT)
return DIAG_DCI_NO_REG;
+ notify_params = (struct dci_notification_tbl *) ioarg;
mutex_lock(&driver->dci_mutex);
driver->num_dci_client++;
pr_debug("diag: id = %d\n", driver->dci_client_id);
driver->dci_client_id++;
+ for (i = 0; i < MAX_DCI_CLIENT; i++) {
+ if (driver->dci_notify_tbl[i].client == NULL) {
+ driver->dci_notify_tbl[i].client = current;
+ driver->dci_notify_tbl[i].list =
+ notify_params->list;
+ driver->dci_notify_tbl[i].signal_type =
+ notify_params->signal_type;
+ break;
+ }
+ }
mutex_unlock(&driver->dci_mutex);
return driver->dci_client_id;
} else if (iocmd == DIAG_IOCTL_DCI_DEINIT) {
@@ -433,6 +444,12 @@
success = i;
}
}
+ for (i = 0; i < MAX_DCI_CLIENT; i++) {
+ if (driver->dci_notify_tbl[i].client == current) {
+ driver->dci_notify_tbl[i].client = NULL;
+ break;
+ }
+ }
/* if any registrations were deleted successfully OR a valid
client_id was sent in DEINIT call , then its DCI client */
if (success >= 0 || ioarg)