diag: Add UART support

DIAG traffic has been supported over USB and SD card. This
change adds capability to route DIAG traffic over UART.

Change-Id: I0d6732fcbb19950700218140d581b5759e676b74
Signed-off-by: Shalabh Jain <shalabhj@codeaurora.org>
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 5c685c3..292fbc3 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -46,6 +46,7 @@
 #define MSG_MASK_SIZE 8000
 #define LOG_MASK_SIZE 8000
 #define EVENT_MASK_SIZE 1000
+#define USER_SPACE_DATA 8000
 #define PKT_SIZE 4096
 #define MAX_EQUIP_ID 12
 
@@ -157,6 +158,7 @@
 	unsigned char *buf_in_wcnss_cntl;
 	unsigned char *usb_buf_out;
 	unsigned char *apps_rsp_buf;
+	unsigned char *user_space_data;
 	smd_channel_t *ch;
 	smd_channel_t *ch_cntl;
 	smd_channel_t *chqdsp;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index c9a9d57..6fa043c 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -355,6 +355,8 @@
 		mutex_lock(&driver->diagchar_mutex);
 		temp = driver->logging_mode;
 		driver->logging_mode = (int)ioarg;
+		if (driver->logging_mode == UART_MODE)
+			driver->logging_mode = MEMORY_DEVICE_MODE;
 		driver->logging_process_id = current->tgid;
 		mutex_unlock(&driver->diagchar_mutex);
 		if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
@@ -363,12 +365,14 @@
 			driver->in_busy_2 = 1;
 			driver->in_busy_qdsp_1 = 1;
 			driver->in_busy_qdsp_2 = 1;
+			driver->in_busy_wcnss = 1;
 		} else if (temp == NO_LOGGING_MODE && driver->logging_mode
 							== MEMORY_DEVICE_MODE) {
 			driver->in_busy_1 = 0;
 			driver->in_busy_2 = 0;
 			driver->in_busy_qdsp_1 = 0;
 			driver->in_busy_qdsp_2 = 0;
+			driver->in_busy_wcnss = 0;
 			/* Poll SMD channels to check for data*/
 			if (driver->ch)
 				queue_work(driver->diag_wq,
@@ -376,6 +380,9 @@
 			if (driver->chqdsp)
 				queue_work(driver->diag_wq,
 					&(driver->diag_read_smd_qdsp_work));
+			if (driver->ch_wcnss)
+				queue_work(driver->diag_wq,
+					&(driver->diag_read_smd_wcnss_work));
 		}
 #ifdef CONFIG_DIAG_OVER_USB
 		else if (temp == USB_MODE && driver->logging_mode
@@ -391,6 +398,7 @@
 			driver->in_busy_2 = 0;
 			driver->in_busy_qdsp_2 = 0;
 			driver->in_busy_qdsp_2 = 0;
+			driver->in_busy_wcnss = 0;
 			/* Poll SMD channels to check for data*/
 			if (driver->ch)
 				queue_work(driver->diag_wq,
@@ -398,6 +406,9 @@
 			if (driver->chqdsp)
 				queue_work(driver->diag_wq,
 					&(driver->diag_read_smd_qdsp_work));
+			if (driver->ch_wcnss)
+				queue_work(driver->diag_wq,
+					&(driver->diag_read_smd_wcnss_work));
 		} else if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
 								== USB_MODE)
 			diagfwd_connect();
@@ -426,10 +437,10 @@
 				  driver->data_ready[index]);
 	mutex_lock(&driver->diagchar_mutex);
 
-	if ((driver->data_ready[index] & MEMORY_DEVICE_LOG_TYPE) && (driver->
+	if ((driver->data_ready[index] & USER_SPACE_LOG_TYPE) && (driver->
 					logging_mode == MEMORY_DEVICE_MODE)) {
 		/*Copy the type of data being passed*/
-		data_type = driver->data_ready[index] & MEMORY_DEVICE_LOG_TYPE;
+		data_type = driver->data_ready[index] & USER_SPACE_LOG_TYPE;
 		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
 		/* place holder for number of data field */
 		ret += 4;
@@ -496,8 +507,7 @@
 					 driver->write_ptr_2->length);
 			driver->in_busy_2 = 0;
 		}
-
-		/* copy q6 data */
+		/* copy lpass data */
 		if (driver->in_busy_qdsp_1 == 1) {
 			num_data++;
 			/*Copy the length of data being passed*/
@@ -520,23 +530,37 @@
 					write_ptr_qdsp_2->length);
 			driver->in_busy_qdsp_2 = 0;
 		}
-
+		/* copy wncss data */
+		if (driver->in_busy_wcnss == 1) {
+			num_data++;
+			/*Copy the length of data being passed*/
+			COPY_USER_SPACE_OR_EXIT(buf+ret,
+				 (driver->write_ptr_wcnss->length), 4);
+			/*Copy the actual data being passed*/
+			COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
+							buf_in_wcnss),
+					 driver->write_ptr_wcnss->length);
+			driver->in_busy_wcnss = 0;
+		}
 		/* copy number of data fields */
 		COPY_USER_SPACE_OR_EXIT(buf+4, num_data, 4);
 		ret -= 4;
-		driver->data_ready[index] ^= MEMORY_DEVICE_LOG_TYPE;
+		driver->data_ready[index] ^= USER_SPACE_LOG_TYPE;
 		if (driver->ch)
 			queue_work(driver->diag_wq,
 					 &(driver->diag_read_smd_work));
 		if (driver->chqdsp)
 			queue_work(driver->diag_wq,
 					 &(driver->diag_read_smd_qdsp_work));
+		if (driver->ch_wcnss)
+			queue_work(driver->diag_wq,
+					 &(driver->diag_read_smd_wcnss_work));
 		APPEND_DEBUG('n');
 		goto exit;
-	} else if (driver->data_ready[index] & MEMORY_DEVICE_LOG_TYPE) {
+	} else if (driver->data_ready[index] & USER_SPACE_LOG_TYPE) {
 		/* In case, the thread wakes up and the logging mode is
 		not memory device any more, the condition needs to be cleared */
-		driver->data_ready[index] ^= MEMORY_DEVICE_LOG_TYPE;
+		driver->data_ready[index] ^= USER_SPACE_LOG_TYPE;
 	}
 
 	if (driver->data_ready[index] & DEINIT_TYPE) {
@@ -612,21 +636,27 @@
 #endif /* DIAG over USB */
 	/* Get the packet type F3/log/event/Pkt response */
 	err = copy_from_user((&pkt_type), buf, 4);
-	/*First 4 bytes indicate the type of payload - ignore these */
+	/* First 4 bytes indicate the type of payload - ignore these */
 	payload_size = count - 4;
 
-	if (pkt_type == MEMORY_DEVICE_LOG_TYPE) {
-		if (!mask_request_validate((unsigned char *)buf)) {
-			printk(KERN_ALERT "mask request Invalid ..cannot send to modem \n");
-			return -EFAULT;
+	if (pkt_type == USER_SPACE_LOG_TYPE) {
+		err = copy_from_user(driver->user_space_data, buf + 4,
+							 payload_size);
+		/* Check masks for On-Device logging */
+		if (pkt_type == USER_SPACE_LOG_TYPE) {
+			if (!mask_request_validate((unsigned char *)buf)) {
+				pr_alert("diag: mask request Invalid\n");
+				return -EFAULT;
+			}
 		}
 		buf = buf + 4;
 #ifdef DIAG_DEBUG
-		pr_debug("diag: masks: %d\n", payload_size);
+		pr_debug("diag: user space data %d\n", payload_size);
 		for (i = 0; i < payload_size; i++)
 			printk(KERN_DEBUG "\t %x", *(((unsigned char *)buf)+i));
 #endif
-		diag_process_hdlc((void *)buf, payload_size);
+		diag_process_hdlc((void *)(driver->user_space_data),
+							 payload_size);
 		return 0;
 	}
 
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index f9664c4..e49d57c 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -61,7 +61,8 @@
 		driver->write_ptr_1->length = (int)(enc.dest - \
 						(void *)(driver->buf_in_1)); \
 		driver->in_busy_1 = 1;					\
-		usb_diag_write(driver->legacy_ch, driver->write_ptr_1);	\
+		diag_device_write(driver->buf_in_1, MODEM_DATA, \
+						 driver->write_ptr_1); \
 		memset(driver->apps_rsp_buf, '\0', 500);		\
 	}								\
 } while (0)
@@ -153,7 +154,7 @@
 						 driver->logging_process_id)
 				break;
 		if (i < driver->num_clients) {
-			driver->data_ready[i] |= MEMORY_DEVICE_LOG_TYPE;
+			driver->data_ready[i] |= USER_SPACE_LOG_TYPE;
 			wake_up_interruptible(&driver->wait_q);
 		} else
 			return -EINVAL;
@@ -982,13 +983,15 @@
 {
 	printk(KERN_DEBUG "diag: USB disconnected\n");
 	driver->usb_connected = 0;
-	driver->in_busy_1 = 1;
-	driver->in_busy_2 = 1;
-	driver->in_busy_qdsp_1 = 1;
-	driver->in_busy_qdsp_2 = 1;
-	driver->in_busy_wcnss = 1;
 	driver->debug_flag = 1;
 	usb_diag_free_req(driver->legacy_ch);
+	if (driver->logging_mode == USB_MODE) {
+		driver->in_busy_1 = 1;
+		driver->in_busy_2 = 1;
+		driver->in_busy_qdsp_1 = 1;
+		driver->in_busy_qdsp_2 = 1;
+		driver->in_busy_wcnss = 1;
+	}
 #ifdef CONFIG_DIAG_SDIO_PIPE
 	if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
 		if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
@@ -1235,6 +1238,10 @@
 	if (driver->hdlc_buf == NULL
 	    && (driver->hdlc_buf = kzalloc(HDLC_MAX, GFP_KERNEL)) == NULL)
 		goto err;
+	if (driver->user_space_data == NULL)
+		driver->user_space_data = kzalloc(USER_SPACE_DATA, GFP_KERNEL);
+		if (driver->user_space_data == NULL)
+			goto err;
 	if (driver->msg_masks == NULL
 	    && (driver->msg_masks = kzalloc(MSG_MASK_SIZE,
 					     GFP_KERNEL)) == NULL)
@@ -1350,6 +1357,7 @@
 		kfree(driver->write_ptr_wcnss);
 		kfree(driver->usb_read_ptr);
 		kfree(driver->apps_rsp_buf);
+		kfree(driver->user_space_data);
 		if (driver->diag_wq)
 			destroy_workqueue(driver->diag_wq);
 }
@@ -1391,5 +1399,6 @@
 	kfree(driver->write_ptr_wcnss);
 	kfree(driver->usb_read_ptr);
 	kfree(driver->apps_rsp_buf);
+	kfree(driver->user_space_data);
 	destroy_workqueue(driver->diag_wq);
 }
diff --git a/drivers/char/diag/diagfwd_sdio.c b/drivers/char/diag/diagfwd_sdio.c
index 8be9f46..f3873aa 100644
--- a/drivers/char/diag/diagfwd_sdio.c
+++ b/drivers/char/diag/diagfwd_sdio.c
@@ -124,10 +124,11 @@
 
 int diagfwd_disconnect_sdio(void)
 {
-	driver->in_busy_sdio = 1;
 	usb_diag_free_req(driver->mdm_ch);
-	if (driver->sdio_ch && (driver->logging_mode == USB_MODE))
+	if (driver->sdio_ch && (driver->logging_mode == USB_MODE)) {
+		driver->in_busy_sdio = 1;
 		diag_sdio_close();
+	}
 	return 0;
 }
 
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 22270de..91d67d5 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -18,10 +18,11 @@
 #define EVENT_MASKS_TYPE		4
 #define PKT_TYPE			8
 #define DEINIT_TYPE			16
-#define MEMORY_DEVICE_LOG_TYPE		32
+#define USER_SPACE_LOG_TYPE		32
 #define USB_MODE			1
 #define MEMORY_DEVICE_MODE		2
 #define NO_LOGGING_MODE			3
+#define UART_MODE			4
 
 /* different values that go in for diag_data_type */
 #define DATA_TYPE_EVENT         	0