blob: a779b241a8f7e121e196e0c2e5830cf0f0f3a525 [file] [log] [blame]
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/slab.h>
14#include <linux/init.h>
15#include <linux/uaccess.h>
16#include <linux/diagchar.h>
17#include <linux/sched.h>
18#include <linux/err.h>
Shalabh Jain5e9a92b2012-06-07 21:53:49 -070019#include <linux/delay.h>
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070020#include <linux/workqueue.h>
21#include <linux/pm_runtime.h>
22#include <linux/platform_device.h>
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -070023#include <linux/pm_wakeup.h>
24#include <linux/spinlock.h>
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070025#include <asm/current.h>
26#ifdef CONFIG_DIAG_OVER_USB
27#include <mach/usbdiag.h>
28#endif
29#include "diagchar_hdlc.h"
30#include "diagmem.h"
31#include "diagchar.h"
32#include "diagfwd.h"
Shalabh Jain16794902012-09-14 10:56:49 -070033#include "diagfwd_cntl.h"
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070034#include "diag_dci.h"
35
36unsigned int dci_max_reg = 100;
37unsigned int dci_max_clients = 10;
Shalabh Jain16794902012-09-14 10:56:49 -070038unsigned char dci_cumulative_log_mask[DCI_LOG_MASK_SIZE];
39unsigned char dci_cumulative_event_mask[DCI_EVENT_MASK_SIZE];
Shalabh Jaina1c69a42012-10-23 12:51:30 -070040struct mutex dci_log_mask_mutex;
41struct mutex dci_event_mask_mutex;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +053042struct mutex dci_health_mutex;
Shalabh Jain16794902012-09-14 10:56:49 -070043
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -070044spinlock_t ws_lock;
45unsigned long ws_lock_flags;
46
47/* Number of milliseconds anticipated to process the DCI data */
48#define DCI_WAKEUP_TIMEOUT 1
49
Shalabh Jain16794902012-09-14 10:56:49 -070050#define DCI_CHK_CAPACITY(entry, new_data_len) \
51((entry->data_len + new_data_len > entry->total_capacity) ? 1 : 0) \
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070052
Ravi Aravamudhan3dc66352013-06-14 10:46:19 -070053#ifdef CONFIG_DEBUG_FS
54struct diag_dci_data_info *dci_data_smd;
55struct mutex dci_stat_mutex;
56
Ravi Aravamudhan67db95c2013-07-18 10:00:50 -070057void diag_dci_smd_record_info(int read_bytes, uint8_t ch_type)
Ravi Aravamudhan3dc66352013-06-14 10:46:19 -070058{
59 static int curr_dci_data_smd;
60 static unsigned long iteration;
61 struct diag_dci_data_info *temp_data = dci_data_smd;
62 if (!temp_data)
63 return;
64 mutex_lock(&dci_stat_mutex);
65 if (curr_dci_data_smd == DIAG_DCI_DEBUG_CNT)
66 curr_dci_data_smd = 0;
67 temp_data += curr_dci_data_smd;
68 temp_data->iteration = iteration + 1;
69 temp_data->data_size = read_bytes;
Ravi Aravamudhan67db95c2013-07-18 10:00:50 -070070 temp_data->ch_type = ch_type;
Ravi Aravamudhan3dc66352013-06-14 10:46:19 -070071 diag_get_timestamp(temp_data->time_stamp);
72 curr_dci_data_smd++;
73 iteration++;
74 mutex_unlock(&dci_stat_mutex);
75}
76#else
Ravi Aravamudhan67db95c2013-07-18 10:00:50 -070077void diag_dci_smd_record_info(int read_bytes, uint8_t ch_type) { }
Ravi Aravamudhan3dc66352013-06-14 10:46:19 -070078#endif
79
Dixon Peterson66fb11b2012-12-04 20:30:54 -080080/* Process the data read from the smd dci channel */
81int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf,
82 int recd_bytes)
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070083{
Dixon Peterson66fb11b2012-12-04 20:30:54 -080084 int read_bytes, dci_pkt_len, i;
Shalabh Jain16794902012-09-14 10:56:49 -070085 uint8_t recv_pkt_cmd_code;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070086
Ravi Aravamudhan67db95c2013-07-18 10:00:50 -070087 diag_dci_smd_record_info(recd_bytes, (uint8_t)smd_info->type);
Dixon Peterson66fb11b2012-12-04 20:30:54 -080088 /* Each SMD read can have multiple DCI packets */
89 read_bytes = 0;
90 while (read_bytes < recd_bytes) {
91 /* read actual length of dci pkt */
92 dci_pkt_len = *(uint16_t *)(buf+2);
93 /* process one dci packet */
94 pr_debug("diag: bytes read = %d, single dci pkt len = %d\n",
95 read_bytes, dci_pkt_len);
96 /* print_hex_dump(KERN_DEBUG, "Single DCI packet :",
Dixon Peterson3ff84ea2012-12-21 20:16:18 -080097 DUMP_PREFIX_ADDRESS, 16, 1, buf, 5 + dci_pkt_len, 1); */
Dixon Peterson66fb11b2012-12-04 20:30:54 -080098 recv_pkt_cmd_code = *(uint8_t *)(buf+4);
99 if (recv_pkt_cmd_code == LOG_CMD_CODE)
100 extract_dci_log(buf+4);
101 else if (recv_pkt_cmd_code == EVENT_CMD_CODE)
102 extract_dci_events(buf+4);
103 else
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800104 extract_dci_pkt_rsp(smd_info, buf); /* pkt response */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800105 read_bytes += 5 + dci_pkt_len;
106 buf += 5 + dci_pkt_len; /* advance to next DCI pkt */
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700107 }
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700108 /* Release wakeup source when there are no more clients to
109 process DCI data */
110 if (driver->num_dci_client == 0)
111 diag_dci_try_deactivate_wakeup_source(smd_info->ch);
112
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800113 /* wake up all sleeping DCI clients which have some data */
114 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
115 if (driver->dci_client_tbl[i].client &&
116 driver->dci_client_tbl[i].data_len) {
117 smd_info->in_busy_1 = 1;
118 diag_update_sleeping_process(
119 driver->dci_client_tbl[i].client->tgid,
120 DCI_DATA_TYPE);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700121 }
122 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800123
124 return 0;
Shalabh Jain16794902012-09-14 10:56:49 -0700125}
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700126
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800127void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf)
Shalabh Jain16794902012-09-14 10:56:49 -0700128{
129 int i = 0, index = -1, cmd_code_len = 1;
130 int curr_client_pid = 0, write_len;
131 struct diag_dci_client_tbl *entry;
132 void *temp_buf = NULL;
133 uint8_t recv_pkt_cmd_code;
134
135 recv_pkt_cmd_code = *(uint8_t *)(buf+4);
136 if (recv_pkt_cmd_code != DCI_PKT_RSP_CODE)
137 cmd_code_len = 4; /* delayed response */
138 write_len = (int)(*(uint16_t *)(buf+2)) - cmd_code_len;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800139
Shalabh Jain16794902012-09-14 10:56:49 -0700140 pr_debug("diag: len = %d\n", write_len);
141 /* look up DCI client with tag */
142 for (i = 0; i < dci_max_reg; i++) {
143 if (driver->req_tracking_tbl[i].tag ==
144 *(int *)(buf+(4+cmd_code_len))) {
145 *(int *)(buf+4+cmd_code_len) =
146 driver->req_tracking_tbl[i].uid;
147 curr_client_pid =
148 driver->req_tracking_tbl[i].pid;
149 index = i;
150 break;
151 }
152 }
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800153 if (index == -1) {
Shalabh Jain16794902012-09-14 10:56:49 -0700154 pr_alert("diag: No matching PID for DCI data\n");
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800155 return;
156 }
Shalabh Jain16794902012-09-14 10:56:49 -0700157 /* Using PID of client process, find client buffer */
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800158 i = diag_dci_find_client_index(curr_client_pid);
159 if (i != DCI_CLIENT_INDEX_INVALID) {
160 /* copy pkt rsp in client buf */
161 entry = &(driver->dci_client_tbl[i]);
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -0700162 mutex_lock(&entry->data_mutex);
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800163 if (DCI_CHK_CAPACITY(entry, 8+write_len)) {
164 pr_alert("diag: create capacity for pkt rsp\n");
165 entry->total_capacity += 8+write_len;
166 temp_buf = krealloc(entry->dci_data,
167 entry->total_capacity, GFP_KERNEL);
168 if (!temp_buf) {
169 pr_err("diag: DCI realloc failed\n");
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -0700170 mutex_unlock(&entry->data_mutex);
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800171 return;
172 } else {
173 entry->dci_data = temp_buf;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800174 }
Shalabh Jain16794902012-09-14 10:56:49 -0700175 }
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800176 *(int *)(entry->dci_data+entry->data_len) =
177 DCI_PKT_RSP_TYPE;
178 entry->data_len += 4;
179 *(int *)(entry->dci_data+entry->data_len)
180 = write_len;
181 entry->data_len += 4;
182 memcpy(entry->dci_data+entry->data_len,
183 buf+4+cmd_code_len, write_len);
184 entry->data_len += write_len;
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -0700185 mutex_unlock(&entry->data_mutex);
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800186 /* delete immediate response entry */
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800187 if (smd_info->buf_in_1[8+cmd_code_len] != 0x80)
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800188 driver->req_tracking_tbl[index].pid = 0;
Shalabh Jain16794902012-09-14 10:56:49 -0700189 }
190}
191
192void extract_dci_events(unsigned char *buf)
193{
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800194 uint16_t event_id, event_id_packet, length, temp_len;
195 uint8_t *event_mask_ptr, byte_mask, payload_len, payload_len_field;
196 uint8_t timestamp[8], bit_index, timestamp_len;
197 uint8_t event_data[MAX_EVENT_SIZE];
198 unsigned int byte_index, total_event_len, i;
Shalabh Jain16794902012-09-14 10:56:49 -0700199 struct diag_dci_client_tbl *entry;
200
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800201 length = *(uint16_t *)(buf + 1); /* total length of event series */
202 if (length == 0) {
203 pr_err("diag: Incoming dci event length is invalid\n");
204 return;
205 }
Shalabh Jain16794902012-09-14 10:56:49 -0700206 temp_len = 0;
207 buf = buf + 3; /* start of event series */
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800208 while (temp_len < (length - 1)) {
209 event_id_packet = *(uint16_t *)(buf + temp_len);
Shalabh Jain16794902012-09-14 10:56:49 -0700210 event_id = event_id_packet & 0x0FFF; /* extract 12 bits */
211 if (event_id_packet & 0x8000) {
212 timestamp_len = 2;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800213 memset(timestamp, 0, 8);
Shalabh Jain16794902012-09-14 10:56:49 -0700214 } else {
215 timestamp_len = 8;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800216 memcpy(timestamp, buf + temp_len + 2, timestamp_len);
Shalabh Jain16794902012-09-14 10:56:49 -0700217 }
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800218 /* 13th and 14th bit represent the payload length */
Shalabh Jain16794902012-09-14 10:56:49 -0700219 if (((event_id_packet & 0x6000) >> 13) == 3) {
220 payload_len_field = 1;
221 payload_len = *(uint8_t *)
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800222 (buf + temp_len + 2 + timestamp_len);
223 if (payload_len < (MAX_EVENT_SIZE - 13)) {
224 /* copy the payload length and the payload */
225 memcpy(event_data + 12, buf + temp_len + 2 +
226 timestamp_len, 1);
227 memcpy(event_data + 13, buf + temp_len + 2 +
228 timestamp_len + 1, payload_len);
229 } else {
230 pr_err("diag: event > %d, payload_len = %d\n",
231 (MAX_EVENT_SIZE - 13), payload_len);
232 return;
233 }
Shalabh Jain16794902012-09-14 10:56:49 -0700234 } else {
235 payload_len_field = 0;
236 payload_len = (event_id_packet & 0x6000) >> 13;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800237 /* copy the payload */
238 memcpy(event_data + 12, buf + temp_len + 2 +
239 timestamp_len, payload_len);
Shalabh Jain16794902012-09-14 10:56:49 -0700240 }
241 /* 2 bytes for the event id & timestamp len is hard coded to 8,
242 as individual events have full timestamp */
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800243 *(uint16_t *)(event_data) = 10 +
244 payload_len_field + payload_len;
245 *(uint16_t *)(event_data + 2) = event_id_packet & 0x7FFF;
246 memcpy(event_data + 4, timestamp, 8);
247 /* 2 bytes for the event length field which is added to
248 the event data */
249 total_event_len = 2 + 10 + payload_len_field + payload_len;
250 byte_index = event_id / 8;
Shalabh Jain16794902012-09-14 10:56:49 -0700251 bit_index = event_id % 8;
252 byte_mask = 0x1 << bit_index;
253 /* parse through event mask tbl of each client and check mask */
254 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
255 if (driver->dci_client_tbl[i].client) {
256 entry = &(driver->dci_client_tbl[i]);
257 event_mask_ptr = entry->dci_event_mask +
258 byte_index;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530259 mutex_lock(&dci_health_mutex);
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -0700260 mutex_lock(&entry->data_mutex);
Shalabh Jain16794902012-09-14 10:56:49 -0700261 if (*event_mask_ptr & byte_mask) {
262 /* copy to client buffer */
263 if (DCI_CHK_CAPACITY(entry,
264 4 + total_event_len)) {
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800265 pr_err("diag: DCI event drop\n");
Shalabh Jain16794902012-09-14 10:56:49 -0700266 driver->dci_client_tbl[i].
267 dropped_events++;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530268 mutex_unlock(
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -0700269 &entry->data_mutex);
270 mutex_unlock(
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530271 &dci_health_mutex);
272 break;
Shalabh Jain16794902012-09-14 10:56:49 -0700273 }
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700274 driver->dci_client_tbl[i].
275 received_events++;
Shalabh Jain16794902012-09-14 10:56:49 -0700276 *(int *)(entry->dci_data+
277 entry->data_len) = DCI_EVENT_TYPE;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800278 /* 4 bytes for DCI_EVENT_TYPE */
279 memcpy(entry->dci_data +
280 entry->data_len + 4, event_data
281 , total_event_len);
Shalabh Jain16794902012-09-14 10:56:49 -0700282 entry->data_len += 4 + total_event_len;
283 }
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -0700284 mutex_unlock(&entry->data_mutex);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530285 mutex_unlock(&dci_health_mutex);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700286 }
287 }
Shalabh Jain16794902012-09-14 10:56:49 -0700288 temp_len += 2 + timestamp_len + payload_len_field + payload_len;
289 }
290}
291
292void extract_dci_log(unsigned char *buf)
293{
294 uint16_t log_code, item_num;
295 uint8_t equip_id, *log_mask_ptr, byte_mask;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800296 unsigned int i, byte_index, byte_offset = 0;
Shalabh Jain16794902012-09-14 10:56:49 -0700297 struct diag_dci_client_tbl *entry;
298
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800299 log_code = *(uint16_t *)(buf + 6);
Shalabh Jain16794902012-09-14 10:56:49 -0700300 equip_id = LOG_GET_EQUIP_ID(log_code);
301 item_num = LOG_GET_ITEM_NUM(log_code);
302 byte_index = item_num/8 + 2;
303 byte_mask = 0x01 << (item_num % 8);
304
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800305 byte_offset = (equip_id * 514) + byte_index;
306 if (byte_offset >= DCI_LOG_MASK_SIZE) {
307 pr_err("diag: Invalid byte_offset %d in dci log\n",
308 byte_offset);
309 return;
310 }
311
Shalabh Jain16794902012-09-14 10:56:49 -0700312 /* parse through log mask table of each client and check mask */
313 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
314 if (driver->dci_client_tbl[i].client) {
315 entry = &(driver->dci_client_tbl[i]);
316 log_mask_ptr = entry->dci_log_mask;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800317 if (!log_mask_ptr)
318 return;
319 log_mask_ptr = log_mask_ptr + byte_offset;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530320 mutex_lock(&dci_health_mutex);
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -0700321 mutex_lock(&entry->data_mutex);
Shalabh Jain16794902012-09-14 10:56:49 -0700322 if (*log_mask_ptr & byte_mask) {
323 pr_debug("\t log code %x needed by client %d",
324 log_code, entry->client->tgid);
325 /* copy to client buffer */
326 if (DCI_CHK_CAPACITY(entry,
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800327 4 + *(uint16_t *)(buf + 2))) {
328 pr_err("diag: DCI log drop\n");
Shalabh Jain16794902012-09-14 10:56:49 -0700329 driver->dci_client_tbl[i].
330 dropped_logs++;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530331 mutex_unlock(
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -0700332 &entry->data_mutex);
333 mutex_unlock(
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530334 &dci_health_mutex);
Shalabh Jain16794902012-09-14 10:56:49 -0700335 return;
336 }
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700337 driver->dci_client_tbl[i].received_logs++;
Shalabh Jain16794902012-09-14 10:56:49 -0700338 *(int *)(entry->dci_data+entry->data_len) =
339 DCI_LOG_TYPE;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800340 memcpy(entry->dci_data + entry->data_len + 4,
341 buf + 4, *(uint16_t *)(buf + 2));
342 entry->data_len += 4 + *(uint16_t *)(buf + 2);
Shalabh Jain16794902012-09-14 10:56:49 -0700343 }
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -0700344 mutex_unlock(&entry->data_mutex);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530345 mutex_unlock(&dci_health_mutex);
Shalabh Jain16794902012-09-14 10:56:49 -0700346 }
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700347 }
348}
349
Dixon Peterson5a26a302012-11-15 17:26:17 -0800350void diag_update_smd_dci_work_fn(struct work_struct *work)
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700351{
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800352 struct diag_smd_info *smd_info = container_of(work,
353 struct diag_smd_info,
354 diag_notify_update_smd_work);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800355 int i, j;
356 char dirty_bits[16];
357 uint8_t *client_log_mask_ptr;
358 uint8_t *log_mask_ptr;
359 int ret;
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800360 int index = smd_info->peripheral;
Dixon Peterson5a26a302012-11-15 17:26:17 -0800361
362 /* Update the peripheral(s) with the dci log and event masks */
363
364 /* If the cntl channel is not up, we can't update logs and events */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800365 if (!driver->smd_cntl[index].ch)
Dixon Peterson5a26a302012-11-15 17:26:17 -0800366 return;
367
368 memset(dirty_bits, 0, 16 * sizeof(uint8_t));
369
370 /*
371 * From each log entry used by each client, determine
372 * which log entries in the cumulative logs that need
373 * to be updated on the peripheral.
374 */
375 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
376 if (driver->dci_client_tbl[i].client) {
377 client_log_mask_ptr =
378 driver->dci_client_tbl[i].dci_log_mask;
379 for (j = 0; j < 16; j++) {
380 if (*(client_log_mask_ptr+1))
381 dirty_bits[j] = 1;
382 client_log_mask_ptr += 514;
383 }
384 }
385 }
386
387 mutex_lock(&dci_log_mask_mutex);
388 /* Update the appropriate dirty bits in the cumulative mask */
389 log_mask_ptr = dci_cumulative_log_mask;
390 for (i = 0; i < 16; i++) {
391 if (dirty_bits[i])
392 *(log_mask_ptr+1) = dirty_bits[i];
393
394 log_mask_ptr += 514;
395 }
396 mutex_unlock(&dci_log_mask_mutex);
397
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800398 ret = diag_send_dci_log_mask(driver->smd_cntl[index].ch);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800399
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800400 ret = diag_send_dci_event_mask(driver->smd_cntl[index].ch);
401
402 smd_info->notify_context = 0;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700403}
404
Dixon Peterson5a26a302012-11-15 17:26:17 -0800405void diag_dci_notify_client(int peripheral_mask, int data)
Shalabh Jain5e9a92b2012-06-07 21:53:49 -0700406{
407 int i, stat;
Dixon Peterson5a26a302012-11-15 17:26:17 -0800408 struct siginfo info;
409 memset(&info, 0, sizeof(struct siginfo));
410 info.si_code = SI_QUEUE;
411 info.si_int = (peripheral_mask | data);
Shalabh Jain5e9a92b2012-06-07 21:53:49 -0700412
413 /* Notify the DCI process that the peripheral DCI Channel is up */
Shalabh Jain16794902012-09-14 10:56:49 -0700414 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
415 if (driver->dci_client_tbl[i].list & peripheral_mask) {
Dixon Peterson5a26a302012-11-15 17:26:17 -0800416 info.si_signo = driver->dci_client_tbl[i].signal_type;
417 stat = send_sig_info(
418 driver->dci_client_tbl[i].signal_type,
419 &info, driver->dci_client_tbl[i].client);
Shalabh Jain5e9a92b2012-06-07 21:53:49 -0700420 if (stat)
Dixon Peterson5a26a302012-11-15 17:26:17 -0800421 pr_err("diag: Err sending dci signal to client, signal data: 0x%x, stat: %d\n",
422 info.si_int, stat);
Shalabh Jain5e9a92b2012-06-07 21:53:49 -0700423 }
424 } /* end of loop for all DCI clients */
425}
426
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700427int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
428 int len, int index)
429{
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700430 int i, status = 0;
431 unsigned int read_len = 0;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700432
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700433 /* The first 4 bytes is the uid tag and the next four bytes is
434 the minmum packet length of a request packet */
435 if (len < DCI_PKT_REQ_MIN_LEN) {
436 pr_err("diag: dci: Invalid pkt len %d in %s\n", len, __func__);
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -0800437 return -EIO;
438 }
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700439 if (len > APPS_BUF_SIZE - 10) {
440 pr_err("diag: dci: Invalid payload length in %s\n", __func__);
441 return -EIO;
442 }
443 /* remove UID from user space pkt before sending to peripheral*/
444 buf = buf + sizeof(int);
445 read_len += sizeof(int);
446 len = len - sizeof(int);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700447 mutex_lock(&driver->dci_mutex);
448 /* prepare DCI packet */
449 driver->apps_dci_buf[0] = CONTROL_CHAR; /* start */
450 driver->apps_dci_buf[1] = 1; /* version */
451 *(uint16_t *)(driver->apps_dci_buf + 2) = len + 4 + 1; /* length */
Shalabh Jain16794902012-09-14 10:56:49 -0700452 driver->apps_dci_buf[4] = DCI_PKT_RSP_CODE;
453 *(int *)(driver->apps_dci_buf + 5) =
454 driver->req_tracking_tbl[index].tag;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700455 for (i = 0; i < len; i++)
456 driver->apps_dci_buf[i+9] = *(buf+i);
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700457 read_len += len;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700458 driver->apps_dci_buf[9+len] = CONTROL_CHAR; /* end */
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700459 if ((read_len + 9) >= USER_SPACE_DATA) {
460 pr_err("diag: dci: Invalid length while forming dci pkt in %s",
461 __func__);
462 return -EIO;
463 }
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700464
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800465 for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800466 struct diag_smd_info *smd_info = driver->separate_cmdrsp[i] ?
467 &driver->smd_dci_cmd[i] :
468 &driver->smd_dci[i];
469 if (entry.client_id == smd_info->peripheral) {
470 if (smd_info->ch) {
471 smd_write(smd_info->ch,
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800472 driver->apps_dci_buf, len + 10);
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800473 status = DIAG_DCI_NO_ERROR;
474 }
475 break;
476 }
477 }
478
479 if (status != DIAG_DCI_NO_ERROR) {
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700480 pr_alert("diag: check DCI channel\n");
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800481 status = DIAG_DCI_SEND_DATA_FAIL;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700482 }
483 mutex_unlock(&driver->dci_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800484 return status;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700485}
486
487int diag_register_dci_transaction(int uid)
488{
489 int i, new_dci_client = 1, ret = -1;
490
491 for (i = 0; i < dci_max_reg; i++) {
Shalabh Jain16794902012-09-14 10:56:49 -0700492 if (driver->req_tracking_tbl[i].pid == current->tgid) {
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700493 new_dci_client = 0;
494 break;
495 }
496 }
497 mutex_lock(&driver->dci_mutex);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700498 /* Make an entry in kernel DCI table */
499 driver->dci_tag++;
500 for (i = 0; i < dci_max_reg; i++) {
Shalabh Jain16794902012-09-14 10:56:49 -0700501 if (driver->req_tracking_tbl[i].pid == 0) {
502 driver->req_tracking_tbl[i].pid = current->tgid;
503 driver->req_tracking_tbl[i].uid = uid;
504 driver->req_tracking_tbl[i].tag = driver->dci_tag;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700505 ret = i;
506 break;
507 }
508 }
509 mutex_unlock(&driver->dci_mutex);
510 return ret;
511}
512
Shalabh Jain16794902012-09-14 10:56:49 -0700513int diag_process_dci_transaction(unsigned char *buf, int len)
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700514{
515 unsigned char *temp = buf;
Shalabh Jain16794902012-09-14 10:56:49 -0700516 uint16_t subsys_cmd_code, log_code, item_num;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700517 int subsys_id, cmd_code, ret = -1, index = -1, found = 0;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700518 struct diag_master_table entry;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800519 int count, set_mask, num_codes, bit_index, event_id, offset = 0, i;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700520 unsigned int byte_index, read_len = 0;
Shalabh Jain16794902012-09-14 10:56:49 -0700521 uint8_t equip_id, *log_mask_ptr, *head_log_mask_ptr, byte_mask;
522 uint8_t *event_mask_ptr;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700523
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800524 if (!driver->smd_dci[MODEM_DATA].ch) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800525 pr_err("diag: DCI smd channel for peripheral %d not valid for dci updates\n",
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800526 driver->smd_dci[MODEM_DATA].peripheral);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800527 return DIAG_DCI_SEND_DATA_FAIL;
528 }
529
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700530 if (!temp) {
531 pr_err("diag: Invalid buffer in %s\n", __func__);
Ravi Aravamudhan66b02932013-06-26 16:15:21 -0700532 return -ENOMEM;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700533 }
534
Shalabh Jain16794902012-09-14 10:56:49 -0700535 /* This is Pkt request/response transaction */
536 if (*(int *)temp > 0) {
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700537 if (len < DCI_PKT_REQ_MIN_LEN || len > USER_SPACE_DATA) {
538 pr_err("diag: dci: Invalid length %d len in %s", len,
539 __func__);
540 return -EIO;
541 }
Shalabh Jain16794902012-09-14 10:56:49 -0700542 /* enter this UID into kernel table and return index */
543 index = diag_register_dci_transaction(*(int *)temp);
544 if (index < 0) {
545 pr_alert("diag: registering new DCI transaction failed\n");
546 return DIAG_DCI_NO_REG;
547 }
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700548 temp += sizeof(int);
Shalabh Jain16794902012-09-14 10:56:49 -0700549 /*
550 * Check for registered peripheral and fwd pkt to
551 * appropriate proc
552 */
553 cmd_code = (int)(*(char *)temp);
554 temp++;
555 subsys_id = (int)(*(char *)temp);
556 temp++;
557 subsys_cmd_code = *(uint16_t *)temp;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700558 temp += sizeof(uint16_t);
559 read_len += sizeof(int) + 2 + sizeof(uint16_t);
560 if (read_len >= USER_SPACE_DATA) {
561 pr_err("diag: dci: Invalid length in %s\n", __func__);
562 return -EIO;
563 }
Shalabh Jain16794902012-09-14 10:56:49 -0700564 pr_debug("diag: %d %d %d", cmd_code, subsys_id,
565 subsys_cmd_code);
566 for (i = 0; i < diag_max_reg; i++) {
567 entry = driver->table[i];
568 if (entry.process_id != NO_PROCESS) {
569 if (entry.cmd_code == cmd_code &&
570 entry.subsys_id == subsys_id &&
571 entry.cmd_code_lo <= subsys_cmd_code &&
572 entry.cmd_code_hi >= subsys_cmd_code) {
573 ret = diag_send_dci_pkt(entry, buf,
574 len, index);
575 } else if (entry.cmd_code == 255
576 && cmd_code == 75) {
577 if (entry.subsys_id == subsys_id &&
578 entry.cmd_code_lo <=
579 subsys_cmd_code &&
580 entry.cmd_code_hi >=
581 subsys_cmd_code) {
582 ret = diag_send_dci_pkt(entry,
583 buf, len, index);
584 }
585 } else if (entry.cmd_code == 255 &&
586 entry.subsys_id == 255) {
587 if (entry.cmd_code_lo <= cmd_code &&
588 entry.cmd_code_hi >=
589 cmd_code) {
590 ret = diag_send_dci_pkt(entry,
591 buf, len, index);
592 }
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700593 }
594 }
595 }
Shalabh Jain16794902012-09-14 10:56:49 -0700596 } else if (*(int *)temp == DCI_LOG_TYPE) {
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700597 /* Minimum length of a log mask config is 12 + 2 bytes for
598 atleast one log code to be set or reset */
599 if (len < DCI_LOG_CON_MIN_LEN || len > USER_SPACE_DATA) {
600 pr_err("diag: dci: Invalid length in %s\n", __func__);
601 return -EIO;
602 }
Shalabh Jain16794902012-09-14 10:56:49 -0700603 /* find client id and table */
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800604 i = diag_dci_find_client_index(current->tgid);
605 if (i == DCI_CLIENT_INDEX_INVALID) {
Shalabh Jain16794902012-09-14 10:56:49 -0700606 pr_err("diag: dci client not registered/found\n");
607 return ret;
608 }
609 /* Extract each log code and put in client table */
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700610 temp += sizeof(int);
611 read_len += sizeof(int);
Shalabh Jain16794902012-09-14 10:56:49 -0700612 set_mask = *(int *)temp;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700613 temp += sizeof(int);
614 read_len += sizeof(int);
Shalabh Jain16794902012-09-14 10:56:49 -0700615 num_codes = *(int *)temp;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700616 temp += sizeof(int);
617 read_len += sizeof(int);
618
619 if (num_codes == 0 || (num_codes >= (USER_SPACE_DATA - 8)/2)) {
620 pr_err("diag: dci: Invalid number of log codes %d\n",
621 num_codes);
622 return -EIO;
623 }
Shalabh Jain16794902012-09-14 10:56:49 -0700624
625 head_log_mask_ptr = driver->dci_client_tbl[i].dci_log_mask;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700626 if (!head_log_mask_ptr) {
627 pr_err("diag: dci: Invalid Log mask pointer in %s\n",
628 __func__);
629 return -ENOMEM;
630 }
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700631 pr_debug("diag: head of dci log mask %p\n", head_log_mask_ptr);
Shalabh Jain16794902012-09-14 10:56:49 -0700632 count = 0; /* iterator for extracting log codes */
633 while (count < num_codes) {
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800634 if (read_len >= USER_SPACE_DATA) {
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700635 pr_err("diag: dci: Invalid length for log type in %s",
636 __func__);
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800637 return -EIO;
638 }
Shalabh Jain16794902012-09-14 10:56:49 -0700639 log_code = *(uint16_t *)temp;
640 equip_id = LOG_GET_EQUIP_ID(log_code);
641 item_num = LOG_GET_ITEM_NUM(log_code);
642 byte_index = item_num/8 + 2;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800643 if (byte_index >= (DCI_MAX_ITEMS_PER_LOG_CODE+2)) {
644 pr_err("diag: dci: Log type, invalid byte index\n");
645 return ret;
646 }
Shalabh Jain16794902012-09-14 10:56:49 -0700647 byte_mask = 0x01 << (item_num % 8);
648 /*
649 * Parse through log mask table and find
650 * relevant range
651 */
652 log_mask_ptr = head_log_mask_ptr;
653 found = 0;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800654 offset = 0;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800655 while (log_mask_ptr && (offset < DCI_LOG_MASK_SIZE)) {
Shalabh Jain16794902012-09-14 10:56:49 -0700656 if (*log_mask_ptr == equip_id) {
657 found = 1;
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700658 pr_debug("diag: find equip id = %x at %p\n",
Shalabh Jain16794902012-09-14 10:56:49 -0700659 equip_id, log_mask_ptr);
660 break;
661 } else {
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700662 pr_debug("diag: did not find equip id = %x at %p\n",
Shalabh Jain16794902012-09-14 10:56:49 -0700663 equip_id, log_mask_ptr);
664 log_mask_ptr += 514;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800665 offset += 514;
Shalabh Jain16794902012-09-14 10:56:49 -0700666 }
667 }
668 if (!found) {
669 pr_err("diag: dci equip id not found\n");
670 return ret;
671 }
672 *(log_mask_ptr+1) = 1; /* set the dirty byte */
673 log_mask_ptr = log_mask_ptr + byte_index;
674 if (set_mask)
675 *log_mask_ptr |= byte_mask;
676 else
677 *log_mask_ptr &= ~byte_mask;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800678 /* add to cumulative mask */
679 update_dci_cumulative_log_mask(
680 offset, byte_index,
681 byte_mask);
Shalabh Jain16794902012-09-14 10:56:49 -0700682 temp += 2;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800683 read_len += 2;
Shalabh Jain16794902012-09-14 10:56:49 -0700684 count++;
685 ret = DIAG_DCI_NO_ERROR;
686 }
Shalabh Jain16794902012-09-14 10:56:49 -0700687 /* send updated mask to peripherals */
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800688 ret = diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
Shalabh Jain16794902012-09-14 10:56:49 -0700689 } else if (*(int *)temp == DCI_EVENT_TYPE) {
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700690 /* Minimum length of a event mask config is 12 + 4 bytes for
691 atleast one event id to be set or reset. */
692 if (len < DCI_EVENT_CON_MIN_LEN || len > USER_SPACE_DATA) {
693 pr_err("diag: dci: Invalid length in %s\n", __func__);
694 return -EIO;
695 }
Shalabh Jain16794902012-09-14 10:56:49 -0700696 /* find client id and table */
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800697 i = diag_dci_find_client_index(current->tgid);
698 if (i == DCI_CLIENT_INDEX_INVALID) {
Shalabh Jain16794902012-09-14 10:56:49 -0700699 pr_err("diag: dci client not registered/found\n");
700 return ret;
701 }
702 /* Extract each log code and put in client table */
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700703 temp += sizeof(int);
704 read_len += sizeof(int);
Shalabh Jain16794902012-09-14 10:56:49 -0700705 set_mask = *(int *)temp;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700706 temp += sizeof(int);
707 read_len += sizeof(int);
Shalabh Jain16794902012-09-14 10:56:49 -0700708 num_codes = *(int *)temp;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700709 temp += sizeof(int);
710 read_len += sizeof(int);
711
712 /* Check for positive number of event ids. Also, the number of
713 event ids should fit in the buffer along with set_mask and
714 num_codes which are 4 bytes each */
715 if (num_codes == 0 || (num_codes >= (USER_SPACE_DATA - 8)/2)) {
716 pr_err("diag: dci: Invalid number of event ids %d\n",
717 num_codes);
718 return -EIO;
719 }
Shalabh Jain16794902012-09-14 10:56:49 -0700720
721 event_mask_ptr = driver->dci_client_tbl[i].dci_event_mask;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700722 if (!event_mask_ptr) {
723 pr_err("diag: dci: Invalid event mask pointer in %s\n",
724 __func__);
725 return -ENOMEM;
726 }
Shalabh Jain16794902012-09-14 10:56:49 -0700727 pr_debug("diag: head of dci event mask %p\n", event_mask_ptr);
728 count = 0; /* iterator for extracting log codes */
729 while (count < num_codes) {
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800730 if (read_len >= USER_SPACE_DATA) {
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700731 pr_err("diag: dci: Invalid length for event type in %s",
732 __func__);
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800733 return -EIO;
734 }
Shalabh Jain16794902012-09-14 10:56:49 -0700735 event_id = *(int *)temp;
736 byte_index = event_id/8;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800737 if (byte_index >= DCI_EVENT_MASK_SIZE) {
738 pr_err("diag: dci: Event type, invalid byte index\n");
739 return ret;
740 }
Shalabh Jain16794902012-09-14 10:56:49 -0700741 bit_index = event_id % 8;
742 byte_mask = 0x1 << bit_index;
743 /*
744 * Parse through event mask table and set
745 * relevant byte & bit combination
746 */
747 if (set_mask)
748 *(event_mask_ptr + byte_index) |= byte_mask;
749 else
750 *(event_mask_ptr + byte_index) &= ~byte_mask;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800751 /* add to cumulative mask */
752 update_dci_cumulative_event_mask(byte_index, byte_mask);
Shalabh Jain16794902012-09-14 10:56:49 -0700753 temp += sizeof(int);
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800754 read_len += sizeof(int);
Shalabh Jain16794902012-09-14 10:56:49 -0700755 count++;
756 ret = DIAG_DCI_NO_ERROR;
757 }
Shalabh Jain16794902012-09-14 10:56:49 -0700758 /* send updated mask to peripherals */
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800759 ret = diag_send_dci_event_mask(driver->smd_cntl[MODEM_DATA].ch);
Shalabh Jain16794902012-09-14 10:56:49 -0700760 } else {
761 pr_alert("diag: Incorrect DCI transaction\n");
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700762 }
763 return ret;
764}
765
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800766int diag_dci_find_client_index(int client_id)
767{
768 int i, ret = DCI_CLIENT_INDEX_INVALID;
769
770 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
771 if (driver->dci_client_tbl[i].client != NULL) {
772 if (driver->dci_client_tbl[i].client->tgid ==
773 client_id) {
774 ret = i;
775 break;
776 }
777 }
778 }
779 return ret;
780}
781
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800782void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask)
Shalabh Jain16794902012-09-14 10:56:49 -0700783{
784 int i;
Shalabh Jain16794902012-09-14 10:56:49 -0700785 uint8_t *event_mask_ptr;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800786 uint8_t *update_ptr = dci_cumulative_event_mask;
787 bool is_set = false;
Shalabh Jain16794902012-09-14 10:56:49 -0700788
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700789 mutex_lock(&dci_event_mask_mutex);
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800790 update_ptr += offset;
791 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
792 event_mask_ptr =
793 driver->dci_client_tbl[i].dci_event_mask;
794 event_mask_ptr += offset;
795 if ((*event_mask_ptr & byte_mask) == byte_mask) {
796 is_set = true;
797 /* break even if one client has the event mask set */
798 break;
799 }
800 }
801 if (is_set == false)
802 *update_ptr &= ~byte_mask;
803 else
804 *update_ptr |= byte_mask;
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700805 mutex_unlock(&dci_event_mask_mutex);
Shalabh Jain16794902012-09-14 10:56:49 -0700806}
807
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800808void clear_client_dci_cumulative_event_mask(int client_index)
809{
810 int i, j;
811 uint8_t *update_ptr = dci_cumulative_event_mask;
812 uint8_t *event_mask_ptr, *client_event_mask_ptr, byte_mask = 0;
813 bool is_set = false;
814
815 event_mask_ptr =
816 (driver->dci_client_tbl[client_index].dci_event_mask);
817
818 mutex_lock(&dci_event_mask_mutex);
819 for (i = 0; i < DCI_EVENT_MASK_SIZE; i++) {
820 is_set = false;
821 /* Already cleared event masks need not to be considered */
822 if (*event_mask_ptr != 0) {
823 byte_mask = *event_mask_ptr;
824 } else {
825 update_ptr++;
826 event_mask_ptr++;
827 continue;
828 }
829 for (j = 0; j < MAX_DCI_CLIENTS; j++) {
830 /* continue searching for valid client */
831 if (driver->dci_client_tbl[j].client == NULL ||
832 client_index == j)
833 continue;
834 client_event_mask_ptr =
835 (driver->dci_client_tbl[j].dci_event_mask);
836 client_event_mask_ptr += i;
837 if (*client_event_mask_ptr & byte_mask) {
838 /*
839 * Break if another client has same
840 * event mask set
841 */
842 if ((*client_event_mask_ptr &
843 byte_mask) == byte_mask) {
844 is_set = true;
845 break;
846 } else {
847 byte_mask =
848 (~(*client_event_mask_ptr) &
849 byte_mask);
850 is_set = false;
851 }
852 }
853 }
854 /*
855 * Clear only if this client has event mask set else
856 * don't update cumulative event mask ptr
857 */
858 if (is_set == false)
859 *update_ptr &= ~byte_mask;
860
861 update_ptr++;
862 event_mask_ptr++;
863 }
864 event_mask_ptr =
865 (driver->dci_client_tbl[client_index].dci_event_mask);
866 memset(event_mask_ptr, 0, DCI_EVENT_MASK_SIZE);
867 mutex_unlock(&dci_event_mask_mutex);
868}
869
870
Dixon Peterson5a26a302012-11-15 17:26:17 -0800871int diag_send_dci_event_mask(smd_channel_t *ch)
Shalabh Jain16794902012-09-14 10:56:49 -0700872{
873 void *buf = driver->buf_event_mask_update;
874 int header_size = sizeof(struct diag_ctrl_event_mask);
875 int wr_size = -ENOMEM, retry_count = 0, timer;
Dixon Peterson5a26a302012-11-15 17:26:17 -0800876 int ret = DIAG_DCI_NO_ERROR;
Shalabh Jain16794902012-09-14 10:56:49 -0700877
878 mutex_lock(&driver->diag_cntl_mutex);
879 /* send event mask update */
880 driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
881 driver->event_mask->data_len = 7 + DCI_EVENT_MASK_SIZE;
882 driver->event_mask->stream_id = DCI_MASK_STREAM;
883 driver->event_mask->status = 3; /* status for valid mask */
884 driver->event_mask->event_config = 1; /* event config */
885 driver->event_mask->event_mask_size = DCI_EVENT_MASK_SIZE;
886 memcpy(buf, driver->event_mask, header_size);
887 memcpy(buf+header_size, dci_cumulative_event_mask, DCI_EVENT_MASK_SIZE);
888 if (ch) {
889 while (retry_count < 3) {
890 wr_size = smd_write(ch, buf,
891 header_size + DCI_EVENT_MASK_SIZE);
892 if (wr_size == -ENOMEM) {
893 retry_count++;
894 for (timer = 0; timer < 5; timer++)
895 udelay(2000);
896 } else {
897 break;
898 }
899 }
Dixon Peterson5a26a302012-11-15 17:26:17 -0800900 if (wr_size != header_size + DCI_EVENT_MASK_SIZE) {
Shalabh Jain16794902012-09-14 10:56:49 -0700901 pr_err("diag: error writing dci event mask %d, tried %d\n",
902 wr_size, header_size + DCI_EVENT_MASK_SIZE);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800903 ret = DIAG_DCI_SEND_DATA_FAIL;
904 }
905 } else {
Shalabh Jain16794902012-09-14 10:56:49 -0700906 pr_err("diag: ch not valid for dci event mask update\n");
Dixon Peterson5a26a302012-11-15 17:26:17 -0800907 ret = DIAG_DCI_SEND_DATA_FAIL;
908 }
Shalabh Jain16794902012-09-14 10:56:49 -0700909 mutex_unlock(&driver->diag_cntl_mutex);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800910
911 return ret;
Shalabh Jain16794902012-09-14 10:56:49 -0700912}
913
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800914void update_dci_cumulative_log_mask(int offset, unsigned int byte_index,
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800915 uint8_t byte_mask)
Shalabh Jain16794902012-09-14 10:56:49 -0700916{
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800917 int i;
Shalabh Jain16794902012-09-14 10:56:49 -0700918 uint8_t *update_ptr = dci_cumulative_log_mask;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800919 uint8_t *log_mask_ptr;
920 bool is_set = false;
Shalabh Jain16794902012-09-14 10:56:49 -0700921
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700922 mutex_lock(&dci_log_mask_mutex);
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800923 *update_ptr = 0;
924 /* set the equipment IDs */
925 for (i = 0; i < 16; i++)
926 *(update_ptr + (i*514)) = i;
927
928 update_ptr += offset;
929 /* update the dirty bit */
930 *(update_ptr+1) = 1;
931 update_ptr = update_ptr + byte_index;
932 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
933 log_mask_ptr =
934 (driver->dci_client_tbl[i].dci_log_mask);
935 log_mask_ptr = log_mask_ptr + offset + byte_index;
936 if ((*log_mask_ptr & byte_mask) == byte_mask) {
937 is_set = true;
938 /* break even if one client has the log mask set */
939 break;
Shalabh Jain16794902012-09-14 10:56:49 -0700940 }
Shalabh Jain16794902012-09-14 10:56:49 -0700941 }
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800942
943 if (is_set == false)
944 *update_ptr &= ~byte_mask;
945 else
946 *update_ptr |= byte_mask;
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700947 mutex_unlock(&dci_log_mask_mutex);
Shalabh Jain16794902012-09-14 10:56:49 -0700948}
949
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800950void clear_client_dci_cumulative_log_mask(int client_index)
951{
952 int i, j, k;
953 uint8_t *update_ptr = dci_cumulative_log_mask;
954 uint8_t *log_mask_ptr, *client_log_mask_ptr, byte_mask = 0;
955 bool is_set = false;
956
957 log_mask_ptr = driver->dci_client_tbl[client_index].dci_log_mask;
958
959 mutex_lock(&dci_log_mask_mutex);
960 *update_ptr = 0;
961 /* set the equipment IDs */
962 for (i = 0; i < 16; i++)
963 *(update_ptr + (i*514)) = i;
964
965 /* update cumulative log mask ptr*/
966 update_ptr += 2;
967 log_mask_ptr += 2;
968 for (i = 0; i < 16; i++) {
969 for (j = 0; j < 512; j++) {
970 is_set = false;
971 /*
972 * Already cleared log masks need
973 * not to be considered
974 */
975 if (*log_mask_ptr != 0) {
976 byte_mask = *log_mask_ptr;
977 } else {
978 update_ptr++;
979 log_mask_ptr++;
980 continue;
981 }
982 for (k = 0; k < MAX_DCI_CLIENTS; k++) {
983 /* continue searching for valid client */
984 if (driver->dci_client_tbl[k].client == NULL ||
985 client_index == k)
986 continue;
987 client_log_mask_ptr =
988 (driver->dci_client_tbl[k].dci_log_mask);
989 client_log_mask_ptr += (i*514) + 2 + j;
990 if (*client_log_mask_ptr & byte_mask) {
991 /*
992 * Break if another client has same
993 * log mask set
994 */
995 if ((*client_log_mask_ptr &
996 byte_mask) == byte_mask) {
997 is_set = true;
998 break;
999 } else {
1000 byte_mask =
1001 (~(*client_log_mask_ptr) &
1002 byte_mask);
1003 is_set = false;
1004 }
1005 }
1006 }
1007 /*
1008 * Clear only if this client has log mask set else
1009 * don't update cumulative log mask ptr
1010 */
1011 if (is_set == false) {
1012 /*
1013 * Update the dirty bit for the equipment
1014 * whose mask is changing
1015 */
1016 dci_cumulative_log_mask[1+(i*514)] = 1;
1017 *update_ptr &= ~byte_mask;
1018 }
1019
1020 update_ptr++;
1021 log_mask_ptr++;
1022 }
1023 update_ptr += 2;
1024 log_mask_ptr += 2;
1025 }
1026 log_mask_ptr = driver->dci_client_tbl[client_index].dci_log_mask;
1027 memset(log_mask_ptr, 0, DCI_LOG_MASK_SIZE);
1028 mutex_unlock(&dci_log_mask_mutex);
1029}
1030
Dixon Peterson5a26a302012-11-15 17:26:17 -08001031int diag_send_dci_log_mask(smd_channel_t *ch)
Shalabh Jain16794902012-09-14 10:56:49 -07001032{
1033 void *buf = driver->buf_log_mask_update;
1034 int header_size = sizeof(struct diag_ctrl_log_mask);
1035 uint8_t *log_mask_ptr = dci_cumulative_log_mask;
1036 int i, wr_size = -ENOMEM, retry_count = 0, timer;
Dixon Peterson5a26a302012-11-15 17:26:17 -08001037 int ret = DIAG_DCI_NO_ERROR;
1038
1039 if (!ch) {
1040 pr_err("diag: ch not valid for dci log mask update\n");
1041 return DIAG_DCI_SEND_DATA_FAIL;
1042 }
Shalabh Jain16794902012-09-14 10:56:49 -07001043
1044 mutex_lock(&driver->diag_cntl_mutex);
1045 for (i = 0; i < 16; i++) {
Ravi Aravamudhan3365bc02013-03-05 16:51:28 -08001046 retry_count = 0;
Shalabh Jain16794902012-09-14 10:56:49 -07001047 driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
1048 driver->log_mask->num_items = 512;
1049 driver->log_mask->data_len = 11 + 512;
1050 driver->log_mask->stream_id = DCI_MASK_STREAM;
1051 driver->log_mask->status = 3; /* status for valid mask */
1052 driver->log_mask->equip_id = *log_mask_ptr;
1053 driver->log_mask->log_mask_size = 512;
1054 memcpy(buf, driver->log_mask, header_size);
1055 memcpy(buf+header_size, log_mask_ptr+2, 512);
1056 /* if dirty byte is set and channel is valid */
1057 if (ch && *(log_mask_ptr+1)) {
1058 while (retry_count < 3) {
1059 wr_size = smd_write(ch, buf, header_size + 512);
1060 if (wr_size == -ENOMEM) {
1061 retry_count++;
1062 for (timer = 0; timer < 5; timer++)
1063 udelay(2000);
1064 } else
1065 break;
1066 }
Dixon Peterson5a26a302012-11-15 17:26:17 -08001067 if (wr_size != header_size + 512) {
Ravi Aravamudhan3365bc02013-03-05 16:51:28 -08001068 pr_err("diag: dci log mask update failed %d, tried %d for equip_id %d\n",
1069 wr_size, header_size + 512,
1070 driver->log_mask->equip_id);
Dixon Peterson5a26a302012-11-15 17:26:17 -08001071 ret = DIAG_DCI_SEND_DATA_FAIL;
1072
1073 } else {
Shalabh Jain16794902012-09-14 10:56:49 -07001074 *(log_mask_ptr+1) = 0; /* clear dirty byte */
1075 pr_debug("diag: updated dci log equip ID %d\n",
1076 *log_mask_ptr);
1077 }
1078 }
1079 log_mask_ptr += 514;
1080 }
1081 mutex_unlock(&driver->diag_cntl_mutex);
Dixon Peterson5a26a302012-11-15 17:26:17 -08001082
1083 return ret;
Shalabh Jain16794902012-09-14 10:56:49 -07001084}
1085
1086void create_dci_log_mask_tbl(unsigned char *tbl_buf)
1087{
1088 uint8_t i; int count = 0;
1089
1090 /* create hard coded table for log mask with 16 categories */
1091 for (i = 0; i < 16; i++) {
1092 *(uint8_t *)tbl_buf = i;
1093 pr_debug("diag: put value %x at %p\n", i, tbl_buf);
1094 memset(tbl_buf+1, 0, 513); /* set dirty bit as 0 */
1095 tbl_buf += 514;
1096 count += 514;
1097 }
1098}
1099
1100void create_dci_event_mask_tbl(unsigned char *tbl_buf)
1101{
1102 memset(tbl_buf, 0, 512);
1103}
1104
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001105static int diag_dci_probe(struct platform_device *pdev)
1106{
1107 int err = 0;
1108 int index;
1109
1110 if (pdev->id == SMD_APPS_MODEM) {
1111 index = MODEM_DATA;
1112 err = smd_open("DIAG_2",
1113 &driver->smd_dci[index].ch,
1114 &driver->smd_dci[index],
1115 diag_smd_notify);
1116 driver->smd_dci[index].ch_save =
1117 driver->smd_dci[index].ch;
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07001118 driver->dci_device = &pdev->dev;
1119 driver->dci_device->power.wakeup = wakeup_source_register
1120 ("DIAG_DCI_WS");
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001121 if (err)
1122 pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
1123 __func__, pdev->id, err);
1124 }
1125
1126 return err;
1127}
1128
1129static int diag_dci_cmd_probe(struct platform_device *pdev)
1130{
1131 int err = 0;
1132 int index;
1133
1134 if (pdev->id == SMD_APPS_MODEM) {
1135 index = MODEM_DATA;
1136 err = smd_named_open_on_edge("DIAG_2_CMD",
1137 pdev->id,
1138 &driver->smd_dci_cmd[index].ch,
1139 &driver->smd_dci_cmd[index],
1140 diag_smd_notify);
1141 driver->smd_dci_cmd[index].ch_save =
1142 driver->smd_dci_cmd[index].ch;
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07001143 driver->dci_cmd_device = &pdev->dev;
1144 driver->dci_cmd_device->power.wakeup = wakeup_source_register
1145 ("DIAG_DCI_CMD_WS");
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001146 if (err)
1147 pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
1148 __func__, pdev->id, err);
1149 }
1150
1151 return err;
1152}
1153
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001154static int diag_dci_runtime_suspend(struct device *dev)
1155{
1156 dev_dbg(dev, "pm_runtime: suspending...\n");
1157 return 0;
1158}
1159
1160static int diag_dci_runtime_resume(struct device *dev)
1161{
1162 dev_dbg(dev, "pm_runtime: resuming...\n");
1163 return 0;
1164}
1165
1166static const struct dev_pm_ops diag_dci_dev_pm_ops = {
1167 .runtime_suspend = diag_dci_runtime_suspend,
1168 .runtime_resume = diag_dci_runtime_resume,
1169};
1170
1171struct platform_driver msm_diag_dci_driver = {
1172 .probe = diag_dci_probe,
1173 .driver = {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001174 .name = "DIAG_2",
1175 .owner = THIS_MODULE,
1176 .pm = &diag_dci_dev_pm_ops,
1177 },
1178};
1179
1180struct platform_driver msm_diag_dci_cmd_driver = {
1181 .probe = diag_dci_cmd_probe,
1182 .driver = {
1183 .name = "DIAG_2_CMD",
1184 .owner = THIS_MODULE,
1185 .pm = &diag_dci_dev_pm_ops,
Shalabh Jain16794902012-09-14 10:56:49 -07001186 },
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001187};
1188
1189int diag_dci_init(void)
1190{
1191 int success = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001192 int i;
Dixon Peterson5a26a302012-11-15 17:26:17 -08001193
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001194 driver->dci_tag = 0;
1195 driver->dci_client_id = 0;
1196 driver->num_dci_client = 0;
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07001197 driver->dci_device = NULL;
1198 driver->dci_cmd_device = NULL;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001199 mutex_init(&driver->dci_mutex);
Shalabh Jaina1c69a42012-10-23 12:51:30 -07001200 mutex_init(&dci_log_mask_mutex);
1201 mutex_init(&dci_event_mask_mutex);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301202 mutex_init(&dci_health_mutex);
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07001203 spin_lock_init(&ws_lock);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301204
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -08001205 for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001206 success = diag_smd_constructor(&driver->smd_dci[i], i,
1207 SMD_DCI_TYPE);
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -08001208 if (!success)
1209 goto err;
1210 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001211
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001212 if (driver->supports_separate_cmdrsp) {
1213 for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++) {
1214 success = diag_smd_constructor(&driver->smd_dci_cmd[i],
1215 i, SMD_DCI_CMD_TYPE);
1216 if (!success)
1217 goto err;
1218 }
1219 }
1220
Shalabh Jain16794902012-09-14 10:56:49 -07001221 if (driver->req_tracking_tbl == NULL) {
1222 driver->req_tracking_tbl = kzalloc(dci_max_reg *
1223 sizeof(struct dci_pkt_req_tracking_tbl), GFP_KERNEL);
1224 if (driver->req_tracking_tbl == NULL)
Shalabh Jain5e9a92b2012-06-07 21:53:49 -07001225 goto err;
1226 }
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001227 if (driver->apps_dci_buf == NULL) {
1228 driver->apps_dci_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
1229 if (driver->apps_dci_buf == NULL)
1230 goto err;
1231 }
Shalabh Jain16794902012-09-14 10:56:49 -07001232 if (driver->dci_client_tbl == NULL) {
1233 driver->dci_client_tbl = kzalloc(MAX_DCI_CLIENTS *
1234 sizeof(struct diag_dci_client_tbl), GFP_KERNEL);
1235 if (driver->dci_client_tbl == NULL)
1236 goto err;
1237 }
1238 driver->diag_dci_wq = create_singlethread_workqueue("diag_dci_wq");
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001239 success = platform_driver_register(&msm_diag_dci_driver);
1240 if (success) {
1241 pr_err("diag: Could not register DCI driver\n");
1242 goto err;
1243 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001244 if (driver->supports_separate_cmdrsp) {
1245 success = platform_driver_register(&msm_diag_dci_cmd_driver);
1246 if (success) {
1247 pr_err("diag: Could not register DCI cmd driver\n");
1248 goto err;
1249 }
1250 }
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001251 return DIAG_DCI_NO_ERROR;
1252err:
1253 pr_err("diag: Could not initialize diag DCI buffers");
Shalabh Jain16794902012-09-14 10:56:49 -07001254 kfree(driver->req_tracking_tbl);
1255 kfree(driver->dci_client_tbl);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001256 kfree(driver->apps_dci_buf);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001257 for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
1258 diag_smd_destructor(&driver->smd_dci[i]);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001259
1260 if (driver->supports_separate_cmdrsp)
1261 for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
1262 diag_smd_destructor(&driver->smd_dci_cmd[i]);
1263
Shalabh Jain16794902012-09-14 10:56:49 -07001264 if (driver->diag_dci_wq)
1265 destroy_workqueue(driver->diag_dci_wq);
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001266 mutex_destroy(&driver->dci_mutex);
1267 mutex_destroy(&dci_log_mask_mutex);
1268 mutex_destroy(&dci_event_mask_mutex);
1269 mutex_destroy(&dci_health_mutex);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001270 return DIAG_DCI_NO_REG;
1271}
1272
1273void diag_dci_exit(void)
1274{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001275 int i;
1276
1277 for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
1278 diag_smd_destructor(&driver->smd_dci[i]);
1279
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001280 platform_driver_unregister(&msm_diag_dci_driver);
Dixon Peterson6dba7572013-04-12 18:45:16 -07001281
1282 if (driver->dci_client_tbl) {
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -07001283 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
Dixon Peterson6dba7572013-04-12 18:45:16 -07001284 kfree(driver->dci_client_tbl[i].dci_data);
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -07001285 mutex_destroy(&driver->dci_client_tbl[i].data_mutex);
1286 }
Dixon Peterson6dba7572013-04-12 18:45:16 -07001287 }
1288
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001289 if (driver->supports_separate_cmdrsp) {
1290 for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
1291 diag_smd_destructor(&driver->smd_dci_cmd[i]);
1292
1293 platform_driver_unregister(&msm_diag_dci_cmd_driver);
1294 }
Shalabh Jain16794902012-09-14 10:56:49 -07001295 kfree(driver->req_tracking_tbl);
1296 kfree(driver->dci_client_tbl);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001297 kfree(driver->apps_dci_buf);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301298 mutex_destroy(&driver->dci_mutex);
1299 mutex_destroy(&dci_log_mask_mutex);
1300 mutex_destroy(&dci_event_mask_mutex);
1301 mutex_destroy(&dci_health_mutex);
Shalabh Jain16794902012-09-14 10:56:49 -07001302 destroy_workqueue(driver->diag_dci_wq);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001303}
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301304
1305int diag_dci_clear_log_mask()
1306{
1307 int i, j, k, err = DIAG_DCI_NO_ERROR;
1308 uint8_t *log_mask_ptr, *update_ptr;
1309
1310 i = diag_dci_find_client_index(current->tgid);
1311 if (i == DCI_CLIENT_INDEX_INVALID)
1312 return DIAG_DCI_TABLE_ERR;
1313
1314 mutex_lock(&dci_log_mask_mutex);
1315 create_dci_log_mask_tbl(
1316 driver->dci_client_tbl[i].dci_log_mask);
1317 memset(dci_cumulative_log_mask,
1318 0x0, DCI_LOG_MASK_SIZE);
1319 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
1320 update_ptr = dci_cumulative_log_mask;
1321 if (driver->dci_client_tbl[i].client) {
1322 log_mask_ptr =
1323 driver->dci_client_tbl[i].dci_log_mask;
1324 for (j = 0; j < 16; j++) {
1325 *update_ptr = j;
1326 *(update_ptr + 1) = 1;
1327 update_ptr += 2;
1328 log_mask_ptr += 2;
1329 for (k = 0; k < 513; k++) {
1330 *update_ptr |= *log_mask_ptr;
1331 update_ptr++;
1332 log_mask_ptr++;
1333 }
1334 }
1335 }
1336 }
1337 mutex_unlock(&dci_log_mask_mutex);
1338 err = diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
1339 return err;
1340}
1341
1342int diag_dci_clear_event_mask()
1343{
1344 int i, j, err = DIAG_DCI_NO_ERROR;
1345 uint8_t *event_mask_ptr, *update_ptr;
1346
1347 i = diag_dci_find_client_index(current->tgid);
1348 if (i == DCI_CLIENT_INDEX_INVALID)
1349 return DIAG_DCI_TABLE_ERR;
1350
1351 mutex_lock(&dci_event_mask_mutex);
1352 memset(driver->dci_client_tbl[i].dci_event_mask,
1353 0x0, DCI_EVENT_MASK_SIZE);
1354 memset(dci_cumulative_event_mask,
1355 0x0, DCI_EVENT_MASK_SIZE);
1356 update_ptr = dci_cumulative_event_mask;
1357 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
1358 event_mask_ptr =
1359 driver->dci_client_tbl[i].dci_event_mask;
1360 for (j = 0; j < DCI_EVENT_MASK_SIZE; j++)
1361 *(update_ptr + j) |= *(event_mask_ptr + j);
1362 }
1363 mutex_unlock(&dci_event_mask_mutex);
1364 err = diag_send_dci_event_mask(driver->smd_cntl[MODEM_DATA].ch);
1365 return err;
1366}
1367
1368int diag_dci_query_log_mask(uint16_t log_code)
1369{
1370 uint16_t item_num;
1371 uint8_t equip_id, *log_mask_ptr, byte_mask;
1372 int i, byte_index, offset;
1373
1374 equip_id = LOG_GET_EQUIP_ID(log_code);
1375 item_num = LOG_GET_ITEM_NUM(log_code);
1376 byte_index = item_num/8 + 2;
1377 byte_mask = 0x01 << (item_num % 8);
1378 offset = equip_id * 514;
1379
1380 i = diag_dci_find_client_index(current->tgid);
1381 if (i != DCI_CLIENT_INDEX_INVALID) {
1382 log_mask_ptr = driver->dci_client_tbl[i].dci_log_mask;
1383 log_mask_ptr = log_mask_ptr + offset + byte_index;
1384 return ((*log_mask_ptr & byte_mask) == byte_mask) ?
1385 1 : 0;
1386 }
1387 return 0;
1388}
1389
1390
1391int diag_dci_query_event_mask(uint16_t event_id)
1392{
1393 uint8_t *event_mask_ptr, byte_mask;
1394 int i, byte_index, bit_index;
1395 byte_index = event_id/8;
1396 bit_index = event_id % 8;
1397 byte_mask = 0x1 << bit_index;
1398
1399 i = diag_dci_find_client_index(current->tgid);
1400 if (i != DCI_CLIENT_INDEX_INVALID) {
1401 event_mask_ptr =
1402 driver->dci_client_tbl[i].dci_event_mask;
1403 event_mask_ptr = event_mask_ptr + byte_index;
1404 if ((*event_mask_ptr & byte_mask) == byte_mask)
1405 return 1;
1406 else
1407 return 0;
1408 }
1409 return 0;
1410}
1411
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001412uint8_t diag_dci_get_cumulative_real_time()
1413{
1414 uint8_t real_time = MODE_NONREALTIME, i;
1415 for (i = 0; i < MAX_DCI_CLIENTS; i++)
1416 if (driver->dci_client_tbl[i].client &&
1417 driver->dci_client_tbl[i].real_time ==
1418 MODE_REALTIME) {
1419 real_time = 1;
1420 break;
1421 }
1422 return real_time;
1423}
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301424
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001425int diag_dci_set_real_time(int client_id, uint8_t real_time)
1426{
1427 int i = DCI_CLIENT_INDEX_INVALID;
1428 i = diag_dci_find_client_index(client_id);
1429
1430 if (i != DCI_CLIENT_INDEX_INVALID)
1431 driver->dci_client_tbl[i].real_time = real_time;
1432 return i;
1433}
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07001434
1435void diag_dci_try_activate_wakeup_source(smd_channel_t *channel)
1436{
1437 spin_lock_irqsave(&ws_lock, ws_lock_flags);
1438 if (channel == driver->smd_dci[MODEM_DATA].ch) {
1439 pm_wakeup_event(driver->dci_device, DCI_WAKEUP_TIMEOUT);
1440 pm_stay_awake(driver->dci_device);
1441 } else if (channel == driver->smd_dci_cmd[MODEM_DATA].ch) {
1442 pm_wakeup_event(driver->dci_cmd_device, DCI_WAKEUP_TIMEOUT);
1443 pm_stay_awake(driver->dci_cmd_device);
1444 }
1445 spin_unlock_irqrestore(&ws_lock, ws_lock_flags);
1446}
1447
1448void diag_dci_try_deactivate_wakeup_source(smd_channel_t *channel)
1449{
1450 spin_lock_irqsave(&ws_lock, ws_lock_flags);
1451 if (channel == driver->smd_dci[MODEM_DATA].ch)
1452 pm_relax(driver->dci_device);
1453 else if (channel == driver->smd_dci_cmd[MODEM_DATA].ch)
1454 pm_relax(driver->dci_cmd_device);
1455 spin_unlock_irqrestore(&ws_lock, ws_lock_flags);
1456}