diag: Add missing fixes for diag sdio bridge

Due to separate branches for Fusion targets, some fixes
for SDIO layer were missing on mainline. This will add the
missing fixes on the mainline.

Change-Id: I56cd617a744ca9d280bac50370dc9aba11958fdf
Signed-off-by: Shalabh Jain <shalabhj@codeaurora.org>
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 292fbc3..10133f9 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -214,7 +214,6 @@
 	struct work_struct diag_read_mdm_work;
 	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;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 0729753..1fb8c9f 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -377,6 +377,9 @@
 			driver->in_busy_qdsp_1 = 1;
 			driver->in_busy_qdsp_2 = 1;
 			driver->in_busy_wcnss = 1;
+#ifdef CONFIG_DIAG_SDIO_PIPE
+			driver->in_busy_sdio = 1;
+#endif
 		} else if (temp == NO_LOGGING_MODE && driver->logging_mode
 							== MEMORY_DEVICE_MODE) {
 			driver->in_busy_1 = 0;
@@ -394,6 +397,13 @@
 			if (driver->ch_wcnss)
 				queue_work(driver->diag_wq,
 					&(driver->diag_read_smd_wcnss_work));
+#ifdef CONFIG_DIAG_SDIO_PIPE
+			driver->in_busy_sdio = 0;
+			/* Poll SDIO channel to check for data */
+			if (driver->sdio_ch)
+				queue_work(driver->diag_sdio_wq,
+					&(driver->diag_read_sdio_work));
+#endif
 		}
 #ifdef CONFIG_DIAG_OVER_USB
 		else if (temp == USB_MODE && driver->logging_mode
@@ -420,9 +430,16 @@
 			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();
+#ifdef CONFIG_DIAG_SDIO_PIPE
+			driver->in_busy_sdio = 0;
+			/* Poll SDIO channel to check for data */
+			if (driver->sdio_ch)
+				queue_work(driver->diag_sdio_wq,
+					&(driver->diag_read_sdio_work));
+#endif
+			} else if (temp == MEMORY_DEVICE_MODE &&
+					 driver->logging_mode == USB_MODE)
+				diagfwd_connect();
 #endif /* DIAG over USB */
 		success = 1;
 	}
@@ -553,6 +570,20 @@
 					 driver->write_ptr_wcnss->length);
 			driver->in_busy_wcnss = 0;
 		}
+#ifdef CONFIG_DIAG_SDIO_PIPE
+		/* copy 9K data over SDIO */
+		if (driver->in_busy_sdio == 1) {
+			num_data++;
+			/*Copy the length of data being passed*/
+			COPY_USER_SPACE_OR_EXIT(buf+ret,
+				 (driver->write_ptr_mdm->length), 4);
+			/*Copy the actual data being passed*/
+			COPY_USER_SPACE_OR_EXIT(buf+ret,
+					*(driver->buf_in_sdio),
+					 driver->write_ptr_mdm->length);
+			driver->in_busy_sdio = 0;
+		}
+#endif
 		/* copy number of data fields */
 		COPY_USER_SPACE_OR_EXIT(buf+4, num_data, 4);
 		ret -= 4;
@@ -566,6 +597,11 @@
 		if (driver->ch_wcnss)
 			queue_work(driver->diag_wq,
 					 &(driver->diag_read_smd_wcnss_work));
+#ifdef CONFIG_DIAG_SDIO_PIPE
+		if (driver->sdio_ch)
+			queue_work(driver->diag_sdio_wq,
+					   &(driver->diag_read_sdio_work));
+#endif
 		APPEND_DEBUG('n');
 		goto exit;
 	} else if (driver->data_ready[index] & USER_SPACE_LOG_TYPE) {
@@ -655,7 +691,7 @@
 							 payload_size);
 		/* Check masks for On-Device logging */
 		if (pkt_type == USER_SPACE_LOG_TYPE) {
-			if (!mask_request_validate((unsigned char *)buf)) {
+			if (!mask_request_validate(driver->user_space_data)) {
 				pr_alert("diag: mask request Invalid\n");
 				return -EFAULT;
 			}
@@ -664,8 +700,21 @@
 #ifdef DIAG_DEBUG
 		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));
+			pr_debug("\t %x", *((driver->user_space_data)+i));
 #endif
+#ifdef CONFIG_DIAG_SDIO_PIPE
+		/* send masks to 9k too */
+		if (driver->sdio_ch) {
+			wait_event_interruptible(driver->wait_q,
+				 (sdio_write_avail(driver->sdio_ch) >=
+					 payload_size));
+			if (driver->sdio_ch && (payload_size > 0)) {
+				sdio_write(driver->sdio_ch, (void *)
+				   (driver->user_space_data), payload_size);
+			}
+		}
+#endif
+		/* send masks to modem now */
 		diag_process_hdlc((void *)(driver->user_space_data),
 							 payload_size);
 		return 0;
@@ -803,11 +852,11 @@
 	uint8_t subsys_id;
 	uint16_t ss_cmd;
 
-	packet_id = mask_buf[4];
+	packet_id = mask_buf[0];
 
 	if (packet_id == 0x4B) {
-		subsys_id = mask_buf[5];
-		ss_cmd = *(uint16_t *)(mask_buf + 6);
+		subsys_id = mask_buf[1];
+		ss_cmd = *(uint16_t *)(mask_buf + 2);
 		/* Packets with SSID which are allowed */
 		switch (subsys_id) {
 		case 0x04: /* DIAG_SUBSYS_WCDMA */
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index c8555cd..a971594 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -9,7 +9,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -72,6 +71,10 @@
 
 int chk_config_get_id(void)
 {
+	/* For all Fusion targets, Modem will always be present */
+	if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
+		return 0;
+
 	switch (socinfo_get_id()) {
 	case APQ8060_MACHINE_ID:
 	case MSM8660_MACHINE_ID:
@@ -191,6 +194,13 @@
 			queue_work(driver->diag_wq, &(driver->
 				diag_read_smd_wcnss_work));
 		}
+#ifdef CONFIG_DIAG_SDIO_PIPE
+		else if (proc_num == SDIO_DATA) {
+			driver->in_busy_sdio = 0;
+			queue_work(driver->diag_sdio_wq,
+				&(driver->diag_read_sdio_work));
+		}
+#endif
 		err = -1;
 	}
 #ifdef CONFIG_DIAG_OVER_USB
@@ -226,7 +236,7 @@
 #ifdef CONFIG_DIAG_SDIO_PIPE
 		else if (proc_num == SDIO_DATA) {
 			if (machine_is_msm8x60_fusion() ||
-					machine_is_msm8x60_fusn_ffa()) {
+					 machine_is_msm8x60_fusn_ffa()) {
 				write_ptr->buf = buf;
 				err = usb_diag_write(driver->mdm_ch, write_ptr);
 			} else
@@ -1051,7 +1061,7 @@
 #ifdef CONFIG_DIAG_SDIO_PIPE
 	else if (buf == (void *)driver->buf_in_sdio)
 		if (machine_is_msm8x60_fusion() ||
-					 machine_is_msm8x60_fusn_ffa())
+			 machine_is_msm8x60_fusn_ffa())
 			diagfwd_write_complete_sdio();
 		else
 			pr_err("diag: Incorrect buffer pointer while WRITE");
@@ -1093,7 +1103,7 @@
 #ifdef CONFIG_DIAG_SDIO_PIPE
 	else if (buf == (void *)driver->usb_buf_mdm_out) {
 		if (machine_is_msm8x60_fusion() ||
-					 machine_is_msm8x60_fusn_ffa()) {
+				 machine_is_msm8x60_fusn_ffa()) {
 			driver->read_len_mdm = diag_read_ptr->actual;
 			diagfwd_read_complete_sdio();
 		} else
diff --git a/drivers/char/diag/diagfwd_sdio.c b/drivers/char/diag/diagfwd_sdio.c
index f3873aa..a145c06 100644
--- a/drivers/char/diag/diagfwd_sdio.c
+++ b/drivers/char/diag/diagfwd_sdio.c
@@ -54,6 +54,13 @@
 			else {
 				APPEND_DEBUG('i');
 				sdio_read(driver->sdio_ch, buf, r);
+				if (((!driver->usb_connected) && (driver->
+					logging_mode == USB_MODE)) || (driver->
+					logging_mode == NO_LOGGING_MODE)) {
+					/* Drop the diag payload */
+					driver->in_busy_sdio = 0;
+					return;
+				}
 				APPEND_DEBUG('j');
 				driver->write_ptr_mdm->length = r;
 				driver->in_busy_sdio = 1;
@@ -149,8 +156,13 @@
 void diag_read_mdm_work_fn(struct work_struct *work)
 {
 	if (driver->sdio_ch) {
-		wait_event_interruptible(driver->wait_q, (sdio_write_avail
-				(driver->sdio_ch) >= driver->read_len_mdm));
+		wait_event_interruptible(driver->wait_q, ((sdio_write_avail
+			(driver->sdio_ch) >= driver->read_len_mdm) ||
+				 !(driver->sdio_ch)));
+		if (!(driver->sdio_ch)) {
+			pr_alert("diag: sdio channel not valid");
+			return;
+		}
 		if (driver->sdio_ch && driver->usb_buf_mdm_out &&
 						 (driver->read_len_mdm > 0))
 			sdio_write(driver->sdio_ch, driver->usb_buf_mdm_out,
@@ -181,15 +193,10 @@
 
 static int diag_sdio_remove(struct platform_device *pdev)
 {
-	queue_work(driver->diag_sdio_wq, &(driver->diag_remove_sdio_work));
-	return 0;
-}
-
-static void diag_remove_sdio_work_fn(struct work_struct *work)
-{
-	pr_debug("diag: sdio remove called\n");
-	/*Disable SDIO channel to prevent further read/write */
+	pr_debug("\n diag: sdio remove called");
+	/* Disable SDIO channel to prevent further read/write */
 	driver->sdio_ch = NULL;
+	return 0;
 }
 
 static int diagfwd_sdio_runtime_suspend(struct device *dev)
@@ -253,7 +260,6 @@
 	INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
 #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)