diff options
Diffstat (limited to 'drivers/char/diag/diagchar_core.c')
-rw-r--r-- | drivers/char/diag/diagchar_core.c | 1235 |
1 files changed, 0 insertions, 1235 deletions
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c deleted file mode 100644 index 300b1d7..0000000 --- a/drivers/char/diag/diagchar_core.c +++ /dev/null @@ -1,1235 +0,0 @@ -/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/cdev.h> -#include <linux/fs.h> -#include <linux/device.h> -#include <linux/uaccess.h> -#include <linux/diagchar.h> -#include <linux/sched.h> -#ifdef CONFIG_DIAG_OVER_USB -#include <mach/usbdiag.h> -#endif -#include <asm/current.h> -#include "diagchar_hdlc.h" -#include "diagmem.h" -#include "diagchar.h" -#include "diagfwd.h" -#include "diagfwd_cntl.h" -#ifdef CONFIG_DIAG_SDIO_PIPE -#include "diagfwd_sdio.h" -#endif -#ifdef CONFIG_DIAG_HSIC_PIPE -#include "diagfwd_hsic.h" -#endif -#include <linux/timer.h> - -MODULE_DESCRIPTION("Diag Char Driver"); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION("1.0"); - -#define INIT 1 -#define EXIT -1 -struct diagchar_dev *driver; -struct diagchar_priv { - int pid; -}; -/* The following variables can be specified by module options */ - /* for copy buffer */ -static unsigned int itemsize = 4096; /*Size of item in the mempool */ -static unsigned int poolsize = 10; /*Number of items in the mempool */ -/* for hdlc buffer */ -static unsigned int itemsize_hdlc = 8192; /*Size of item in the mempool */ -static unsigned int poolsize_hdlc = 8; /*Number of items in the mempool */ -/* for write structure buffer */ -static unsigned int itemsize_write_struct = 20; /*Size of item in the mempool */ -static unsigned int poolsize_write_struct = 8; /* Num of items in the mempool */ -/* This is the max number of user-space clients supported at initialization*/ -static unsigned int max_clients = 15; -static unsigned int threshold_client_limit = 30; -/* This is the maximum number of pkt registrations supported at initialization*/ -unsigned int diag_max_reg = 600; -unsigned int diag_threshold_reg = 750; - -/* Timer variables */ -static struct timer_list drain_timer; -static int timer_in_progress; -void *buf_hdlc; -module_param(itemsize, uint, 0); -module_param(poolsize, uint, 0); -module_param(max_clients, uint, 0); - -/* delayed_rsp_id 0 represents no delay in the response. Any other number - means that the diag packet has a delayed response. */ -static uint16_t delayed_rsp_id = 1; -#define DIAGPKT_MAX_DELAYED_RSP 0xFFFF -/* This macro gets the next delayed respose id. Once it reaches - DIAGPKT_MAX_DELAYED_RSP, it stays at DIAGPKT_MAX_DELAYED_RSP */ - -#define DIAGPKT_NEXT_DELAYED_RSP_ID(x) \ -((x < DIAGPKT_MAX_DELAYED_RSP) ? x++ : DIAGPKT_MAX_DELAYED_RSP) - -#define COPY_USER_SPACE_OR_EXIT(buf, data, length) \ -do { \ - if ((count < ret+length) || (copy_to_user(buf, \ - (void *)&data, length))) { \ - ret = -EFAULT; \ - goto exit; \ - } \ - ret += length; \ -} while (0) - -static void drain_timer_func(unsigned long data) -{ - queue_work(driver->diag_wq , &(driver->diag_drain_work)); -} - -void diag_drain_work_fn(struct work_struct *work) -{ - int err = 0; - timer_in_progress = 0; - - mutex_lock(&driver->diagchar_mutex); - if (buf_hdlc) { - err = diag_device_write(buf_hdlc, APPS_DATA, NULL); - if (err) { - /*Free the buffer right away if write failed */ - diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC); - diagmem_free(driver, (unsigned char *)driver-> - write_ptr_svc, POOL_TYPE_WRITE_STRUCT); - } - buf_hdlc = NULL; -#ifdef DIAG_DEBUG - pr_debug("diag: Number of bytes written " - "from timer is %d ", driver->used); -#endif - driver->used = 0; - } - mutex_unlock(&driver->diagchar_mutex); -} - -void diag_read_smd_work_fn(struct work_struct *work) -{ - __diag_smd_send_req(); -} - -void diag_read_smd_qdsp_work_fn(struct work_struct *work) -{ - __diag_smd_qdsp_send_req(); -} - -void diag_read_smd_wcnss_work_fn(struct work_struct *work) -{ - __diag_smd_wcnss_send_req(); -} - -void diag_add_client(int i, struct file *file) -{ - struct diagchar_priv *diagpriv_data; - - driver->client_map[i].pid = current->tgid; - diagpriv_data = kmalloc(sizeof(struct diagchar_priv), - GFP_KERNEL); - if (diagpriv_data) - diagpriv_data->pid = current->tgid; - file->private_data = diagpriv_data; - strlcpy(driver->client_map[i].name, current->comm, 20); - driver->client_map[i].name[19] = '\0'; -} - -static int diagchar_open(struct inode *inode, struct file *file) -{ - int i = 0; - void *temp; - - if (driver) { - mutex_lock(&driver->diagchar_mutex); - - for (i = 0; i < driver->num_clients; i++) - if (driver->client_map[i].pid == 0) - break; - - if (i < driver->num_clients) { - diag_add_client(i, file); - } else { - if (i < threshold_client_limit) { - driver->num_clients++; - temp = krealloc(driver->client_map - , (driver->num_clients) * sizeof(struct - diag_client_map), GFP_KERNEL); - if (!temp) - goto fail; - else - driver->client_map = temp; - temp = krealloc(driver->data_ready - , (driver->num_clients) * sizeof(int), - GFP_KERNEL); - if (!temp) - goto fail; - else - driver->data_ready = temp; - diag_add_client(i, file); - } else { - mutex_unlock(&driver->diagchar_mutex); - pr_alert("Max client limit for DIAG reached\n"); - pr_info("Cannot open handle %s" - " %d", current->comm, current->tgid); - for (i = 0; i < driver->num_clients; i++) - pr_debug("%d) %s PID=%d", i, driver-> - client_map[i].name, - driver->client_map[i].pid); - return -ENOMEM; - } - } - driver->data_ready[i] |= MSG_MASKS_TYPE; - driver->data_ready[i] |= EVENT_MASKS_TYPE; - driver->data_ready[i] |= LOG_MASKS_TYPE; - - if (driver->ref_count == 0) - diagmem_init(driver); - driver->ref_count++; - mutex_unlock(&driver->diagchar_mutex); - return 0; - } - return -ENOMEM; - -fail: - mutex_unlock(&driver->diagchar_mutex); - driver->num_clients--; - pr_alert("diag: Insufficient memory for new client"); - return -ENOMEM; -} - -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; - } -#ifdef CONFIG_DIAG_HSIC_PIPE - if (driver->logging_mode == MEMORY_DEVICE_MODE) - queue_work(driver->diag_hsic_wq, &driver->diag_disconnect_work); -#endif - -#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; -#ifndef CONFIG_DIAG_HSIC_PIPE - /* HSIC PIPE use case, connect over usb is not required */ - diagfwd_connect(); -#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; -} - -int diag_find_polling_reg(int i) -{ - uint16_t subsys_id, cmd_code_lo, cmd_code_hi; - - subsys_id = driver->table[i].subsys_id; - cmd_code_lo = driver->table[i].cmd_code_lo; - cmd_code_hi = driver->table[i].cmd_code_hi; - if (driver->table[i].cmd_code == 0x0C) - return 1; - else if (driver->table[i].cmd_code == 0xFF) { - if (subsys_id == 0x04 && cmd_code_hi == 0x0E && - cmd_code_lo == 0x0E) - return 1; - else if (subsys_id == 0x08 && cmd_code_hi == 0x02 && - cmd_code_lo == 0x02) - return 1; - else if (subsys_id == 0x32 && cmd_code_hi == 0x03 && - cmd_code_lo == 0x03) - return 1; - } - return 0; -} - -void diag_clear_reg(int proc_num) -{ - int i; - - mutex_lock(&driver->diagchar_mutex); - /* reset polling flag */ - driver->polling_reg_flag = 0; - for (i = 0; i < diag_max_reg; i++) { - if (driver->table[i].client_id == proc_num) - driver->table[i].process_id = 0; - } - /* re-scan the registration table */ - for (i = 0; i < diag_max_reg; i++) { - if (diag_find_polling_reg(i) == 1) { - driver->polling_reg_flag = 1; - break; - } - } - mutex_unlock(&driver->diagchar_mutex); -} - -void diag_add_reg(int j, struct bindpkt_params *params, - int *success, int *count_entries) -{ - *success = 1; - driver->table[j].cmd_code = params->cmd_code; - driver->table[j].subsys_id = params->subsys_id; - driver->table[j].cmd_code_lo = params->cmd_code_lo; - driver->table[j].cmd_code_hi = params->cmd_code_hi; - - /* check if incoming reg is polling & polling is yet not registered */ - if (driver->polling_reg_flag == 0) - if (diag_find_polling_reg(j) == 1) - driver->polling_reg_flag = 1; - if (params->proc_id == APPS_PROC) { - driver->table[j].process_id = current->tgid; - driver->table[j].client_id = APPS_PROC; - } else { - driver->table[j].process_id = NON_APPS_PROC; - driver->table[j].client_id = params->client_id; - } - (*count_entries)++; -} - -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_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_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->sub_logging_mode = UART_MODE; - } else - driver->sub_logging_mode = NO_LOGGING_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_HSIC_PIPE - driver->in_busy_hsic_read = 1; - driver->in_busy_hsic_write = 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_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_HSIC_PIPE - driver->in_busy_hsic_read = 0; - if (driver->hsic_ch) - queue_work(driver->diag_hsic_wq, - &driver->diag_read_hsic_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(); -#ifdef CONFIG_DIAG_HSIC_PIPE - diagfwd_connect_hsic(WRITE_TO_SD); -#endif - 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_HSIC_PIPE - if (driver->hsic_ch) - queue_work(driver->diag_hsic_wq, - &driver->diag_read_hsic_work); -#endif - } else if (temp == MEMORY_DEVICE_MODE && - driver->logging_mode == USB_MODE) - diagfwd_connect(); -#endif /* DIAG over USB */ - success = 1; - } - - return success; -} - -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)) { - /*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_HSIC_PIPE - 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); -#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 -#ifdef CONFIG_DIAG_HSIC_PIPE - /* driver->in_busy_hsic_read = 0; */ - if (driver->hsic_ch) - queue_work(driver->diag_hsic_wq, - &driver->diag_read_hsic_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; - } - -exit: - mutex_unlock(&driver->diagchar_mutex); - return ret; -} - -static int diagchar_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - int err, ret = 0, pkt_type; -#ifdef DIAG_DEBUG - int length = 0, i; -#endif - struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 }; - struct diag_hdlc_dest_type enc = { NULL, NULL, 0 }; - void *buf_copy = NULL; - int payload_size; -#ifdef CONFIG_DIAG_OVER_USB - if (((driver->logging_mode == USB_MODE) && (!driver->usb_connected)) || - (driver->logging_mode == NO_LOGGING_MODE)) { - /*Drop the diag payload */ - return -EIO; - } -#endif /* DIAG over USB */ - /* Get the packet type F3/log/event/Pkt response */ - err = copy_from_user((&pkt_type), buf, 4); - /* First 4 bytes indicate the type of payload - ignore these */ - payload_size = count - 4; - - if (pkt_type == USER_SPACE_LOG_TYPE) { - err = copy_from_user(driver->user_space_data, buf + 4, - payload_size); - /* Check masks for On-Device logging */ - if (driver->mask_check) { - if (!mask_request_validate(driver->user_space_data)) { - pr_alert("diag: mask request Invalid\n"); - return -EFAULT; - } - } - buf = buf + 4; - - /* To removed "0x7E", when received only "0x7E" */ - if (0x7e == *(((unsigned char *)buf))) - return 0; - -#ifdef DIAG_DEBUG - pr_debug("diag: user space data %d\n", payload_size); - for (i = 0; i < payload_size; i++) - pr_debug("\t %x", *((driver->user_space_data)+i)); -#endif -#ifdef CONFIG_DIAG_SDIO_PIPE - /* send masks to 9k too */ - if (driver->sdio_ch) { - wait_event_interruptible(driver->wait_q, - (sdio_write_avail(driver->sdio_ch) >= - payload_size)); - if (driver->sdio_ch && (payload_size > 0)) { - sdio_write(driver->sdio_ch, (void *) - (driver->user_space_data), payload_size); - } - } -#endif -#ifdef CONFIG_DIAG_HSIC_PIPE - if (driver->hsic_ch) { - // QXDM Logging zero_pkt (with silent log on) second fix by JAGADISH KRISHNAMOORTHY - pr_info("%s: hsic line busy %d \n",__func__,driver->in_busy_hsic_write); - /* wait till write is succesfully written to CP */ - if (driver->in_busy_hsic_write) - wait_event_interruptible(driver->wait_q, - (driver->in_busy_hsic_write != 1)); - - if (!driver->in_busy_hsic_write) { - driver->in_busy_hsic_write = 1; - err = diag_bridge_write((driver->user_space_data), - payload_size); - if (err) { - pr_err("%s: data on hsic write err: %d\n", - __func__, 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 ((-ESHUTDOWN) != err) - driver->in_busy_hsic_write = 0; - } - } - } -#endif -#if 0 - /* send masks to modem now */ - diag_process_hdlc((void *)(driver->user_space_data), - payload_size); -#endif - return count; - } - - if (payload_size > itemsize) { - pr_err("diag: Dropping packet, packet payload size crosses" - "4KB limit. Current payload size %d\n", - payload_size); - driver->dropped_count++; - return -EBADMSG; - } - - buf_copy = diagmem_alloc(driver, payload_size, POOL_TYPE_COPY); - if (!buf_copy) { - driver->dropped_count++; - return -ENOMEM; - } - - err = copy_from_user(buf_copy, buf + 4, payload_size); - if (err) { - printk(KERN_INFO "diagchar : copy_from_user failed\n"); - ret = -EFAULT; - goto fail_free_copy; - } -#ifdef DIAG_DEBUG - printk(KERN_DEBUG "data is -->\n"); - for (i = 0; i < payload_size; i++) - printk(KERN_DEBUG "\t %x \t", *(((unsigned char *)buf_copy)+i)); -#endif - send.state = DIAG_STATE_START; - send.pkt = buf_copy; - send.last = (void *)(buf_copy + payload_size - 1); - send.terminate = 1; -#ifdef DIAG_DEBUG - pr_debug("diag: Already used bytes in buffer %d, and" - " incoming payload size is %d\n", driver->used, payload_size); - printk(KERN_DEBUG "hdlc encoded data is -->\n"); - for (i = 0; i < payload_size + 8; i++) { - printk(KERN_DEBUG "\t %x \t", *(((unsigned char *)buf_hdlc)+i)); - if (*(((unsigned char *)buf_hdlc)+i) != 0x7e) - length++; - } -#endif - mutex_lock(&driver->diagchar_mutex); - if (!buf_hdlc) - buf_hdlc = diagmem_alloc(driver, HDLC_OUT_BUF_SIZE, - POOL_TYPE_HDLC); - if (!buf_hdlc) { - ret = -ENOMEM; - goto fail_free_hdlc; - } - if (HDLC_OUT_BUF_SIZE - driver->used <= (2*payload_size) + 3) { - err = diag_device_write(buf_hdlc, APPS_DATA, NULL); - if (err) { - /*Free the buffer right away if write failed */ - diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC); - diagmem_free(driver, (unsigned char *)driver-> - write_ptr_svc, POOL_TYPE_WRITE_STRUCT); - ret = -EIO; - goto fail_free_hdlc; - } - buf_hdlc = NULL; - driver->used = 0; - buf_hdlc = diagmem_alloc(driver, HDLC_OUT_BUF_SIZE, - POOL_TYPE_HDLC); - if (!buf_hdlc) { - ret = -ENOMEM; - goto fail_free_hdlc; - } - } - - enc.dest = buf_hdlc + driver->used; - enc.dest_last = (void *)(buf_hdlc + driver->used + 2*payload_size + 3); - diag_hdlc_encode(&send, &enc); - - /* This is to check if after HDLC encoding, we are still within the - limits of aggregation buffer. If not, we write out the current buffer - and start aggregation in a newly allocated buffer */ - if ((unsigned int) enc.dest >= - (unsigned int)(buf_hdlc + HDLC_OUT_BUF_SIZE)) { - err = diag_device_write(buf_hdlc, APPS_DATA, NULL); - if (err) { - /*Free the buffer right away if write failed */ - diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC); - diagmem_free(driver, (unsigned char *)driver-> - write_ptr_svc, POOL_TYPE_WRITE_STRUCT); - ret = -EIO; - goto fail_free_hdlc; - } - buf_hdlc = NULL; - driver->used = 0; - buf_hdlc = diagmem_alloc(driver, HDLC_OUT_BUF_SIZE, - POOL_TYPE_HDLC); - if (!buf_hdlc) { - ret = -ENOMEM; - goto fail_free_hdlc; - } - enc.dest = buf_hdlc + driver->used; - enc.dest_last = (void *)(buf_hdlc + driver->used + - (2*payload_size) + 3); - diag_hdlc_encode(&send, &enc); - } - - driver->used = (uint32_t) enc.dest - (uint32_t) buf_hdlc; - if (pkt_type == DATA_TYPE_RESPONSE) { - err = diag_device_write(buf_hdlc, APPS_DATA, NULL); - if (err) { - /*Free the buffer right away if write failed */ - diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC); - diagmem_free(driver, (unsigned char *)driver-> - write_ptr_svc, POOL_TYPE_WRITE_STRUCT); - ret = -EIO; - goto fail_free_hdlc; - } - buf_hdlc = NULL; - driver->used = 0; - } - - mutex_unlock(&driver->diagchar_mutex); - diagmem_free(driver, buf_copy, POOL_TYPE_COPY); - if (!timer_in_progress) { - timer_in_progress = 1; - ret = mod_timer(&drain_timer, jiffies + msecs_to_jiffies(500)); - } - return count; - -fail_free_hdlc: - buf_hdlc = NULL; - driver->used = 0; - diagmem_free(driver, buf_copy, POOL_TYPE_COPY); - mutex_unlock(&driver->diagchar_mutex); - return ret; - -fail_free_copy: - diagmem_free(driver, buf_copy, POOL_TYPE_COPY); - return ret; -} - -int mask_request_validate(unsigned char mask_buf[]) -{ - uint8_t packet_id; - uint8_t subsys_id; - uint16_t ss_cmd; - - packet_id = mask_buf[0]; - - if (packet_id == 0x4B) { - subsys_id = mask_buf[1]; - ss_cmd = *(uint16_t *)(mask_buf + 2); - /* Packets with SSID which are allowed */ - switch (subsys_id) { - case 0x04: /* DIAG_SUBSYS_WCDMA */ - if ((ss_cmd == 0) || (ss_cmd == 0xF)) - return 1; - break; - case 0x08: /* DIAG_SUBSYS_GSM */ - if ((ss_cmd == 0) || (ss_cmd == 0x1)) - return 1; - break; - case 0x09: /* DIAG_SUBSYS_UMTS */ - case 0x0F: /* DIAG_SUBSYS_CM */ - if (ss_cmd == 0) - return 1; - break; - case 0x0C: /* DIAG_SUBSYS_OS */ - if ((ss_cmd == 2) || (ss_cmd == 0x100)) - return 1; /* MPU and APU */ - break; - case 0x12: /* DIAG_SUBSYS_DIAG_SERV */ - if ((ss_cmd == 0) || (ss_cmd == 0x6) || (ss_cmd == 0x7)) - return 1; - break; - case 0x13: /* DIAG_SUBSYS_FS */ - if ((ss_cmd == 0) || (ss_cmd == 0x1)) - return 1; - break; - default: - return 0; - break; - } - } else { - switch (packet_id) { - case 0x00: /* Version Number */ - case 0x0C: /* CDMA status packet */ - case 0x1C: /* Diag Version */ - case 0x1D: /* Time Stamp */ - case 0x60: /* Event Report Control */ - case 0x63: /* Status snapshot */ - case 0x73: /* Logging Configuration */ - case 0x7C: /* Extended build ID */ - case 0x7D: /* Extended Message configuration */ - case 0x81: /* Event get mask */ - case 0x82: /* Set the event mask */ - return 1; - break; - default: - return 0; - break; - } - } - return 0; -} - -static const struct file_operations diagcharfops = { - .owner = THIS_MODULE, - .read = diagchar_read, - .write = diagchar_write, - .unlocked_ioctl = diagchar_ioctl, - .open = diagchar_open, - .release = diagchar_close -}; - -static int diagchar_setup_cdev(dev_t devno) -{ - - int err; - - cdev_init(driver->cdev, &diagcharfops); - - driver->cdev->owner = THIS_MODULE; - driver->cdev->ops = &diagcharfops; - - err = cdev_add(driver->cdev, devno, 1); - - if (err) { - printk(KERN_INFO "diagchar cdev registration failed !\n\n"); - return -1; - } - - driver->diagchar_class = class_create(THIS_MODULE, "diag"); - - if (IS_ERR(driver->diagchar_class)) { - printk(KERN_ERR "Error creating diagchar class.\n"); - return -1; - } - - device_create(driver->diagchar_class, NULL, devno, - (void *)driver, "diag"); - - return 0; - -} - -static int diagchar_cleanup(void) -{ - if (driver) { - if (driver->cdev) { - /* TODO - Check if device exists before deleting */ - device_destroy(driver->diagchar_class, - MKDEV(driver->major, - driver->minor_start)); - cdev_del(driver->cdev); - } - if (!IS_ERR(driver->diagchar_class)) - class_destroy(driver->diagchar_class); - kfree(driver); - } - return 0; -} - -#ifdef CONFIG_DIAG_SDIO_PIPE -void diag_sdio_fn(int type) -{ - if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) { - if (type == INIT) - diagfwd_sdio_init(); - else if (type == EXIT) - diagfwd_sdio_exit(); - } -} -#else -inline void diag_sdio_fn(int type) {} -#endif - -#ifdef CONFIG_DIAG_HSIC_PIPE -void diag_hsic_fn(int type) -{ - if (type == INIT) - diagfwd_hsic_init(); - else if (type == EXIT) - diagfwd_hsic_exit(); -} -#else -inline void diag_hsic_fn(int type) {} -#endif - -static int __init diagchar_init(void) -{ - dev_t dev; - int error; - - pr_debug("diagfwd initializing ..\n"); - driver = kzalloc(sizeof(struct diagchar_dev) + 5, GFP_KERNEL); - - if (driver) { - driver->used = 0; - timer_in_progress = 0; - driver->debug_flag = 1; - setup_timer(&drain_timer, drain_timer_func, 1234); - driver->itemsize = itemsize; - driver->poolsize = poolsize; - driver->itemsize_hdlc = itemsize_hdlc; - driver->poolsize_hdlc = poolsize_hdlc; - driver->itemsize_write_struct = itemsize_write_struct; - driver->poolsize_write_struct = poolsize_write_struct; - driver->num_clients = max_clients; - driver->logging_mode = USB_MODE; - driver->mask_check = 0; - mutex_init(&driver->diagchar_mutex); - init_waitqueue_head(&driver->wait_q); - INIT_WORK(&(driver->diag_drain_work), diag_drain_work_fn); - INIT_WORK(&(driver->diag_read_smd_work), diag_read_smd_work_fn); - INIT_WORK(&(driver->diag_read_smd_cntl_work), - diag_read_smd_cntl_work_fn); - INIT_WORK(&(driver->diag_read_smd_qdsp_work), - diag_read_smd_qdsp_work_fn); - INIT_WORK(&(driver->diag_read_smd_qdsp_cntl_work), - diag_read_smd_qdsp_cntl_work_fn); - INIT_WORK(&(driver->diag_read_smd_wcnss_work), - diag_read_smd_wcnss_work_fn); - INIT_WORK(&(driver->diag_read_smd_wcnss_cntl_work), - diag_read_smd_wcnss_cntl_work_fn); - diagfwd_init(); - diagfwd_cntl_init(); - diag_sdio_fn(INIT); - diag_hsic_fn(INIT); - pr_debug("diagchar initializing ..\n"); - driver->num = 1; - driver->name = ((void *)driver) + sizeof(struct diagchar_dev); - strlcpy(driver->name, "diag", 4); - - /* Get major number from kernel and initialize */ - error = alloc_chrdev_region(&dev, driver->minor_start, - driver->num, driver->name); - if (!error) { - driver->major = MAJOR(dev); - driver->minor_start = MINOR(dev); - } else { - printk(KERN_INFO "Major number not allocated\n"); - goto fail; - } - driver->cdev = cdev_alloc(); - error = diagchar_setup_cdev(dev); - if (error) - goto fail; - } else { - printk(KERN_INFO "kzalloc failed\n"); - goto fail; - } - - pr_info("diagchar initialized now"); - return 0; - -fail: - diagchar_cleanup(); - diagfwd_exit(); - diagfwd_cntl_exit(); - diag_sdio_fn(EXIT); - diag_hsic_fn(EXIT); - return -1; -} - -static void __exit diagchar_exit(void) -{ - printk(KERN_INFO "diagchar exiting ..\n"); - /* On Driver exit, send special pool type to - ensure no memory leaks */ - diagmem_exit(driver, POOL_TYPE_ALL); - diagfwd_exit(); - diagfwd_cntl_exit(); - diag_sdio_fn(EXIT); - diag_hsic_fn(EXIT); - diagchar_cleanup(); - printk(KERN_INFO "done diagchar exit\n"); -} - -module_init(diagchar_init); -module_exit(diagchar_exit); |