diag: Implement new polling response mechanism

PC tools send various polling commands to target to detect its
presence. Initially modem used to respond to all pollings. However,
with new targets, we have applications processor as master as well
as subsystem restart. Due to these new features, modem does not respond
all the time. This change implements a new mechanism to respond to
polling.

The DIAG driver maintains a flag variable to keep track of any polling
command registered by a remote peripheral. As long as any polling command
is present, diag driver ignores a special polling request. If no peripheral
has registered for any polling at all, then diag responds to this special
polling request.

Change-Id: I6ba1744dd3dd4982027b671efce3beffb9a27786
Signed-off-by: Shalabh Jain <shalabhj@codeaurora.org>
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index a9faff0..7d28604 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -128,6 +128,7 @@
 	struct diag_client_map *client_map;
 	int *data_ready;
 	int num_clients;
+	int polling_reg_flag;
 	struct diag_write_device *buf_tbl;
 
 	/* Memory pool parameters */
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index a703148..e24d896 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -60,8 +60,8 @@
 static unsigned int max_clients = 15;
 static unsigned int threshold_client_limit = 30;
 /* This is the maximum number of pkt registrations supported at initialization*/
-unsigned int diag_max_registration = 500;
-unsigned int diag_threshold_registration = 650;
+unsigned int diag_max_registration = 600;
+unsigned int diag_threshold_registration = 750;
 
 /* Timer variables */
 static struct timer_list drain_timer;
@@ -256,15 +256,49 @@
 	return -ENOMEM;
 }
 
+int diag_find_polling_reg(int i)
+{
+	uint16_t subsys_id, cmd_code_lo, cmd_code_hi;
+
+	subsys_id = driver->table[i].subsys_id;
+	cmd_code_lo = driver->table[i].cmd_code_lo;
+	cmd_code_hi = driver->table[i].cmd_code_hi;
+	if (driver->table[i].cmd_code == 0x0C)
+		return 1;
+	else if (driver->table[i].cmd_code == 0xFF) {
+		if (subsys_id == 0x04 && cmd_code_hi == 0x0E &&
+			 cmd_code_lo == 0x0E)
+			return 1;
+		else if (subsys_id == 0x08 && cmd_code_hi == 0x02 &&
+			 cmd_code_lo == 0x02)
+			return 1;
+		else if (subsys_id == 0x32 && cmd_code_hi == 0x03  &&
+			 cmd_code_lo == 0x03)
+			return 1;
+	}
+	return 0;
+}
+
 void diag_clear_reg(int proc_num)
 {
 	int i;
 
+	mutex_lock(&driver->diagchar_mutex);
+	/* reset polling flag */
+	driver->polling_reg_flag = 0;
 	for (i = 0; i < diag_max_registration; i++) {
 		if (driver->table[i].client_id == proc_num) {
 			driver->table[i].process_id = 0;
 		}
 	}
+	/* re-scan the registration table */
+	for (i = 0; i < diag_max_registration; i++) {
+		if (diag_find_polling_reg(i) == 1) {
+			driver->polling_reg_flag = 1;
+			break;
+		}
+	}
+	mutex_unlock(&driver->diagchar_mutex);
 }
 
 void diag_add_reg(int j, struct bindpkt_params *params,
@@ -275,6 +309,11 @@
 	driver->table[j].subsys_id = params->subsys_id;
 	driver->table[j].cmd_code_lo = params->cmd_code_lo;
 	driver->table[j].cmd_code_hi = params->cmd_code_hi;
+
+	/* check if incoming reg is polling & polling is yet not registered */
+	if (driver->polling_reg_flag == 0)
+		if (diag_find_polling_reg(j) == 1)
+			driver->polling_reg_flag = 1;
 	if (params->proc_id == APPS_PROC) {
 		driver->table[j].process_id = current->tgid;
 		driver->table[j].client_id = APPS_PROC;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 07322cd..5838bba 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -891,8 +891,8 @@
 	/* Check for polling for Apps only DIAG */
 	else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
 		(*(buf+2) == 0x03)) {
-		/* If there is NO MODEM present */
-		if (!(driver->ch)) {
+		/* If no one has registered for polling */
+		if (!(driver->polling_reg_flag)) {
 			/* Respond to polling for Apps only DIAG */
 			for (i = 0; i < 3; i++)
 				driver->apps_rsp_buf[i] = *(buf+i);
@@ -901,13 +901,10 @@
 
 			ENCODE_RSP_AND_SEND(15);
 			return 0;
-		} else {
-			/* Since Modem is present, send error response */
-			return 1;
 		}
 	}
 	 /* Check for ID for NO MODEM present */
-	else if (!(driver->ch)) {
+	else if (!(driver->polling_reg_flag)) {
 		/* respond to 0x0 command */
 		if (*buf == 0x00) {
 			for (i = 0; i < 55; i++)
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index df2cd65..22a2ccb 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -192,6 +192,7 @@
 
 void diagfwd_cntl_init(void)
 {
+	driver->polling_reg_flag = 0;
 	if (driver->buf_in_cntl == NULL) {
 		driver->buf_in_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
 		if (driver->buf_in_cntl == NULL)