blob: 0c93101779b7c0e5fd0d5fe13cc4c086aa5cd743 [file] [log] [blame]
Dixon Petersond6a20a92012-09-27 15:58:50 -07001/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
2 *
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/delay.h>
15#include <linux/diagchar.h>
16#include <linux/kmemleak.h>
17#include <linux/workqueue.h>
18#include "diagchar.h"
19#include "diagfwd_cntl.h"
20#include "diag_masks.h"
21
22int diag_event_config;
23int diag_event_num_bytes;
24
25#define ALL_EQUIP_ID 100
26#define ALL_SSID -1
27#define MAX_SSID_PER_RANGE 100
28
Ravi Aravamudhand09f8772012-12-20 14:48:30 -080029#define FEATURE_MASK_LEN_BYTES 1
30#define APPS_RESPOND_LOG_ON_DEMAND 0x04
31
Dixon Petersond6a20a92012-09-27 15:58:50 -070032struct mask_info {
33 int equip_id;
34 int num_items;
35 int index;
36};
37
38#define CREATE_MSG_MASK_TBL_ROW(XX) \
39do { \
40 *(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX; \
41 msg_mask_tbl_ptr += 4; \
42 *(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX ## _LAST; \
43 msg_mask_tbl_ptr += 4; \
44 /* mimic the last entry as actual_last while creation */ \
45 *(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX ## _LAST; \
46 msg_mask_tbl_ptr += 4; \
47 /* increment by MAX_SSID_PER_RANGE cells */ \
48 msg_mask_tbl_ptr += MAX_SSID_PER_RANGE * sizeof(int); \
49} while (0)
50
51#define WAIT_FOR_SMD(num_delays, delay_time) \
52do { \
53 int count; \
54 for (count = 0; count < (num_delays); count++) \
55 udelay((delay_time)); \
56} while (0)
57
58static void diag_print_mask_table(void)
59{
60/* Enable this to print mask table when updated */
61#ifdef MASK_DEBUG
62 int first, last, actual_last;
63 uint8_t *ptr = driver->msg_masks;
64 int i = 0;
65 pr_info("diag: F3 message mask table\n");
66 while (*(uint32_t *)(ptr + 4)) {
67 first = *(uint32_t *)ptr;
68 ptr += 4;
69 last = *(uint32_t *)ptr;
70 ptr += 4;
71 actual_last = *(uint32_t *)ptr;
72 ptr += 4;
73 pr_info("diag: SSID %d, %d - %d\n", first, last, actual_last);
74 for (i = 0 ; i <= actual_last - first ; i++)
75 pr_info("diag: MASK:%x\n", *((uint32_t *)ptr + i));
76 ptr += MAX_SSID_PER_RANGE*4;
77 }
78#endif
79}
80
81void diag_create_msg_mask_table(void)
82{
83 uint8_t *msg_mask_tbl_ptr = driver->msg_masks;
84
85 CREATE_MSG_MASK_TBL_ROW(0);
86 CREATE_MSG_MASK_TBL_ROW(1);
87 CREATE_MSG_MASK_TBL_ROW(2);
88 CREATE_MSG_MASK_TBL_ROW(3);
89 CREATE_MSG_MASK_TBL_ROW(4);
90 CREATE_MSG_MASK_TBL_ROW(5);
91 CREATE_MSG_MASK_TBL_ROW(6);
92 CREATE_MSG_MASK_TBL_ROW(7);
93 CREATE_MSG_MASK_TBL_ROW(8);
94 CREATE_MSG_MASK_TBL_ROW(9);
95 CREATE_MSG_MASK_TBL_ROW(10);
96 CREATE_MSG_MASK_TBL_ROW(11);
97 CREATE_MSG_MASK_TBL_ROW(12);
98 CREATE_MSG_MASK_TBL_ROW(13);
99 CREATE_MSG_MASK_TBL_ROW(14);
100 CREATE_MSG_MASK_TBL_ROW(15);
101 CREATE_MSG_MASK_TBL_ROW(16);
102 CREATE_MSG_MASK_TBL_ROW(17);
103 CREATE_MSG_MASK_TBL_ROW(18);
104 CREATE_MSG_MASK_TBL_ROW(19);
105 CREATE_MSG_MASK_TBL_ROW(20);
106 CREATE_MSG_MASK_TBL_ROW(21);
107 CREATE_MSG_MASK_TBL_ROW(22);
108 CREATE_MSG_MASK_TBL_ROW(23);
109}
110
111static void diag_set_msg_mask(int rt_mask)
112{
113 int first_ssid, last_ssid, i;
114 uint8_t *parse_ptr, *ptr = driver->msg_masks;
115
116 mutex_lock(&driver->diagchar_mutex);
117 while (*(uint32_t *)(ptr + 4)) {
118 first_ssid = *(uint32_t *)ptr;
119 ptr += 8; /* increment by 8 to skip 'last' */
120 last_ssid = *(uint32_t *)ptr;
121 ptr += 4;
122 parse_ptr = ptr;
123 pr_debug("diag: updating range %d %d\n", first_ssid, last_ssid);
124 for (i = 0; i < last_ssid - first_ssid + 1; i++) {
125 *(int *)parse_ptr = rt_mask;
126 parse_ptr += 4;
127 }
128 ptr += MAX_SSID_PER_RANGE * 4;
129 }
130 mutex_unlock(&driver->diagchar_mutex);
131}
132
133static void diag_update_msg_mask(int start, int end , uint8_t *buf)
134{
135 int found = 0, first, last, actual_last;
136 uint8_t *actual_last_ptr;
137 uint8_t *ptr = driver->msg_masks;
138 uint8_t *ptr_buffer_start = &(*(driver->msg_masks));
139 uint8_t *ptr_buffer_end = &(*(driver->msg_masks)) + MSG_MASK_SIZE;
140
141 mutex_lock(&driver->diagchar_mutex);
142
143 /* First SSID can be zero : So check that last is non-zero */
144 while (*(uint32_t *)(ptr + 4)) {
145 first = *(uint32_t *)ptr;
146 ptr += 4;
147 last = *(uint32_t *)ptr;
148 ptr += 4;
149 actual_last = *(uint32_t *)ptr;
150 actual_last_ptr = ptr;
151 ptr += 4;
152 if (start >= first && start <= actual_last) {
153 ptr += (start - first)*4;
154 if (end > actual_last) {
155 pr_info("diag: ssid range mismatch\n");
156 actual_last = end;
157 *(uint32_t *)(actual_last_ptr) = end;
158 }
159 if (CHK_OVERFLOW(ptr_buffer_start, ptr, ptr_buffer_end,
160 (((end - start)+1)*4))) {
161 pr_debug("diag: update ssid start %d, end %d\n",
162 start, end);
163 memcpy(ptr, buf , ((end - start)+1)*4);
164 } else
165 pr_alert("diag: Not enough space MSG_MASK\n");
166 found = 1;
167 break;
168 } else {
169 ptr += MAX_SSID_PER_RANGE*4;
170 }
171 }
172 /* Entry was not found - add new table */
173 if (!found) {
174 if (CHK_OVERFLOW(ptr_buffer_start, ptr, ptr_buffer_end,
175 8 + ((end - start) + 1)*4)) {
176 memcpy(ptr, &(start) , 4);
177 ptr += 4;
178 memcpy(ptr, &(end), 4);
179 ptr += 4;
180 memcpy(ptr, &(end), 4); /* create actual_last entry */
181 ptr += 4;
182 pr_debug("diag: adding NEW ssid start %d, end %d\n",
183 start, end);
184 memcpy(ptr, buf , ((end - start) + 1)*4);
185 } else
186 pr_alert("diag: Not enough buffer space for MSG_MASK\n");
187 }
188 mutex_unlock(&driver->diagchar_mutex);
189 diag_print_mask_table();
190}
191
192void diag_toggle_event_mask(int toggle)
193{
194 uint8_t *ptr = driver->event_masks;
195
196 mutex_lock(&driver->diagchar_mutex);
197 if (toggle)
198 memset(ptr, 0xFF, EVENT_MASK_SIZE);
199 else
200 memset(ptr, 0, EVENT_MASK_SIZE);
201 mutex_unlock(&driver->diagchar_mutex);
202}
203
204
205static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bytes)
206{
207 uint8_t *ptr = driver->event_masks;
208 uint8_t *temp = buf + 2;
209
210 mutex_lock(&driver->diagchar_mutex);
211 if (!toggle)
212 memset(ptr, 0 , EVENT_MASK_SIZE);
213 else
214 if (CHK_OVERFLOW(ptr, ptr,
215 ptr+EVENT_MASK_SIZE, num_bytes))
216 memcpy(ptr, temp , num_bytes);
217 else
218 printk(KERN_CRIT "Not enough buffer space for EVENT_MASK\n");
219 mutex_unlock(&driver->diagchar_mutex);
220}
221
222static void diag_disable_log_mask(void)
223{
224 int i = 0;
225 struct mask_info *parse_ptr = (struct mask_info *)(driver->log_masks);
226
227 pr_debug("diag: disable log masks\n");
228 mutex_lock(&driver->diagchar_mutex);
229 for (i = 0; i < MAX_EQUIP_ID; i++) {
230 pr_debug("diag: equip id %d\n", parse_ptr->equip_id);
231 if (!(parse_ptr->equip_id)) /* Reached a null entry */
232 break;
233 memset(driver->log_masks + parse_ptr->index, 0,
234 (parse_ptr->num_items + 7)/8);
235 parse_ptr++;
236 }
237 mutex_unlock(&driver->diagchar_mutex);
238}
239
240int chk_equip_id_and_mask(int equip_id, uint8_t *buf)
241{
242 int i = 0, flag = 0, num_items, offset;
243 unsigned char *ptr_data;
244 struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
245
246 pr_debug("diag: received equip id = %d\n", equip_id);
247 /* Check if this is valid equipment ID */
248 for (i = 0; i < MAX_EQUIP_ID; i++) {
249 if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
250 offset = ptr->index;
251 num_items = ptr->num_items;
252 flag = 1;
253 break;
254 }
255 ptr++;
256 }
257 if (!flag)
258 return -EPERM;
259 ptr_data = driver->log_masks + offset;
260 memcpy(buf, ptr_data, (num_items+7)/8);
261 return 0;
262}
263
264static void diag_update_log_mask(int equip_id, uint8_t *buf, int num_items)
265{
266 uint8_t *temp = buf;
267 int i = 0;
268 unsigned char *ptr_data;
269 int offset = (sizeof(struct mask_info))*MAX_EQUIP_ID;
270 struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
271
272 pr_debug("diag: received equip id = %d\n", equip_id);
273 mutex_lock(&driver->diagchar_mutex);
274 /* Check if we already know index of this equipment ID */
275 for (i = 0; i < MAX_EQUIP_ID; i++) {
276 if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
277 offset = ptr->index;
278 break;
279 }
280 if ((ptr->equip_id == 0) && (ptr->index == 0)) {
281 /* Reached a null entry */
282 ptr->equip_id = equip_id;
283 ptr->num_items = num_items;
284 ptr->index = driver->log_masks_length;
285 offset = driver->log_masks_length;
286 driver->log_masks_length += ((num_items+7)/8);
287 break;
288 }
289 ptr++;
290 }
291 ptr_data = driver->log_masks + offset;
292 if (CHK_OVERFLOW(driver->log_masks, ptr_data, driver->log_masks
293 + LOG_MASK_SIZE, (num_items+7)/8))
294 memcpy(ptr_data, temp , (num_items+7)/8);
295 else
296 pr_err("diag: Not enough buffer space for LOG_MASK\n");
297 mutex_unlock(&driver->diagchar_mutex);
298}
299
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800300void diag_mask_update_fn(struct work_struct *work)
Dixon Petersond6a20a92012-09-27 15:58:50 -0700301{
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800302 struct diag_smd_info *smd_info = container_of(work,
303 struct diag_smd_info,
304 diag_notify_update_smd_work);
305 if (!smd_info) {
306 pr_err("diag: In %s, smd info is null, cannot update masks for the peripheral\n",
307 __func__);
308 return;
309 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700310
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800311 diag_send_msg_mask_update(smd_info->ch, ALL_SSID, ALL_SSID,
312 smd_info->peripheral);
313 diag_send_log_mask_update(smd_info->ch, ALL_EQUIP_ID);
314 diag_send_event_mask_update(smd_info->ch, diag_event_num_bytes);
Ravi Aravamudhand09f8772012-12-20 14:48:30 -0800315 diag_send_feature_mask_update(smd_info->ch, smd_info->peripheral);
Dixon Petersond6a20a92012-09-27 15:58:50 -0700316
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800317 smd_info->notify_context = 0;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700318}
319
320void diag_send_log_mask_update(smd_channel_t *ch, int equip_id)
321{
322 void *buf = driver->buf_log_mask_update;
323 int header_size = sizeof(struct diag_ctrl_log_mask);
324 struct mask_info *ptr = (struct mask_info *)driver->log_masks;
325 int i, size, wr_size = -ENOMEM, retry_count = 0;
326
327 mutex_lock(&driver->diag_cntl_mutex);
328 for (i = 0; i < MAX_EQUIP_ID; i++) {
329 size = (ptr->num_items+7)/8;
330 /* reached null entry */
331 if ((ptr->equip_id == 0) && (ptr->index == 0))
332 break;
333 driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
334 driver->log_mask->num_items = ptr->num_items;
335 driver->log_mask->data_len = 11 + size;
336 driver->log_mask->stream_id = 1; /* 2, if dual stream */
337 driver->log_mask->status = 3; /* status for valid mask */
338 driver->log_mask->equip_id = ptr->equip_id;
339 driver->log_mask->log_mask_size = size;
340 /* send only desired update, NOT ALL */
341 if (equip_id == ALL_EQUIP_ID || equip_id ==
342 driver->log_mask->equip_id) {
343 memcpy(buf, driver->log_mask, header_size);
344 memcpy(buf+header_size, driver->log_masks+ptr->index,
345 size);
346 if (ch) {
347 while (retry_count < 3) {
348 wr_size = smd_write(ch, buf,
349 header_size + size);
350 if (wr_size == -ENOMEM) {
351 retry_count++;
352 WAIT_FOR_SMD(5, 2000);
353 } else
354 break;
355 }
356 if (wr_size != header_size + size)
357 pr_err("diag: log mask update failed %d, tried %d",
358 wr_size, header_size + size);
359 else
360 pr_debug("diag: updated log equip ID %d,len %d\n",
361 driver->log_mask->equip_id,
362 driver->log_mask->log_mask_size);
363 } else
364 pr_err("diag: ch not valid for log update\n");
365 }
366 ptr++;
367 }
368 mutex_unlock(&driver->diag_cntl_mutex);
369}
370
371void diag_send_event_mask_update(smd_channel_t *ch, int num_bytes)
372{
373 void *buf = driver->buf_event_mask_update;
374 int header_size = sizeof(struct diag_ctrl_event_mask);
375 int wr_size = -ENOMEM, retry_count = 0;
376
377 mutex_lock(&driver->diag_cntl_mutex);
378 if (num_bytes == 0) {
379 pr_debug("diag: event mask not set yet, so no update\n");
380 mutex_unlock(&driver->diag_cntl_mutex);
381 return;
382 }
383 /* send event mask update */
384 driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
385 driver->event_mask->data_len = 7 + num_bytes;
386 driver->event_mask->stream_id = 1; /* 2, if dual stream */
387 driver->event_mask->status = 3; /* status for valid mask */
388 driver->event_mask->event_config = diag_event_config; /* event config */
389 driver->event_mask->event_mask_size = num_bytes;
390 memcpy(buf, driver->event_mask, header_size);
391 memcpy(buf+header_size, driver->event_masks, num_bytes);
392 if (ch) {
393 while (retry_count < 3) {
394 wr_size = smd_write(ch, buf, header_size + num_bytes);
395 if (wr_size == -ENOMEM) {
396 retry_count++;
397 WAIT_FOR_SMD(5, 2000);
398 } else
399 break;
400 }
401 if (wr_size != header_size + num_bytes)
402 pr_err("diag: error writing event mask %d, tried %d\n",
403 wr_size, header_size + num_bytes);
404 } else
405 pr_err("diag: ch not valid for event update\n");
406 mutex_unlock(&driver->diag_cntl_mutex);
407}
408
409void diag_send_msg_mask_update(smd_channel_t *ch, int updated_ssid_first,
410 int updated_ssid_last, int proc)
411{
412 void *buf = driver->buf_msg_mask_update;
413 int first, last, actual_last, size = -ENOMEM, retry_count = 0;
414 int header_size = sizeof(struct diag_ctrl_msg_mask);
415 uint8_t *ptr = driver->msg_masks;
416
417 mutex_lock(&driver->diag_cntl_mutex);
418 while (*(uint32_t *)(ptr + 4)) {
419 first = *(uint32_t *)ptr;
420 ptr += 4;
421 last = *(uint32_t *)ptr;
422 ptr += 4;
423 actual_last = *(uint32_t *)ptr;
424 ptr += 4;
425 if ((updated_ssid_first >= first && updated_ssid_last <=
426 actual_last) || (updated_ssid_first == ALL_SSID)) {
427 /* send f3 mask update */
428 driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
429 driver->msg_mask->msg_mask_size = actual_last -
430 first + 1;
431 driver->msg_mask->data_len = 11 +
432 4 * (driver->msg_mask->msg_mask_size);
433 driver->msg_mask->stream_id = 1; /* 2, if dual stream */
434 driver->msg_mask->status = 3; /* status valid mask */
435 driver->msg_mask->msg_mode = 0; /* Legcay mode */
436 driver->msg_mask->ssid_first = first;
437 driver->msg_mask->ssid_last = actual_last;
438 memcpy(buf, driver->msg_mask, header_size);
439 memcpy(buf+header_size, ptr,
440 4 * (driver->msg_mask->msg_mask_size));
441 if (ch) {
442 while (retry_count < 3) {
443 size = smd_write(ch, buf, header_size +
444 4*(driver->msg_mask->msg_mask_size));
445 if (size == -ENOMEM) {
446 retry_count++;
447 WAIT_FOR_SMD(5, 2000);
448 } else
449 break;
450 }
451 if (size != header_size +
452 4*(driver->msg_mask->msg_mask_size))
453 pr_err("diag: proc %d, msg mask update fail %d, tried %d\n",
454 proc, size, (header_size +
455 4*(driver->msg_mask->msg_mask_size)));
456 else
457 pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
458 first, actual_last, proc);
459 } else
460 pr_err("diag: proc %d, ch invalid msg mask update\n",
461 proc);
462 }
463 ptr += MAX_SSID_PER_RANGE*4;
464 }
465 mutex_unlock(&driver->diag_cntl_mutex);
466}
467
Ravi Aravamudhand09f8772012-12-20 14:48:30 -0800468void diag_send_feature_mask_update(smd_channel_t *ch, int proc)
469{
470 void *buf = driver->buf_feature_mask_update;
471 int header_size = sizeof(struct diag_ctrl_feature_mask);
472 int wr_size = -ENOMEM, retry_count = 0, timer;
473 uint8_t feature_byte = 0;
474
475 mutex_lock(&driver->diag_cntl_mutex);
476 /* send feature mask update */
477 driver->feature_mask->ctrl_pkt_id = DIAG_CTRL_MSG_FEATURE;
478 driver->feature_mask->ctrl_pkt_data_len = 4 + FEATURE_MASK_LEN_BYTES;
479 driver->feature_mask->feature_mask_len = FEATURE_MASK_LEN_BYTES;
480 memcpy(buf, driver->feature_mask, header_size);
481 feature_byte |= APPS_RESPOND_LOG_ON_DEMAND;
482 memcpy(buf+header_size, &feature_byte, FEATURE_MASK_LEN_BYTES);
483
484 if (ch) {
485 while (retry_count < 3) {
486 wr_size = smd_write(ch, buf, header_size +
487 FEATURE_MASK_LEN_BYTES);
488 if (wr_size == -ENOMEM) {
489 retry_count++;
490 for (timer = 0; timer < 5; timer++)
491 udelay(2000);
492 } else
493 break;
494 }
495 if (wr_size != header_size + FEATURE_MASK_LEN_BYTES)
496 pr_err("diag: proc %d fail feature update %d, tried %d",
497 proc, wr_size, header_size + FEATURE_MASK_LEN_BYTES);
498 } else
499 pr_err("diag: ch invalid, feature update on proc %d\n", proc);
500 mutex_unlock(&driver->diag_cntl_mutex);
501
502}
503
Dixon Petersond6a20a92012-09-27 15:58:50 -0700504int diag_process_apps_masks(unsigned char *buf, int len)
505{
506 int packet_type = 1;
507 int i;
508 int ssid_first, ssid_last, ssid_range;
509 int rt_mask, rt_first_ssid, rt_last_ssid, rt_mask_size;
510 uint8_t *rt_mask_ptr;
511 int equip_id, num_items;
512#if defined(CONFIG_DIAG_OVER_USB)
513 int payload_length;
514#endif
515
516 /* Set log masks */
517 if (*buf == 0x73 && *(int *)(buf+4) == 3) {
518 buf += 8;
519 /* Read Equip ID and pass as first param below*/
520 diag_update_log_mask(*(int *)buf, buf+8, *(int *)(buf+4));
521 diag_update_userspace_clients(LOG_MASKS_TYPE);
522#if defined(CONFIG_DIAG_OVER_USB)
523 if (chk_apps_only()) {
524 driver->apps_rsp_buf[0] = 0x73;
525 *(int *)(driver->apps_rsp_buf + 4) = 0x3; /* op. ID */
526 *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success */
527 payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800528 if (payload_length > APPS_BUF_SIZE - 12) {
529 pr_err("diag: log masks: buffer overflow\n");
530 return -EIO;
531 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700532 for (i = 0; i < payload_length; i++)
533 *(int *)(driver->apps_rsp_buf+12+i) = *(buf+i);
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800534
535 for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
536 if (driver->smd_cntl[i].ch)
537 diag_send_log_mask_update(
538 driver->smd_cntl[i].ch,
539 *(int *)buf);
540 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700541 encode_rsp_and_send(12 + payload_length - 1);
542 return 0;
543 }
544#endif
545 } /* Get log masks */
546 else if (*buf == 0x73 && *(int *)(buf+4) == 4) {
547#if defined(CONFIG_DIAG_OVER_USB)
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800548 if (!(driver->smd_data[MODEM_DATA].ch) &&
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800549 chk_apps_only()) {
Dixon Petersond6a20a92012-09-27 15:58:50 -0700550 equip_id = *(int *)(buf + 8);
551 num_items = *(int *)(buf + 12);
552 driver->apps_rsp_buf[0] = 0x73;
553 driver->apps_rsp_buf[1] = 0x0;
554 driver->apps_rsp_buf[2] = 0x0;
555 driver->apps_rsp_buf[3] = 0x0;
556 *(int *)(driver->apps_rsp_buf + 4) = 0x4;
557 if (!chk_equip_id_and_mask(equip_id,
558 driver->apps_rsp_buf+20))
559 *(int *)(driver->apps_rsp_buf + 8) = 0x0;
560 else
561 *(int *)(driver->apps_rsp_buf + 8) = 0x1;
562 *(int *)(driver->apps_rsp_buf + 12) = equip_id;
563 *(int *)(driver->apps_rsp_buf + 16) = num_items;
564 encode_rsp_and_send(20+(num_items+7)/8-1);
565 return 0;
566 }
567#endif
568 } /* Disable log masks */
569 else if (*buf == 0x73 && *(int *)(buf+4) == 0) {
570 /* Disable mask for each log code */
571 diag_disable_log_mask();
572 diag_update_userspace_clients(LOG_MASKS_TYPE);
573#if defined(CONFIG_DIAG_OVER_USB)
574 if (chk_apps_only()) {
575 driver->apps_rsp_buf[0] = 0x73;
576 driver->apps_rsp_buf[1] = 0x0;
577 driver->apps_rsp_buf[2] = 0x0;
578 driver->apps_rsp_buf[3] = 0x0;
579 *(int *)(driver->apps_rsp_buf + 4) = 0x0;
580 *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* status */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800581 for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
582 if (driver->smd_cntl[i].ch)
583 diag_send_log_mask_update(
584 driver->smd_cntl[i].ch,
585 ALL_EQUIP_ID);
586
587 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700588 encode_rsp_and_send(11);
589 return 0;
590 }
591#endif
592 } /* Get runtime message mask */
593 else if ((*buf == 0x7d) && (*(buf+1) == 0x3)) {
594 ssid_first = *(uint16_t *)(buf + 2);
595 ssid_last = *(uint16_t *)(buf + 4);
596#if defined(CONFIG_DIAG_OVER_USB)
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800597 if (!(driver->smd_data[MODEM_DATA].ch) &&
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800598 chk_apps_only()) {
Dixon Petersond6a20a92012-09-27 15:58:50 -0700599 driver->apps_rsp_buf[0] = 0x7d;
600 driver->apps_rsp_buf[1] = 0x3;
601 *(uint16_t *)(driver->apps_rsp_buf+2) = ssid_first;
602 *(uint16_t *)(driver->apps_rsp_buf+4) = ssid_last;
603 driver->apps_rsp_buf[6] = 0x1; /* Success Status */
604 driver->apps_rsp_buf[7] = 0x0;
605 rt_mask_ptr = driver->msg_masks;
606 while (*(uint32_t *)(rt_mask_ptr + 4)) {
607 rt_first_ssid = *(uint32_t *)rt_mask_ptr;
608 rt_mask_ptr += 8; /* +8 to skip 'last' */
609 rt_last_ssid = *(uint32_t *)rt_mask_ptr;
610 rt_mask_ptr += 4;
611 if (ssid_first == rt_first_ssid && ssid_last ==
612 rt_last_ssid) {
613 rt_mask_size = 4 * (rt_last_ssid -
614 rt_first_ssid + 1);
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800615 if (rt_mask_size > APPS_BUF_SIZE - 8) {
616 pr_err("diag: rt masks: buffer overflow\n");
617 return -EIO;
618 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700619 memcpy(driver->apps_rsp_buf+8,
620 rt_mask_ptr, rt_mask_size);
621 encode_rsp_and_send(8+rt_mask_size-1);
622 return 0;
623 }
624 rt_mask_ptr += MAX_SSID_PER_RANGE*4;
625 }
626 }
627#endif
628 } /* Set runtime message mask */
629 else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
630 ssid_first = *(uint16_t *)(buf + 2);
631 ssid_last = *(uint16_t *)(buf + 4);
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800632 if (ssid_last < ssid_first) {
633 pr_err("diag: Invalid msg mask ssid values, first: %d, last: %d\n",
634 ssid_first, ssid_last);
635 return -EIO;
636 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700637 ssid_range = 4 * (ssid_last - ssid_first + 1);
Ravi Aravamudhanf70200e2013-02-13 10:05:36 -0800638 if (ssid_range > APPS_BUF_SIZE - 8) {
639 pr_err("diag: Not enough space for message mask, ssid_range: %d\n",
640 ssid_range);
641 return -EIO;
642 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700643 pr_debug("diag: received mask update for ssid_first = %d, ssid_last = %d",
644 ssid_first, ssid_last);
645 diag_update_msg_mask(ssid_first, ssid_last , buf + 8);
646 diag_update_userspace_clients(MSG_MASKS_TYPE);
647#if defined(CONFIG_DIAG_OVER_USB)
648 if (chk_apps_only()) {
649 for (i = 0; i < 8 + ssid_range; i++)
650 *(driver->apps_rsp_buf + i) = *(buf+i);
651 *(driver->apps_rsp_buf + 6) = 0x1;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800652 for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
653 if (driver->smd_cntl[i].ch)
654 diag_send_msg_mask_update(
655 driver->smd_cntl[i].ch,
656 ssid_first, ssid_last,
657 driver->smd_cntl[i].peripheral);
658
659 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700660 encode_rsp_and_send(8 + ssid_range - 1);
661 return 0;
662 }
663#endif
664 } /* Set ALL runtime message mask */
665 else if ((*buf == 0x7d) && (*(buf+1) == 0x5)) {
666 rt_mask = *(int *)(buf + 4);
667 diag_set_msg_mask(rt_mask);
668 diag_update_userspace_clients(MSG_MASKS_TYPE);
669#if defined(CONFIG_DIAG_OVER_USB)
670 if (chk_apps_only()) {
671 driver->apps_rsp_buf[0] = 0x7d; /* cmd_code */
672 driver->apps_rsp_buf[1] = 0x5; /* set subcommand */
673 driver->apps_rsp_buf[2] = 1; /* success */
674 driver->apps_rsp_buf[3] = 0; /* rsvd */
675 *(int *)(driver->apps_rsp_buf + 4) = rt_mask;
676 /* send msg mask update to peripheral */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800677 for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
678 if (driver->smd_cntl[i].ch)
679 diag_send_msg_mask_update(
680 driver->smd_cntl[i].ch,
681 ALL_SSID, ALL_SSID,
682 driver->smd_cntl[i].peripheral);
683
684 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700685 encode_rsp_and_send(7);
686 return 0;
687 }
688#endif
689 } else if (*buf == 0x82) { /* event mask change */
690 buf += 4;
691 diag_event_num_bytes = (*(uint16_t *)buf)/8+1;
692 diag_update_event_mask(buf, 1, (*(uint16_t *)buf)/8+1);
693 diag_update_userspace_clients(EVENT_MASKS_TYPE);
694#if defined(CONFIG_DIAG_OVER_USB)
695 if (chk_apps_only()) {
696 driver->apps_rsp_buf[0] = 0x82;
697 driver->apps_rsp_buf[1] = 0x0;
698 *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
699 *(uint16_t *)(driver->apps_rsp_buf + 4) =
700 EVENT_LAST_ID + 1;
701 memcpy(driver->apps_rsp_buf+6, driver->event_masks,
702 EVENT_LAST_ID/8+1);
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800703 for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
704 if (driver->smd_cntl[i].ch)
705 diag_send_event_mask_update(
706 driver->smd_cntl[i].ch,
707 diag_event_num_bytes);
708 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700709 encode_rsp_and_send(6 + EVENT_LAST_ID/8);
710 return 0;
711 }
712#endif
713 } else if (*buf == 0x60) {
714 diag_event_config = *(buf+1);
715 diag_toggle_event_mask(*(buf+1));
716 diag_update_userspace_clients(EVENT_MASKS_TYPE);
717#if defined(CONFIG_DIAG_OVER_USB)
718 if (chk_apps_only()) {
719 driver->apps_rsp_buf[0] = 0x60;
720 driver->apps_rsp_buf[1] = 0x0;
721 driver->apps_rsp_buf[2] = 0x0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800722 for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
723 if (driver->smd_cntl[i].ch)
724 diag_send_event_mask_update(
725 driver->smd_cntl[i].ch,
726 diag_event_num_bytes);
727 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700728 encode_rsp_and_send(2);
729 return 0;
730 }
731#endif
Ravi Aravamudhand09f8772012-12-20 14:48:30 -0800732 } else if (*buf == 0x78) {
733 if (!(driver->smd_cntl[MODEM_DATA].ch) ||
734 (driver->log_on_demand_support)) {
735 driver->apps_rsp_buf[0] = 0x78;
736 /* Copy log code received */
737 *(uint16_t *)(driver->apps_rsp_buf+1) =
738 *(uint16_t *)buf;
739 driver->apps_rsp_buf[3] = 0x1;/* Unknown */
740 encode_rsp_and_send(3);
741 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700742 }
743
744 return packet_type;
745}
746
747void diag_masks_init(void)
748{
749 if (driver->event_mask == NULL) {
750 driver->event_mask = kzalloc(sizeof(
751 struct diag_ctrl_event_mask), GFP_KERNEL);
752 if (driver->event_mask == NULL)
753 goto err;
754 kmemleak_not_leak(driver->event_mask);
755 }
756 if (driver->msg_mask == NULL) {
757 driver->msg_mask = kzalloc(sizeof(
758 struct diag_ctrl_msg_mask), GFP_KERNEL);
759 if (driver->msg_mask == NULL)
760 goto err;
761 kmemleak_not_leak(driver->msg_mask);
762 }
763 if (driver->log_mask == NULL) {
764 driver->log_mask = kzalloc(sizeof(
765 struct diag_ctrl_log_mask), GFP_KERNEL);
766 if (driver->log_mask == NULL)
767 goto err;
768 kmemleak_not_leak(driver->log_mask);
769 }
770
771 if (driver->buf_msg_mask_update == NULL) {
772 driver->buf_msg_mask_update = kzalloc(APPS_BUF_SIZE,
773 GFP_KERNEL);
774 if (driver->buf_msg_mask_update == NULL)
775 goto err;
776 kmemleak_not_leak(driver->buf_msg_mask_update);
777 }
778 if (driver->buf_log_mask_update == NULL) {
779 driver->buf_log_mask_update = kzalloc(APPS_BUF_SIZE,
780 GFP_KERNEL);
781 if (driver->buf_log_mask_update == NULL)
782 goto err;
783 kmemleak_not_leak(driver->buf_log_mask_update);
784 }
785 if (driver->buf_event_mask_update == NULL) {
786 driver->buf_event_mask_update = kzalloc(APPS_BUF_SIZE,
787 GFP_KERNEL);
788 if (driver->buf_event_mask_update == NULL)
789 goto err;
790 kmemleak_not_leak(driver->buf_event_mask_update);
791 }
792 if (driver->msg_masks == NULL) {
793 driver->msg_masks = kzalloc(MSG_MASK_SIZE, GFP_KERNEL);
794 if (driver->msg_masks == NULL)
795 goto err;
796 kmemleak_not_leak(driver->msg_masks);
797 }
Ravi Aravamudhand09f8772012-12-20 14:48:30 -0800798 if (driver->buf_feature_mask_update == NULL) {
799 driver->buf_feature_mask_update = kzalloc(sizeof(
800 struct diag_ctrl_feature_mask) +
801 FEATURE_MASK_LEN_BYTES, GFP_KERNEL);
802 if (driver->buf_feature_mask_update == NULL)
803 goto err;
804 kmemleak_not_leak(driver->buf_feature_mask_update);
805 }
806 if (driver->feature_mask == NULL) {
807 driver->feature_mask = kzalloc(sizeof(
808 struct diag_ctrl_feature_mask), GFP_KERNEL);
809 if (driver->feature_mask == NULL)
810 goto err;
811 kmemleak_not_leak(driver->feature_mask);
812 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700813 diag_create_msg_mask_table();
814 diag_event_num_bytes = 0;
815 if (driver->log_masks == NULL) {
816 driver->log_masks = kzalloc(LOG_MASK_SIZE, GFP_KERNEL);
817 if (driver->log_masks == NULL)
818 goto err;
819 kmemleak_not_leak(driver->log_masks);
820 }
821 driver->log_masks_length = (sizeof(struct mask_info))*MAX_EQUIP_ID;
822 if (driver->event_masks == NULL) {
823 driver->event_masks = kzalloc(EVENT_MASK_SIZE, GFP_KERNEL);
824 if (driver->event_masks == NULL)
825 goto err;
826 kmemleak_not_leak(driver->event_masks);
827 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700828 return;
829err:
830 pr_err("diag: Could not initialize diag mask buffers");
831 kfree(driver->event_mask);
832 kfree(driver->log_mask);
833 kfree(driver->msg_mask);
834 kfree(driver->msg_masks);
835 kfree(driver->log_masks);
836 kfree(driver->event_masks);
Ravi Aravamudhand09f8772012-12-20 14:48:30 -0800837 kfree(driver->feature_mask);
838 kfree(driver->buf_feature_mask_update);
Dixon Petersond6a20a92012-09-27 15:58:50 -0700839}
840
841void diag_masks_exit(void)
842{
843 kfree(driver->event_mask);
844 kfree(driver->log_mask);
845 kfree(driver->msg_mask);
846 kfree(driver->msg_masks);
847 kfree(driver->log_masks);
848 kfree(driver->event_masks);
Ravi Aravamudhand09f8772012-12-20 14:48:30 -0800849 kfree(driver->feature_mask);
850 kfree(driver->buf_feature_mask_update);
Dixon Petersond6a20a92012-09-27 15:58:50 -0700851}