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; } }
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; } }
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; } }
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; } }
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; }
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; } }
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; }