long diagchar_ioctl(struct file *filp, unsigned int iocmd, unsigned long ioarg) { int i, j, count_entries = 0, temp; int success = -1; void *temp_buf; if (iocmd == DIAG_IOCTL_COMMAND_REG) { struct bindpkt_params_per_process *pkt_params = (struct bindpkt_params_per_process *) ioarg; mutex_lock(&driver->diagchar_mutex); for (i = 0; i < diag_max_registration; i++) { if (driver->table[i].process_id == 0) { diag_add_reg(i, pkt_params->params, &success, &count_entries); if (pkt_params->count > count_entries) { pkt_params->params++; } else { mutex_unlock(&driver->diagchar_mutex); return success; } } } if (i < diag_threshold_registration) { /* Increase table size by amount required */ diag_max_registration += pkt_params->count - count_entries; /* Make sure size doesnt go beyond threshold */ if (diag_max_registration > diag_threshold_registration) diag_max_registration = diag_threshold_registration; temp_buf = krealloc(driver->table, diag_max_registration*sizeof(struct diag_master_table), GFP_KERNEL); if (!temp_buf) { diag_max_registration -= pkt_params->count - count_entries; pr_alert("diag: Insufficient memory for reg."); mutex_unlock(&driver->diagchar_mutex); return 0; } else { driver->table = temp_buf; } for (j = i; j < diag_max_registration; j++) { diag_add_reg(j, pkt_params->params, &success, &count_entries); if (pkt_params->count > count_entries) { pkt_params->params++; } else { mutex_unlock(&driver->diagchar_mutex); return success; } } } else { mutex_unlock(&driver->diagchar_mutex); pr_err("Max size reached, Pkt Registration failed for" " Process %d", current->tgid); } success = 0; } else if (iocmd == DIAG_IOCTL_GET_DELAYED_RSP_ID) { struct diagpkt_delay_params *delay_params = (struct diagpkt_delay_params *) ioarg; if ((delay_params->rsp_ptr) && (delay_params->size == sizeof(delayed_rsp_id)) && (delay_params->num_bytes_ptr)) { *((uint16_t *)delay_params->rsp_ptr) = DIAGPKT_NEXT_DELAYED_RSP_ID(delayed_rsp_id); *(delay_params->num_bytes_ptr) = sizeof(delayed_rsp_id); success = 0; } } else if (iocmd == DIAG_IOCTL_LSM_DEINIT) { for (i = 0; i < driver->num_clients; i++) if (driver->client_map[i].pid == current->tgid) break; if (i == -1) return -EINVAL; driver->data_ready[i] |= DEINIT_TYPE; wake_up_interruptible(&driver->wait_q); success = 1; } else if (iocmd == DIAG_IOCTL_SWITCH_LOGGING) { mutex_lock(&driver->diagchar_mutex); temp = driver->logging_mode; driver->logging_mode = (int)ioarg; if (driver->logging_mode == MEMORY_DEVICE_MODE) driver->mask_check = 1; if (driver->logging_mode == UART_MODE) { driver->mask_check = 0; 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 == NO_LOGGING_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 driver->in_busy_sdio = 1; #endif } 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, &(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 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 == NO_LOGGING_MODE) diagfwd_disconnect(); else if (temp == NO_LOGGING_MODE && driver->logging_mode == USB_MODE) diagfwd_connect(); else if (temp == USB_MODE && driver->logging_mode == MEMORY_DEVICE_MODE) { diagfwd_disconnect(); driver->in_busy_1 = 0; 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, &(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 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; } return success; }
long diagchar_ioctl(struct file *filp, unsigned int iocmd, unsigned long ioarg) { int i, j, temp, success = -1; unsigned int count_entries = 0, interim_count = 0; void *temp_buf; if (iocmd == DIAG_IOCTL_COMMAND_REG) { struct bindpkt_params_per_process pkt_params; struct bindpkt_params *params; struct bindpkt_params *head_params; if (copy_from_user(&pkt_params, (void *)ioarg, sizeof(struct bindpkt_params_per_process))) { return -EFAULT; } if ((UINT32_MAX/sizeof(struct bindpkt_params)) < pkt_params.count) { pr_alert("diag: integer overflow while multiply\n"); return -EFAULT; } params = kzalloc(pkt_params.count*sizeof( struct bindpkt_params), GFP_KERNEL); if (!params) { pr_alert("diag: unable to alloc memory\n"); return -ENOMEM; } else head_params = params; if (copy_from_user(params, pkt_params.params, pkt_params.count*sizeof(struct bindpkt_params))) { kfree(head_params); return -EFAULT; } mutex_lock(&driver->diagchar_mutex); for (i = 0; i < diag_max_reg; i++) { if (driver->table[i].process_id == 0) { diag_add_reg(i, params, &success, &count_entries); if (pkt_params.count > count_entries) { params++; } else { mutex_unlock(&driver->diagchar_mutex); kfree(head_params); return success; } } } if (i < diag_threshold_reg) { /* Increase table size by amount required */ if (pkt_params.count >= count_entries) { interim_count = pkt_params.count - count_entries; } else { pr_alert("diag: error in params count\n"); kfree(head_params); mutex_unlock(&driver->diagchar_mutex); return -EFAULT; } if (UINT32_MAX - diag_max_reg >= interim_count) { diag_max_reg += interim_count; } else { pr_alert("diag: Integer overflow\n"); kfree(head_params); mutex_unlock(&driver->diagchar_mutex); return -EFAULT; } /* Make sure size doesnt go beyond threshold */ if (diag_max_reg > diag_threshold_reg) { diag_max_reg = diag_threshold_reg; pr_info("diag: best case memory allocation\n"); } if (UINT32_MAX/sizeof(struct diag_master_table) < diag_max_reg) { pr_alert("diag: integer overflow\n"); kfree(head_params); mutex_unlock(&driver->diagchar_mutex); return -EFAULT; } temp_buf = krealloc(driver->table, diag_max_reg*sizeof(struct diag_master_table), GFP_KERNEL); if (!temp_buf) { pr_alert("diag: Insufficient memory for reg.\n"); mutex_unlock(&driver->diagchar_mutex); if (pkt_params.count >= count_entries) { interim_count = pkt_params.count - count_entries; } else { pr_alert("diag: params count error\n"); mutex_unlock(&driver->diagchar_mutex); kfree(head_params); return -EFAULT; } if (diag_max_reg >= interim_count) { diag_max_reg -= interim_count; } else { pr_alert("diag: Integer underflow\n"); mutex_unlock(&driver->diagchar_mutex); kfree(head_params); return -EFAULT; } kfree(head_params); return 0; } else { driver->table = temp_buf; } for (j = i; j < diag_max_reg; j++) { diag_add_reg(j, params, &success, &count_entries); if (pkt_params.count > count_entries) { params++; } else { mutex_unlock(&driver->diagchar_mutex); kfree(head_params); return success; } } kfree(head_params); mutex_unlock(&driver->diagchar_mutex); } else { mutex_unlock(&driver->diagchar_mutex); kfree(head_params); pr_err("Max size reached, Pkt Registration failed for" " Process %d", current->tgid); } success = 0; } else if (iocmd == DIAG_IOCTL_GET_DELAYED_RSP_ID) { struct diagpkt_delay_params delay_params; uint16_t interim_rsp_id; int interim_size; if (copy_from_user(&delay_params, (void *)ioarg, sizeof(struct diagpkt_delay_params))) return -EFAULT; if ((delay_params.rsp_ptr) && (delay_params.size == sizeof(delayed_rsp_id)) && (delay_params.num_bytes_ptr)) { interim_rsp_id = DIAGPKT_NEXT_DELAYED_RSP_ID( delayed_rsp_id); if (copy_to_user((void *)delay_params.rsp_ptr, &interim_rsp_id, sizeof(uint16_t))) return -EFAULT; interim_size = sizeof(delayed_rsp_id); if (copy_to_user((void *)delay_params.num_bytes_ptr, &interim_size, sizeof(int))) return -EFAULT; success = 0; } } else if (iocmd == DIAG_IOCTL_LSM_DEINIT) { for (i = 0; i < driver->num_clients; i++) if (driver->client_map[i].pid == current->tgid) break; if (i == -1) return -EINVAL; driver->data_ready[i] |= DEINIT_TYPE; wake_up_interruptible(&driver->wait_q); success = 1; } else if (iocmd == DIAG_IOCTL_SWITCH_LOGGING) { mutex_lock(&driver->diagchar_mutex); temp = driver->logging_mode; driver->logging_mode = (int)ioarg; if (driver->logging_mode == MEMORY_DEVICE_MODE) driver->mask_check = 1; if (driver->logging_mode == UART_MODE) { driver->mask_check = 0; 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 == NO_LOGGING_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 driver->in_busy_sdio = 1; #endif } 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, &(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 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 == NO_LOGGING_MODE) diagfwd_disconnect(); else if (temp == NO_LOGGING_MODE && driver->logging_mode == USB_MODE) diagfwd_connect(); else if (temp == USB_MODE && driver->logging_mode == MEMORY_DEVICE_MODE) { diagfwd_disconnect(); driver->in_busy_1 = 0; 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, &(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 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; } return success; }
long diagchar_ioctl(struct file *filp, unsigned int iocmd, unsigned long ioarg) { int i, j, temp, success = -1, status; unsigned int count_entries = 0, interim_count = 0; void *temp_buf; uint16_t support_list = 0; struct dci_notification_tbl *dci_params; if (iocmd == DIAG_IOCTL_COMMAND_REG) { struct bindpkt_params_per_process pkt_params; struct bindpkt_params *params; struct bindpkt_params *head_params; if (copy_from_user(&pkt_params, (void *)ioarg, sizeof(struct bindpkt_params_per_process))) { return -EFAULT; } if ((UINT32_MAX/sizeof(struct bindpkt_params)) < pkt_params.count) { pr_warning("diag: integer overflow while multiply\n"); return -EFAULT; } params = kzalloc(pkt_params.count*sizeof( struct bindpkt_params), GFP_KERNEL); if (!params) { pr_err("diag: unable to alloc memory\n"); return -ENOMEM; } else head_params = params; if (copy_from_user(params, pkt_params.params, pkt_params.count*sizeof(struct bindpkt_params))) { kfree(head_params); return -EFAULT; } mutex_lock(&driver->diagchar_mutex); for (i = 0; i < diag_max_reg; i++) { if (driver->table[i].process_id == 0) { diag_add_reg(i, params, &success, &count_entries); if (pkt_params.count > count_entries) { params++; } else { mutex_unlock(&driver->diagchar_mutex); kfree(head_params); return success; } } } if (i < diag_threshold_reg) { /* Increase table size by amount required */ if (pkt_params.count >= count_entries) { interim_count = pkt_params.count - count_entries; } else { pr_warning("diag: error in params count\n"); kfree(head_params); mutex_unlock(&driver->diagchar_mutex); return -EFAULT; } if (UINT32_MAX - diag_max_reg >= interim_count) { diag_max_reg += interim_count; } else { pr_warning("diag: Integer overflow\n"); kfree(head_params); mutex_unlock(&driver->diagchar_mutex); return -EFAULT; } /* Make sure size doesnt go beyond threshold */ if (diag_max_reg > diag_threshold_reg) { diag_max_reg = diag_threshold_reg; pr_info("diag: best case memory allocation\n"); } if (UINT32_MAX/sizeof(struct diag_master_table) < diag_max_reg) { pr_warning("diag: integer overflow\n"); kfree(head_params); mutex_unlock(&driver->diagchar_mutex); return -EFAULT; } temp_buf = krealloc(driver->table, diag_max_reg*sizeof(struct diag_master_table), GFP_KERNEL); if (!temp_buf) { pr_alert("diag: Insufficient memory for reg.\n"); mutex_unlock(&driver->diagchar_mutex); if (pkt_params.count >= count_entries) { interim_count = pkt_params.count - count_entries; } else { pr_warning("diag: params count error\n"); mutex_unlock(&driver->diagchar_mutex); kfree(head_params); return -EFAULT; } if (diag_max_reg >= interim_count) { diag_max_reg -= interim_count; } else { pr_warning("diag: Integer underflow\n"); mutex_unlock(&driver->diagchar_mutex); kfree(head_params); return -EFAULT; } kfree(head_params); return 0; } else { driver->table = temp_buf; } for (j = i; j < diag_max_reg; j++) { diag_add_reg(j, params, &success, &count_entries); if (pkt_params.count > count_entries) { params++; } else { mutex_unlock(&driver->diagchar_mutex); kfree(head_params); return success; } } kfree(head_params); mutex_unlock(&driver->diagchar_mutex); } else { mutex_unlock(&driver->diagchar_mutex); kfree(head_params); pr_err("Max size reached, Pkt Registration failed for" " Process %d", current->tgid); } success = 0; } else if (iocmd == DIAG_IOCTL_GET_DELAYED_RSP_ID) { struct diagpkt_delay_params delay_params; uint16_t interim_rsp_id; int interim_size; if (copy_from_user(&delay_params, (void *)ioarg, sizeof(struct diagpkt_delay_params))) return -EFAULT; if ((delay_params.rsp_ptr) && (delay_params.size == sizeof(delayed_rsp_id)) && (delay_params.num_bytes_ptr)) { interim_rsp_id = DIAGPKT_NEXT_DELAYED_RSP_ID( delayed_rsp_id); if (copy_to_user((void *)delay_params.rsp_ptr, &interim_rsp_id, sizeof(uint16_t))) return -EFAULT; interim_size = sizeof(delayed_rsp_id); if (copy_to_user((void *)delay_params.num_bytes_ptr, &interim_size, sizeof(int))) return -EFAULT; success = 0; } } else if (iocmd == DIAG_IOCTL_DCI_REG) { if (driver->dci_state == DIAG_DCI_NO_REG) return DIAG_DCI_NO_REG; if (driver->num_dci_client >= MAX_DCI_CLIENT) return DIAG_DCI_NO_REG; dci_params = kzalloc(sizeof(struct dci_notification_tbl), GFP_KERNEL); if (dci_params == NULL) { pr_err("diag: unable to alloc memory\n"); return -ENOMEM; } if (copy_from_user(dci_params, (void *)ioarg, sizeof(struct dci_notification_tbl))) return -EFAULT; mutex_lock(&driver->dci_mutex); driver->num_dci_client++; diag_printk(1,"diag:%s id = %d\n",__func__, driver->dci_client_id); driver->dci_client_id++; for (i = 0; i < MAX_DCI_CLIENT; i++) { if (driver->dci_notify_tbl[i].client == NULL) { driver->dci_notify_tbl[i].client = current; driver->dci_notify_tbl[i].list = dci_params->list; driver->dci_notify_tbl[i].signal_type = dci_params->signal_type; break; } } mutex_unlock(&driver->dci_mutex); kfree(dci_params); return driver->dci_client_id; } else if (iocmd == DIAG_IOCTL_DCI_DEINIT) { success = -1; /* Delete this process from DCI table */ mutex_lock(&driver->dci_mutex); for (i = 0; i < dci_max_reg; i++) { if (driver->dci_tbl[i].pid == current->tgid) { diag_printk(1,"diag:%s delete %d\n",__func__, current->tgid); driver->dci_tbl[i].pid = 0; success = i; } } for (i = 0; i < MAX_DCI_CLIENT; i++) { if (driver->dci_notify_tbl[i].client == current) { driver->dci_notify_tbl[i].client = NULL; break; } } /* if any registrations were deleted successfully OR a valid client_id was sent in DEINIT call , then its DCI client */ if (success >= 0 || ioarg) driver->num_dci_client--; driver->num_dci_client--; mutex_unlock(&driver->dci_mutex); for (i = 0; i < dci_max_reg; i++) if (driver->dci_tbl[i].pid != 0) diag_printk(1,"diag:%s PID = %d, UID = %d, tag = %d\n",__func__, driver->dci_tbl[i].pid, driver->dci_tbl[i].uid, driver->dci_tbl[i].tag); diag_printk(1,"diag:%s complete deleting registrations\n",__func__); return success; } else if (iocmd == DIAG_IOCTL_DCI_SUPPORT) { if (driver->ch_dci) support_list = support_list | DIAG_CON_MPSS; *(uint16_t *)ioarg = support_list; return DIAG_DCI_NO_ERROR; } else if (iocmd == DIAG_IOCTL_LSM_DEINIT) { for (i = 0; i < driver->num_clients; i++) if (driver->client_map[i].pid == current->tgid) break; if (i == -1) return -EINVAL; driver->data_ready[i] |= DEINIT_TYPE; wake_up_interruptible(&driver->wait_q); success = 1; } else if (iocmd == DIAG_IOCTL_SWITCH_LOGGING) { mutex_lock(&driver->diagchar_mutex); temp = driver->logging_mode; driver->logging_mode = (int)ioarg; if (driver->logging_mode == MEMORY_DEVICE_MODE) { diag_clear_hsic_tbl(); driver->mask_check = 1; if (driver->socket_process) { /* * Notify the socket logging process that we * are switching to MEMORY_DEVICE_MODE */ status = send_sig(SIGCONT, driver->socket_process, 0); if (status) { pr_err("diag: %s, Error notifying ", __func__); pr_err("socket process, status: %d\n", status); } } } if (driver->logging_mode == UART_MODE) { diag_clear_hsic_tbl(); driver->mask_check = 0; driver->logging_mode = MEMORY_DEVICE_MODE; } if (driver->logging_mode == SOCKET_MODE) { diag_clear_hsic_tbl(); driver->socket_process = current; driver->mask_check = 0; 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 == NO_LOGGING_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 = 1; driver->in_busy_wcnss_2 = 1; #ifdef CONFIG_DIAG_SDIO_PIPE driver->in_busy_sdio = 1; #endif #ifdef CONFIG_DIAG_BRIDGE_CODE diagfwd_disconnect_bridge(0); diag_clear_hsic_tbl(); #endif } 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_1 = 0; driver->in_busy_wcnss_2 = 0; /* Poll SMD channels to check for data*/ 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 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_BRIDGE_CODE diagfwd_connect_bridge(0); #endif } #ifdef CONFIG_DIAG_OVER_USB else if (temp == USB_MODE && driver->logging_mode == NO_LOGGING_MODE) { diagfwd_disconnect(); #ifdef CONFIG_DIAG_BRIDGE_CODE diagfwd_disconnect_bridge(0); #endif } else if (temp == NO_LOGGING_MODE && driver->logging_mode == USB_MODE) { diagfwd_connect(); #ifdef CONFIG_DIAG_BRIDGE_CODE diagfwd_connect_bridge(0); #endif } else if (temp == USB_MODE && driver->logging_mode == MEMORY_DEVICE_MODE) { diagfwd_disconnect(); 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_1 = 0; driver->in_busy_wcnss_2 = 0; /* Poll SMD channels to check for data*/ 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 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_BRIDGE_CODE diagfwd_cancel_hsic(); diagfwd_connect_bridge(0); #endif } else if (temp == MEMORY_DEVICE_MODE && driver->logging_mode == USB_MODE) { diagfwd_connect(); #ifdef CONFIG_DIAG_BRIDGE_CODE diag_clear_hsic_tbl(); diagfwd_cancel_hsic(); diagfwd_connect_bridge(0); #endif } #endif /* DIAG over USB */ success = 1; } return success; }
long diagchar_ioctl(struct file *filp, unsigned int iocmd, unsigned long ioarg) { int i, j, count_entries = 0, temp; int success = -1; void *temp_buf; uint16_t support_list = 0; struct dci_notification_tbl *notify_params; if (iocmd == DIAG_IOCTL_COMMAND_REG) { struct bindpkt_params_per_process *pkt_params = (struct bindpkt_params_per_process *) ioarg; mutex_lock(&driver->diagchar_mutex); for (i = 0; i < diag_max_reg; i++) { if (driver->table[i].process_id == 0) { diag_add_reg(i, pkt_params->params, &success, &count_entries); if (pkt_params->count > count_entries) { pkt_params->params++; } else { mutex_unlock(&driver->diagchar_mutex); return success; } } } if (i < diag_threshold_reg) { /* Increase table size by amount required */ diag_max_reg += pkt_params->count - count_entries; /* Make sure size doesnt go beyond threshold */ if (diag_max_reg > diag_threshold_reg) { diag_max_reg = diag_threshold_reg; pr_info("diag: best case memory allocation\n"); } temp_buf = krealloc(driver->table, diag_max_reg*sizeof(struct diag_master_table), GFP_KERNEL); if (!temp_buf) { diag_max_reg -= pkt_params->count - count_entries; pr_alert("diag: Insufficient memory for reg."); mutex_unlock(&driver->diagchar_mutex); return 0; } else { driver->table = temp_buf; } for (j = i; j < diag_max_reg; j++) { diag_add_reg(j, pkt_params->params, &success, &count_entries); if (pkt_params->count > count_entries) { pkt_params->params++; } else { mutex_unlock(&driver->diagchar_mutex); return success; } } mutex_unlock(&driver->diagchar_mutex); } else { mutex_unlock(&driver->diagchar_mutex); pr_err("Max size reached, Pkt Registration failed for" " Process %d", current->tgid); } success = 0; } else if (iocmd == DIAG_IOCTL_GET_DELAYED_RSP_ID) { struct diagpkt_delay_params *delay_params = (struct diagpkt_delay_params *) ioarg; if ((delay_params->rsp_ptr) && (delay_params->size == sizeof(delayed_rsp_id)) && (delay_params->num_bytes_ptr)) { *((uint16_t *)delay_params->rsp_ptr) = DIAGPKT_NEXT_DELAYED_RSP_ID(delayed_rsp_id); *(delay_params->num_bytes_ptr) = sizeof(delayed_rsp_id); success = 0; } } else if (iocmd == DIAG_IOCTL_DCI_REG) { if (driver->dci_state == DIAG_DCI_NO_REG) return DIAG_DCI_NO_REG; if (driver->num_dci_client >= MAX_DCI_CLIENT) return DIAG_DCI_NO_REG; notify_params = (struct dci_notification_tbl *) ioarg; mutex_lock(&driver->dci_mutex); driver->num_dci_client++; pr_debug("diag: id = %d\n", driver->dci_client_id); driver->dci_client_id++; for (i = 0; i < MAX_DCI_CLIENT; i++) { if (driver->dci_notify_tbl[i].client == NULL) { driver->dci_notify_tbl[i].client = current; driver->dci_notify_tbl[i].list = notify_params->list; driver->dci_notify_tbl[i].signal_type = notify_params->signal_type; break; } } mutex_unlock(&driver->dci_mutex); return driver->dci_client_id; } else if (iocmd == DIAG_IOCTL_DCI_DEINIT) { success = -1; /* Delete this process from DCI table */ mutex_lock(&driver->dci_mutex); for (i = 0; i < dci_max_reg; i++) { if (driver->dci_tbl[i].pid == current->tgid) { pr_debug("diag: delete %d\n", current->tgid); driver->dci_tbl[i].pid = 0; success = i; } } for (i = 0; i < MAX_DCI_CLIENT; i++) { if (driver->dci_notify_tbl[i].client == current) { driver->dci_notify_tbl[i].client = NULL; break; } } /* if any registrations were deleted successfully OR a valid client_id was sent in DEINIT call , then its DCI client */ if (success >= 0 || ioarg) driver->num_dci_client--; driver->num_dci_client--; mutex_unlock(&driver->dci_mutex); for (i = 0; i < dci_max_reg; i++) if (driver->dci_tbl[i].pid != 0) pr_debug("diag: PID = %d, UID = %d, tag = %d\n", driver->dci_tbl[i].pid, driver->dci_tbl[i].uid, driver->dci_tbl[i].tag); pr_debug("diag: complete deleting registrations\n"); return success; } else if (iocmd == DIAG_IOCTL_DCI_SUPPORT) { if (driver->ch_dci) support_list = support_list | DIAG_CON_MPSS; *(uint16_t *)ioarg = support_list; return DIAG_DCI_NO_ERROR; } else if (iocmd == DIAG_IOCTL_LSM_DEINIT) { for (i = 0; i < driver->num_clients; i++) if (driver->client_map[i].pid == current->tgid) break; if (i == -1) return -EINVAL; driver->data_ready[i] |= DEINIT_TYPE; wake_up_interruptible(&driver->wait_q); success = 1; } else if (iocmd == DIAG_IOCTL_SWITCH_LOGGING) { mutex_lock(&driver->diagchar_mutex); temp = driver->logging_mode; driver->logging_mode = (int)ioarg; if (driver->logging_mode == MEMORY_DEVICE_MODE) driver->mask_check = 1; if (driver->logging_mode == UART_MODE) { driver->mask_check = 0; 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 == NO_LOGGING_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 = 1; driver->in_busy_wcnss_2 = 1; #ifdef CONFIG_DIAG_SDIO_PIPE driver->in_busy_sdio = 1; #endif #ifdef CONFIG_DIAG_BRIDGE_CODE diagfwd_disconnect_bridge(0); #endif } 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_1 = 0; driver->in_busy_wcnss_2 = 0; /* Poll SMD channels to check for data*/ 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 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_BRIDGE_CODE diagfwd_connect_bridge(0); #endif } #ifdef CONFIG_DIAG_OVER_USB else if (temp == USB_MODE && driver->logging_mode == NO_LOGGING_MODE) { diagfwd_disconnect(); #ifdef CONFIG_DIAG_BRIDGE_CODE diagfwd_disconnect_bridge(0); #endif } else if (temp == NO_LOGGING_MODE && driver->logging_mode == USB_MODE) { diagfwd_connect(); #ifdef CONFIG_DIAG_BRIDGE_CODE diagfwd_connect_bridge(0); #endif } else if (temp == USB_MODE && driver->logging_mode == MEMORY_DEVICE_MODE) { diagfwd_disconnect(); 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_1 = 0; driver->in_busy_wcnss_2 = 0; /* Poll SMD channels to check for data*/ 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 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_BRIDGE_CODE diagfwd_cancel_hsic(); diagfwd_connect_bridge(0); #endif } else if (temp == MEMORY_DEVICE_MODE && driver->logging_mode == USB_MODE) { diagfwd_connect(); #ifdef CONFIG_DIAG_BRIDGE_CODE diagfwd_cancel_hsic(); diagfwd_connect_bridge(0); #endif } #endif /* DIAG over USB */ success = 1; } return success; }
long diagchar_ioctl(struct file *filp, unsigned int iocmd, unsigned long ioarg) { int i, j, count_entries = 0, temp; int success = -1; void *temp_buf; uint16_t support_list = 0; struct diag_dci_client_tbl *params = kzalloc(sizeof(struct diag_dci_client_tbl), GFP_KERNEL); struct diag_dci_health_stats stats; int status; if (iocmd == DIAG_IOCTL_COMMAND_REG) { struct bindpkt_params_per_process *pkt_params = (struct bindpkt_params_per_process *) ioarg; mutex_lock(&driver->diagchar_mutex); for (i = 0; i < diag_max_reg; i++) { if (driver->table[i].process_id == 0) { diag_add_reg(i, pkt_params->params, &success, &count_entries); if (pkt_params->count > count_entries) { pkt_params->params++; } else { mutex_unlock(&driver->diagchar_mutex); return success; } } } if (i < diag_threshold_reg) { /* Increase table size by amount required */ diag_max_reg += pkt_params->count - count_entries; /* Make sure size doesnt go beyond threshold */ if (diag_max_reg > diag_threshold_reg) { diag_max_reg = diag_threshold_reg; pr_info("diag: best case memory allocation\n"); } temp_buf = krealloc(driver->table, diag_max_reg*sizeof(struct diag_master_table), GFP_KERNEL); if (!temp_buf) { diag_max_reg -= pkt_params->count - count_entries; pr_alert("diag: Insufficient memory for reg."); mutex_unlock(&driver->diagchar_mutex); return 0; } else { driver->table = temp_buf; } for (j = i; j < diag_max_reg; j++) { diag_add_reg(j, pkt_params->params, &success, &count_entries); if (pkt_params->count > count_entries) { pkt_params->params++; } else { mutex_unlock(&driver->diagchar_mutex); return success; } } mutex_unlock(&driver->diagchar_mutex); } else { mutex_unlock(&driver->diagchar_mutex); pr_err("Max size reached, Pkt Registration failed for" " Process %d", current->tgid); } success = 0; } else if (iocmd == DIAG_IOCTL_GET_DELAYED_RSP_ID) { struct diagpkt_delay_params *delay_params = (struct diagpkt_delay_params *) ioarg; if ((delay_params->rsp_ptr) && (delay_params->size == sizeof(delayed_rsp_id)) && (delay_params->num_bytes_ptr)) { *((uint16_t *)delay_params->rsp_ptr) = DIAGPKT_NEXT_DELAYED_RSP_ID(delayed_rsp_id); *(delay_params->num_bytes_ptr) = sizeof(delayed_rsp_id); success = 0; } } else if (iocmd == DIAG_IOCTL_DCI_REG) { if (driver->dci_state == DIAG_DCI_NO_REG) return DIAG_DCI_NO_REG; if (driver->num_dci_client >= MAX_DCI_CLIENTS) return DIAG_DCI_NO_REG; if (copy_from_user(params, (void *)ioarg, sizeof(struct diag_dci_client_tbl))) return -EFAULT; mutex_lock(&driver->dci_mutex); if (!(driver->num_dci_client)) driver->in_busy_dci = 0; driver->num_dci_client++; pr_debug("diag: id = %d\n", driver->dci_client_id); driver->dci_client_id++; for (i = 0; i < MAX_DCI_CLIENTS; i++) { if (driver->dci_client_tbl[i].client == NULL) { driver->dci_client_tbl[i].client = current; driver->dci_client_tbl[i].list = params->list; driver->dci_client_tbl[i].signal_type = params->signal_type; create_dci_log_mask_tbl(driver-> dci_client_tbl[i].dci_log_mask); create_dci_event_mask_tbl(driver-> dci_client_tbl[i].dci_event_mask); driver->dci_client_tbl[i].data_len = 0; driver->dci_client_tbl[i].dci_data = kzalloc(IN_BUF_SIZE, GFP_KERNEL); driver->dci_client_tbl[i].total_capacity = IN_BUF_SIZE; driver->dci_client_tbl[i].dropped_logs = 0; driver->dci_client_tbl[i].dropped_events = 0; driver->dci_client_tbl[i].received_logs = 0; driver->dci_client_tbl[i].received_events = 0; break; } } mutex_unlock(&driver->dci_mutex); return driver->dci_client_id; } else if (iocmd == DIAG_IOCTL_DCI_DEINIT) { success = -1; /* Delete this process from DCI table */ mutex_lock(&driver->dci_mutex); for (i = 0; i < dci_max_reg; i++) if (driver->req_tracking_tbl[i].pid == current->tgid) driver->req_tracking_tbl[i].pid = 0; for (i = 0; i < MAX_DCI_CLIENTS; i++) { if (driver->dci_client_tbl[i].client && driver->dci_client_tbl[i].client->tgid == current->tgid) { driver->dci_client_tbl[i].client = NULL; success = i; break; } } if (success >= 0) driver->num_dci_client--; mutex_unlock(&driver->dci_mutex); return success; } else if (iocmd == DIAG_IOCTL_DCI_SUPPORT) { if (driver->ch_dci) support_list = support_list | DIAG_CON_MPSS; *(uint16_t *)ioarg = support_list; return DIAG_DCI_NO_ERROR; } else if (iocmd == DIAG_IOCTL_DCI_HEALTH_STATS) { if (copy_from_user(&stats, (void *)ioarg, sizeof(struct diag_dci_health_stats))) return -EFAULT; for (i = 0; i < MAX_DCI_CLIENTS; i++) { params = &(driver->dci_client_tbl[i]); if (params->client && params->client->tgid == current->tgid) { stats.dropped_logs = params->dropped_logs; stats.dropped_events = params->dropped_events; stats.received_logs = params->received_logs; stats.received_events = params->received_events; if (stats.reset_status) { params->dropped_logs = 0; params->dropped_events = 0; params->received_logs = 0; params->received_events = 0; } break; } } if (copy_to_user((void *)ioarg, &stats, sizeof(struct diag_dci_health_stats))) return -EFAULT; return DIAG_DCI_NO_ERROR; } else if (iocmd == DIAG_IOCTL_LSM_DEINIT) { for (i = 0; i < driver->num_clients; i++) if (driver->client_map[i].pid == current->tgid) break; if (i == -1) return -EINVAL; driver->data_ready[i] |= DEINIT_TYPE; wake_up_interruptible(&driver->wait_q); success = 1; } else if (iocmd == DIAG_IOCTL_SWITCH_LOGGING) { mutex_lock(&driver->diagchar_mutex); temp = driver->logging_mode; driver->logging_mode = (int)ioarg; if (temp == driver->logging_mode) { mutex_unlock(&driver->diagchar_mutex); pr_alert("diag: forbidden logging change requested\n"); return 0; } if (driver->logging_mode == MEMORY_DEVICE_MODE) { diag_clear_hsic_tbl(); driver->mask_check = 1; if (driver->socket_process) { /* * Notify the socket logging process that we * are switching to MEMORY_DEVICE_MODE */ status = send_sig(SIGCONT, driver->socket_process, 0); if (status) { pr_err("diag: %s, Error notifying ", __func__); pr_err("socket process, status: %d\n", status); } } } if (driver->logging_mode == SOCKET_MODE) driver->socket_process = current; if (driver->logging_mode == CALLBACK_MODE) driver->callback_process = current; if (driver->logging_mode == UART_MODE || driver->logging_mode == SOCKET_MODE || driver->logging_mode == CALLBACK_MODE) { diag_clear_hsic_tbl(); driver->mask_check = 0; 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 == NO_LOGGING_MODE) { driver->in_busy_1 = 1; driver->in_busy_2 = 1; driver->in_busy_lpass_1 = 1; driver->in_busy_lpass_2 = 1; driver->in_busy_wcnss_1 = 1; driver->in_busy_wcnss_2 = 1; #ifdef CONFIG_DIAG_SDIO_PIPE driver->in_busy_sdio = 1; #endif #ifdef CONFIG_DIAG_BRIDGE_CODE diagfwd_disconnect_bridge(0); diag_clear_hsic_tbl(); #endif } 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_lpass_1 = 0; driver->in_busy_lpass_2 = 0; driver->in_busy_wcnss_1 = 0; driver->in_busy_wcnss_2 = 0; /* Poll SMD channels to check for data*/ 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 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_BRIDGE_CODE diagfwd_connect_bridge(0); #endif } #ifdef CONFIG_DIAG_OVER_USB else if (temp == USB_MODE && driver->logging_mode == NO_LOGGING_MODE) { diagfwd_disconnect(); #ifdef CONFIG_DIAG_BRIDGE_CODE diagfwd_disconnect_bridge(0); #endif } else if (temp == NO_LOGGING_MODE && driver->logging_mode == USB_MODE) { diagfwd_connect(); #ifdef CONFIG_DIAG_BRIDGE_CODE diagfwd_connect_bridge(0); #endif } else if (temp == USB_MODE && driver->logging_mode == MEMORY_DEVICE_MODE) { diagfwd_disconnect(); driver->in_busy_1 = 0; driver->in_busy_2 = 0; driver->in_busy_lpass_1 = 0; driver->in_busy_lpass_2 = 0; driver->in_busy_wcnss_1 = 0; driver->in_busy_wcnss_2 = 0; /* Poll SMD channels to check for data*/ 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 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_BRIDGE_CODE diagfwd_cancel_hsic(); diagfwd_connect_bridge(0); #endif } else if (temp == MEMORY_DEVICE_MODE && driver->logging_mode == USB_MODE) { diagfwd_connect(); #ifdef CONFIG_DIAG_BRIDGE_CODE diag_clear_hsic_tbl(); diagfwd_cancel_hsic(); diagfwd_connect_bridge(0); #endif } #endif /* DIAG over USB */ success = 1; } else if (iocmd == DIAG_IOCTL_REMOTE_DEV) { uint16_t remote_dev = diag_get_remote_device_mask(); if (copy_to_user((void *)ioarg, &remote_dev, sizeof(uint16_t))) success = -EFAULT; else success = 1; } return success; }