static int diagchar_close(struct inode *inode, struct file *file) { int i = 0; struct diagchar_priv *diagpriv_data = file->private_data; if (!(file->private_data)) { pr_alert("diag: Invalid file pointer"); return -ENOMEM; } /* clean up any DCI registrations for this client * This will specially help in case of ungraceful exit of any DCI client * This call will remove any pending registrations of such client */ diagchar_ioctl(NULL, DIAG_IOCTL_DCI_DEINIT, 0); /* If the exiting process is the socket process */ if (driver->socket_process && (driver->socket_process->tgid == current->tgid)) { driver->socket_process = NULL; } #ifdef CONFIG_DIAG_OVER_USB /* If the SD logging process exits, change logging to USB mode */ if (driver->logging_process_id == current->tgid) { 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 */ /* Delete the pkt response table entry for the exiting process */ for (i = 0; i < diag_max_reg; i++) if (driver->table[i].process_id == current->tgid) driver->table[i].process_id = 0; if (driver) { mutex_lock(&driver->diagchar_mutex); driver->ref_count--; /* On Client exit, try to destroy all 3 pools */ diagmem_exit(driver, POOL_TYPE_COPY); diagmem_exit(driver, POOL_TYPE_HDLC); diagmem_exit(driver, POOL_TYPE_WRITE_STRUCT); for (i = 0; i < driver->num_clients; i++) { if (NULL != diagpriv_data && diagpriv_data->pid == driver->client_map[i].pid) { driver->client_map[i].pid = 0; kfree(diagpriv_data); diagpriv_data = NULL; break; } } mutex_unlock(&driver->diagchar_mutex); return 0; } return -ENOMEM; }
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; 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_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) { 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 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; }
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; 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 *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_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; if (copy_from_user(¬ify_params, (void *)ioarg, sizeof(struct dci_notification_tbl))) return -EFAULT; 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; if (copy_to_user((void *)ioarg, &support_list, sizeof(uint16_t))) 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 (driver->logging_mode == MEMORY_DEVICE_MODE) { diag_clear_hsic_tbl(); driver->mask_check = 1; } if (driver->logging_mode == UART_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_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; }