blob: 91b90a84b3880c37ea86ecedffd28beff06d541c [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) {
Ravi Aravamudhan67d6f4f2013-07-31 11:35:07 -0700212 /* The packet has the two smallest byte of the
213 * timestamp
214 */
Shalabh Jain16794902012-09-14 10:56:49 -0700215 timestamp_len = 2;
216 } else {
Ravi Aravamudhan67d6f4f2013-07-31 11:35:07 -0700217 /* The packet has the full timestamp. The first event
218 * will always have full timestamp. Save it in the
219 * timestamp buffer and use it for subsequent events if
220 * necessary.
221 */
Shalabh Jain16794902012-09-14 10:56:49 -0700222 timestamp_len = 8;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800223 memcpy(timestamp, buf + temp_len + 2, timestamp_len);
Shalabh Jain16794902012-09-14 10:56:49 -0700224 }
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800225 /* 13th and 14th bit represent the payload length */
Shalabh Jain16794902012-09-14 10:56:49 -0700226 if (((event_id_packet & 0x6000) >> 13) == 3) {
227 payload_len_field = 1;
228 payload_len = *(uint8_t *)
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800229 (buf + temp_len + 2 + timestamp_len);
230 if (payload_len < (MAX_EVENT_SIZE - 13)) {
231 /* copy the payload length and the payload */
232 memcpy(event_data + 12, buf + temp_len + 2 +
233 timestamp_len, 1);
234 memcpy(event_data + 13, buf + temp_len + 2 +
235 timestamp_len + 1, payload_len);
236 } else {
237 pr_err("diag: event > %d, payload_len = %d\n",
238 (MAX_EVENT_SIZE - 13), payload_len);
239 return;
240 }
Shalabh Jain16794902012-09-14 10:56:49 -0700241 } else {
242 payload_len_field = 0;
243 payload_len = (event_id_packet & 0x6000) >> 13;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800244 /* copy the payload */
245 memcpy(event_data + 12, buf + temp_len + 2 +
246 timestamp_len, payload_len);
Shalabh Jain16794902012-09-14 10:56:49 -0700247 }
248 /* 2 bytes for the event id & timestamp len is hard coded to 8,
249 as individual events have full timestamp */
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800250 *(uint16_t *)(event_data) = 10 +
251 payload_len_field + payload_len;
252 *(uint16_t *)(event_data + 2) = event_id_packet & 0x7FFF;
253 memcpy(event_data + 4, timestamp, 8);
254 /* 2 bytes for the event length field which is added to
255 the event data */
256 total_event_len = 2 + 10 + payload_len_field + payload_len;
257 byte_index = event_id / 8;
Shalabh Jain16794902012-09-14 10:56:49 -0700258 bit_index = event_id % 8;
259 byte_mask = 0x1 << bit_index;
260 /* parse through event mask tbl of each client and check mask */
261 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
262 if (driver->dci_client_tbl[i].client) {
263 entry = &(driver->dci_client_tbl[i]);
264 event_mask_ptr = entry->dci_event_mask +
265 byte_index;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530266 mutex_lock(&dci_health_mutex);
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -0700267 mutex_lock(&entry->data_mutex);
Shalabh Jain16794902012-09-14 10:56:49 -0700268 if (*event_mask_ptr & byte_mask) {
269 /* copy to client buffer */
270 if (DCI_CHK_CAPACITY(entry,
271 4 + total_event_len)) {
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800272 pr_err("diag: DCI event drop\n");
Shalabh Jain16794902012-09-14 10:56:49 -0700273 driver->dci_client_tbl[i].
274 dropped_events++;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530275 mutex_unlock(
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -0700276 &entry->data_mutex);
277 mutex_unlock(
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530278 &dci_health_mutex);
279 break;
Shalabh Jain16794902012-09-14 10:56:49 -0700280 }
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700281 driver->dci_client_tbl[i].
282 received_events++;
Shalabh Jain16794902012-09-14 10:56:49 -0700283 *(int *)(entry->dci_data+
284 entry->data_len) = DCI_EVENT_TYPE;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800285 /* 4 bytes for DCI_EVENT_TYPE */
286 memcpy(entry->dci_data +
287 entry->data_len + 4, event_data
288 , total_event_len);
Shalabh Jain16794902012-09-14 10:56:49 -0700289 entry->data_len += 4 + total_event_len;
290 }
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -0700291 mutex_unlock(&entry->data_mutex);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530292 mutex_unlock(&dci_health_mutex);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700293 }
294 }
Shalabh Jain16794902012-09-14 10:56:49 -0700295 temp_len += 2 + timestamp_len + payload_len_field + payload_len;
296 }
297}
298
299void extract_dci_log(unsigned char *buf)
300{
301 uint16_t log_code, item_num;
302 uint8_t equip_id, *log_mask_ptr, byte_mask;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800303 unsigned int i, byte_index, byte_offset = 0;
Shalabh Jain16794902012-09-14 10:56:49 -0700304 struct diag_dci_client_tbl *entry;
305
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800306 log_code = *(uint16_t *)(buf + 6);
Shalabh Jain16794902012-09-14 10:56:49 -0700307 equip_id = LOG_GET_EQUIP_ID(log_code);
308 item_num = LOG_GET_ITEM_NUM(log_code);
309 byte_index = item_num/8 + 2;
310 byte_mask = 0x01 << (item_num % 8);
311
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800312 byte_offset = (equip_id * 514) + byte_index;
313 if (byte_offset >= DCI_LOG_MASK_SIZE) {
314 pr_err("diag: Invalid byte_offset %d in dci log\n",
315 byte_offset);
316 return;
317 }
318
Shalabh Jain16794902012-09-14 10:56:49 -0700319 /* parse through log mask table of each client and check mask */
320 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
321 if (driver->dci_client_tbl[i].client) {
322 entry = &(driver->dci_client_tbl[i]);
323 log_mask_ptr = entry->dci_log_mask;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800324 if (!log_mask_ptr)
325 return;
326 log_mask_ptr = log_mask_ptr + byte_offset;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530327 mutex_lock(&dci_health_mutex);
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -0700328 mutex_lock(&entry->data_mutex);
Shalabh Jain16794902012-09-14 10:56:49 -0700329 if (*log_mask_ptr & byte_mask) {
330 pr_debug("\t log code %x needed by client %d",
331 log_code, entry->client->tgid);
332 /* copy to client buffer */
333 if (DCI_CHK_CAPACITY(entry,
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800334 4 + *(uint16_t *)(buf + 2))) {
335 pr_err("diag: DCI log drop\n");
Shalabh Jain16794902012-09-14 10:56:49 -0700336 driver->dci_client_tbl[i].
337 dropped_logs++;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530338 mutex_unlock(
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -0700339 &entry->data_mutex);
340 mutex_unlock(
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530341 &dci_health_mutex);
Shalabh Jain16794902012-09-14 10:56:49 -0700342 return;
343 }
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700344 driver->dci_client_tbl[i].received_logs++;
Shalabh Jain16794902012-09-14 10:56:49 -0700345 *(int *)(entry->dci_data+entry->data_len) =
346 DCI_LOG_TYPE;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800347 memcpy(entry->dci_data + entry->data_len + 4,
348 buf + 4, *(uint16_t *)(buf + 2));
349 entry->data_len += 4 + *(uint16_t *)(buf + 2);
Shalabh Jain16794902012-09-14 10:56:49 -0700350 }
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -0700351 mutex_unlock(&entry->data_mutex);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530352 mutex_unlock(&dci_health_mutex);
Shalabh Jain16794902012-09-14 10:56:49 -0700353 }
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700354 }
355}
356
Dixon Peterson5a26a302012-11-15 17:26:17 -0800357void diag_update_smd_dci_work_fn(struct work_struct *work)
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700358{
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800359 struct diag_smd_info *smd_info = container_of(work,
360 struct diag_smd_info,
361 diag_notify_update_smd_work);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800362 int i, j;
363 char dirty_bits[16];
364 uint8_t *client_log_mask_ptr;
365 uint8_t *log_mask_ptr;
366 int ret;
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800367 int index = smd_info->peripheral;
Dixon Peterson5a26a302012-11-15 17:26:17 -0800368
369 /* Update the peripheral(s) with the dci log and event masks */
370
371 /* If the cntl channel is not up, we can't update logs and events */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800372 if (!driver->smd_cntl[index].ch)
Dixon Peterson5a26a302012-11-15 17:26:17 -0800373 return;
374
375 memset(dirty_bits, 0, 16 * sizeof(uint8_t));
376
377 /*
378 * From each log entry used by each client, determine
379 * which log entries in the cumulative logs that need
380 * to be updated on the peripheral.
381 */
382 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
383 if (driver->dci_client_tbl[i].client) {
384 client_log_mask_ptr =
385 driver->dci_client_tbl[i].dci_log_mask;
386 for (j = 0; j < 16; j++) {
387 if (*(client_log_mask_ptr+1))
388 dirty_bits[j] = 1;
389 client_log_mask_ptr += 514;
390 }
391 }
392 }
393
394 mutex_lock(&dci_log_mask_mutex);
395 /* Update the appropriate dirty bits in the cumulative mask */
396 log_mask_ptr = dci_cumulative_log_mask;
397 for (i = 0; i < 16; i++) {
398 if (dirty_bits[i])
399 *(log_mask_ptr+1) = dirty_bits[i];
400
401 log_mask_ptr += 514;
402 }
403 mutex_unlock(&dci_log_mask_mutex);
404
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800405 ret = diag_send_dci_log_mask(driver->smd_cntl[index].ch);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800406
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800407 ret = diag_send_dci_event_mask(driver->smd_cntl[index].ch);
408
409 smd_info->notify_context = 0;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700410}
411
Dixon Peterson5a26a302012-11-15 17:26:17 -0800412void diag_dci_notify_client(int peripheral_mask, int data)
Shalabh Jain5e9a92b2012-06-07 21:53:49 -0700413{
414 int i, stat;
Dixon Peterson5a26a302012-11-15 17:26:17 -0800415 struct siginfo info;
416 memset(&info, 0, sizeof(struct siginfo));
417 info.si_code = SI_QUEUE;
418 info.si_int = (peripheral_mask | data);
Shalabh Jain5e9a92b2012-06-07 21:53:49 -0700419
420 /* Notify the DCI process that the peripheral DCI Channel is up */
Shalabh Jain16794902012-09-14 10:56:49 -0700421 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
Ravi Aravamudhan80daefc2013-09-09 11:36:02 -0700422 if (!driver->dci_client_tbl[i].client)
423 continue;
Shalabh Jain16794902012-09-14 10:56:49 -0700424 if (driver->dci_client_tbl[i].list & peripheral_mask) {
Dixon Peterson5a26a302012-11-15 17:26:17 -0800425 info.si_signo = driver->dci_client_tbl[i].signal_type;
426 stat = send_sig_info(
427 driver->dci_client_tbl[i].signal_type,
428 &info, driver->dci_client_tbl[i].client);
Shalabh Jain5e9a92b2012-06-07 21:53:49 -0700429 if (stat)
Dixon Peterson5a26a302012-11-15 17:26:17 -0800430 pr_err("diag: Err sending dci signal to client, signal data: 0x%x, stat: %d\n",
431 info.si_int, stat);
Shalabh Jain5e9a92b2012-06-07 21:53:49 -0700432 }
433 } /* end of loop for all DCI clients */
434}
435
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700436int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
437 int len, int index)
438{
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700439 int i, status = 0;
440 unsigned int read_len = 0;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700441
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700442 /* The first 4 bytes is the uid tag and the next four bytes is
443 the minmum packet length of a request packet */
444 if (len < DCI_PKT_REQ_MIN_LEN) {
445 pr_err("diag: dci: Invalid pkt len %d in %s\n", len, __func__);
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -0800446 return -EIO;
447 }
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700448 if (len > APPS_BUF_SIZE - 10) {
449 pr_err("diag: dci: Invalid payload length in %s\n", __func__);
450 return -EIO;
451 }
452 /* remove UID from user space pkt before sending to peripheral*/
453 buf = buf + sizeof(int);
454 read_len += sizeof(int);
455 len = len - sizeof(int);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700456 mutex_lock(&driver->dci_mutex);
457 /* prepare DCI packet */
458 driver->apps_dci_buf[0] = CONTROL_CHAR; /* start */
459 driver->apps_dci_buf[1] = 1; /* version */
460 *(uint16_t *)(driver->apps_dci_buf + 2) = len + 4 + 1; /* length */
Shalabh Jain16794902012-09-14 10:56:49 -0700461 driver->apps_dci_buf[4] = DCI_PKT_RSP_CODE;
462 *(int *)(driver->apps_dci_buf + 5) =
463 driver->req_tracking_tbl[index].tag;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700464 for (i = 0; i < len; i++)
465 driver->apps_dci_buf[i+9] = *(buf+i);
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700466 read_len += len;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700467 driver->apps_dci_buf[9+len] = CONTROL_CHAR; /* end */
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700468 if ((read_len + 9) >= USER_SPACE_DATA) {
469 pr_err("diag: dci: Invalid length while forming dci pkt in %s",
470 __func__);
Ravi Aravamudhane422f9c2013-07-24 15:53:43 -0700471 mutex_unlock(&driver->dci_mutex);
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700472 return -EIO;
473 }
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700474
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800475 for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800476 struct diag_smd_info *smd_info = driver->separate_cmdrsp[i] ?
477 &driver->smd_dci_cmd[i] :
478 &driver->smd_dci[i];
479 if (entry.client_id == smd_info->peripheral) {
480 if (smd_info->ch) {
481 smd_write(smd_info->ch,
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800482 driver->apps_dci_buf, len + 10);
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800483 status = DIAG_DCI_NO_ERROR;
484 }
485 break;
486 }
487 }
488
489 if (status != DIAG_DCI_NO_ERROR) {
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700490 pr_alert("diag: check DCI channel\n");
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800491 status = DIAG_DCI_SEND_DATA_FAIL;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700492 }
493 mutex_unlock(&driver->dci_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800494 return status;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700495}
496
497int diag_register_dci_transaction(int uid)
498{
499 int i, new_dci_client = 1, ret = -1;
500
501 for (i = 0; i < dci_max_reg; i++) {
Shalabh Jain16794902012-09-14 10:56:49 -0700502 if (driver->req_tracking_tbl[i].pid == current->tgid) {
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700503 new_dci_client = 0;
504 break;
505 }
506 }
507 mutex_lock(&driver->dci_mutex);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700508 /* Make an entry in kernel DCI table */
509 driver->dci_tag++;
510 for (i = 0; i < dci_max_reg; i++) {
Shalabh Jain16794902012-09-14 10:56:49 -0700511 if (driver->req_tracking_tbl[i].pid == 0) {
512 driver->req_tracking_tbl[i].pid = current->tgid;
513 driver->req_tracking_tbl[i].uid = uid;
514 driver->req_tracking_tbl[i].tag = driver->dci_tag;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700515 ret = i;
516 break;
517 }
518 }
519 mutex_unlock(&driver->dci_mutex);
520 return ret;
521}
522
Shalabh Jain16794902012-09-14 10:56:49 -0700523int diag_process_dci_transaction(unsigned char *buf, int len)
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700524{
525 unsigned char *temp = buf;
Shalabh Jain16794902012-09-14 10:56:49 -0700526 uint16_t subsys_cmd_code, log_code, item_num;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700527 int subsys_id, cmd_code, ret = -1, index = -1, found = 0;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700528 struct diag_master_table entry;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800529 int count, set_mask, num_codes, bit_index, event_id, offset = 0, i;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700530 unsigned int byte_index, read_len = 0;
Shalabh Jain16794902012-09-14 10:56:49 -0700531 uint8_t equip_id, *log_mask_ptr, *head_log_mask_ptr, byte_mask;
532 uint8_t *event_mask_ptr;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700533
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800534 if (!driver->smd_dci[MODEM_DATA].ch) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800535 pr_err("diag: DCI smd channel for peripheral %d not valid for dci updates\n",
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800536 driver->smd_dci[MODEM_DATA].peripheral);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800537 return DIAG_DCI_SEND_DATA_FAIL;
538 }
539
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700540 if (!temp) {
541 pr_err("diag: Invalid buffer in %s\n", __func__);
Ravi Aravamudhan66b02932013-06-26 16:15:21 -0700542 return -ENOMEM;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700543 }
544
Shalabh Jain16794902012-09-14 10:56:49 -0700545 /* This is Pkt request/response transaction */
546 if (*(int *)temp > 0) {
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700547 if (len < DCI_PKT_REQ_MIN_LEN || len > USER_SPACE_DATA) {
548 pr_err("diag: dci: Invalid length %d len in %s", len,
549 __func__);
550 return -EIO;
551 }
Shalabh Jain16794902012-09-14 10:56:49 -0700552 /* enter this UID into kernel table and return index */
553 index = diag_register_dci_transaction(*(int *)temp);
554 if (index < 0) {
555 pr_alert("diag: registering new DCI transaction failed\n");
556 return DIAG_DCI_NO_REG;
557 }
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700558 temp += sizeof(int);
Shalabh Jain16794902012-09-14 10:56:49 -0700559 /*
560 * Check for registered peripheral and fwd pkt to
561 * appropriate proc
562 */
563 cmd_code = (int)(*(char *)temp);
564 temp++;
565 subsys_id = (int)(*(char *)temp);
566 temp++;
567 subsys_cmd_code = *(uint16_t *)temp;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700568 temp += sizeof(uint16_t);
569 read_len += sizeof(int) + 2 + sizeof(uint16_t);
570 if (read_len >= USER_SPACE_DATA) {
571 pr_err("diag: dci: Invalid length in %s\n", __func__);
572 return -EIO;
573 }
Shalabh Jain16794902012-09-14 10:56:49 -0700574 pr_debug("diag: %d %d %d", cmd_code, subsys_id,
575 subsys_cmd_code);
576 for (i = 0; i < diag_max_reg; i++) {
577 entry = driver->table[i];
578 if (entry.process_id != NO_PROCESS) {
579 if (entry.cmd_code == cmd_code &&
580 entry.subsys_id == subsys_id &&
581 entry.cmd_code_lo <= subsys_cmd_code &&
582 entry.cmd_code_hi >= subsys_cmd_code) {
583 ret = diag_send_dci_pkt(entry, buf,
584 len, index);
585 } else if (entry.cmd_code == 255
586 && cmd_code == 75) {
587 if (entry.subsys_id == subsys_id &&
588 entry.cmd_code_lo <=
589 subsys_cmd_code &&
590 entry.cmd_code_hi >=
591 subsys_cmd_code) {
592 ret = diag_send_dci_pkt(entry,
593 buf, len, index);
594 }
595 } else if (entry.cmd_code == 255 &&
596 entry.subsys_id == 255) {
597 if (entry.cmd_code_lo <= cmd_code &&
598 entry.cmd_code_hi >=
599 cmd_code) {
600 ret = diag_send_dci_pkt(entry,
601 buf, len, index);
602 }
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700603 }
604 }
605 }
Shalabh Jain16794902012-09-14 10:56:49 -0700606 } else if (*(int *)temp == DCI_LOG_TYPE) {
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700607 /* Minimum length of a log mask config is 12 + 2 bytes for
608 atleast one log code to be set or reset */
609 if (len < DCI_LOG_CON_MIN_LEN || len > USER_SPACE_DATA) {
610 pr_err("diag: dci: Invalid length in %s\n", __func__);
611 return -EIO;
612 }
Shalabh Jain16794902012-09-14 10:56:49 -0700613 /* find client id and table */
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800614 i = diag_dci_find_client_index(current->tgid);
615 if (i == DCI_CLIENT_INDEX_INVALID) {
Shalabh Jain16794902012-09-14 10:56:49 -0700616 pr_err("diag: dci client not registered/found\n");
617 return ret;
618 }
619 /* Extract each log code and put in client table */
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700620 temp += sizeof(int);
621 read_len += sizeof(int);
Shalabh Jain16794902012-09-14 10:56:49 -0700622 set_mask = *(int *)temp;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700623 temp += sizeof(int);
624 read_len += sizeof(int);
Shalabh Jain16794902012-09-14 10:56:49 -0700625 num_codes = *(int *)temp;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700626 temp += sizeof(int);
627 read_len += sizeof(int);
628
629 if (num_codes == 0 || (num_codes >= (USER_SPACE_DATA - 8)/2)) {
630 pr_err("diag: dci: Invalid number of log codes %d\n",
631 num_codes);
632 return -EIO;
633 }
Shalabh Jain16794902012-09-14 10:56:49 -0700634
635 head_log_mask_ptr = driver->dci_client_tbl[i].dci_log_mask;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700636 if (!head_log_mask_ptr) {
637 pr_err("diag: dci: Invalid Log mask pointer in %s\n",
638 __func__);
639 return -ENOMEM;
640 }
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700641 pr_debug("diag: head of dci log mask %p\n", head_log_mask_ptr);
Shalabh Jain16794902012-09-14 10:56:49 -0700642 count = 0; /* iterator for extracting log codes */
643 while (count < num_codes) {
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800644 if (read_len >= USER_SPACE_DATA) {
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700645 pr_err("diag: dci: Invalid length for log type in %s",
646 __func__);
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800647 return -EIO;
648 }
Shalabh Jain16794902012-09-14 10:56:49 -0700649 log_code = *(uint16_t *)temp;
650 equip_id = LOG_GET_EQUIP_ID(log_code);
651 item_num = LOG_GET_ITEM_NUM(log_code);
652 byte_index = item_num/8 + 2;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800653 if (byte_index >= (DCI_MAX_ITEMS_PER_LOG_CODE+2)) {
654 pr_err("diag: dci: Log type, invalid byte index\n");
655 return ret;
656 }
Shalabh Jain16794902012-09-14 10:56:49 -0700657 byte_mask = 0x01 << (item_num % 8);
658 /*
659 * Parse through log mask table and find
660 * relevant range
661 */
662 log_mask_ptr = head_log_mask_ptr;
663 found = 0;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800664 offset = 0;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800665 while (log_mask_ptr && (offset < DCI_LOG_MASK_SIZE)) {
Shalabh Jain16794902012-09-14 10:56:49 -0700666 if (*log_mask_ptr == equip_id) {
667 found = 1;
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700668 pr_debug("diag: find equip id = %x at %p\n",
Shalabh Jain16794902012-09-14 10:56:49 -0700669 equip_id, log_mask_ptr);
670 break;
671 } else {
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700672 pr_debug("diag: did not find equip id = %x at %p\n",
Shalabh Jain16794902012-09-14 10:56:49 -0700673 equip_id, log_mask_ptr);
674 log_mask_ptr += 514;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800675 offset += 514;
Shalabh Jain16794902012-09-14 10:56:49 -0700676 }
677 }
678 if (!found) {
679 pr_err("diag: dci equip id not found\n");
680 return ret;
681 }
682 *(log_mask_ptr+1) = 1; /* set the dirty byte */
683 log_mask_ptr = log_mask_ptr + byte_index;
684 if (set_mask)
685 *log_mask_ptr |= byte_mask;
686 else
687 *log_mask_ptr &= ~byte_mask;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800688 /* add to cumulative mask */
689 update_dci_cumulative_log_mask(
690 offset, byte_index,
691 byte_mask);
Shalabh Jain16794902012-09-14 10:56:49 -0700692 temp += 2;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800693 read_len += 2;
Shalabh Jain16794902012-09-14 10:56:49 -0700694 count++;
695 ret = DIAG_DCI_NO_ERROR;
696 }
Shalabh Jain16794902012-09-14 10:56:49 -0700697 /* send updated mask to peripherals */
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800698 ret = diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
Shalabh Jain16794902012-09-14 10:56:49 -0700699 } else if (*(int *)temp == DCI_EVENT_TYPE) {
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700700 /* Minimum length of a event mask config is 12 + 4 bytes for
701 atleast one event id to be set or reset. */
702 if (len < DCI_EVENT_CON_MIN_LEN || len > USER_SPACE_DATA) {
703 pr_err("diag: dci: Invalid length in %s\n", __func__);
704 return -EIO;
705 }
Shalabh Jain16794902012-09-14 10:56:49 -0700706 /* find client id and table */
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800707 i = diag_dci_find_client_index(current->tgid);
708 if (i == DCI_CLIENT_INDEX_INVALID) {
Shalabh Jain16794902012-09-14 10:56:49 -0700709 pr_err("diag: dci client not registered/found\n");
710 return ret;
711 }
712 /* Extract each log code and put in client table */
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700713 temp += sizeof(int);
714 read_len += sizeof(int);
Shalabh Jain16794902012-09-14 10:56:49 -0700715 set_mask = *(int *)temp;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700716 temp += sizeof(int);
717 read_len += sizeof(int);
Shalabh Jain16794902012-09-14 10:56:49 -0700718 num_codes = *(int *)temp;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700719 temp += sizeof(int);
720 read_len += sizeof(int);
721
722 /* Check for positive number of event ids. Also, the number of
723 event ids should fit in the buffer along with set_mask and
724 num_codes which are 4 bytes each */
725 if (num_codes == 0 || (num_codes >= (USER_SPACE_DATA - 8)/2)) {
726 pr_err("diag: dci: Invalid number of event ids %d\n",
727 num_codes);
728 return -EIO;
729 }
Shalabh Jain16794902012-09-14 10:56:49 -0700730
731 event_mask_ptr = driver->dci_client_tbl[i].dci_event_mask;
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700732 if (!event_mask_ptr) {
733 pr_err("diag: dci: Invalid event mask pointer in %s\n",
734 __func__);
735 return -ENOMEM;
736 }
Shalabh Jain16794902012-09-14 10:56:49 -0700737 pr_debug("diag: head of dci event mask %p\n", event_mask_ptr);
738 count = 0; /* iterator for extracting log codes */
739 while (count < num_codes) {
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800740 if (read_len >= USER_SPACE_DATA) {
Ravi Aravamudhanb77c6942013-06-04 10:10:11 -0700741 pr_err("diag: dci: Invalid length for event type in %s",
742 __func__);
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800743 return -EIO;
744 }
Shalabh Jain16794902012-09-14 10:56:49 -0700745 event_id = *(int *)temp;
746 byte_index = event_id/8;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800747 if (byte_index >= DCI_EVENT_MASK_SIZE) {
748 pr_err("diag: dci: Event type, invalid byte index\n");
749 return ret;
750 }
Shalabh Jain16794902012-09-14 10:56:49 -0700751 bit_index = event_id % 8;
752 byte_mask = 0x1 << bit_index;
753 /*
754 * Parse through event mask table and set
755 * relevant byte & bit combination
756 */
757 if (set_mask)
758 *(event_mask_ptr + byte_index) |= byte_mask;
759 else
760 *(event_mask_ptr + byte_index) &= ~byte_mask;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800761 /* add to cumulative mask */
762 update_dci_cumulative_event_mask(byte_index, byte_mask);
Shalabh Jain16794902012-09-14 10:56:49 -0700763 temp += sizeof(int);
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800764 read_len += sizeof(int);
Shalabh Jain16794902012-09-14 10:56:49 -0700765 count++;
766 ret = DIAG_DCI_NO_ERROR;
767 }
Shalabh Jain16794902012-09-14 10:56:49 -0700768 /* send updated mask to peripherals */
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800769 ret = diag_send_dci_event_mask(driver->smd_cntl[MODEM_DATA].ch);
Shalabh Jain16794902012-09-14 10:56:49 -0700770 } else {
771 pr_alert("diag: Incorrect DCI transaction\n");
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700772 }
773 return ret;
774}
775
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800776int diag_dci_find_client_index(int client_id)
777{
778 int i, ret = DCI_CLIENT_INDEX_INVALID;
779
780 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
781 if (driver->dci_client_tbl[i].client != NULL) {
782 if (driver->dci_client_tbl[i].client->tgid ==
783 client_id) {
784 ret = i;
785 break;
786 }
787 }
788 }
789 return ret;
790}
791
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800792void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask)
Shalabh Jain16794902012-09-14 10:56:49 -0700793{
794 int i;
Shalabh Jain16794902012-09-14 10:56:49 -0700795 uint8_t *event_mask_ptr;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800796 uint8_t *update_ptr = dci_cumulative_event_mask;
797 bool is_set = false;
Shalabh Jain16794902012-09-14 10:56:49 -0700798
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700799 mutex_lock(&dci_event_mask_mutex);
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800800 update_ptr += offset;
801 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
802 event_mask_ptr =
803 driver->dci_client_tbl[i].dci_event_mask;
804 event_mask_ptr += offset;
805 if ((*event_mask_ptr & byte_mask) == byte_mask) {
806 is_set = true;
807 /* break even if one client has the event mask set */
808 break;
809 }
810 }
811 if (is_set == false)
812 *update_ptr &= ~byte_mask;
813 else
814 *update_ptr |= byte_mask;
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700815 mutex_unlock(&dci_event_mask_mutex);
Shalabh Jain16794902012-09-14 10:56:49 -0700816}
817
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800818void clear_client_dci_cumulative_event_mask(int client_index)
819{
820 int i, j;
821 uint8_t *update_ptr = dci_cumulative_event_mask;
822 uint8_t *event_mask_ptr, *client_event_mask_ptr, byte_mask = 0;
823 bool is_set = false;
824
825 event_mask_ptr =
826 (driver->dci_client_tbl[client_index].dci_event_mask);
827
828 mutex_lock(&dci_event_mask_mutex);
829 for (i = 0; i < DCI_EVENT_MASK_SIZE; i++) {
830 is_set = false;
831 /* Already cleared event masks need not to be considered */
832 if (*event_mask_ptr != 0) {
833 byte_mask = *event_mask_ptr;
834 } else {
835 update_ptr++;
836 event_mask_ptr++;
837 continue;
838 }
839 for (j = 0; j < MAX_DCI_CLIENTS; j++) {
840 /* continue searching for valid client */
841 if (driver->dci_client_tbl[j].client == NULL ||
842 client_index == j)
843 continue;
844 client_event_mask_ptr =
845 (driver->dci_client_tbl[j].dci_event_mask);
846 client_event_mask_ptr += i;
847 if (*client_event_mask_ptr & byte_mask) {
848 /*
849 * Break if another client has same
850 * event mask set
851 */
852 if ((*client_event_mask_ptr &
853 byte_mask) == byte_mask) {
854 is_set = true;
855 break;
856 } else {
857 byte_mask =
858 (~(*client_event_mask_ptr) &
859 byte_mask);
860 is_set = false;
861 }
862 }
863 }
864 /*
865 * Clear only if this client has event mask set else
866 * don't update cumulative event mask ptr
867 */
868 if (is_set == false)
869 *update_ptr &= ~byte_mask;
870
871 update_ptr++;
872 event_mask_ptr++;
873 }
874 event_mask_ptr =
875 (driver->dci_client_tbl[client_index].dci_event_mask);
876 memset(event_mask_ptr, 0, DCI_EVENT_MASK_SIZE);
877 mutex_unlock(&dci_event_mask_mutex);
878}
879
880
Dixon Peterson5a26a302012-11-15 17:26:17 -0800881int diag_send_dci_event_mask(smd_channel_t *ch)
Shalabh Jain16794902012-09-14 10:56:49 -0700882{
883 void *buf = driver->buf_event_mask_update;
884 int header_size = sizeof(struct diag_ctrl_event_mask);
885 int wr_size = -ENOMEM, retry_count = 0, timer;
Dixon Peterson5a26a302012-11-15 17:26:17 -0800886 int ret = DIAG_DCI_NO_ERROR;
Shalabh Jain16794902012-09-14 10:56:49 -0700887
888 mutex_lock(&driver->diag_cntl_mutex);
889 /* send event mask update */
890 driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
891 driver->event_mask->data_len = 7 + DCI_EVENT_MASK_SIZE;
892 driver->event_mask->stream_id = DCI_MASK_STREAM;
893 driver->event_mask->status = 3; /* status for valid mask */
894 driver->event_mask->event_config = 1; /* event config */
895 driver->event_mask->event_mask_size = DCI_EVENT_MASK_SIZE;
896 memcpy(buf, driver->event_mask, header_size);
897 memcpy(buf+header_size, dci_cumulative_event_mask, DCI_EVENT_MASK_SIZE);
898 if (ch) {
899 while (retry_count < 3) {
900 wr_size = smd_write(ch, buf,
901 header_size + DCI_EVENT_MASK_SIZE);
902 if (wr_size == -ENOMEM) {
903 retry_count++;
904 for (timer = 0; timer < 5; timer++)
905 udelay(2000);
906 } else {
907 break;
908 }
909 }
Dixon Peterson5a26a302012-11-15 17:26:17 -0800910 if (wr_size != header_size + DCI_EVENT_MASK_SIZE) {
Shalabh Jain16794902012-09-14 10:56:49 -0700911 pr_err("diag: error writing dci event mask %d, tried %d\n",
912 wr_size, header_size + DCI_EVENT_MASK_SIZE);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800913 ret = DIAG_DCI_SEND_DATA_FAIL;
914 }
915 } else {
Shalabh Jain16794902012-09-14 10:56:49 -0700916 pr_err("diag: ch not valid for dci event mask update\n");
Dixon Peterson5a26a302012-11-15 17:26:17 -0800917 ret = DIAG_DCI_SEND_DATA_FAIL;
918 }
Shalabh Jain16794902012-09-14 10:56:49 -0700919 mutex_unlock(&driver->diag_cntl_mutex);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800920
921 return ret;
Shalabh Jain16794902012-09-14 10:56:49 -0700922}
923
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800924void update_dci_cumulative_log_mask(int offset, unsigned int byte_index,
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800925 uint8_t byte_mask)
Shalabh Jain16794902012-09-14 10:56:49 -0700926{
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800927 int i;
Shalabh Jain16794902012-09-14 10:56:49 -0700928 uint8_t *update_ptr = dci_cumulative_log_mask;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800929 uint8_t *log_mask_ptr;
930 bool is_set = false;
Shalabh Jain16794902012-09-14 10:56:49 -0700931
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700932 mutex_lock(&dci_log_mask_mutex);
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800933 *update_ptr = 0;
934 /* set the equipment IDs */
935 for (i = 0; i < 16; i++)
936 *(update_ptr + (i*514)) = i;
937
938 update_ptr += offset;
939 /* update the dirty bit */
940 *(update_ptr+1) = 1;
941 update_ptr = update_ptr + byte_index;
942 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
943 log_mask_ptr =
944 (driver->dci_client_tbl[i].dci_log_mask);
945 log_mask_ptr = log_mask_ptr + offset + byte_index;
946 if ((*log_mask_ptr & byte_mask) == byte_mask) {
947 is_set = true;
948 /* break even if one client has the log mask set */
949 break;
Shalabh Jain16794902012-09-14 10:56:49 -0700950 }
Shalabh Jain16794902012-09-14 10:56:49 -0700951 }
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800952
953 if (is_set == false)
954 *update_ptr &= ~byte_mask;
955 else
956 *update_ptr |= byte_mask;
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700957 mutex_unlock(&dci_log_mask_mutex);
Shalabh Jain16794902012-09-14 10:56:49 -0700958}
959
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800960void clear_client_dci_cumulative_log_mask(int client_index)
961{
962 int i, j, k;
963 uint8_t *update_ptr = dci_cumulative_log_mask;
964 uint8_t *log_mask_ptr, *client_log_mask_ptr, byte_mask = 0;
965 bool is_set = false;
966
967 log_mask_ptr = driver->dci_client_tbl[client_index].dci_log_mask;
968
969 mutex_lock(&dci_log_mask_mutex);
970 *update_ptr = 0;
971 /* set the equipment IDs */
972 for (i = 0; i < 16; i++)
973 *(update_ptr + (i*514)) = i;
974
975 /* update cumulative log mask ptr*/
976 update_ptr += 2;
977 log_mask_ptr += 2;
978 for (i = 0; i < 16; i++) {
979 for (j = 0; j < 512; j++) {
980 is_set = false;
981 /*
982 * Already cleared log masks need
983 * not to be considered
984 */
985 if (*log_mask_ptr != 0) {
986 byte_mask = *log_mask_ptr;
987 } else {
988 update_ptr++;
989 log_mask_ptr++;
990 continue;
991 }
992 for (k = 0; k < MAX_DCI_CLIENTS; k++) {
993 /* continue searching for valid client */
994 if (driver->dci_client_tbl[k].client == NULL ||
995 client_index == k)
996 continue;
997 client_log_mask_ptr =
998 (driver->dci_client_tbl[k].dci_log_mask);
999 client_log_mask_ptr += (i*514) + 2 + j;
1000 if (*client_log_mask_ptr & byte_mask) {
1001 /*
1002 * Break if another client has same
1003 * log mask set
1004 */
1005 if ((*client_log_mask_ptr &
1006 byte_mask) == byte_mask) {
1007 is_set = true;
1008 break;
1009 } else {
1010 byte_mask =
1011 (~(*client_log_mask_ptr) &
1012 byte_mask);
1013 is_set = false;
1014 }
1015 }
1016 }
1017 /*
1018 * Clear only if this client has log mask set else
1019 * don't update cumulative log mask ptr
1020 */
1021 if (is_set == false) {
1022 /*
1023 * Update the dirty bit for the equipment
1024 * whose mask is changing
1025 */
1026 dci_cumulative_log_mask[1+(i*514)] = 1;
1027 *update_ptr &= ~byte_mask;
1028 }
1029
1030 update_ptr++;
1031 log_mask_ptr++;
1032 }
1033 update_ptr += 2;
1034 log_mask_ptr += 2;
1035 }
1036 log_mask_ptr = driver->dci_client_tbl[client_index].dci_log_mask;
1037 memset(log_mask_ptr, 0, DCI_LOG_MASK_SIZE);
1038 mutex_unlock(&dci_log_mask_mutex);
1039}
1040
Dixon Peterson5a26a302012-11-15 17:26:17 -08001041int diag_send_dci_log_mask(smd_channel_t *ch)
Shalabh Jain16794902012-09-14 10:56:49 -07001042{
1043 void *buf = driver->buf_log_mask_update;
1044 int header_size = sizeof(struct diag_ctrl_log_mask);
1045 uint8_t *log_mask_ptr = dci_cumulative_log_mask;
1046 int i, wr_size = -ENOMEM, retry_count = 0, timer;
Dixon Peterson5a26a302012-11-15 17:26:17 -08001047 int ret = DIAG_DCI_NO_ERROR;
1048
1049 if (!ch) {
1050 pr_err("diag: ch not valid for dci log mask update\n");
1051 return DIAG_DCI_SEND_DATA_FAIL;
1052 }
Shalabh Jain16794902012-09-14 10:56:49 -07001053
1054 mutex_lock(&driver->diag_cntl_mutex);
1055 for (i = 0; i < 16; i++) {
Ravi Aravamudhan3365bc02013-03-05 16:51:28 -08001056 retry_count = 0;
Shalabh Jain16794902012-09-14 10:56:49 -07001057 driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
1058 driver->log_mask->num_items = 512;
1059 driver->log_mask->data_len = 11 + 512;
1060 driver->log_mask->stream_id = DCI_MASK_STREAM;
1061 driver->log_mask->status = 3; /* status for valid mask */
1062 driver->log_mask->equip_id = *log_mask_ptr;
1063 driver->log_mask->log_mask_size = 512;
1064 memcpy(buf, driver->log_mask, header_size);
1065 memcpy(buf+header_size, log_mask_ptr+2, 512);
1066 /* if dirty byte is set and channel is valid */
1067 if (ch && *(log_mask_ptr+1)) {
1068 while (retry_count < 3) {
1069 wr_size = smd_write(ch, buf, header_size + 512);
1070 if (wr_size == -ENOMEM) {
1071 retry_count++;
1072 for (timer = 0; timer < 5; timer++)
1073 udelay(2000);
1074 } else
1075 break;
1076 }
Dixon Peterson5a26a302012-11-15 17:26:17 -08001077 if (wr_size != header_size + 512) {
Ravi Aravamudhan3365bc02013-03-05 16:51:28 -08001078 pr_err("diag: dci log mask update failed %d, tried %d for equip_id %d\n",
1079 wr_size, header_size + 512,
1080 driver->log_mask->equip_id);
Dixon Peterson5a26a302012-11-15 17:26:17 -08001081 ret = DIAG_DCI_SEND_DATA_FAIL;
1082
1083 } else {
Shalabh Jain16794902012-09-14 10:56:49 -07001084 *(log_mask_ptr+1) = 0; /* clear dirty byte */
1085 pr_debug("diag: updated dci log equip ID %d\n",
1086 *log_mask_ptr);
1087 }
1088 }
1089 log_mask_ptr += 514;
1090 }
1091 mutex_unlock(&driver->diag_cntl_mutex);
Dixon Peterson5a26a302012-11-15 17:26:17 -08001092
1093 return ret;
Shalabh Jain16794902012-09-14 10:56:49 -07001094}
1095
1096void create_dci_log_mask_tbl(unsigned char *tbl_buf)
1097{
1098 uint8_t i; int count = 0;
1099
1100 /* create hard coded table for log mask with 16 categories */
1101 for (i = 0; i < 16; i++) {
1102 *(uint8_t *)tbl_buf = i;
1103 pr_debug("diag: put value %x at %p\n", i, tbl_buf);
1104 memset(tbl_buf+1, 0, 513); /* set dirty bit as 0 */
1105 tbl_buf += 514;
1106 count += 514;
1107 }
1108}
1109
1110void create_dci_event_mask_tbl(unsigned char *tbl_buf)
1111{
1112 memset(tbl_buf, 0, 512);
1113}
1114
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001115static int diag_dci_probe(struct platform_device *pdev)
1116{
1117 int err = 0;
1118 int index;
1119
1120 if (pdev->id == SMD_APPS_MODEM) {
1121 index = MODEM_DATA;
1122 err = smd_open("DIAG_2",
1123 &driver->smd_dci[index].ch,
1124 &driver->smd_dci[index],
1125 diag_smd_notify);
1126 driver->smd_dci[index].ch_save =
1127 driver->smd_dci[index].ch;
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07001128 driver->dci_device = &pdev->dev;
1129 driver->dci_device->power.wakeup = wakeup_source_register
1130 ("DIAG_DCI_WS");
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001131 if (err)
1132 pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
1133 __func__, pdev->id, err);
1134 }
1135
1136 return err;
1137}
1138
1139static int diag_dci_cmd_probe(struct platform_device *pdev)
1140{
1141 int err = 0;
1142 int index;
1143
1144 if (pdev->id == SMD_APPS_MODEM) {
1145 index = MODEM_DATA;
1146 err = smd_named_open_on_edge("DIAG_2_CMD",
1147 pdev->id,
1148 &driver->smd_dci_cmd[index].ch,
1149 &driver->smd_dci_cmd[index],
1150 diag_smd_notify);
1151 driver->smd_dci_cmd[index].ch_save =
1152 driver->smd_dci_cmd[index].ch;
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07001153 driver->dci_cmd_device = &pdev->dev;
1154 driver->dci_cmd_device->power.wakeup = wakeup_source_register
1155 ("DIAG_DCI_CMD_WS");
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001156 if (err)
1157 pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
1158 __func__, pdev->id, err);
1159 }
1160
1161 return err;
1162}
1163
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001164static int diag_dci_runtime_suspend(struct device *dev)
1165{
1166 dev_dbg(dev, "pm_runtime: suspending...\n");
1167 return 0;
1168}
1169
1170static int diag_dci_runtime_resume(struct device *dev)
1171{
1172 dev_dbg(dev, "pm_runtime: resuming...\n");
1173 return 0;
1174}
1175
1176static const struct dev_pm_ops diag_dci_dev_pm_ops = {
1177 .runtime_suspend = diag_dci_runtime_suspend,
1178 .runtime_resume = diag_dci_runtime_resume,
1179};
1180
1181struct platform_driver msm_diag_dci_driver = {
1182 .probe = diag_dci_probe,
1183 .driver = {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001184 .name = "DIAG_2",
1185 .owner = THIS_MODULE,
1186 .pm = &diag_dci_dev_pm_ops,
1187 },
1188};
1189
1190struct platform_driver msm_diag_dci_cmd_driver = {
1191 .probe = diag_dci_cmd_probe,
1192 .driver = {
1193 .name = "DIAG_2_CMD",
1194 .owner = THIS_MODULE,
1195 .pm = &diag_dci_dev_pm_ops,
Shalabh Jain16794902012-09-14 10:56:49 -07001196 },
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001197};
1198
1199int diag_dci_init(void)
1200{
1201 int success = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001202 int i;
Dixon Peterson5a26a302012-11-15 17:26:17 -08001203
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001204 driver->dci_tag = 0;
1205 driver->dci_client_id = 0;
1206 driver->num_dci_client = 0;
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07001207 driver->dci_device = NULL;
1208 driver->dci_cmd_device = NULL;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001209 mutex_init(&driver->dci_mutex);
Shalabh Jaina1c69a42012-10-23 12:51:30 -07001210 mutex_init(&dci_log_mask_mutex);
1211 mutex_init(&dci_event_mask_mutex);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301212 mutex_init(&dci_health_mutex);
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07001213 spin_lock_init(&ws_lock);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301214
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -08001215 for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001216 success = diag_smd_constructor(&driver->smd_dci[i], i,
1217 SMD_DCI_TYPE);
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -08001218 if (!success)
1219 goto err;
1220 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001221
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001222 if (driver->supports_separate_cmdrsp) {
1223 for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++) {
1224 success = diag_smd_constructor(&driver->smd_dci_cmd[i],
1225 i, SMD_DCI_CMD_TYPE);
1226 if (!success)
1227 goto err;
1228 }
1229 }
1230
Shalabh Jain16794902012-09-14 10:56:49 -07001231 if (driver->req_tracking_tbl == NULL) {
1232 driver->req_tracking_tbl = kzalloc(dci_max_reg *
1233 sizeof(struct dci_pkt_req_tracking_tbl), GFP_KERNEL);
1234 if (driver->req_tracking_tbl == NULL)
Shalabh Jain5e9a92b2012-06-07 21:53:49 -07001235 goto err;
1236 }
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001237 if (driver->apps_dci_buf == NULL) {
1238 driver->apps_dci_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
1239 if (driver->apps_dci_buf == NULL)
1240 goto err;
1241 }
Shalabh Jain16794902012-09-14 10:56:49 -07001242 if (driver->dci_client_tbl == NULL) {
1243 driver->dci_client_tbl = kzalloc(MAX_DCI_CLIENTS *
1244 sizeof(struct diag_dci_client_tbl), GFP_KERNEL);
1245 if (driver->dci_client_tbl == NULL)
1246 goto err;
1247 }
1248 driver->diag_dci_wq = create_singlethread_workqueue("diag_dci_wq");
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001249 success = platform_driver_register(&msm_diag_dci_driver);
1250 if (success) {
1251 pr_err("diag: Could not register DCI driver\n");
1252 goto err;
1253 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001254 if (driver->supports_separate_cmdrsp) {
1255 success = platform_driver_register(&msm_diag_dci_cmd_driver);
1256 if (success) {
1257 pr_err("diag: Could not register DCI cmd driver\n");
1258 goto err;
1259 }
1260 }
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001261 return DIAG_DCI_NO_ERROR;
1262err:
1263 pr_err("diag: Could not initialize diag DCI buffers");
Shalabh Jain16794902012-09-14 10:56:49 -07001264 kfree(driver->req_tracking_tbl);
1265 kfree(driver->dci_client_tbl);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001266 kfree(driver->apps_dci_buf);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001267 for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
1268 diag_smd_destructor(&driver->smd_dci[i]);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001269
1270 if (driver->supports_separate_cmdrsp)
1271 for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
1272 diag_smd_destructor(&driver->smd_dci_cmd[i]);
1273
Shalabh Jain16794902012-09-14 10:56:49 -07001274 if (driver->diag_dci_wq)
1275 destroy_workqueue(driver->diag_dci_wq);
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001276 mutex_destroy(&driver->dci_mutex);
1277 mutex_destroy(&dci_log_mask_mutex);
1278 mutex_destroy(&dci_event_mask_mutex);
1279 mutex_destroy(&dci_health_mutex);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001280 return DIAG_DCI_NO_REG;
1281}
1282
1283void diag_dci_exit(void)
1284{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001285 int i;
1286
1287 for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
1288 diag_smd_destructor(&driver->smd_dci[i]);
1289
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001290 platform_driver_unregister(&msm_diag_dci_driver);
Dixon Peterson6dba7572013-04-12 18:45:16 -07001291
1292 if (driver->dci_client_tbl) {
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -07001293 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
Dixon Peterson6dba7572013-04-12 18:45:16 -07001294 kfree(driver->dci_client_tbl[i].dci_data);
Ravi Aravamudhan618cb2e2013-06-12 18:48:41 -07001295 mutex_destroy(&driver->dci_client_tbl[i].data_mutex);
1296 }
Dixon Peterson6dba7572013-04-12 18:45:16 -07001297 }
1298
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001299 if (driver->supports_separate_cmdrsp) {
1300 for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
1301 diag_smd_destructor(&driver->smd_dci_cmd[i]);
1302
1303 platform_driver_unregister(&msm_diag_dci_cmd_driver);
1304 }
Shalabh Jain16794902012-09-14 10:56:49 -07001305 kfree(driver->req_tracking_tbl);
1306 kfree(driver->dci_client_tbl);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001307 kfree(driver->apps_dci_buf);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301308 mutex_destroy(&driver->dci_mutex);
1309 mutex_destroy(&dci_log_mask_mutex);
1310 mutex_destroy(&dci_event_mask_mutex);
1311 mutex_destroy(&dci_health_mutex);
Shalabh Jain16794902012-09-14 10:56:49 -07001312 destroy_workqueue(driver->diag_dci_wq);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001313}
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301314
1315int diag_dci_clear_log_mask()
1316{
1317 int i, j, k, err = DIAG_DCI_NO_ERROR;
1318 uint8_t *log_mask_ptr, *update_ptr;
1319
1320 i = diag_dci_find_client_index(current->tgid);
1321 if (i == DCI_CLIENT_INDEX_INVALID)
1322 return DIAG_DCI_TABLE_ERR;
1323
1324 mutex_lock(&dci_log_mask_mutex);
1325 create_dci_log_mask_tbl(
1326 driver->dci_client_tbl[i].dci_log_mask);
1327 memset(dci_cumulative_log_mask,
1328 0x0, DCI_LOG_MASK_SIZE);
1329 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
1330 update_ptr = dci_cumulative_log_mask;
1331 if (driver->dci_client_tbl[i].client) {
1332 log_mask_ptr =
1333 driver->dci_client_tbl[i].dci_log_mask;
1334 for (j = 0; j < 16; j++) {
1335 *update_ptr = j;
1336 *(update_ptr + 1) = 1;
1337 update_ptr += 2;
1338 log_mask_ptr += 2;
1339 for (k = 0; k < 513; k++) {
1340 *update_ptr |= *log_mask_ptr;
1341 update_ptr++;
1342 log_mask_ptr++;
1343 }
1344 }
1345 }
1346 }
1347 mutex_unlock(&dci_log_mask_mutex);
1348 err = diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
1349 return err;
1350}
1351
1352int diag_dci_clear_event_mask()
1353{
1354 int i, j, err = DIAG_DCI_NO_ERROR;
1355 uint8_t *event_mask_ptr, *update_ptr;
1356
1357 i = diag_dci_find_client_index(current->tgid);
1358 if (i == DCI_CLIENT_INDEX_INVALID)
1359 return DIAG_DCI_TABLE_ERR;
1360
1361 mutex_lock(&dci_event_mask_mutex);
1362 memset(driver->dci_client_tbl[i].dci_event_mask,
1363 0x0, DCI_EVENT_MASK_SIZE);
1364 memset(dci_cumulative_event_mask,
1365 0x0, DCI_EVENT_MASK_SIZE);
1366 update_ptr = dci_cumulative_event_mask;
1367 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
1368 event_mask_ptr =
1369 driver->dci_client_tbl[i].dci_event_mask;
1370 for (j = 0; j < DCI_EVENT_MASK_SIZE; j++)
1371 *(update_ptr + j) |= *(event_mask_ptr + j);
1372 }
1373 mutex_unlock(&dci_event_mask_mutex);
1374 err = diag_send_dci_event_mask(driver->smd_cntl[MODEM_DATA].ch);
1375 return err;
1376}
1377
1378int diag_dci_query_log_mask(uint16_t log_code)
1379{
1380 uint16_t item_num;
1381 uint8_t equip_id, *log_mask_ptr, byte_mask;
1382 int i, byte_index, offset;
1383
1384 equip_id = LOG_GET_EQUIP_ID(log_code);
1385 item_num = LOG_GET_ITEM_NUM(log_code);
1386 byte_index = item_num/8 + 2;
1387 byte_mask = 0x01 << (item_num % 8);
1388 offset = equip_id * 514;
1389
1390 i = diag_dci_find_client_index(current->tgid);
1391 if (i != DCI_CLIENT_INDEX_INVALID) {
1392 log_mask_ptr = driver->dci_client_tbl[i].dci_log_mask;
1393 log_mask_ptr = log_mask_ptr + offset + byte_index;
1394 return ((*log_mask_ptr & byte_mask) == byte_mask) ?
1395 1 : 0;
1396 }
1397 return 0;
1398}
1399
1400
1401int diag_dci_query_event_mask(uint16_t event_id)
1402{
1403 uint8_t *event_mask_ptr, byte_mask;
1404 int i, byte_index, bit_index;
1405 byte_index = event_id/8;
1406 bit_index = event_id % 8;
1407 byte_mask = 0x1 << bit_index;
1408
1409 i = diag_dci_find_client_index(current->tgid);
1410 if (i != DCI_CLIENT_INDEX_INVALID) {
1411 event_mask_ptr =
1412 driver->dci_client_tbl[i].dci_event_mask;
1413 event_mask_ptr = event_mask_ptr + byte_index;
1414 if ((*event_mask_ptr & byte_mask) == byte_mask)
1415 return 1;
1416 else
1417 return 0;
1418 }
1419 return 0;
1420}
1421
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001422uint8_t diag_dci_get_cumulative_real_time()
1423{
1424 uint8_t real_time = MODE_NONREALTIME, i;
1425 for (i = 0; i < MAX_DCI_CLIENTS; i++)
1426 if (driver->dci_client_tbl[i].client &&
1427 driver->dci_client_tbl[i].real_time ==
1428 MODE_REALTIME) {
1429 real_time = 1;
1430 break;
1431 }
1432 return real_time;
1433}
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301434
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001435int diag_dci_set_real_time(int client_id, uint8_t real_time)
1436{
1437 int i = DCI_CLIENT_INDEX_INVALID;
1438 i = diag_dci_find_client_index(client_id);
1439
1440 if (i != DCI_CLIENT_INDEX_INVALID)
1441 driver->dci_client_tbl[i].real_time = real_time;
1442 return i;
1443}
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07001444
1445void diag_dci_try_activate_wakeup_source(smd_channel_t *channel)
1446{
1447 spin_lock_irqsave(&ws_lock, ws_lock_flags);
1448 if (channel == driver->smd_dci[MODEM_DATA].ch) {
1449 pm_wakeup_event(driver->dci_device, DCI_WAKEUP_TIMEOUT);
1450 pm_stay_awake(driver->dci_device);
1451 } else if (channel == driver->smd_dci_cmd[MODEM_DATA].ch) {
1452 pm_wakeup_event(driver->dci_cmd_device, DCI_WAKEUP_TIMEOUT);
1453 pm_stay_awake(driver->dci_cmd_device);
1454 }
1455 spin_unlock_irqrestore(&ws_lock, ws_lock_flags);
1456}
1457
1458void diag_dci_try_deactivate_wakeup_source(smd_channel_t *channel)
1459{
1460 spin_lock_irqsave(&ws_lock, ws_lock_flags);
1461 if (channel == driver->smd_dci[MODEM_DATA].ch)
1462 pm_relax(driver->dci_device);
1463 else if (channel == driver->smd_dci_cmd[MODEM_DATA].ch)
1464 pm_relax(driver->dci_cmd_device);
1465 spin_unlock_irqrestore(&ws_lock, ws_lock_flags);
1466}