Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac10fd2a authored by Ravi Aravamudhan's avatar Ravi Aravamudhan
Browse files

diag: dci: Add DCI command response support on APSS



Add support to enable clients to send command requests registered
on the Apps processor through DCI. It also handles dedicated
commands that are handled exclusively by the Apps processor.

Change-Id: I8bea5cbe9f787ef7213bb4d995bb0ab68a06dab2
Signed-off-by: default avatarRavi Aravamudhan <aravamud@codeaurora.org>
parent 03ccedbc
Loading
Loading
Loading
Loading
+324 −99
Original line number Diff line number Diff line
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2014, The Linux Foundation. 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
@@ -23,7 +23,9 @@
#include <linux/pm_wakeup.h>
#include <linux/spinlock.h>
#include <linux/ratelimit.h>
#include <linux/reboot.h>
#include <asm/current.h>
#include <mach/restart.h>
#ifdef CONFIG_DIAG_OVER_USB
#include <mach/usbdiag.h>
#endif
@@ -282,19 +284,31 @@ void diag_process_apps_dci_read_data(int data_type, void *buf, int recd_bytes)
		return;
	}

	if (data_type != DATA_TYPE_DCI_LOG && data_type != DATA_TYPE_DCI_EVENT)
	if (data_type != DATA_TYPE_DCI_LOG && data_type != DATA_TYPE_DCI_EVENT
						&& data_type != DCI_PKT_TYPE) {
		pr_err("diag: In %s, unsupported data_type: 0x%x\n",
				__func__, (unsigned int)data_type);
		return;
	}

	cmd_code = *(uint8_t *)buf;

	if (cmd_code == LOG_CMD_CODE) {
	switch (cmd_code) {
	case LOG_CMD_CODE:
		extract_dci_log(buf, recd_bytes, APPS_DATA);
	} else if (cmd_code == EVENT_CMD_CODE) {
		break;
	case EVENT_CMD_CODE:
		extract_dci_events(buf, recd_bytes, APPS_DATA);
	} else {
		break;
	case DCI_PKT_RSP_CODE:
	case DCI_DELAYED_RSP_CODE:
		extract_dci_pkt_rsp(buf, recd_bytes, APPS_DATA, NULL);
		break;
	default:
		pr_err("diag: In %s, unsupported command code: 0x%x, not log or event\n",
		       __func__, cmd_code);
		return;

	}

	/* wake up all sleeping DCI clients which have some data */
@@ -352,7 +366,8 @@ int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf,
			extract_dci_events(buf + 4, recd_bytes - 4,
					   smd_info->peripheral);
		} else
			extract_dci_pkt_rsp(smd_info, buf, recd_bytes);
			extract_dci_pkt_rsp(buf + 4, dci_pkt_len,
					    smd_info->peripheral, smd_info);
		read_bytes += 5 + dci_pkt_len;
		buf += 5 + dci_pkt_len; /* advance to next DCI pkt */
	}
@@ -541,48 +556,61 @@ static int diag_dci_remove_req_entry(unsigned char *buf, int len,
	return 0;
}

void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf,
									int len)
void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source,
			 struct diag_smd_info *smd_info)
{
	int cmd_code_len = 1;
	int curr_client_pid = 0, write_len, *tag = NULL;
	int tag, curr_client_pid = 0;
	struct diag_dci_client_tbl *entry = NULL;
	void *temp_buf = NULL;
	uint8_t recv_pkt_cmd_code, delete_flag = 0;
	uint8_t dci_cmd_code, cmd_code_len, delete_flag = 0;
	uint32_t rsp_len = 0;
	struct diag_dci_buffer_t *rsp_buf = NULL;
	struct dci_pkt_req_entry_t *req_entry = NULL;
	unsigned char *temp = buf;

	recv_pkt_cmd_code = *(uint8_t *)(buf+4);
	if (recv_pkt_cmd_code != DCI_PKT_RSP_CODE)
		cmd_code_len = 4; /* delayed response */
	if (!buf) {
		pr_err("diag: Invalid pointer in %s\n", __func__);
		return;
	}
	dci_cmd_code = *(uint8_t *)(temp);
	if (dci_cmd_code == DCI_PKT_RSP_CODE) {
		cmd_code_len = sizeof(uint8_t);
	} else if (dci_cmd_code == DCI_DELAYED_RSP_CODE) {
		cmd_code_len = sizeof(uint32_t);
	} else {
		pr_err("diag: In %s, invalid command code %d\n", __func__,
								dci_cmd_code);
		return;
	}
	temp += cmd_code_len;
	tag = *(int *)temp;
	temp += sizeof(int);

	/* Skip the Start(1) and the version(1) bytes */
	write_len = (int)(*(uint16_t *)(buf+2));
	/* Check if the length embedded in the packet is correct.
	/*
	 * The size of the response is (total length) - (length of the command
	 * code, the tag (int)
	 */
	rsp_len = len - (cmd_code_len + sizeof(int));
	/*
	 * Check if the length embedded in the packet is correct.
	 * Include the start (1), version (1), length (2) and the end
	 * (1) bytes while checking. Total = 5 bytes
	 */
	write_len -= cmd_code_len;
	if ((write_len <= 0) || (write_len > (len - 5))) {
		pr_err("diag: Invalid length in %s, len: %d, write_len: %d",
						__func__, len, write_len);
	if ((rsp_len == 0) || (rsp_len > (len - 5))) {
		pr_err("diag: Invalid length in %s, len: %d, rsp_len: %d",
						__func__, len, rsp_len);
		return;
	}
	pr_debug("diag: len = %d\n", write_len);

	tag = (int *)(buf + (4 + cmd_code_len)); /* Retrieve the Tag field */
	req_entry = diag_dci_get_request_entry(*tag);
	req_entry = diag_dci_get_request_entry(tag);
	if (!req_entry) {
		pr_err("diag: No matching PID for DCI data\n");
		return;
	}
	*tag = req_entry->uid; /* Replace the tag field with UID */
	curr_client_pid = req_entry->pid;

	/* Remove the headers and send only the response to this function */
	delete_flag = diag_dci_remove_req_entry(buf + 8 + cmd_code_len,
						len - (8 + cmd_code_len),
						req_entry);
	delete_flag = diag_dci_remove_req_entry(temp, rsp_len, req_entry);
	if (delete_flag < 0)
		return;

@@ -592,7 +620,7 @@ void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf,
		return;
	}

	rsp_buf = entry->buffers[smd_info->peripheral].buf_cmd;
	rsp_buf = entry->buffers[data_source].buf_cmd;

	mutex_lock(&rsp_buf->data_mutex);
	/*
@@ -600,9 +628,9 @@ void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf,
	 * the rsp is the rsp length (write_len) + DCI_PKT_RSP_TYPE header (int)
	 * + field for length (int) + delete_flag (uint8_t)
	 */
	if ((rsp_buf->data_len + 9 + write_len) > rsp_buf->capacity) {
	if ((rsp_buf->data_len + 9 + rsp_len) > rsp_buf->capacity) {
		pr_alert("diag: create capacity for pkt rsp\n");
		rsp_buf->capacity += 9 + write_len;
		rsp_buf->capacity += 9 + rsp_len;
		temp_buf = krealloc(rsp_buf->data, rsp_buf->capacity,
				    GFP_KERNEL);
		if (!temp_buf) {
@@ -615,13 +643,17 @@ void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf,
	}
	*(int *)(rsp_buf->data + rsp_buf->data_len) = DCI_PKT_RSP_TYPE;
	rsp_buf->data_len += sizeof(int);
	*(int *)(rsp_buf->data + rsp_buf->data_len) = write_len;
	/* Packet Length = Response Length + Length of uid field (int) */
	*(int *)(rsp_buf->data + rsp_buf->data_len) = rsp_len + sizeof(int);
	rsp_buf->data_len += sizeof(int);
	*(uint8_t *)(rsp_buf->data + rsp_buf->data_len) = delete_flag;
	rsp_buf->data_len += sizeof(uint8_t);
	memcpy(rsp_buf->data+rsp_buf->data_len, buf+4+cmd_code_len, write_len);
	rsp_buf->data_len += write_len;
	rsp_buf->data_source = smd_info->peripheral;
	*(int *)(rsp_buf->data + rsp_buf->data_len) = req_entry->uid;
	rsp_buf->data_len += sizeof(int);
	memcpy(rsp_buf->data + rsp_buf->data_len, temp, rsp_len);
	rsp_buf->data_len += rsp_len;
	rsp_buf->data_source = data_source;
	if (smd_info)
		smd_info->in_busy_1 = 1;
	mutex_unlock(&rsp_buf->data_mutex);

@@ -956,7 +988,7 @@ void diag_dci_notify_client(int peripheral_mask, int data)
static int diag_send_dci_pkt(struct diag_master_table entry,
			     unsigned char *buf, int len, int tag)
{
	int i, status = 0;
	int i, status = DIAG_DCI_NO_ERROR;
	unsigned int read_len = 0;

	/* The first 4 bytes is the uid tag and the next four bytes is
@@ -990,6 +1022,14 @@ static int diag_send_dci_pkt(struct diag_master_table entry,
		mutex_unlock(&driver->dci_mutex);
		return -EIO;
	}
	/* This command is registered locally on the Apps */
	if (entry.client_id == APPS_DATA) {
		driver->dci_pkt_length = len + 10;
		diag_update_pkt_buffer(driver->apps_dci_buf, DCI_PKT_TYPE);
		diag_update_sleeping_process(entry.process_id, DCI_PKT_TYPE);
		mutex_unlock(&driver->dci_mutex);
		return DIAG_DCI_NO_ERROR;
	}

	for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
		if (entry.client_id == i) {
@@ -1011,34 +1051,163 @@ static int diag_send_dci_pkt(struct diag_master_table entry,
	return status;
}

int diag_process_dci_transaction(unsigned char *buf, int len)
static int diag_dci_process_apps_pkt(struct diag_pkt_header_t *pkt_header,
				     unsigned char *req_buf, int tag)
{
	uint8_t cmd_code, subsys_id, i, goto_download = 0;
	uint8_t header_len = sizeof(struct diag_dci_pkt_header_t);
	uint16_t ss_cmd_code;
	uint32_t write_len = 0;
	unsigned char *dest_buf = driver->apps_dci_buf;
	unsigned char *payload_ptr = driver->apps_dci_buf + header_len;
	struct diag_dci_pkt_header_t dci_header;

	if (!pkt_header || !req_buf || tag < 0)
		return -EIO;

	cmd_code = pkt_header->cmd_code;
	subsys_id = pkt_header->subsys_id;
	ss_cmd_code = pkt_header->subsys_cmd_code;

	if (cmd_code == DIAG_CMD_DOWNLOAD) {
		*payload_ptr = DIAG_CMD_DOWNLOAD;
		write_len = sizeof(uint8_t);
		goto_download = 1;
		goto fill_buffer;
	} else if (cmd_code == DIAG_CMD_VERSION) {
		if (chk_polling_response()) {
			for (i = 0; i < 55; i++, write_len++, payload_ptr++)
				*(payload_ptr) = 0;
			goto fill_buffer;
		}
	} else if (cmd_code == DIAG_CMD_EXT_BUILD) {
		if (chk_polling_response()) {
			*payload_ptr = DIAG_CMD_EXT_BUILD;
			write_len = sizeof(uint8_t);
			payload_ptr += sizeof(uint8_t);
			for (i = 0; i < 8; i++, write_len++, payload_ptr++)
				*(payload_ptr) = 0;
			*(int *)(payload_ptr) = chk_config_get_id();
			write_len += sizeof(int);
			goto fill_buffer;
		}
	} else if (cmd_code == DIAG_CMD_LOG_ON_DMND) {
		if (driver->log_on_demand_support) {
			*payload_ptr = DIAG_CMD_LOG_ON_DMND;
			write_len = sizeof(uint8_t);
			payload_ptr += sizeof(uint8_t);
			*(uint16_t *)(payload_ptr) = *(uint16_t *)(req_buf + 1);
			write_len += sizeof(uint16_t);
			payload_ptr += sizeof(uint16_t);
			*payload_ptr = 0x1; /* Unknown */
			write_len += sizeof(uint8_t);
			goto fill_buffer;
		}
	} else if (cmd_code != DIAG_CMD_DIAG_SUBSYS) {
		return DIAG_DCI_TABLE_ERR;
	}

	if (subsys_id == DIAG_SS_DIAG) {
		if (ss_cmd_code == DIAG_DIAG_MAX_PKT_SZ) {
			memcpy(payload_ptr, pkt_header,
					sizeof(struct diag_pkt_header_t));
			write_len = sizeof(struct diag_pkt_header_t);
			*(uint32_t *)(payload_ptr + write_len) = PKT_SIZE;
			write_len += sizeof(uint32_t);
		} else if (ss_cmd_code == DIAG_DIAG_STM) {
			write_len = diag_process_stm_cmd(req_buf, payload_ptr);
		}
	} else if (subsys_id == DIAG_SS_PARAMS) {
		if (ss_cmd_code == DIAG_DIAG_POLL) {
			if (chk_polling_response()) {
				memcpy(payload_ptr, pkt_header,
					sizeof(struct diag_pkt_header_t));
				write_len = sizeof(struct diag_pkt_header_t);
				payload_ptr += write_len;
				for (i = 0; i < 12; i++, write_len++) {
					*(payload_ptr) = 0;
					payload_ptr++;
				}
			}
		} else if (ss_cmd_code == DIAG_DEL_RSP_WRAP) {
			memcpy(payload_ptr, pkt_header,
					sizeof(struct diag_pkt_header_t));
			write_len = sizeof(struct diag_pkt_header_t);
			*(int *)(payload_ptr + write_len) = wrap_enabled;
			write_len += sizeof(int);
		} else if (ss_cmd_code == DIAG_DEL_RSP_WRAP_CNT) {
			wrap_enabled = true;
			memcpy(payload_ptr, pkt_header,
					sizeof(struct diag_pkt_header_t));
			write_len = sizeof(struct diag_pkt_header_t);
			*(uint16_t *)(payload_ptr + write_len) = wrap_count;
			write_len += sizeof(uint16_t);
		}
	}

fill_buffer:
	if (write_len > 0) {
		/* Check if we are within the range of the buffer*/
		if (write_len + header_len > PKT_SIZE) {
			pr_err("diag: In %s, invalid length %d\n", __func__,
						write_len + header_len);
			return -ENOMEM;
		}
		dci_header.start = CONTROL_CHAR;
		dci_header.version = 1;
		/*
		 * Length of the rsp pkt = actual data len + pkt rsp code
		 * (uint8_t) + tag (int)
		 */
		dci_header.len = write_len + sizeof(uint8_t) + sizeof(int);
		dci_header.pkt_code = DCI_PKT_RSP_CODE;
		dci_header.tag = tag;
		driver->in_busy_dcipktdata = 1;
		memcpy(dest_buf, &dci_header, header_len);
		diag_process_apps_dci_read_data(DCI_PKT_TYPE, dest_buf + 4,
						dci_header.len);
		driver->in_busy_dcipktdata = 0;

		if (goto_download) {
			/*
			 * Sleep for sometime so that the response reaches the
			 * client. The value 5000 empirically as an optimum
			 * time for the response to reach the client.
			 */
			usleep_range(5000, 5100);
			/* call download API */
			msm_set_restart_mode(RESTART_DLOAD);
			pr_alert("diag: download mode set, Rebooting SoC..\n");
			kernel_restart(NULL);
		}
		return DIAG_DCI_NO_ERROR;
	}

	return DIAG_DCI_TABLE_ERR;
}

static int diag_process_dci_pkt_rsp(unsigned char *buf, int len)
{
	int req_uid, ret = DIAG_DCI_TABLE_ERR, i;
	struct diag_pkt_header_t *header = NULL;
	unsigned char *temp = buf;
	uint16_t log_code, item_num;
	int ret = -1, found = 0, req_uid;
	unsigned char *req_buf = NULL;
	uint8_t retry_count = 0, max_retries = 3, found = 0;
	uint32_t read_len = 0;
	struct diag_master_table entry;
	int count, set_mask, num_codes, bit_index, event_id, offset = 0, i;
	unsigned int byte_index, read_len = 0;
	uint8_t equip_id, *log_mask_ptr, *head_log_mask_ptr, byte_mask;
	uint8_t *event_mask_ptr;
	struct diag_dci_client_tbl *dci_entry = NULL;
	struct dci_pkt_req_entry_t *req_entry = NULL;
	struct diag_pkt_header_t *header = NULL;

	if (!temp) {
		pr_err("diag: Invalid buffer in %s\n", __func__);
		return -ENOMEM;
	}
	if (!buf)
		return -EIO;

	/* This is Pkt request/response transaction */
	if (*(int *)temp > 0) {
	if (len < DCI_PKT_REQ_MIN_LEN || len > USER_SPACE_DATA) {
			pr_err("diag: dci: Invalid length %d len in %s", len,
								__func__);
		pr_err("diag: dci: Invalid length %d len in %s", len, __func__);
		return -EIO;
	}
		req_uid = *(int *)temp;

	req_uid = *(int *)temp; /* UID of the request */
	temp += sizeof(int);
	req_buf = temp; /* Start of the Request */
	header = (struct diag_pkt_header_t *)temp;
	temp += sizeof(struct diag_pkt_header_t);
	read_len = sizeof(int) + sizeof(struct diag_pkt_header_t);
@@ -1046,21 +1215,47 @@ int diag_process_dci_transaction(unsigned char *buf, int len)
		pr_err("diag: dci: Invalid length in %s\n", __func__);
		return -EIO;
	}
		/* check if the command is allowed on DCI */

	/* Check if the command is allowed on DCI */
	if (diag_dci_filter_commands(header)) {
		pr_debug("diag: command not supported %d %d %d",
				 header->cmd_code,
				 header->subsys_id,
			 header->cmd_code, header->subsys_id,
			 header->subsys_cmd_code);
		return DIAG_DCI_SEND_DATA_FAIL;
	}
		/* enter this UID into kernel table */

	/*
	 * Previous packet is yet to be consumed by the client. Wait
	 * till the buffer is free.
	 */
	while (retry_count < max_retries) {
		retry_count++;
		if (driver->in_busy_dcipktdata)
			usleep_range(10000, 10100);
		else
			break;
	}
	/* The buffer is still busy */
	if (driver->in_busy_dcipktdata) {
		pr_err("diag: In %s, apps dci buffer is still busy. Dropping packet\n",
								__func__);
		return -EAGAIN;
	}

	/* Register this new DCI packet */
	req_entry = diag_register_dci_transaction(req_uid);
	if (!req_entry) {
		pr_alert("diag: registering new DCI transaction failed\n");
		return DIAG_DCI_NO_REG;
	}
		for (i = 0; i < diag_max_reg; i++) {

	/* Check if it is a dedicated Apps command */
	ret = diag_dci_process_apps_pkt(header, req_buf, req_entry->tag);
	if (ret == DIAG_DCI_NO_ERROR || ret < 0)
		return ret;

	/* Check the registration table for command entries */
	for (i = 0; i < diag_max_reg && !found; i++) {
		entry = driver->table[i];
		if (entry.process_id == NO_PROCESS)
			continue;
@@ -1070,25 +1265,55 @@ int diag_process_dci_transaction(unsigned char *buf, int len)
			    entry.cmd_code_hi >= header->subsys_cmd_code) {
			ret = diag_send_dci_pkt(entry, buf, len,
						req_entry->tag);
			} else if (entry.cmd_code == 255 &&
				   header->cmd_code == 75) {
			found = 1;
		} else if (entry.cmd_code == 255 && header->cmd_code == 75) {
			if (entry.subsys_id == header->subsys_id &&
				    entry.cmd_code_lo <=
				    header->subsys_cmd_code &&
				    entry.cmd_code_hi >=
				    header->subsys_cmd_code) {
			    entry.cmd_code_lo <= header->subsys_cmd_code &&
			    entry.cmd_code_hi >= header->subsys_cmd_code) {
				ret = diag_send_dci_pkt(entry, buf, len,
							req_entry->tag);
				found = 1;
			}
			} else if (entry.cmd_code == 255 &&
				   entry.subsys_id == 255) {
		} else if (entry.cmd_code == 255 && entry.subsys_id == 255) {
			if (entry.cmd_code_lo <= header->cmd_code &&
			    entry.cmd_code_hi >= header->cmd_code) {
				/*
				 * If its a Mode reset command, make sure it is
				 * registered on the Apps Processor
				 */
				if (entry.cmd_code_lo == MODE_CMD &&
				    entry.cmd_code_hi == MODE_CMD)
					if (entry.client_id != APPS_DATA)
						continue;
					ret = diag_send_dci_pkt(entry, buf, len,
								req_entry->tag);
					found = 1;
			}
		}
	}

	return ret;
}

int diag_process_dci_transaction(unsigned char *buf, int len)
{
	unsigned char *temp = buf;
	uint16_t log_code, item_num;
	int ret = -1, found = 0;
	int count, set_mask, num_codes, bit_index, event_id, offset = 0;
	unsigned int byte_index, read_len = 0;
	uint8_t equip_id, *log_mask_ptr, *head_log_mask_ptr, byte_mask;
	uint8_t *event_mask_ptr;
	struct diag_dci_client_tbl *dci_entry = NULL;

	if (!temp) {
		pr_err("diag: Invalid buffer in %s\n", __func__);
		return -ENOMEM;
	}

	/* This is Pkt request/response transaction */
	if (*(int *)temp > 0) {
		return diag_process_dci_pkt_rsp(buf, len);
	} else if (*(int *)temp == DCI_LOG_TYPE) {
		/* Minimum length of a log mask config is 12 + 2 bytes for
		   atleast one log code to be set or reset */
+11 −3
Original line number Diff line number Diff line
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2014, The Linux Foundation. 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
@@ -128,6 +128,14 @@ struct diag_log_event_stats {
	int is_set;
};

struct diag_dci_pkt_header_t {
	uint8_t start;
	uint8_t version;
	uint16_t len;
	uint8_t pkt_code;
	int tag;
} __packed;

enum {
	DIAG_DCI_NO_ERROR = 1001,	/* No error */
	DIAG_DCI_NO_REG,		/* Could not register */
@@ -163,8 +171,8 @@ void diag_process_apps_dci_read_data(int data_type, void *buf, int recd_bytes);
int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf,
								int recd_bytes);
int diag_process_dci_transaction(unsigned char *buf, int len);
void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf,
								int len);
void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source,
			 struct diag_smd_info *smd_info);
struct diag_dci_client_tbl *diag_dci_get_client_entry(void);
/* DCI Log streaming functions */
void create_dci_log_mask_tbl(unsigned char *tbl_buf);
+22 −1
Original line number Diff line number Diff line
/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2008-2014, The Linux Foundation. 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
@@ -111,6 +111,24 @@
#define DIAG_STM_WCNSS	0x04
#define DIAG_STM_APPS	0x08

#define DIAG_CMD_VERSION	0
#define DIAG_CMD_DOWNLOAD	0x3A
#define DIAG_CMD_DIAG_SUBSYS	0x4B
#define DIAG_CMD_LOG_ON_DMND	0x78
#define DIAG_CMD_EXT_BUILD	0x7c

#define DIAG_SS_DIAG		0x12
#define DIAG_SS_PARAMS		0x32

#define DIAG_DIAG_MAX_PKT_SZ	0x55
#define DIAG_DIAG_STM		0x20E
#define DIAG_DIAG_POLL		0x03
#define DIAG_DEL_RSP_WRAP	0x04
#define DIAG_DEL_RSP_WRAP_CNT	0x05

#define MODE_CMD	41
#define RESET_ID	2

/*
 * The status bit masks when received in a signal handler are to be
 * used in conjunction with the peripheral list bit mask to determine the
@@ -413,6 +431,9 @@ struct diagchar_dev {
	struct diag_master_table *table;
	uint8_t *pkt_buf;
	int pkt_length;
	uint8_t *dci_pkt_buf; /* For Apps DCI packets */
	uint32_t dci_pkt_length;
	int in_busy_dcipktdata;
	struct diag_request *usb_read_ptr;
	struct diag_request *write_ptr_svc;
	int logging_mode;
+24 −8
Original line number Diff line number Diff line
/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2008-2014, The Linux Foundation. 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
@@ -1367,6 +1367,17 @@ drop:
		goto exit;
	}

	if (driver->data_ready[index] & DCI_PKT_TYPE) {
		/* Copy the type of data being passed */
		data_type = driver->data_ready[index] & DCI_PKT_TYPE;
		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
		COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->dci_pkt_buf),
					driver->dci_pkt_length);
		driver->data_ready[index] ^= DCI_PKT_TYPE;
		driver->in_busy_dcipktdata = 0;
		goto exit;
	}

	if (driver->data_ready[index] & DCI_EVENT_MASKS_TYPE) {
		/*Copy the type of data being passed*/
		data_type = driver->data_ready[index] & DCI_EVENT_MASKS_TYPE;
@@ -1436,7 +1447,7 @@ static ssize_t diagchar_write(struct file *file, const char __user *buf,
				size_t count, loff_t *ppos)
{
	int err, ret = 0, pkt_type, token_offset = 0;
	int remote_proc = 0;
	int remote_proc = 0, data_type;
	uint8_t index;
#ifdef DIAG_DEBUG
	int length = 0, i;
@@ -1750,16 +1761,20 @@ static ssize_t diagchar_write(struct file *file, const char __user *buf,
		return -EFAULT;
	}

	if (pkt_type & (DATA_TYPE_DCI_LOG | DATA_TYPE_DCI_EVENT)) {
		int data_type = pkt_type &
				(DATA_TYPE_DCI_LOG | DATA_TYPE_DCI_EVENT);
	data_type = pkt_type &
		    (DATA_TYPE_DCI_LOG | DATA_TYPE_DCI_EVENT | DCI_PKT_TYPE);
	if (data_type) {
		diag_process_apps_dci_read_data(data_type, buf_copy,
						payload_size);

		if (pkt_type & DATA_TYPE_DCI_LOG)
			pkt_type ^= DATA_TYPE_DCI_LOG;
		else
		else if (pkt_type & DATA_TYPE_DCI_EVENT) {
			pkt_type ^= DATA_TYPE_DCI_EVENT;
		} else {
			pkt_type ^= DCI_PKT_TYPE;
			diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
			return 0;
		}

		/*
		 * If the data is not headed for normal processing or the usb
@@ -2123,6 +2138,7 @@ static int __init diagchar_init(void)
		driver->callback_process = NULL;
		driver->mask_check = 0;
		driver->in_busy_pktdata = 0;
		driver->in_busy_dcipktdata = 0;
		mutex_init(&driver->diagchar_mutex);
		init_waitqueue_head(&driver->wait_q);
		init_waitqueue_head(&driver->smd_wait_q);
+68 −23
Original line number Diff line number Diff line
/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2008-2014, The Linux Foundation. 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
@@ -43,9 +43,6 @@
#include "diag_masks.h"
#include "diagfwd_bridge.h"

#define MODE_CMD		41
#define RESET_ID		2

#define STM_CMD_VERSION_OFFSET	4
#define STM_CMD_MASK_OFFSET	5
#define STM_CMD_DATA_OFFSET	6
@@ -1060,17 +1057,46 @@ int diag_device_write(void *buf, int data_type, struct diag_request *write_ptr)
    return err;
}

static void diag_update_pkt_buffer(unsigned char *buf)
void diag_update_pkt_buffer(unsigned char *buf, int type)
{
	unsigned char *ptr = driver->pkt_buf;
	unsigned char *ptr = NULL;
	unsigned char *temp = buf;
	unsigned int length;
	int *in_busy = NULL;

	if (!buf) {
		pr_err("diag: Invalid buffer in %s\n", __func__);
		return;
	}

	switch (type) {
	case PKT_TYPE:
		ptr = driver->pkt_buf;
		length = driver->pkt_length;
		in_busy = &driver->in_busy_pktdata;
		break;
	case DCI_PKT_TYPE:
		ptr = driver->dci_pkt_buf;
		length = driver->dci_pkt_length;
		in_busy = &driver->in_busy_dcipktdata;
		break;
	default:
		pr_err("diag: Invalid type %d in %s\n", type, __func__);
		return;
	}

	if (!ptr || length == 0) {
		pr_err("diag: Invalid ptr %p and length %d in %s",
						ptr, length, __func__);
		return;
	}
	mutex_lock(&driver->diagchar_mutex);
	if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, driver->pkt_length)) {
		memcpy(ptr, temp , driver->pkt_length);
		driver->in_busy_pktdata = 1;
	} else
	if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, length)) {
		memcpy(ptr, temp , length);
		*in_busy = 1;
	} else {
		printk(KERN_CRIT " Not enough buffer space for PKT_RESP\n");
	}
	mutex_unlock(&driver->diagchar_mutex);
}

@@ -1119,7 +1145,7 @@ int diag_send_data(struct diag_master_table entry, unsigned char *buf,
	if (entry.process_id != NON_APPS_PROC) {
		/* If the message is to be sent to the apps process */
		if (type != MODEM_DATA) {
			diag_update_pkt_buffer(buf);
			diag_update_pkt_buffer(buf, PKT_TYPE);
			diag_update_sleeping_process(entry.process_id,
							PKT_TYPE);
		}
@@ -1195,16 +1221,24 @@ void diag_process_stm_mask(uint8_t cmd, uint8_t data_mask, int data_type,
	}
}

int diag_process_stm_cmd(unsigned char *buf)
int diag_process_stm_cmd(unsigned char *buf, unsigned char *dest_buf)
{
	uint8_t version = *(buf+STM_CMD_VERSION_OFFSET);
	uint8_t mask = *(buf+STM_CMD_MASK_OFFSET);
	uint8_t cmd = *(buf+STM_CMD_DATA_OFFSET);
	uint8_t version, mask, cmd;
	uint8_t rsp_supported = 0;
	uint8_t rsp_smd_comply = 0;
	int valid_command = 1;
	int i;

	if (!buf || !dest_buf) {
		pr_err("diag: Invalid pointers buf: %p, dest_buf %p in %s\n",
		       buf, dest_buf, __func__);
		return -EIO;
	}

	version = *(buf + STM_CMD_VERSION_OFFSET);
	mask = *(buf + STM_CMD_MASK_OFFSET);
	cmd = *(buf + STM_CMD_DATA_OFFSET);

	/* Check if command is valid */
	if ((version != 1) || (mask == 0) || (0 != (mask >> 4)) ||
			(cmd != ENABLE_STM && cmd != DISABLE_STM)) {
@@ -1228,15 +1262,13 @@ int diag_process_stm_cmd(unsigned char *buf)
	}

	for (i = 0; i < STM_CMD_NUM_BYTES; i++)
		driver->apps_rsp_buf[i] = *(buf+i);
		dest_buf[i] = *(buf + i);

	driver->apps_rsp_buf[STM_RSP_VALID_INDEX] = valid_command;
	driver->apps_rsp_buf[STM_RSP_SUPPORTED_INDEX] = rsp_supported;
	driver->apps_rsp_buf[STM_RSP_SMD_COMPLY_INDEX] = rsp_smd_comply;
	dest_buf[STM_RSP_VALID_INDEX] = valid_command;
	dest_buf[STM_RSP_SUPPORTED_INDEX] = rsp_supported;
	dest_buf[STM_RSP_SMD_COMPLY_INDEX] = rsp_smd_comply;

	encode_rsp_and_send(STM_RSP_NUM_BYTES-1);

	return 0;
	return STM_RSP_NUM_BYTES;
}

int diag_apps_responds()
@@ -1333,7 +1365,12 @@ int diag_process_apps_pkt(unsigned char *buf, int len)
		return 0;
	} else if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
		(*(uint16_t *)(buf+2) == 0x020E)) {
		return diag_process_stm_cmd(buf);
		len = diag_process_stm_cmd(buf, driver->apps_rsp_buf);
		if (len > 0) {
			encode_rsp_and_send(len - 1);
			return 0;
		}
		return len;
	}
	/* Check for Apps Only & get event mask request */
	else if (diag_apps_responds() && *buf == 0x81) {
@@ -2641,6 +2678,12 @@ void diagfwd_init(void)
			 GFP_KERNEL)) == NULL)
		goto err;
	kmemleak_not_leak(driver->pkt_buf);
	if (driver->dci_pkt_buf == NULL) {
		driver->dci_pkt_buf = kzalloc(PKT_SIZE, GFP_KERNEL);
		if (!driver->dci_pkt_buf)
			goto err;
	}
	kmemleak_not_leak(driver->dci_pkt_buf);
	if (driver->apps_rsp_buf == NULL) {
		driver->apps_rsp_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
		if (driver->apps_rsp_buf == NULL)
@@ -2691,6 +2734,7 @@ err:
	kfree(driver->data_ready);
	kfree(driver->table);
	kfree(driver->pkt_buf);
	kfree(driver->dci_pkt_buf);
	kfree(driver->usb_read_ptr);
	kfree(driver->apps_rsp_buf);
	kfree(driver->user_space_data_buf);
@@ -2731,6 +2775,7 @@ void diagfwd_exit(void)
	kfree(driver->data_ready);
	kfree(driver->table);
	kfree(driver->pkt_buf);
	kfree(driver->dci_pkt_buf);
	kfree(driver->usb_read_ptr);
	kfree(driver->apps_rsp_buf);
	kfree(driver->user_space_data_buf);
Loading