Exemplo n.º 1
0
static void diagfwd_bridge_notifier(void *priv, unsigned event,
					struct diag_request *d_req)
{
	int index;

	switch (event) {
	case USB_DIAG_CONNECT:
		queue_work(driver->diag_wq,
			 &driver->diag_connect_work);
		break;
	case USB_DIAG_DISCONNECT:
		queue_work(driver->diag_wq,
			 &driver->diag_disconnect_work);
		break;
	case USB_DIAG_READ_DONE:
		index = (int)(d_req->context);
		queue_work(diag_bridge[index].wq,
		&diag_bridge[index].usb_read_complete_work);
		break;
	case USB_DIAG_WRITE_DONE:
		index = (int)(d_req->context);
		if (index == SMUX && driver->diag_smux_enabled)
			diagfwd_write_complete_smux();
		else if (index < MAX_HSIC_CH &&
					diag_hsic[index].hsic_device_enabled)
			diagfwd_write_complete_hsic(d_req, index);
		break;
	default:
		pr_err("diag: in %s: Unknown event from USB diag:%u\n",
			__func__, event);
		break;
	}
}
Exemplo n.º 2
0
static void diagfwd_hsic_notifier(void *priv, unsigned event,
					struct diag_request *d_req)
{
	switch (event) {
	case USB_DIAG_CONNECT:
		diagfwd_connect_hsic(WRITE_TO_USB);
		break;
	case USB_DIAG_QXDM_DISCONNECT: // zero_pky.patch by jagadish
		/* send zero packet */
		driver->zero_cfg_mode = 1;
		/* Intentional fall through */
	case USB_DIAG_DISCONNECT:
		queue_work(driver->diag_hsic_wq, &driver->diag_disconnect_work);
		break;
	case USB_DIAG_READ_DONE:
		queue_work(driver->diag_hsic_wq,
				&driver->diag_usb_read_complete_work);
		break;
	case USB_DIAG_WRITE_DONE:
		diagfwd_write_complete_hsic();
		break;
	default:
		pr_err("DIAG in %s: Unknown event from USB diag:%u\n",
			__func__, event);
		break;
	}
}
Exemplo n.º 3
0
static void diagfwd_bridge_notifier(void *priv, unsigned event,
                                    struct diag_request *d_req)
{
    switch (event) {
    case USB_DIAG_CONNECT:
        diagfwd_connect_bridge(1);
        break;
    case USB_DIAG_DISCONNECT:
        queue_work(driver->diag_bridge_wq,
                   &driver->diag_disconnect_work);
        break;
    case USB_DIAG_READ_DONE:
        queue_work(driver->diag_bridge_wq,
                   &driver->diag_usb_read_complete_work);
        break;
    case USB_DIAG_WRITE_DONE:
        if (driver->hsic_device_enabled)
            diagfwd_write_complete_hsic();
        else if (driver->diag_smux_enabled)
            diagfwd_write_complete_smux();
        break;
    default:
        pr_err("diag: in %s: Unknown event from USB diag:%u\n",
               __func__, event);
        break;
    }
}
Exemplo n.º 4
0
void mtsk_tty_busy_unlock(char *buf, int proc_num)
{
	if (buf == (void *)driver->buf_in_1 && driver->ch) {
		driver->in_busy_1 = 0;
		queue_work(driver->diag_wq,
			   &(driver->diag_read_smd_work));
	} else if (buf == (void *)driver->buf_in_2 && driver->ch) {
		driver->in_busy_2 =0;
		queue_work(driver->diag_wq,
			   &(driver->diag_read_smd_work));
	} else if (buf == (void *)driver->buf_in_qdsp_1 && driver->chqdsp) {
		driver->in_busy_qdsp_1 =0;
		queue_work(driver->diag_wq,
			   &(driver->diag_read_smd_qdsp_work));
	} else if (buf == (void *)driver->buf_in_qdsp_2 && driver->chqdsp) {
		driver->in_busy_qdsp_2 =0;
		queue_work(driver->diag_wq,
			   &(driver->diag_read_smd_qdsp_work));
	} else if (buf == (void *)driver->buf_in_wcnss_1 && driver->ch_wcnss) {
		driver->in_busy_wcnss_1 = 0;
		queue_work(driver->diag_wq,
			   &(driver->diag_read_smd_wcnss_work));
	} else if (buf == (void *)driver->buf_in_wcnss_2 && driver->ch_wcnss) {
		driver->in_busy_wcnss_2 = 0;
		queue_work(driver->diag_wq,
			   &(driver->diag_read_smd_wcnss_work));
	}
#ifdef CONFIG_MTS_USE_HSIC
	else if (proc_num == HSIC_DATA &&
		 driver->hsic_device_enabled &&
		 driver->hsic_ch) {
		diagfwd_write_complete_hsic( );
	}
#endif
}
static void diagfwd_hsic_notifier(void *priv, unsigned event,
					struct diag_request *d_req)
{
	switch (event) {
	case USB_DIAG_CONNECT:
		diagfwd_connect_hsic();
		break;
	case USB_DIAG_DISCONNECT:
		diagfwd_disconnect_hsic();
		break;
	case USB_DIAG_READ_DONE:
		diagfwd_read_complete_hsic(d_req);
		break;
	case USB_DIAG_WRITE_DONE:
		diagfwd_write_complete_hsic();
		break;
	default:
		pr_err("DIAG in %s: Unknown event from USB diag:%u\n",
			__func__, event);
		break;
	}
}
Exemplo n.º 6
0
static int diagchar_read(struct file *file, char __user *buf, size_t count,
			  loff_t *ppos)
{
	int index = -1, i = 0, ret = 0;
	int num_data = 0, data_type;
	for (i = 0; i < driver->num_clients; i++)
		if (driver->client_map[i].pid == current->tgid)
			index = i;

	if (index == -1) {
		pr_err("diag: Client PID not found in table");
		return -EINVAL;
	}

	wait_event_interruptible(driver->wait_q,
				  driver->data_ready[index]);
	mutex_lock(&driver->diagchar_mutex);

	if ((driver->data_ready[index] & USER_SPACE_LOG_TYPE) && (driver->
					logging_mode == MEMORY_DEVICE_MODE)) {
		pr_debug("diag: process woken up\n");
		/*Copy the type of data being passed*/
		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;

		for (i = 0; i < driver->poolsize_write_struct; i++) {
			if (driver->buf_tbl[i].length > 0) {
#ifdef DIAG_DEBUG
				pr_debug("diag: WRITING the buf address "
				       "and length is %x , %d\n", (unsigned int)
					(driver->buf_tbl[i].buf),
					driver->buf_tbl[i].length);
#endif
				num_data++;
				/* Copy the length of data being passed */
				if (copy_to_user(buf+ret, (void *)&(driver->
						buf_tbl[i].length), 4)) {
						num_data--;
						goto drop;
				}
				ret += 4;

				/* Copy the actual data being passed */
				if (copy_to_user(buf+ret, (void *)driver->
				buf_tbl[i].buf, driver->buf_tbl[i].length)) {
					ret -= 4;
					num_data--;
					goto drop;
				}
				ret += driver->buf_tbl[i].length;
drop:
#ifdef DIAG_DEBUG
				pr_debug("diag: DEQUEUE buf address and"
				       " length is %x,%d\n", (unsigned int)
				       (driver->buf_tbl[i].buf), driver->
				       buf_tbl[i].length);
#endif
				diagmem_free(driver, (unsigned char *)
				(driver->buf_tbl[i].buf), POOL_TYPE_HDLC);
				driver->buf_tbl[i].length = 0;
				driver->buf_tbl[i].buf = 0;
			}
		}

		/* copy modem data */
		if (driver->in_busy_1 == 1) {
			num_data++;
			/*Copy the length of data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret,
					 (driver->write_ptr_1->length), 4);
			/*Copy the actual data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret,
					*(driver->buf_in_1),
					 driver->write_ptr_1->length);
			driver->in_busy_1 = 0;
		}
		if (driver->in_busy_2 == 1) {
			num_data++;
			/*Copy the length of data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret,
					 (driver->write_ptr_2->length), 4);
			/*Copy the actual data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret,
					 *(driver->buf_in_2),
					 driver->write_ptr_2->length);
			driver->in_busy_2 = 0;
		}
		/* copy lpass data */
		if (driver->in_busy_qdsp_1 == 1) {
			num_data++;
			/*Copy the length of data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret,
				 (driver->write_ptr_qdsp_1->length), 4);
			/*Copy the actual data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
							buf_in_qdsp_1),
					 driver->write_ptr_qdsp_1->length);
			driver->in_busy_qdsp_1 = 0;
		}
		if (driver->in_busy_qdsp_2 == 1) {
			num_data++;
			/*Copy the length of data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret,
				 (driver->write_ptr_qdsp_2->length), 4);
			/*Copy the actual data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
				buf_in_qdsp_2), driver->
					write_ptr_qdsp_2->length);
			driver->in_busy_qdsp_2 = 0;
		}
		/* copy wncss data */
		if (driver->in_busy_wcnss_1 == 1) {
			num_data++;
			/*Copy the length of data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret,
				 (driver->write_ptr_wcnss_1->length), 4);
			/*Copy the actual data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
							buf_in_wcnss_1),
					 driver->write_ptr_wcnss_1->length);
			driver->in_busy_wcnss_1 = 0;
		}
		if (driver->in_busy_wcnss_2 == 1) {
			num_data++;
			/*Copy the length of data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret,
				 (driver->write_ptr_wcnss_2->length), 4);
			/*Copy the actual data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
							buf_in_wcnss_2),
					 driver->write_ptr_wcnss_2->length);
			driver->in_busy_wcnss_2 = 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
#ifdef CONFIG_DIAG_BRIDGE_CODE
		pr_debug("diag: Copy data to user space %d\n",
			 driver->in_busy_hsic_write_on_device);
		if (driver->in_busy_hsic_write_on_device == 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_hsic),
					 driver->write_ptr_mdm->length);
			pr_debug("diag: data copied\n");
			/* call the write complete function */
			diagfwd_write_complete_hsic();
		}
#endif
		/* copy number of data fields */
		COPY_USER_SPACE_OR_EXIT(buf+4, num_data, 4);
		ret -= 4;
		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));
#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) {
		/* 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] ^= USER_SPACE_LOG_TYPE;
	}

	if (driver->data_ready[index] & DEINIT_TYPE) {
		/*Copy the type of data being passed*/
		data_type = driver->data_ready[index] & DEINIT_TYPE;
		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
		driver->data_ready[index] ^= DEINIT_TYPE;
		goto exit;
	}

	if (driver->data_ready[index] & MSG_MASKS_TYPE) {
		/*Copy the type of data being passed*/
		data_type = driver->data_ready[index] & MSG_MASKS_TYPE;
		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
		COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->msg_masks),
							 MSG_MASK_SIZE);
		driver->data_ready[index] ^= MSG_MASKS_TYPE;
		goto exit;
	}

	if (driver->data_ready[index] & EVENT_MASKS_TYPE) {
		/*Copy the type of data being passed*/
		data_type = driver->data_ready[index] & EVENT_MASKS_TYPE;
		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
		COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->event_masks),
							 EVENT_MASK_SIZE);
		driver->data_ready[index] ^= EVENT_MASKS_TYPE;
		goto exit;
	}

	if (driver->data_ready[index] & LOG_MASKS_TYPE) {
		/*Copy the type of data being passed*/
		data_type = driver->data_ready[index] & LOG_MASKS_TYPE;
		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
		COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->log_masks),
							 LOG_MASK_SIZE);
		driver->data_ready[index] ^= LOG_MASKS_TYPE;
		goto exit;
	}

	if (driver->data_ready[index] & PKT_TYPE) {
		/*Copy the type of data being passed*/
		data_type = driver->data_ready[index] & PKT_TYPE;
		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
		COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->pkt_buf),
							 driver->pkt_length);
		driver->data_ready[index] ^= PKT_TYPE;
		goto exit;
	}

	if (driver->data_ready[index] & DCI_DATA_TYPE) {
		/*Copy the type of data being passed*/
		data_type = driver->data_ready[index] & DCI_DATA_TYPE;
		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
		COPY_USER_SPACE_OR_EXIT(buf+4,
			 driver->write_ptr_dci->length, 4);
		/* check delayed vs immediate response */
		if (*(uint8_t *)(driver->buf_in_dci+4) == DCI_CMD_CODE)
			COPY_USER_SPACE_OR_EXIT(buf+8,
		*(driver->buf_in_dci + 5), driver->write_ptr_dci->length);
		else
			COPY_USER_SPACE_OR_EXIT(buf+8,
		*(driver->buf_in_dci + 8), driver->write_ptr_dci->length);
		driver->in_busy_dci = 0;
		driver->data_ready[index] ^= DCI_DATA_TYPE;
		if (driver->ch_dci)
			queue_work(driver->diag_wq,
				 &(driver->diag_read_smd_dci_work));
		goto exit;
	}
exit:
	mutex_unlock(&driver->diagchar_mutex);
	return ret;
}
Exemplo n.º 7
0
static int diagfwd_read_complete_bridge(struct diag_request *diag_read_ptr)
{
	
	driver->in_busy_hsic_read_on_device = 0;
	driver->read_len_mdm = diag_read_ptr->actual;

	if (driver->diag_smux_enabled) {
		diagfwd_read_complete_smux();
		return 0;
	}
	
	if (!driver->hsic_ch) {
		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
		return 0;
	}

#if DIAG_XPST && defined(CONFIG_DIAG_BRIDGE_CODE)
	if (!driver->in_busy_hsic_write && driver->usb_buf_mdm_out &&
		(driver->read_len_mdm > 0) && !driver->nohdlc) {
#else
	if (!driver->in_busy_hsic_write && driver->usb_buf_mdm_out &&
		(driver->read_len_mdm > 0)) {
#endif

		int err;
		driver->in_busy_hsic_write = 1;
		err = diag_bridge_write(driver->usb_buf_mdm_out,
					driver->read_len_mdm);
		if (err) {
			pr_err_ratelimited("diag: mdm data on hsic write err: %d\n",
					err);
			if ((-ENODEV) != err)
				driver->in_busy_hsic_write = 0;
		}
	}

	if (!driver->in_busy_hsic_write)
		queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);

	return 0;
}

static void diagfwd_bridge_notifier(void *priv, unsigned event,
					struct diag_request *d_req)
{
	switch (event) {
	case USB_DIAG_CONNECT:
		diagfwd_connect_bridge(1);
		break;
	case USB_DIAG_DISCONNECT:
		queue_work(driver->diag_bridge_wq,
			 &driver->diag_disconnect_work);
		break;
	case USB_DIAG_READ_DONE:
		queue_work(driver->diag_bridge_wq,
				&driver->diag_usb_read_complete_work);
		break;
	case USB_DIAG_WRITE_DONE:
		if (driver->hsic_device_enabled)
			diagfwd_write_complete_hsic(d_req);
		else if (driver->diag_smux_enabled)
			diagfwd_write_complete_smux();
		break;
	default:
		pr_err("diag: in %s: Unknown event from USB diag:%u\n",
			__func__, event);
		break;
	}
}

static void diag_usb_read_complete_fn(struct work_struct *w)
{
	diagfwd_read_complete_bridge(driver->usb_read_mdm_ptr);
}
int diagfwd_read_complete_bridge(struct diag_request *diag_read_ptr)
{
	 int index = (int)(diag_read_ptr->context);

	
	diag_bridge[index].read_len = diag_read_ptr->actual;

	if (index == SMUX) {
		if (driver->diag_smux_enabled) {
			diagfwd_read_complete_smux();
			return 0;
		} else {
			pr_warning("diag: incorrect callback for smux\n");
		}
	}

	
	driver->in_busy_hsic_read_on_device = 0;
	if (!driver->hsic_ch) {
		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
		return 0;
	}

#if DIAG_XPST
	if (!driver->in_busy_hsic_write && diag_bridge[HSIC].usb_buf_out &&
		(diag_bridge[HSIC].read_len > 0) && !driver->nohdlc) {
#else
	if (!driver->in_busy_hsic_write && diag_bridge[HSIC].usb_buf_out &&
		(diag_bridge[HSIC].read_len > 0)) {
#endif

		int err;
		driver->in_busy_hsic_write = 1;
		err = diag_bridge_write(diag_bridge[HSIC].usb_buf_out,
					diag_bridge[HSIC].read_len);
		if (err) {
			pr_err_ratelimited("diag: mdm data on HSIC write err: %d\n",
					err);
			if ((-ENODEV) != err)
				driver->in_busy_hsic_write = 0;
		}
	}

	if (!driver->in_busy_hsic_write)
		queue_work(diag_bridge[HSIC].wq,
			 &diag_bridge[HSIC].diag_read_work);

	return 0;
}

static void diagfwd_bridge_notifier(void *priv, unsigned event,
					struct diag_request *d_req)
{
	int index;

	switch (event) {
	case USB_DIAG_CONNECT:
		diagfwd_connect_bridge(1);
		break;
	case USB_DIAG_DISCONNECT:
		queue_work(driver->diag_wq,
			 &driver->diag_disconnect_work);
		break;
	case USB_DIAG_READ_DONE:
		index = (int)(d_req->context);
		queue_work(diag_bridge[index].wq,
		&diag_bridge[index].usb_read_complete_work);
		break;
	case USB_DIAG_WRITE_DONE:
		index = (int)(d_req->context);
		if (index == HSIC &&  driver->hsic_device_enabled)
			diagfwd_write_complete_hsic(d_req);
		else if (index == SMUX && driver->diag_smux_enabled)
			diagfwd_write_complete_smux();
		break;
	default:
		pr_err("diag: in %s: Unknown event from USB diag:%u\n",
			__func__, event);
		break;
	}
}
/* Called after the asychronous usb_diag_read() on mdm channel is complete */
int diagfwd_read_complete_bridge(struct diag_request *diag_read_ptr)
{
	 int index = (int)(diag_read_ptr->context);

	/* The read of the usb on the mdm (not HSIC/SMUX) has completed */
	diag_bridge[index].read_len = diag_read_ptr->actual;

	if (index == SMUX) {
		if (driver->diag_smux_enabled) {
			diagfwd_read_complete_smux();
			return 0;
		} else {
			pr_warning("diag: incorrect callback for smux\n");
		}
	}

	/* If SMUX not enabled, check for HSIC */
	diag_hsic[index].in_busy_hsic_read_on_device = 0;
	if (!diag_hsic[index].hsic_ch) {
		pr_err("DIAG in %s: hsic_ch == 0, ch %d\n", __func__, index);
		return 0;
	}

	/*
	 * The read of the usb driver on the mdm channel has completed.
	 * If there is no write on the HSIC in progress, check if the
	 * read has data to pass on to the HSIC. If so, pass the usb
	 * mdm data on to the HSIC.
	 */
#if DIAG_XPST
	if (!diag_hsic[index].in_busy_hsic_write &&
		diag_bridge[index].usb_buf_out &&
		(diag_bridge[index].read_len > 0) && !driver->nohdlc) {
#else
	if (!diag_hsic[index].in_busy_hsic_write &&
		diag_bridge[index].usb_buf_out &&
		(diag_bridge[index].read_len > 0)) {
#endif
		/*
		 * Initiate the HSIC write. The HSIC write is
		 * asynchronous. When complete the write
		 * complete callback function will be called
		 */
		int err;
		diag_hsic[index].in_busy_hsic_write = 1;
		err = diag_bridge_write(index, diag_bridge[index].usb_buf_out,
					diag_bridge[index].read_len);
		if (err) {
			pr_err_ratelimited("diag: mdm data on HSIC write err: %d\n",
					err);
			/*
			 * If the error is recoverable, then clear
			 * the write flag, so we will resubmit a
			 * write on the next frame.  Otherwise, don't
			 * resubmit a write on the next frame.
			 */
			if ((-ENODEV) != err)
				diag_hsic[index].in_busy_hsic_write = 0;
		}
	}

	/*
	 * If there is no write of the usb mdm data on the
	 * HSIC channel
	 */
	if (!diag_hsic[index].in_busy_hsic_write)
		queue_work(diag_bridge[index].wq,
			 &diag_bridge[index].diag_read_work);

	return 0;
}

static void diagfwd_bridge_notifier(void *priv, unsigned event,
					struct diag_request *d_req)
{
	int index;

	switch (event) {
	case USB_DIAG_CONNECT:
		queue_work(driver->diag_wq,
			 &driver->diag_connect_work);
		break;
	case USB_DIAG_DISCONNECT:
		queue_work(driver->diag_wq,
			 &driver->diag_disconnect_work);
		break;
	case USB_DIAG_READ_DONE:
		index = (int)(d_req->context);
		queue_work(diag_bridge[index].wq,
		&diag_bridge[index].usb_read_complete_work);
		break;
	case USB_DIAG_WRITE_DONE:
		index = (int)(d_req->context);
		if (index == SMUX && driver->diag_smux_enabled)
			diagfwd_write_complete_smux();
		else if (diag_hsic[index].hsic_device_enabled)
			diagfwd_write_complete_hsic(d_req, index);
		break;
	default:
		pr_err("diag: in %s: Unknown event from USB diag:%u\n",
			__func__, event);
		break;
	}
}
Exemplo n.º 10
0
static int diagchar_read(struct file *file, char __user *buf, size_t count,
			  loff_t *ppos)
{
	struct diag_dci_client_tbl *entry;
	int index = -1, i = 0, ret = 0;
	int num_data = 0, data_type;
#if defined(CONFIG_DIAG_SDIO_PIPE) || defined(CONFIG_DIAG_BRIDGE_CODE)
	int mdm_token = MDM_TOKEN;
#endif

	for (i = 0; i < driver->num_clients; i++)
		if (driver->client_map[i].pid == current->tgid)
			index = i;

	if (index == -1) {
		pr_err("diag: Client PID not found in table");
		return -EINVAL;
	}

	wait_event_interruptible(driver->wait_q,
				  driver->data_ready[index]);
	mutex_lock(&driver->diagchar_mutex);

	if ((driver->data_ready[index] & USER_SPACE_DATA_TYPE) && (driver->
					logging_mode == MEMORY_DEVICE_MODE)) {
#ifdef CONFIG_DIAG_BRIDGE_CODE
		unsigned long spin_lock_flags;
		struct diag_write_device hsic_buf_tbl[NUM_HSIC_BUF_TBL_ENTRIES];
#endif

		pr_debug("diag: process woken up\n");
		/*Copy the type of data being passed*/
		data_type = driver->data_ready[index] & USER_SPACE_DATA_TYPE;
		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
		/* place holder for number of data field */
		ret += 4;

		for (i = 0; i < driver->poolsize_write_struct; i++) {
			if (driver->buf_tbl[i].length > 0) {
#ifdef DIAG_DEBUG
				pr_debug("diag: WRITING the buf address "
				       "and length is %x , %d\n", (unsigned int)
					(driver->buf_tbl[i].buf),
					driver->buf_tbl[i].length);
#endif
				num_data++;
				/* Copy the length of data being passed */
				if (copy_to_user(buf+ret, (void *)&(driver->
						buf_tbl[i].length), 4)) {
						num_data--;
						goto drop;
				}
				ret += 4;

				/* Copy the actual data being passed */
				if (copy_to_user(buf+ret, (void *)driver->
				buf_tbl[i].buf, driver->buf_tbl[i].length)) {
					ret -= 4;
					num_data--;
					goto drop;
				}
				ret += driver->buf_tbl[i].length;
drop:
#ifdef DIAG_DEBUG
				pr_debug("diag: DEQUEUE buf address and"
				       " length is %x,%d\n", (unsigned int)
				       (driver->buf_tbl[i].buf), driver->
				       buf_tbl[i].length);
#endif
				diagmem_free(driver, (unsigned char *)
				(driver->buf_tbl[i].buf), POOL_TYPE_HDLC);
				driver->buf_tbl[i].length = 0;
				driver->buf_tbl[i].buf = 0;
			}
		}

		/* copy modem data */
		if (driver->in_busy_1 == 1) {
			num_data++;
			/*Copy the length of data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret,
					 (driver->write_ptr_1->length), 4);
			/*Copy the actual data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret,
					*(driver->buf_in_1),
					 driver->write_ptr_1->length);
			driver->in_busy_1 = 0;
		}
		if (driver->in_busy_2 == 1) {
			num_data++;
			/*Copy the length of data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret,
					 (driver->write_ptr_2->length), 4);
			/*Copy the actual data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret,
					 *(driver->buf_in_2),
					 driver->write_ptr_2->length);
			driver->in_busy_2 = 0;
		}
		/* copy lpass data */
		if (driver->in_busy_lpass_1 == 1) {
			num_data++;
			/*Copy the length of data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret,
				 (driver->write_ptr_lpass_1->length), 4);
			/*Copy the actual data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
							buf_in_lpass_1),
					 driver->write_ptr_lpass_1->length);
			driver->in_busy_lpass_1 = 0;
		}
		if (driver->in_busy_lpass_2 == 1) {
			num_data++;
			/*Copy the length of data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret,
				 (driver->write_ptr_lpass_2->length), 4);
			/*Copy the actual data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
				buf_in_lpass_2), driver->
					write_ptr_lpass_2->length);
			driver->in_busy_lpass_2 = 0;
		}
		/* copy wncss data */
		if (driver->in_busy_wcnss_1 == 1) {
			num_data++;
			/*Copy the length of data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret,
				 (driver->write_ptr_wcnss_1->length), 4);
			/*Copy the actual data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
							buf_in_wcnss_1),
					 driver->write_ptr_wcnss_1->length);
			driver->in_busy_wcnss_1 = 0;
		}
		if (driver->in_busy_wcnss_2 == 1) {
			num_data++;
			/*Copy the length of data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret,
				 (driver->write_ptr_wcnss_2->length), 4);
			/*Copy the actual data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
							buf_in_wcnss_2),
					 driver->write_ptr_wcnss_2->length);
			driver->in_busy_wcnss_2 = 0;
		}
#ifdef CONFIG_DIAG_SDIO_PIPE
		/* copy 9K data over SDIO */
		if (driver->in_busy_sdio == 1) {
			num_data++;
			/*Copy the negative  token of data being passed*/
			COPY_USER_SPACE_OR_EXIT(buf+ret, mdm_token, 4);
			/*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
#ifdef CONFIG_DIAG_BRIDGE_CODE
		spin_lock_irqsave(&driver->hsic_spinlock, spin_lock_flags);
		for (i = 0; i < driver->poolsize_hsic_write; i++) {
			hsic_buf_tbl[i].buf = driver->hsic_buf_tbl[i].buf;
			driver->hsic_buf_tbl[i].buf = 0;
			hsic_buf_tbl[i].length =
					driver->hsic_buf_tbl[i].length;
			driver->hsic_buf_tbl[i].length = 0;
		}
		driver->num_hsic_buf_tbl_entries = 0;
		spin_unlock_irqrestore(&driver->hsic_spinlock,
					spin_lock_flags);

		for (i = 0; i < driver->poolsize_hsic_write; i++) {
			if (hsic_buf_tbl[i].length > 0) {
				pr_debug("diag: HSIC copy to user, i: %d, buf: %x, len: %d\n",
					 i, (unsigned int)hsic_buf_tbl[i].buf,
					hsic_buf_tbl[i].length);
				num_data++;

				/* Copy the negative token */
				if (copy_to_user(buf+ret, &mdm_token, 4)) {
					num_data--;
					goto drop_hsic;
				}
				ret += 4;

				/* Copy the length of data being passed */
				if (copy_to_user(buf+ret,
					(void *)&(hsic_buf_tbl[i].length),
					4)) {
					num_data--;
					goto drop_hsic;
				}
				ret += 4;

				/* Copy the actual data being passed */
				if (copy_to_user(buf+ret,
						(void *)hsic_buf_tbl[i].buf,
						hsic_buf_tbl[i].length)) {
					ret -= 4;
					num_data--;
					goto drop_hsic;
				}
				ret += hsic_buf_tbl[i].length;
drop_hsic:
				/* Return the buffer to the pool */
				diagmem_free(driver,
					(unsigned char *)(hsic_buf_tbl[i].buf),
					POOL_TYPE_HSIC);

				/* Call the write complete function */
				diagfwd_write_complete_hsic(NULL);
			}
		}
		if (driver->in_busy_smux == 1) {
			num_data++;

			/* Copy the negative  token of data being passed */
			COPY_USER_SPACE_OR_EXIT(buf+ret, mdm_token, 4);
			/* 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_smux),
					driver->write_ptr_mdm->length);
			pr_debug("diag: SMUX  data copied\n");
			driver->in_busy_smux = 0;
		}
#endif
		/* copy number of data fields */
		COPY_USER_SPACE_OR_EXIT(buf+4, num_data, 4);
		ret -= 4;
		driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
		if (driver->ch)
			queue_work(driver->diag_wq,
					 &(driver->diag_read_smd_work));
		if (driver->chlpass)
			queue_work(driver->diag_wq,
					 &(driver->diag_read_smd_lpass_work));
		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_DATA_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] ^= USER_SPACE_DATA_TYPE;
	}

	if (driver->data_ready[index] & DEINIT_TYPE) {
		/*Copy the type of data being passed*/
		data_type = driver->data_ready[index] & DEINIT_TYPE;
		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
		driver->data_ready[index] ^= DEINIT_TYPE;
		goto exit;
	}

	if (driver->data_ready[index] & MSG_MASKS_TYPE) {
		/*Copy the type of data being passed*/
		data_type = driver->data_ready[index] & MSG_MASKS_TYPE;
		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
		COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->msg_masks),
							 MSG_MASK_SIZE);
		driver->data_ready[index] ^= MSG_MASKS_TYPE;
		goto exit;
	}

	if (driver->data_ready[index] & EVENT_MASKS_TYPE) {
		/*Copy the type of data being passed*/
		data_type = driver->data_ready[index] & EVENT_MASKS_TYPE;
		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
		COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->event_masks),
							 EVENT_MASK_SIZE);
		driver->data_ready[index] ^= EVENT_MASKS_TYPE;
		goto exit;
	}

	if (driver->data_ready[index] & LOG_MASKS_TYPE) {
		/*Copy the type of data being passed*/
		data_type = driver->data_ready[index] & LOG_MASKS_TYPE;
		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
		COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->log_masks),
							 LOG_MASK_SIZE);
		driver->data_ready[index] ^= LOG_MASKS_TYPE;
		goto exit;
	}

	if (driver->data_ready[index] & PKT_TYPE) {
		/*Copy the type of data being passed*/
		data_type = driver->data_ready[index] & PKT_TYPE;
		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
		COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->pkt_buf),
							 driver->pkt_length);
		driver->data_ready[index] ^= PKT_TYPE;
		goto exit;
	}

	if (driver->data_ready[index] & DCI_DATA_TYPE) {
		/* Copy the type of data being passed */
		data_type = driver->data_ready[index] & DCI_DATA_TYPE;
		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
		/* check the current client and copy its data */
		for (i = 0; i < MAX_DCI_CLIENTS; i++) {
			entry = &(driver->dci_client_tbl[i]);
			if (entry && (current->tgid == entry->client->tgid)) {
				COPY_USER_SPACE_OR_EXIT(buf+4,
						entry->data_len, 4);
				COPY_USER_SPACE_OR_EXIT(buf+8,
					 *(entry->dci_data), entry->data_len);
				entry->data_len = 0;
				break;
			}
		}
		driver->data_ready[index] ^= DCI_DATA_TYPE;
		driver->in_busy_dci = 0;
		if (driver->ch_dci)
			queue_work(driver->diag_dci_wq,
				&(driver->diag_read_smd_dci_work));
		goto exit;
	}
exit:
	mutex_unlock(&driver->diagchar_mutex);
	return ret;
}