blob: 6ae5d031309e462335c2302840fa2bd77622e91b [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>
23#include <asm/current.h>
24#ifdef CONFIG_DIAG_OVER_USB
25#include <mach/usbdiag.h>
26#endif
27#include "diagchar_hdlc.h"
28#include "diagmem.h"
29#include "diagchar.h"
30#include "diagfwd.h"
Shalabh Jain16794902012-09-14 10:56:49 -070031#include "diagfwd_cntl.h"
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070032#include "diag_dci.h"
33
34unsigned int dci_max_reg = 100;
35unsigned int dci_max_clients = 10;
Shalabh Jain16794902012-09-14 10:56:49 -070036unsigned char dci_cumulative_log_mask[DCI_LOG_MASK_SIZE];
37unsigned char dci_cumulative_event_mask[DCI_EVENT_MASK_SIZE];
Shalabh Jaina1c69a42012-10-23 12:51:30 -070038struct mutex dci_log_mask_mutex;
39struct mutex dci_event_mask_mutex;
Shalabh Jain16794902012-09-14 10:56:49 -070040
41#define DCI_CHK_CAPACITY(entry, new_data_len) \
42((entry->data_len + new_data_len > entry->total_capacity) ? 1 : 0) \
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070043
Dixon Peterson66fb11b2012-12-04 20:30:54 -080044/* Process the data read from the smd dci channel */
45int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf,
46 int recd_bytes)
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070047{
Dixon Peterson66fb11b2012-12-04 20:30:54 -080048 int read_bytes, dci_pkt_len, i;
Shalabh Jain16794902012-09-14 10:56:49 -070049 uint8_t recv_pkt_cmd_code;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070050
Dixon Peterson66fb11b2012-12-04 20:30:54 -080051 /* Each SMD read can have multiple DCI packets */
52 read_bytes = 0;
53 while (read_bytes < recd_bytes) {
54 /* read actual length of dci pkt */
55 dci_pkt_len = *(uint16_t *)(buf+2);
56 /* process one dci packet */
57 pr_debug("diag: bytes read = %d, single dci pkt len = %d\n",
58 read_bytes, dci_pkt_len);
59 /* print_hex_dump(KERN_DEBUG, "Single DCI packet :",
60 DUMP_PREFIX_ADDRESS, 16, 1, buf, 5 + dci_pkt_len, 1);*/
61 recv_pkt_cmd_code = *(uint8_t *)(buf+4);
62 if (recv_pkt_cmd_code == LOG_CMD_CODE)
63 extract_dci_log(buf+4);
64 else if (recv_pkt_cmd_code == EVENT_CMD_CODE)
65 extract_dci_events(buf+4);
66 else
67 extract_dci_pkt_rsp(buf); /* pkt response */
68 read_bytes += 5 + dci_pkt_len;
69 buf += 5 + dci_pkt_len; /* advance to next DCI pkt */
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070070 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -080071 /* wake up all sleeping DCI clients which have some data */
72 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
73 if (driver->dci_client_tbl[i].client &&
74 driver->dci_client_tbl[i].data_len) {
75 smd_info->in_busy_1 = 1;
76 diag_update_sleeping_process(
77 driver->dci_client_tbl[i].client->tgid,
78 DCI_DATA_TYPE);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070079 }
80 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -080081
82 return 0;
Shalabh Jain16794902012-09-14 10:56:49 -070083}
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070084
Shalabh Jain16794902012-09-14 10:56:49 -070085void extract_dci_pkt_rsp(unsigned char *buf)
86{
87 int i = 0, index = -1, cmd_code_len = 1;
88 int curr_client_pid = 0, write_len;
89 struct diag_dci_client_tbl *entry;
90 void *temp_buf = NULL;
91 uint8_t recv_pkt_cmd_code;
92
93 recv_pkt_cmd_code = *(uint8_t *)(buf+4);
94 if (recv_pkt_cmd_code != DCI_PKT_RSP_CODE)
95 cmd_code_len = 4; /* delayed response */
96 write_len = (int)(*(uint16_t *)(buf+2)) - cmd_code_len;
97 pr_debug("diag: len = %d\n", write_len);
98 /* look up DCI client with tag */
99 for (i = 0; i < dci_max_reg; i++) {
100 if (driver->req_tracking_tbl[i].tag ==
101 *(int *)(buf+(4+cmd_code_len))) {
102 *(int *)(buf+4+cmd_code_len) =
103 driver->req_tracking_tbl[i].uid;
104 curr_client_pid =
105 driver->req_tracking_tbl[i].pid;
106 index = i;
107 break;
108 }
109 }
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800110 if (index == -1) {
Shalabh Jain16794902012-09-14 10:56:49 -0700111 pr_alert("diag: No matching PID for DCI data\n");
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800112 return;
113 }
Shalabh Jain16794902012-09-14 10:56:49 -0700114 /* Using PID of client process, find client buffer */
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800115 i = diag_dci_find_client_index(curr_client_pid);
116 if (i != DCI_CLIENT_INDEX_INVALID) {
117 /* copy pkt rsp in client buf */
118 entry = &(driver->dci_client_tbl[i]);
119 if (DCI_CHK_CAPACITY(entry, 8+write_len)) {
120 pr_alert("diag: create capacity for pkt rsp\n");
121 entry->total_capacity += 8+write_len;
122 temp_buf = krealloc(entry->dci_data,
123 entry->total_capacity, GFP_KERNEL);
124 if (!temp_buf) {
125 pr_err("diag: DCI realloc failed\n");
126 return;
127 } else {
128 entry->dci_data = temp_buf;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800129 }
Shalabh Jain16794902012-09-14 10:56:49 -0700130 }
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800131 *(int *)(entry->dci_data+entry->data_len) =
132 DCI_PKT_RSP_TYPE;
133 entry->data_len += 4;
134 *(int *)(entry->dci_data+entry->data_len)
135 = write_len;
136 entry->data_len += 4;
137 memcpy(entry->dci_data+entry->data_len,
138 buf+4+cmd_code_len, write_len);
139 entry->data_len += write_len;
140 /* delete immediate response entry */
141 if (driver->smd_dci[MODEM_DATA].
142 buf_in_1[8+cmd_code_len] != 0x80)
143 driver->req_tracking_tbl[index].pid = 0;
Shalabh Jain16794902012-09-14 10:56:49 -0700144 }
145}
146
147void extract_dci_events(unsigned char *buf)
148{
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800149 uint16_t event_id, event_id_packet, length, temp_len;
150 uint8_t *event_mask_ptr, byte_mask, payload_len, payload_len_field;
151 uint8_t timestamp[8], bit_index, timestamp_len;
152 uint8_t event_data[MAX_EVENT_SIZE];
153 unsigned int byte_index, total_event_len, i;
Shalabh Jain16794902012-09-14 10:56:49 -0700154 struct diag_dci_client_tbl *entry;
155
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800156 length = *(uint16_t *)(buf + 1); /* total length of event series */
157 if (length == 0) {
158 pr_err("diag: Incoming dci event length is invalid\n");
159 return;
160 }
Shalabh Jain16794902012-09-14 10:56:49 -0700161 temp_len = 0;
162 buf = buf + 3; /* start of event series */
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800163 while (temp_len < (length - 1)) {
164 event_id_packet = *(uint16_t *)(buf + temp_len);
Shalabh Jain16794902012-09-14 10:56:49 -0700165 event_id = event_id_packet & 0x0FFF; /* extract 12 bits */
166 if (event_id_packet & 0x8000) {
167 timestamp_len = 2;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800168 memset(timestamp, 0, 8);
Shalabh Jain16794902012-09-14 10:56:49 -0700169 } else {
170 timestamp_len = 8;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800171 memcpy(timestamp, buf + temp_len + 2, timestamp_len);
Shalabh Jain16794902012-09-14 10:56:49 -0700172 }
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800173 /* 13th and 14th bit represent the payload length */
Shalabh Jain16794902012-09-14 10:56:49 -0700174 if (((event_id_packet & 0x6000) >> 13) == 3) {
175 payload_len_field = 1;
176 payload_len = *(uint8_t *)
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800177 (buf + temp_len + 2 + timestamp_len);
178 if (payload_len < (MAX_EVENT_SIZE - 13)) {
179 /* copy the payload length and the payload */
180 memcpy(event_data + 12, buf + temp_len + 2 +
181 timestamp_len, 1);
182 memcpy(event_data + 13, buf + temp_len + 2 +
183 timestamp_len + 1, payload_len);
184 } else {
185 pr_err("diag: event > %d, payload_len = %d\n",
186 (MAX_EVENT_SIZE - 13), payload_len);
187 return;
188 }
Shalabh Jain16794902012-09-14 10:56:49 -0700189 } else {
190 payload_len_field = 0;
191 payload_len = (event_id_packet & 0x6000) >> 13;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800192 /* copy the payload */
193 memcpy(event_data + 12, buf + temp_len + 2 +
194 timestamp_len, payload_len);
Shalabh Jain16794902012-09-14 10:56:49 -0700195 }
196 /* 2 bytes for the event id & timestamp len is hard coded to 8,
197 as individual events have full timestamp */
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800198 *(uint16_t *)(event_data) = 10 +
199 payload_len_field + payload_len;
200 *(uint16_t *)(event_data + 2) = event_id_packet & 0x7FFF;
201 memcpy(event_data + 4, timestamp, 8);
202 /* 2 bytes for the event length field which is added to
203 the event data */
204 total_event_len = 2 + 10 + payload_len_field + payload_len;
205 byte_index = event_id / 8;
Shalabh Jain16794902012-09-14 10:56:49 -0700206 bit_index = event_id % 8;
207 byte_mask = 0x1 << bit_index;
208 /* parse through event mask tbl of each client and check mask */
209 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
210 if (driver->dci_client_tbl[i].client) {
211 entry = &(driver->dci_client_tbl[i]);
212 event_mask_ptr = entry->dci_event_mask +
213 byte_index;
214 if (*event_mask_ptr & byte_mask) {
215 /* copy to client buffer */
216 if (DCI_CHK_CAPACITY(entry,
217 4 + total_event_len)) {
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800218 pr_err("diag: DCI event drop\n");
Shalabh Jain16794902012-09-14 10:56:49 -0700219 driver->dci_client_tbl[i].
220 dropped_events++;
221 return;
222 }
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700223 driver->dci_client_tbl[i].
224 received_events++;
Shalabh Jain16794902012-09-14 10:56:49 -0700225 *(int *)(entry->dci_data+
226 entry->data_len) = DCI_EVENT_TYPE;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800227 /* 4 bytes for DCI_EVENT_TYPE */
228 memcpy(entry->dci_data +
229 entry->data_len + 4, event_data
230 , total_event_len);
Shalabh Jain16794902012-09-14 10:56:49 -0700231 entry->data_len += 4 + total_event_len;
232 }
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700233 }
234 }
Shalabh Jain16794902012-09-14 10:56:49 -0700235 temp_len += 2 + timestamp_len + payload_len_field + payload_len;
236 }
237}
238
239void extract_dci_log(unsigned char *buf)
240{
241 uint16_t log_code, item_num;
242 uint8_t equip_id, *log_mask_ptr, byte_mask;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800243 unsigned int i, byte_index, byte_offset = 0;
Shalabh Jain16794902012-09-14 10:56:49 -0700244 struct diag_dci_client_tbl *entry;
245
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800246 log_code = *(uint16_t *)(buf + 6);
Shalabh Jain16794902012-09-14 10:56:49 -0700247 equip_id = LOG_GET_EQUIP_ID(log_code);
248 item_num = LOG_GET_ITEM_NUM(log_code);
249 byte_index = item_num/8 + 2;
250 byte_mask = 0x01 << (item_num % 8);
251
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800252 byte_offset = (equip_id * 514) + byte_index;
253 if (byte_offset >= DCI_LOG_MASK_SIZE) {
254 pr_err("diag: Invalid byte_offset %d in dci log\n",
255 byte_offset);
256 return;
257 }
258
Shalabh Jain16794902012-09-14 10:56:49 -0700259 /* parse through log mask table of each client and check mask */
260 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
261 if (driver->dci_client_tbl[i].client) {
262 entry = &(driver->dci_client_tbl[i]);
263 log_mask_ptr = entry->dci_log_mask;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800264 if (!log_mask_ptr)
265 return;
266 log_mask_ptr = log_mask_ptr + byte_offset;
Shalabh Jain16794902012-09-14 10:56:49 -0700267 if (*log_mask_ptr & byte_mask) {
268 pr_debug("\t log code %x needed by client %d",
269 log_code, entry->client->tgid);
270 /* copy to client buffer */
271 if (DCI_CHK_CAPACITY(entry,
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800272 4 + *(uint16_t *)(buf + 2))) {
273 pr_err("diag: DCI log drop\n");
Shalabh Jain16794902012-09-14 10:56:49 -0700274 driver->dci_client_tbl[i].
275 dropped_logs++;
276 return;
277 }
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700278 driver->dci_client_tbl[i].received_logs++;
Shalabh Jain16794902012-09-14 10:56:49 -0700279 *(int *)(entry->dci_data+entry->data_len) =
280 DCI_LOG_TYPE;
Ravi Aravamudhanc8a192a2013-02-22 10:23:15 -0800281 memcpy(entry->dci_data + entry->data_len + 4,
282 buf + 4, *(uint16_t *)(buf + 2));
283 entry->data_len += 4 + *(uint16_t *)(buf + 2);
Shalabh Jain16794902012-09-14 10:56:49 -0700284 }
285 }
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700286 }
287}
288
Dixon Peterson5a26a302012-11-15 17:26:17 -0800289void diag_update_smd_dci_work_fn(struct work_struct *work)
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700290{
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800291 struct diag_smd_info *smd_info = container_of(work,
292 struct diag_smd_info,
293 diag_notify_update_smd_work);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800294 int i, j;
295 char dirty_bits[16];
296 uint8_t *client_log_mask_ptr;
297 uint8_t *log_mask_ptr;
298 int ret;
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800299 int index = smd_info->peripheral;
Dixon Peterson5a26a302012-11-15 17:26:17 -0800300
301 /* Update the peripheral(s) with the dci log and event masks */
302
303 /* If the cntl channel is not up, we can't update logs and events */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800304 if (!driver->smd_cntl[index].ch)
Dixon Peterson5a26a302012-11-15 17:26:17 -0800305 return;
306
307 memset(dirty_bits, 0, 16 * sizeof(uint8_t));
308
309 /*
310 * From each log entry used by each client, determine
311 * which log entries in the cumulative logs that need
312 * to be updated on the peripheral.
313 */
314 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
315 if (driver->dci_client_tbl[i].client) {
316 client_log_mask_ptr =
317 driver->dci_client_tbl[i].dci_log_mask;
318 for (j = 0; j < 16; j++) {
319 if (*(client_log_mask_ptr+1))
320 dirty_bits[j] = 1;
321 client_log_mask_ptr += 514;
322 }
323 }
324 }
325
326 mutex_lock(&dci_log_mask_mutex);
327 /* Update the appropriate dirty bits in the cumulative mask */
328 log_mask_ptr = dci_cumulative_log_mask;
329 for (i = 0; i < 16; i++) {
330 if (dirty_bits[i])
331 *(log_mask_ptr+1) = dirty_bits[i];
332
333 log_mask_ptr += 514;
334 }
335 mutex_unlock(&dci_log_mask_mutex);
336
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800337 ret = diag_send_dci_log_mask(driver->smd_cntl[index].ch);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800338
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800339 ret = diag_send_dci_event_mask(driver->smd_cntl[index].ch);
340
341 smd_info->notify_context = 0;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700342}
343
Dixon Peterson5a26a302012-11-15 17:26:17 -0800344void diag_dci_notify_client(int peripheral_mask, int data)
Shalabh Jain5e9a92b2012-06-07 21:53:49 -0700345{
346 int i, stat;
Dixon Peterson5a26a302012-11-15 17:26:17 -0800347 struct siginfo info;
348 memset(&info, 0, sizeof(struct siginfo));
349 info.si_code = SI_QUEUE;
350 info.si_int = (peripheral_mask | data);
Shalabh Jain5e9a92b2012-06-07 21:53:49 -0700351
352 /* Notify the DCI process that the peripheral DCI Channel is up */
Shalabh Jain16794902012-09-14 10:56:49 -0700353 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
354 if (driver->dci_client_tbl[i].list & peripheral_mask) {
Dixon Peterson5a26a302012-11-15 17:26:17 -0800355 info.si_signo = driver->dci_client_tbl[i].signal_type;
356 stat = send_sig_info(
357 driver->dci_client_tbl[i].signal_type,
358 &info, driver->dci_client_tbl[i].client);
Shalabh Jain5e9a92b2012-06-07 21:53:49 -0700359 if (stat)
Dixon Peterson5a26a302012-11-15 17:26:17 -0800360 pr_err("diag: Err sending dci signal to client, signal data: 0x%x, stat: %d\n",
361 info.si_int, stat);
Shalabh Jain5e9a92b2012-06-07 21:53:49 -0700362 }
363 } /* end of loop for all DCI clients */
364}
365
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700366static int diag_dci_probe(struct platform_device *pdev)
367{
368 int err = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800369 int index;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700370
371 if (pdev->id == SMD_APPS_MODEM) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800372 index = MODEM_DATA;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800373 err = smd_open("DIAG_2", &driver->smd_dci[index].ch,
374 &driver->smd_dci[index],
375 diag_smd_notify);
376 driver->smd_dci[index].ch_save =
377 driver->smd_dci[index].ch;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700378 if (err)
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800379 pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
380 __func__, pdev->id, err);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700381 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800382
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700383 return err;
384}
385
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700386int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
387 int len, int index)
388{
389 int i;
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800390 int status = 0;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700391
392 /* remove UID from user space pkt before sending to peripheral */
393 buf = buf + 4;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800394 if (len > APPS_BUF_SIZE - 10) {
395 pr_err("diag: dci: buffer overwrite possible since payload bigger than buf size\n");
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -0800396 return -EIO;
397 }
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700398 len = len - 4;
399 mutex_lock(&driver->dci_mutex);
400 /* prepare DCI packet */
401 driver->apps_dci_buf[0] = CONTROL_CHAR; /* start */
402 driver->apps_dci_buf[1] = 1; /* version */
403 *(uint16_t *)(driver->apps_dci_buf + 2) = len + 4 + 1; /* length */
Shalabh Jain16794902012-09-14 10:56:49 -0700404 driver->apps_dci_buf[4] = DCI_PKT_RSP_CODE;
405 *(int *)(driver->apps_dci_buf + 5) =
406 driver->req_tracking_tbl[index].tag;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700407 for (i = 0; i < len; i++)
408 driver->apps_dci_buf[i+9] = *(buf+i);
409 driver->apps_dci_buf[9+len] = CONTROL_CHAR; /* end */
410
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800411 for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
412 if (entry.client_id == driver->smd_dci[i].peripheral) {
413 if (driver->smd_dci[i].ch) {
414 smd_write(driver->smd_dci[i].ch,
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800415 driver->apps_dci_buf, len + 10);
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800416 status = DIAG_DCI_NO_ERROR;
417 }
418 break;
419 }
420 }
421
422 if (status != DIAG_DCI_NO_ERROR) {
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700423 pr_alert("diag: check DCI channel\n");
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800424 status = DIAG_DCI_SEND_DATA_FAIL;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700425 }
426 mutex_unlock(&driver->dci_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800427 return status;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700428}
429
430int diag_register_dci_transaction(int uid)
431{
432 int i, new_dci_client = 1, ret = -1;
433
434 for (i = 0; i < dci_max_reg; i++) {
Shalabh Jain16794902012-09-14 10:56:49 -0700435 if (driver->req_tracking_tbl[i].pid == current->tgid) {
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700436 new_dci_client = 0;
437 break;
438 }
439 }
440 mutex_lock(&driver->dci_mutex);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700441 /* Make an entry in kernel DCI table */
442 driver->dci_tag++;
443 for (i = 0; i < dci_max_reg; i++) {
Shalabh Jain16794902012-09-14 10:56:49 -0700444 if (driver->req_tracking_tbl[i].pid == 0) {
445 driver->req_tracking_tbl[i].pid = current->tgid;
446 driver->req_tracking_tbl[i].uid = uid;
447 driver->req_tracking_tbl[i].tag = driver->dci_tag;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700448 ret = i;
449 break;
450 }
451 }
452 mutex_unlock(&driver->dci_mutex);
453 return ret;
454}
455
Shalabh Jain16794902012-09-14 10:56:49 -0700456int diag_process_dci_transaction(unsigned char *buf, int len)
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700457{
458 unsigned char *temp = buf;
Shalabh Jain16794902012-09-14 10:56:49 -0700459 uint16_t subsys_cmd_code, log_code, item_num;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800460 int subsys_id, cmd_code, ret = -1, index = -1, found = 0, read_len = 0;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700461 struct diag_master_table entry;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800462 int count, set_mask, num_codes, bit_index, event_id, offset = 0, i;
463 unsigned int byte_index;
Shalabh Jain16794902012-09-14 10:56:49 -0700464 uint8_t equip_id, *log_mask_ptr, *head_log_mask_ptr, byte_mask;
465 uint8_t *event_mask_ptr;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700466
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800467 if (!driver->smd_dci[MODEM_DATA].ch) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800468 pr_err("diag: DCI smd channel for peripheral %d not valid for dci updates\n",
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800469 driver->smd_dci[MODEM_DATA].peripheral);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800470 return DIAG_DCI_SEND_DATA_FAIL;
471 }
472
Shalabh Jain16794902012-09-14 10:56:49 -0700473 /* This is Pkt request/response transaction */
474 if (*(int *)temp > 0) {
475 /* enter this UID into kernel table and return index */
476 index = diag_register_dci_transaction(*(int *)temp);
477 if (index < 0) {
478 pr_alert("diag: registering new DCI transaction failed\n");
479 return DIAG_DCI_NO_REG;
480 }
481 temp += 4;
482 /*
483 * Check for registered peripheral and fwd pkt to
484 * appropriate proc
485 */
486 cmd_code = (int)(*(char *)temp);
487 temp++;
488 subsys_id = (int)(*(char *)temp);
489 temp++;
490 subsys_cmd_code = *(uint16_t *)temp;
491 temp += 2;
492 pr_debug("diag: %d %d %d", cmd_code, subsys_id,
493 subsys_cmd_code);
494 for (i = 0; i < diag_max_reg; i++) {
495 entry = driver->table[i];
496 if (entry.process_id != NO_PROCESS) {
497 if (entry.cmd_code == cmd_code &&
498 entry.subsys_id == subsys_id &&
499 entry.cmd_code_lo <= subsys_cmd_code &&
500 entry.cmd_code_hi >= subsys_cmd_code) {
501 ret = diag_send_dci_pkt(entry, buf,
502 len, index);
503 } else if (entry.cmd_code == 255
504 && cmd_code == 75) {
505 if (entry.subsys_id == subsys_id &&
506 entry.cmd_code_lo <=
507 subsys_cmd_code &&
508 entry.cmd_code_hi >=
509 subsys_cmd_code) {
510 ret = diag_send_dci_pkt(entry,
511 buf, len, index);
512 }
513 } else if (entry.cmd_code == 255 &&
514 entry.subsys_id == 255) {
515 if (entry.cmd_code_lo <= cmd_code &&
516 entry.cmd_code_hi >=
517 cmd_code) {
518 ret = diag_send_dci_pkt(entry,
519 buf, len, index);
520 }
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700521 }
522 }
523 }
Shalabh Jain16794902012-09-14 10:56:49 -0700524 } else if (*(int *)temp == DCI_LOG_TYPE) {
525 /* find client id and table */
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800526 i = diag_dci_find_client_index(current->tgid);
527 if (i == DCI_CLIENT_INDEX_INVALID) {
Shalabh Jain16794902012-09-14 10:56:49 -0700528 pr_err("diag: dci client not registered/found\n");
529 return ret;
530 }
531 /* Extract each log code and put in client table */
532 temp += 4;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800533 read_len += 4;
Shalabh Jain16794902012-09-14 10:56:49 -0700534 set_mask = *(int *)temp;
535 temp += 4;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800536 read_len += 4;
Shalabh Jain16794902012-09-14 10:56:49 -0700537 num_codes = *(int *)temp;
538 temp += 4;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800539 read_len += 4;
Shalabh Jain16794902012-09-14 10:56:49 -0700540
541 head_log_mask_ptr = driver->dci_client_tbl[i].dci_log_mask;
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700542 pr_debug("diag: head of dci log mask %p\n", head_log_mask_ptr);
Shalabh Jain16794902012-09-14 10:56:49 -0700543 count = 0; /* iterator for extracting log codes */
544 while (count < num_codes) {
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800545 if (read_len >= USER_SPACE_DATA) {
546 pr_err("diag: dci: Log type, possible buffer overflow\n");
547 return -EIO;
548 }
Shalabh Jain16794902012-09-14 10:56:49 -0700549 log_code = *(uint16_t *)temp;
550 equip_id = LOG_GET_EQUIP_ID(log_code);
551 item_num = LOG_GET_ITEM_NUM(log_code);
552 byte_index = item_num/8 + 2;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800553 if (byte_index >= (DCI_MAX_ITEMS_PER_LOG_CODE+2)) {
554 pr_err("diag: dci: Log type, invalid byte index\n");
555 return ret;
556 }
Shalabh Jain16794902012-09-14 10:56:49 -0700557 byte_mask = 0x01 << (item_num % 8);
558 /*
559 * Parse through log mask table and find
560 * relevant range
561 */
562 log_mask_ptr = head_log_mask_ptr;
563 found = 0;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800564 offset = 0;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800565 while (log_mask_ptr && (offset < DCI_LOG_MASK_SIZE)) {
Shalabh Jain16794902012-09-14 10:56:49 -0700566 if (*log_mask_ptr == equip_id) {
567 found = 1;
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700568 pr_debug("diag: find equip id = %x at %p\n",
Shalabh Jain16794902012-09-14 10:56:49 -0700569 equip_id, log_mask_ptr);
570 break;
571 } else {
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700572 pr_debug("diag: did not find equip id = %x at %p\n",
Shalabh Jain16794902012-09-14 10:56:49 -0700573 equip_id, log_mask_ptr);
574 log_mask_ptr += 514;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800575 offset += 514;
Shalabh Jain16794902012-09-14 10:56:49 -0700576 }
577 }
578 if (!found) {
579 pr_err("diag: dci equip id not found\n");
580 return ret;
581 }
582 *(log_mask_ptr+1) = 1; /* set the dirty byte */
583 log_mask_ptr = log_mask_ptr + byte_index;
584 if (set_mask)
585 *log_mask_ptr |= byte_mask;
586 else
587 *log_mask_ptr &= ~byte_mask;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800588 /* add to cumulative mask */
589 update_dci_cumulative_log_mask(
590 offset, byte_index,
591 byte_mask);
Shalabh Jain16794902012-09-14 10:56:49 -0700592 temp += 2;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800593 read_len += 2;
Shalabh Jain16794902012-09-14 10:56:49 -0700594 count++;
595 ret = DIAG_DCI_NO_ERROR;
596 }
Shalabh Jain16794902012-09-14 10:56:49 -0700597 /* send updated mask to peripherals */
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800598 ret = diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
Shalabh Jain16794902012-09-14 10:56:49 -0700599 } else if (*(int *)temp == DCI_EVENT_TYPE) {
600 /* find client id and table */
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800601 i = diag_dci_find_client_index(current->tgid);
602 if (i == DCI_CLIENT_INDEX_INVALID) {
Shalabh Jain16794902012-09-14 10:56:49 -0700603 pr_err("diag: dci client not registered/found\n");
604 return ret;
605 }
606 /* Extract each log code and put in client table */
607 temp += 4;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800608 read_len += 4;
Shalabh Jain16794902012-09-14 10:56:49 -0700609 set_mask = *(int *)temp;
610 temp += 4;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800611 read_len += 4;
Shalabh Jain16794902012-09-14 10:56:49 -0700612 num_codes = *(int *)temp;
613 temp += 4;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800614 read_len += 4;
Shalabh Jain16794902012-09-14 10:56:49 -0700615
616 event_mask_ptr = driver->dci_client_tbl[i].dci_event_mask;
617 pr_debug("diag: head of dci event mask %p\n", event_mask_ptr);
618 count = 0; /* iterator for extracting log codes */
619 while (count < num_codes) {
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800620 if (read_len >= USER_SPACE_DATA) {
621 pr_err("diag: dci: Event type, possible buffer overflow\n");
622 return -EIO;
623 }
Shalabh Jain16794902012-09-14 10:56:49 -0700624 event_id = *(int *)temp;
625 byte_index = event_id/8;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800626 if (byte_index >= DCI_EVENT_MASK_SIZE) {
627 pr_err("diag: dci: Event type, invalid byte index\n");
628 return ret;
629 }
Shalabh Jain16794902012-09-14 10:56:49 -0700630 bit_index = event_id % 8;
631 byte_mask = 0x1 << bit_index;
632 /*
633 * Parse through event mask table and set
634 * relevant byte & bit combination
635 */
636 if (set_mask)
637 *(event_mask_ptr + byte_index) |= byte_mask;
638 else
639 *(event_mask_ptr + byte_index) &= ~byte_mask;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800640 /* add to cumulative mask */
641 update_dci_cumulative_event_mask(byte_index, byte_mask);
Shalabh Jain16794902012-09-14 10:56:49 -0700642 temp += sizeof(int);
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800643 read_len += sizeof(int);
Shalabh Jain16794902012-09-14 10:56:49 -0700644 count++;
645 ret = DIAG_DCI_NO_ERROR;
646 }
Shalabh Jain16794902012-09-14 10:56:49 -0700647 /* send updated mask to peripherals */
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800648 ret = diag_send_dci_event_mask(driver->smd_cntl[MODEM_DATA].ch);
Shalabh Jain16794902012-09-14 10:56:49 -0700649 } else {
650 pr_alert("diag: Incorrect DCI transaction\n");
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700651 }
652 return ret;
653}
654
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800655int diag_dci_find_client_index(int client_id)
656{
657 int i, ret = DCI_CLIENT_INDEX_INVALID;
658
659 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
660 if (driver->dci_client_tbl[i].client != NULL) {
661 if (driver->dci_client_tbl[i].client->tgid ==
662 client_id) {
663 ret = i;
664 break;
665 }
666 }
667 }
668 return ret;
669}
670
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800671void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask)
Shalabh Jain16794902012-09-14 10:56:49 -0700672{
673 int i;
Shalabh Jain16794902012-09-14 10:56:49 -0700674 uint8_t *event_mask_ptr;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800675 uint8_t *update_ptr = dci_cumulative_event_mask;
676 bool is_set = false;
Shalabh Jain16794902012-09-14 10:56:49 -0700677
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700678 mutex_lock(&dci_event_mask_mutex);
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800679 update_ptr += offset;
680 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
681 event_mask_ptr =
682 driver->dci_client_tbl[i].dci_event_mask;
683 event_mask_ptr += offset;
684 if ((*event_mask_ptr & byte_mask) == byte_mask) {
685 is_set = true;
686 /* break even if one client has the event mask set */
687 break;
688 }
689 }
690 if (is_set == false)
691 *update_ptr &= ~byte_mask;
692 else
693 *update_ptr |= byte_mask;
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700694 mutex_unlock(&dci_event_mask_mutex);
Shalabh Jain16794902012-09-14 10:56:49 -0700695}
696
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800697void clear_client_dci_cumulative_event_mask(int client_index)
698{
699 int i, j;
700 uint8_t *update_ptr = dci_cumulative_event_mask;
701 uint8_t *event_mask_ptr, *client_event_mask_ptr, byte_mask = 0;
702 bool is_set = false;
703
704 event_mask_ptr =
705 (driver->dci_client_tbl[client_index].dci_event_mask);
706
707 mutex_lock(&dci_event_mask_mutex);
708 for (i = 0; i < DCI_EVENT_MASK_SIZE; i++) {
709 is_set = false;
710 /* Already cleared event masks need not to be considered */
711 if (*event_mask_ptr != 0) {
712 byte_mask = *event_mask_ptr;
713 } else {
714 update_ptr++;
715 event_mask_ptr++;
716 continue;
717 }
718 for (j = 0; j < MAX_DCI_CLIENTS; j++) {
719 /* continue searching for valid client */
720 if (driver->dci_client_tbl[j].client == NULL ||
721 client_index == j)
722 continue;
723 client_event_mask_ptr =
724 (driver->dci_client_tbl[j].dci_event_mask);
725 client_event_mask_ptr += i;
726 if (*client_event_mask_ptr & byte_mask) {
727 /*
728 * Break if another client has same
729 * event mask set
730 */
731 if ((*client_event_mask_ptr &
732 byte_mask) == byte_mask) {
733 is_set = true;
734 break;
735 } else {
736 byte_mask =
737 (~(*client_event_mask_ptr) &
738 byte_mask);
739 is_set = false;
740 }
741 }
742 }
743 /*
744 * Clear only if this client has event mask set else
745 * don't update cumulative event mask ptr
746 */
747 if (is_set == false)
748 *update_ptr &= ~byte_mask;
749
750 update_ptr++;
751 event_mask_ptr++;
752 }
753 event_mask_ptr =
754 (driver->dci_client_tbl[client_index].dci_event_mask);
755 memset(event_mask_ptr, 0, DCI_EVENT_MASK_SIZE);
756 mutex_unlock(&dci_event_mask_mutex);
757}
758
759
Dixon Peterson5a26a302012-11-15 17:26:17 -0800760int diag_send_dci_event_mask(smd_channel_t *ch)
Shalabh Jain16794902012-09-14 10:56:49 -0700761{
762 void *buf = driver->buf_event_mask_update;
763 int header_size = sizeof(struct diag_ctrl_event_mask);
764 int wr_size = -ENOMEM, retry_count = 0, timer;
Dixon Peterson5a26a302012-11-15 17:26:17 -0800765 int ret = DIAG_DCI_NO_ERROR;
Shalabh Jain16794902012-09-14 10:56:49 -0700766
767 mutex_lock(&driver->diag_cntl_mutex);
768 /* send event mask update */
769 driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
770 driver->event_mask->data_len = 7 + DCI_EVENT_MASK_SIZE;
771 driver->event_mask->stream_id = DCI_MASK_STREAM;
772 driver->event_mask->status = 3; /* status for valid mask */
773 driver->event_mask->event_config = 1; /* event config */
774 driver->event_mask->event_mask_size = DCI_EVENT_MASK_SIZE;
775 memcpy(buf, driver->event_mask, header_size);
776 memcpy(buf+header_size, dci_cumulative_event_mask, DCI_EVENT_MASK_SIZE);
777 if (ch) {
778 while (retry_count < 3) {
779 wr_size = smd_write(ch, buf,
780 header_size + DCI_EVENT_MASK_SIZE);
781 if (wr_size == -ENOMEM) {
782 retry_count++;
783 for (timer = 0; timer < 5; timer++)
784 udelay(2000);
785 } else {
786 break;
787 }
788 }
Dixon Peterson5a26a302012-11-15 17:26:17 -0800789 if (wr_size != header_size + DCI_EVENT_MASK_SIZE) {
Shalabh Jain16794902012-09-14 10:56:49 -0700790 pr_err("diag: error writing dci event mask %d, tried %d\n",
791 wr_size, header_size + DCI_EVENT_MASK_SIZE);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800792 ret = DIAG_DCI_SEND_DATA_FAIL;
793 }
794 } else {
Shalabh Jain16794902012-09-14 10:56:49 -0700795 pr_err("diag: ch not valid for dci event mask update\n");
Dixon Peterson5a26a302012-11-15 17:26:17 -0800796 ret = DIAG_DCI_SEND_DATA_FAIL;
797 }
Shalabh Jain16794902012-09-14 10:56:49 -0700798 mutex_unlock(&driver->diag_cntl_mutex);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800799
800 return ret;
Shalabh Jain16794902012-09-14 10:56:49 -0700801}
802
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800803void update_dci_cumulative_log_mask(int offset, unsigned int byte_index,
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800804 uint8_t byte_mask)
Shalabh Jain16794902012-09-14 10:56:49 -0700805{
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800806 int i;
Shalabh Jain16794902012-09-14 10:56:49 -0700807 uint8_t *update_ptr = dci_cumulative_log_mask;
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800808 uint8_t *log_mask_ptr;
809 bool is_set = false;
Shalabh Jain16794902012-09-14 10:56:49 -0700810
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700811 mutex_lock(&dci_log_mask_mutex);
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800812 *update_ptr = 0;
813 /* set the equipment IDs */
814 for (i = 0; i < 16; i++)
815 *(update_ptr + (i*514)) = i;
816
817 update_ptr += offset;
818 /* update the dirty bit */
819 *(update_ptr+1) = 1;
820 update_ptr = update_ptr + byte_index;
821 for (i = 0; i < MAX_DCI_CLIENTS; i++) {
822 log_mask_ptr =
823 (driver->dci_client_tbl[i].dci_log_mask);
824 log_mask_ptr = log_mask_ptr + offset + byte_index;
825 if ((*log_mask_ptr & byte_mask) == byte_mask) {
826 is_set = true;
827 /* break even if one client has the log mask set */
828 break;
Shalabh Jain16794902012-09-14 10:56:49 -0700829 }
Shalabh Jain16794902012-09-14 10:56:49 -0700830 }
Ravi Aravamudhandf2947a2012-11-16 18:10:05 -0800831
832 if (is_set == false)
833 *update_ptr &= ~byte_mask;
834 else
835 *update_ptr |= byte_mask;
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700836 mutex_unlock(&dci_log_mask_mutex);
Shalabh Jain16794902012-09-14 10:56:49 -0700837}
838
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800839void clear_client_dci_cumulative_log_mask(int client_index)
840{
841 int i, j, k;
842 uint8_t *update_ptr = dci_cumulative_log_mask;
843 uint8_t *log_mask_ptr, *client_log_mask_ptr, byte_mask = 0;
844 bool is_set = false;
845
846 log_mask_ptr = driver->dci_client_tbl[client_index].dci_log_mask;
847
848 mutex_lock(&dci_log_mask_mutex);
849 *update_ptr = 0;
850 /* set the equipment IDs */
851 for (i = 0; i < 16; i++)
852 *(update_ptr + (i*514)) = i;
853
854 /* update cumulative log mask ptr*/
855 update_ptr += 2;
856 log_mask_ptr += 2;
857 for (i = 0; i < 16; i++) {
858 for (j = 0; j < 512; j++) {
859 is_set = false;
860 /*
861 * Already cleared log masks need
862 * not to be considered
863 */
864 if (*log_mask_ptr != 0) {
865 byte_mask = *log_mask_ptr;
866 } else {
867 update_ptr++;
868 log_mask_ptr++;
869 continue;
870 }
871 for (k = 0; k < MAX_DCI_CLIENTS; k++) {
872 /* continue searching for valid client */
873 if (driver->dci_client_tbl[k].client == NULL ||
874 client_index == k)
875 continue;
876 client_log_mask_ptr =
877 (driver->dci_client_tbl[k].dci_log_mask);
878 client_log_mask_ptr += (i*514) + 2 + j;
879 if (*client_log_mask_ptr & byte_mask) {
880 /*
881 * Break if another client has same
882 * log mask set
883 */
884 if ((*client_log_mask_ptr &
885 byte_mask) == byte_mask) {
886 is_set = true;
887 break;
888 } else {
889 byte_mask =
890 (~(*client_log_mask_ptr) &
891 byte_mask);
892 is_set = false;
893 }
894 }
895 }
896 /*
897 * Clear only if this client has log mask set else
898 * don't update cumulative log mask ptr
899 */
900 if (is_set == false) {
901 /*
902 * Update the dirty bit for the equipment
903 * whose mask is changing
904 */
905 dci_cumulative_log_mask[1+(i*514)] = 1;
906 *update_ptr &= ~byte_mask;
907 }
908
909 update_ptr++;
910 log_mask_ptr++;
911 }
912 update_ptr += 2;
913 log_mask_ptr += 2;
914 }
915 log_mask_ptr = driver->dci_client_tbl[client_index].dci_log_mask;
916 memset(log_mask_ptr, 0, DCI_LOG_MASK_SIZE);
917 mutex_unlock(&dci_log_mask_mutex);
918}
919
Dixon Peterson5a26a302012-11-15 17:26:17 -0800920int diag_send_dci_log_mask(smd_channel_t *ch)
Shalabh Jain16794902012-09-14 10:56:49 -0700921{
922 void *buf = driver->buf_log_mask_update;
923 int header_size = sizeof(struct diag_ctrl_log_mask);
924 uint8_t *log_mask_ptr = dci_cumulative_log_mask;
925 int i, wr_size = -ENOMEM, retry_count = 0, timer;
Dixon Peterson5a26a302012-11-15 17:26:17 -0800926 int ret = DIAG_DCI_NO_ERROR;
927
928 if (!ch) {
929 pr_err("diag: ch not valid for dci log mask update\n");
930 return DIAG_DCI_SEND_DATA_FAIL;
931 }
Shalabh Jain16794902012-09-14 10:56:49 -0700932
933 mutex_lock(&driver->diag_cntl_mutex);
934 for (i = 0; i < 16; i++) {
Ravi Aravamudhan3365bc02013-03-05 16:51:28 -0800935 retry_count = 0;
Shalabh Jain16794902012-09-14 10:56:49 -0700936 driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
937 driver->log_mask->num_items = 512;
938 driver->log_mask->data_len = 11 + 512;
939 driver->log_mask->stream_id = DCI_MASK_STREAM;
940 driver->log_mask->status = 3; /* status for valid mask */
941 driver->log_mask->equip_id = *log_mask_ptr;
942 driver->log_mask->log_mask_size = 512;
943 memcpy(buf, driver->log_mask, header_size);
944 memcpy(buf+header_size, log_mask_ptr+2, 512);
945 /* if dirty byte is set and channel is valid */
946 if (ch && *(log_mask_ptr+1)) {
947 while (retry_count < 3) {
948 wr_size = smd_write(ch, buf, header_size + 512);
949 if (wr_size == -ENOMEM) {
950 retry_count++;
951 for (timer = 0; timer < 5; timer++)
952 udelay(2000);
953 } else
954 break;
955 }
Dixon Peterson5a26a302012-11-15 17:26:17 -0800956 if (wr_size != header_size + 512) {
Ravi Aravamudhan3365bc02013-03-05 16:51:28 -0800957 pr_err("diag: dci log mask update failed %d, tried %d for equip_id %d\n",
958 wr_size, header_size + 512,
959 driver->log_mask->equip_id);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800960 ret = DIAG_DCI_SEND_DATA_FAIL;
961
962 } else {
Shalabh Jain16794902012-09-14 10:56:49 -0700963 *(log_mask_ptr+1) = 0; /* clear dirty byte */
964 pr_debug("diag: updated dci log equip ID %d\n",
965 *log_mask_ptr);
966 }
967 }
968 log_mask_ptr += 514;
969 }
970 mutex_unlock(&driver->diag_cntl_mutex);
Dixon Peterson5a26a302012-11-15 17:26:17 -0800971
972 return ret;
Shalabh Jain16794902012-09-14 10:56:49 -0700973}
974
975void create_dci_log_mask_tbl(unsigned char *tbl_buf)
976{
977 uint8_t i; int count = 0;
978
979 /* create hard coded table for log mask with 16 categories */
980 for (i = 0; i < 16; i++) {
981 *(uint8_t *)tbl_buf = i;
982 pr_debug("diag: put value %x at %p\n", i, tbl_buf);
983 memset(tbl_buf+1, 0, 513); /* set dirty bit as 0 */
984 tbl_buf += 514;
985 count += 514;
986 }
987}
988
989void create_dci_event_mask_tbl(unsigned char *tbl_buf)
990{
991 memset(tbl_buf, 0, 512);
992}
993
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700994static int diag_dci_runtime_suspend(struct device *dev)
995{
996 dev_dbg(dev, "pm_runtime: suspending...\n");
997 return 0;
998}
999
1000static int diag_dci_runtime_resume(struct device *dev)
1001{
1002 dev_dbg(dev, "pm_runtime: resuming...\n");
1003 return 0;
1004}
1005
1006static const struct dev_pm_ops diag_dci_dev_pm_ops = {
1007 .runtime_suspend = diag_dci_runtime_suspend,
1008 .runtime_resume = diag_dci_runtime_resume,
1009};
1010
1011struct platform_driver msm_diag_dci_driver = {
1012 .probe = diag_dci_probe,
1013 .driver = {
Shalabh Jain16794902012-09-14 10:56:49 -07001014 .name = "DIAG_2",
1015 .owner = THIS_MODULE,
1016 .pm = &diag_dci_dev_pm_ops,
1017 },
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001018};
1019
1020int diag_dci_init(void)
1021{
1022 int success = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001023 int i;
Dixon Peterson5a26a302012-11-15 17:26:17 -08001024
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001025 driver->dci_tag = 0;
1026 driver->dci_client_id = 0;
1027 driver->num_dci_client = 0;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001028 mutex_init(&driver->dci_mutex);
Shalabh Jaina1c69a42012-10-23 12:51:30 -07001029 mutex_init(&dci_log_mask_mutex);
1030 mutex_init(&dci_event_mask_mutex);
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -08001031 for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
1032 success = diag_smd_constructor(&driver->smd_dci[i],
1033 i, SMD_DCI_TYPE);
1034 if (!success)
1035 goto err;
1036 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001037
Shalabh Jain16794902012-09-14 10:56:49 -07001038 if (driver->req_tracking_tbl == NULL) {
1039 driver->req_tracking_tbl = kzalloc(dci_max_reg *
1040 sizeof(struct dci_pkt_req_tracking_tbl), GFP_KERNEL);
1041 if (driver->req_tracking_tbl == NULL)
Shalabh Jain5e9a92b2012-06-07 21:53:49 -07001042 goto err;
1043 }
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001044 if (driver->apps_dci_buf == NULL) {
1045 driver->apps_dci_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
1046 if (driver->apps_dci_buf == NULL)
1047 goto err;
1048 }
Shalabh Jain16794902012-09-14 10:56:49 -07001049 if (driver->dci_client_tbl == NULL) {
1050 driver->dci_client_tbl = kzalloc(MAX_DCI_CLIENTS *
1051 sizeof(struct diag_dci_client_tbl), GFP_KERNEL);
1052 if (driver->dci_client_tbl == NULL)
1053 goto err;
1054 }
1055 driver->diag_dci_wq = create_singlethread_workqueue("diag_dci_wq");
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001056 success = platform_driver_register(&msm_diag_dci_driver);
1057 if (success) {
1058 pr_err("diag: Could not register DCI driver\n");
1059 goto err;
1060 }
1061 return DIAG_DCI_NO_ERROR;
1062err:
1063 pr_err("diag: Could not initialize diag DCI buffers");
Shalabh Jain16794902012-09-14 10:56:49 -07001064 kfree(driver->req_tracking_tbl);
1065 kfree(driver->dci_client_tbl);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001066 kfree(driver->apps_dci_buf);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001067 for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
1068 diag_smd_destructor(&driver->smd_dci[i]);
Shalabh Jain16794902012-09-14 10:56:49 -07001069 if (driver->diag_dci_wq)
1070 destroy_workqueue(driver->diag_dci_wq);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001071 return DIAG_DCI_NO_REG;
1072}
1073
1074void diag_dci_exit(void)
1075{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001076 int i;
1077
1078 for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
1079 diag_smd_destructor(&driver->smd_dci[i]);
1080
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001081 platform_driver_unregister(&msm_diag_dci_driver);
Shalabh Jain16794902012-09-14 10:56:49 -07001082 kfree(driver->req_tracking_tbl);
1083 kfree(driver->dci_client_tbl);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001084 kfree(driver->apps_dci_buf);
Shalabh Jain16794902012-09-14 10:56:49 -07001085 destroy_workqueue(driver->diag_dci_wq);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001086}