aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/diag/diagchar_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/diag/diagchar_core.c')
-rw-r--r--drivers/char/diag/diagchar_core.c1235
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);