blob: 65ddfec7589e4545f71f29f1be01ebe92e2ecf18 [file] [log] [blame]
Dixon Peterson32e70bb2011-12-16 13:26:45 -08001/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -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 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070012#include <linux/slab.h>
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/err.h>
17#include <linux/platform_device.h>
18#include <linux/sched.h>
19#include <linux/workqueue.h>
20#include <linux/pm_runtime.h>
21#include <linux/diagchar.h>
22#include <linux/delay.h>
23#include <linux/reboot.h>
Dixon Petersonb4618a42012-02-29 18:56:31 -080024#include <linux/of.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#ifdef CONFIG_DIAG_OVER_USB
26#include <mach/usbdiag.h>
27#endif
28#include <mach/msm_smd.h>
29#include <mach/socinfo.h>
30#include <mach/restart.h>
31#include "diagmem.h"
32#include "diagchar.h"
33#include "diagfwd.h"
34#include "diagfwd_cntl.h"
35#include "diagchar_hdlc.h"
36#ifdef CONFIG_DIAG_SDIO_PIPE
37#include "diagfwd_sdio.h"
38#endif
39#define MODE_CMD 41
40#define RESET_ID 2
41
42int diag_debug_buf_idx;
43unsigned char diag_debug_buf[1024];
44static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
45struct diag_master_table entry;
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -080046smd_channel_t *ch_temp, *chqdsp_temp, *ch_wcnss_temp;
Shalabh Jain321c8b52012-02-22 12:37:06 -080047int diag_event_num_bytes;
48int diag_event_config;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070049struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
50struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
Shalabh Jain321c8b52012-02-22 12:37:06 -080051struct mask_info {
52 int equip_id;
53 int num_items;
54 int index;
55};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056
57#define ENCODE_RSP_AND_SEND(buf_length) \
58do { \
59 send.state = DIAG_STATE_START; \
60 send.pkt = driver->apps_rsp_buf; \
61 send.last = (void *)(driver->apps_rsp_buf + buf_length); \
62 send.terminate = 1; \
63 if (!driver->in_busy_1) { \
64 enc.dest = driver->buf_in_1; \
Shalabh Jain321c8b52012-02-22 12:37:06 -080065 enc.dest_last = (void *)(driver->buf_in_1 + APPS_BUF_SIZE - 1);\
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066 diag_hdlc_encode(&send, &enc); \
67 driver->write_ptr_1->buf = driver->buf_in_1; \
68 driver->write_ptr_1->length = (int)(enc.dest - \
69 (void *)(driver->buf_in_1)); \
Shalabh Jain3893bf92011-09-18 18:37:16 -070070 driver->in_busy_1 = 1; \
Shalabh Jain69890aa2011-10-10 12:59:16 -070071 diag_device_write(driver->buf_in_1, MODEM_DATA, \
72 driver->write_ptr_1); \
Shalabh Jain321c8b52012-02-22 12:37:06 -080073 memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE); \
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070074 } \
75} while (0)
76
77#define CHK_OVERFLOW(bufStart, start, end, length) \
78((bufStart <= start) && (end - start >= length)) ? 1 : 0
79
Dixon Petersonb4618a42012-02-29 18:56:31 -080080/* Determine if this device uses a device tree */
81#ifdef CONFIG_OF
82static int has_device_tree(void)
83{
84 struct device_node *node;
85
86 node = of_find_node_by_path("/");
87 if (node) {
88 of_node_put(node);
89 return 1;
90 }
91 return 0;
92}
93#else
94static int has_device_tree(void)
95{
96 return 0;
97}
98#endif
99
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700100int chk_config_get_id(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700101{
Shalabh Jain482bf122011-12-06 03:54:47 -0800102 /* For all Fusion targets, Modem will always be present */
103 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
104 return 0;
105
Dixon Petersonb4618a42012-02-29 18:56:31 -0800106 if (driver->use_device_tree) {
107 if (machine_is_copper())
108 return MSM8974_TOOLS_ID;
109 else
110 return 0;
111 } else {
112 switch (socinfo_get_msm_cpu()) {
113 case MSM_CPU_8X60:
114 return APQ8060_TOOLS_ID;
115 case MSM_CPU_8960:
116 return AO8960_TOOLS_ID;
117 case MSM_CPU_8064:
118 return APQ8064_TOOLS_ID;
119 case MSM_CPU_8930:
120 return MSM8930_TOOLS_ID;
121 case MSM_CPU_COPPER:
122 return MSM8974_TOOLS_ID;
123 case MSM_CPU_8625:
124 return MSM8625_TOOLS_ID;
125 default:
126 return 0;
127 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700128 }
129}
130
131/*
Shalabh Jain321c8b52012-02-22 12:37:06 -0800132 * This will return TRUE for targets which support apps only mode and hence SSR.
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700133 * This applies to 8960 and newer targets.
134 */
135int chk_apps_only(void)
136{
Dixon Petersonb4618a42012-02-29 18:56:31 -0800137 if (driver->use_device_tree)
138 return 1;
139
140 switch (socinfo_get_msm_cpu()) {
141 case MSM_CPU_8960:
142 case MSM_CPU_8064:
143 case MSM_CPU_8930:
144 case MSM_CPU_8627:
145 case MSM_CPU_9615:
146 case MSM_CPU_COPPER:
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700147 return 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 default:
149 return 0;
150 }
151}
152
Shalabh Jain10f5f432012-01-11 11:45:44 +0530153/*
154 * This will return TRUE for targets which support apps as master.
155 * Thus, SW DLOAD and Mode Reset are supported on apps processor.
156 * This applies to 8960 and newer targets.
157 */
158int chk_apps_master(void)
159{
Dixon Petersonb4618a42012-02-29 18:56:31 -0800160 if (driver->use_device_tree)
161 return 1;
162 else if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm9615() ||
163 cpu_is_apq8064() || cpu_is_msm8627())
164 return 1;
165 else
166 return 0;
167}
168
169inline int chk_polling_response(void)
170{
171 if (!(driver->polling_reg_flag) && chk_apps_master())
172 /*
173 * If the apps processor is master and no other processor
174 * has registered to respond for polling
175 */
176 return 1;
177 else if (!(driver->ch) && !(chk_apps_master()))
178 /*
179 * If the apps processor is not the master and the modem
180 * is not up
181 */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530182 return 1;
183 else
184 return 0;
185}
186
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187void __diag_smd_send_req(void)
188{
189 void *buf = NULL;
190 int *in_busy_ptr = NULL;
191 struct diag_request *write_ptr_modem = NULL;
192
193 if (!driver->in_busy_1) {
194 buf = driver->buf_in_1;
195 write_ptr_modem = driver->write_ptr_1;
196 in_busy_ptr = &(driver->in_busy_1);
197 } else if (!driver->in_busy_2) {
198 buf = driver->buf_in_2;
199 write_ptr_modem = driver->write_ptr_2;
200 in_busy_ptr = &(driver->in_busy_2);
201 }
202
203 if (driver->ch && buf) {
204 int r = smd_read_avail(driver->ch);
205
206 if (r > IN_BUF_SIZE) {
207 if (r < MAX_IN_BUF_SIZE) {
208 pr_err("diag: SMD sending in "
209 "packets upto %d bytes", r);
210 buf = krealloc(buf, r, GFP_KERNEL);
211 } else {
212 pr_err("diag: SMD sending in "
213 "packets more than %d bytes", MAX_IN_BUF_SIZE);
214 return;
215 }
216 }
217 if (r > 0) {
218 if (!buf)
219 pr_info("Out of diagmem for Modem\n");
220 else {
221 APPEND_DEBUG('i');
222 smd_read(driver->ch, buf, r);
223 APPEND_DEBUG('j');
224 write_ptr_modem->length = r;
225 *in_busy_ptr = 1;
226 diag_device_write(buf, MODEM_DATA,
227 write_ptr_modem);
228 }
229 }
230 }
231}
232
233int diag_device_write(void *buf, int proc_num, struct diag_request *write_ptr)
234{
235 int i, err = 0;
236
237 if (driver->logging_mode == MEMORY_DEVICE_MODE) {
238 if (proc_num == APPS_DATA) {
239 for (i = 0; i < driver->poolsize_write_struct; i++)
240 if (driver->buf_tbl[i].length == 0) {
241 driver->buf_tbl[i].buf = buf;
242 driver->buf_tbl[i].length =
243 driver->used;
244#ifdef DIAG_DEBUG
245 pr_debug("diag: ENQUEUE buf ptr"
246 " and length is %x , %d\n",
247 (unsigned int)(driver->buf_
248 tbl[i].buf), driver->buf_tbl[i].length);
249#endif
250 break;
251 }
252 }
253 for (i = 0; i < driver->num_clients; i++)
254 if (driver->client_map[i].pid ==
255 driver->logging_process_id)
256 break;
257 if (i < driver->num_clients) {
Shalabh Jain69890aa2011-10-10 12:59:16 -0700258 driver->data_ready[i] |= USER_SPACE_LOG_TYPE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 wake_up_interruptible(&driver->wait_q);
260 } else
261 return -EINVAL;
262 } else if (driver->logging_mode == NO_LOGGING_MODE) {
263 if (proc_num == MODEM_DATA) {
264 driver->in_busy_1 = 0;
265 driver->in_busy_2 = 0;
266 queue_work(driver->diag_wq, &(driver->
267 diag_read_smd_work));
268 } else if (proc_num == QDSP_DATA) {
269 driver->in_busy_qdsp_1 = 0;
270 driver->in_busy_qdsp_2 = 0;
271 queue_work(driver->diag_wq, &(driver->
272 diag_read_smd_qdsp_work));
273 } else if (proc_num == WCNSS_DATA) {
Ashay Jaiswal29620122012-03-21 12:02:36 +0530274 driver->in_busy_wcnss_1 = 0;
275 driver->in_busy_wcnss_2 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276 queue_work(driver->diag_wq, &(driver->
277 diag_read_smd_wcnss_work));
278 }
Shalabh Jain482bf122011-12-06 03:54:47 -0800279#ifdef CONFIG_DIAG_SDIO_PIPE
280 else if (proc_num == SDIO_DATA) {
281 driver->in_busy_sdio = 0;
282 queue_work(driver->diag_sdio_wq,
283 &(driver->diag_read_sdio_work));
284 }
285#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700286 err = -1;
287 }
288#ifdef CONFIG_DIAG_OVER_USB
289 else if (driver->logging_mode == USB_MODE) {
290 if (proc_num == APPS_DATA) {
291 driver->write_ptr_svc = (struct diag_request *)
292 (diagmem_alloc(driver, sizeof(struct diag_request),
293 POOL_TYPE_WRITE_STRUCT));
294 if (driver->write_ptr_svc) {
295 driver->write_ptr_svc->length = driver->used;
296 driver->write_ptr_svc->buf = buf;
297 err = usb_diag_write(driver->legacy_ch,
298 driver->write_ptr_svc);
299 } else
300 err = -1;
301 } else if (proc_num == MODEM_DATA) {
302 write_ptr->buf = buf;
303#ifdef DIAG_DEBUG
304 printk(KERN_INFO "writing data to USB,"
305 "pkt length %d\n", write_ptr->length);
306 print_hex_dump(KERN_DEBUG, "Written Packet Data to"
307 " USB: ", 16, 1, DUMP_PREFIX_ADDRESS,
308 buf, write_ptr->length, 1);
309#endif /* DIAG DEBUG */
310 err = usb_diag_write(driver->legacy_ch, write_ptr);
311 } else if (proc_num == QDSP_DATA) {
312 write_ptr->buf = buf;
313 err = usb_diag_write(driver->legacy_ch, write_ptr);
314 } else if (proc_num == WCNSS_DATA) {
315 write_ptr->buf = buf;
316 err = usb_diag_write(driver->legacy_ch, write_ptr);
317 }
318#ifdef CONFIG_DIAG_SDIO_PIPE
319 else if (proc_num == SDIO_DATA) {
320 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -0800321 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322 write_ptr->buf = buf;
323 err = usb_diag_write(driver->mdm_ch, write_ptr);
324 } else
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800325 pr_err("diag: Incorrect sdio data "
326 "while USB write\n");
327 }
328#endif
329#ifdef CONFIG_DIAG_HSIC_PIPE
330 else if (proc_num == HSIC_DATA) {
331 if (driver->hsic_device_enabled) {
332 write_ptr->buf = buf;
333 err = usb_diag_write(driver->mdm_ch, write_ptr);
334 } else
335 pr_err("diag: Incorrect hsic data "
336 "while USB write\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337 }
338#endif
339 APPEND_DEBUG('d');
340 }
341#endif /* DIAG OVER USB */
342 return err;
343}
344
345void __diag_smd_wcnss_send_req(void)
346{
Ashay Jaiswal29620122012-03-21 12:02:36 +0530347 void *buf = NULL;
348 int *in_busy_wcnss_ptr = NULL;
349 struct diag_request *write_ptr_wcnss = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700350
Ashay Jaiswal29620122012-03-21 12:02:36 +0530351 if (!driver->in_busy_wcnss_1) {
352 buf = driver->buf_in_wcnss_1;
353 write_ptr_wcnss = driver->write_ptr_wcnss_1;
354 in_busy_wcnss_ptr = &(driver->in_busy_wcnss_1);
355 } else if (!driver->in_busy_wcnss_2) {
356 buf = driver->buf_in_wcnss_2;
357 write_ptr_wcnss = driver->write_ptr_wcnss_2;
358 in_busy_wcnss_ptr = &(driver->in_busy_wcnss_2);
359 }
360
361 if (driver->ch_wcnss && buf) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362 int r = smd_read_avail(driver->ch_wcnss);
363 if (r > IN_BUF_SIZE) {
364 if (r < MAX_IN_BUF_SIZE) {
365 pr_err("diag: wcnss packets > %d bytes", r);
366 buf = krealloc(buf, r, GFP_KERNEL);
367 } else {
368 pr_err("diag: wcnss pkt > %d", MAX_IN_BUF_SIZE);
369 return;
370 }
371 }
372 if (r > 0) {
373 if (!buf) {
374 pr_err("Out of diagmem for wcnss\n");
375 } else {
376 APPEND_DEBUG('i');
377 smd_read(driver->ch_wcnss, buf, r);
378 APPEND_DEBUG('j');
379 write_ptr_wcnss->length = r;
380 *in_busy_wcnss_ptr = 1;
381 diag_device_write(buf, WCNSS_DATA,
382 write_ptr_wcnss);
383 }
384 }
385 }
386}
387
388void __diag_smd_qdsp_send_req(void)
389{
390 void *buf = NULL;
391 int *in_busy_qdsp_ptr = NULL;
392 struct diag_request *write_ptr_qdsp = NULL;
393
394 if (!driver->in_busy_qdsp_1) {
395 buf = driver->buf_in_qdsp_1;
396 write_ptr_qdsp = driver->write_ptr_qdsp_1;
397 in_busy_qdsp_ptr = &(driver->in_busy_qdsp_1);
398 } else if (!driver->in_busy_qdsp_2) {
399 buf = driver->buf_in_qdsp_2;
400 write_ptr_qdsp = driver->write_ptr_qdsp_2;
401 in_busy_qdsp_ptr = &(driver->in_busy_qdsp_2);
402 }
403
404 if (driver->chqdsp && buf) {
405 int r = smd_read_avail(driver->chqdsp);
406
407 if (r > IN_BUF_SIZE) {
408 if (r < MAX_IN_BUF_SIZE) {
409 pr_err("diag: SMD sending in "
410 "packets upto %d bytes", r);
411 buf = krealloc(buf, r, GFP_KERNEL);
412 } else {
413 pr_err("diag: SMD sending in "
414 "packets more than %d bytes", MAX_IN_BUF_SIZE);
415 return;
416 }
417 }
418 if (r > 0) {
419 if (!buf)
420 printk(KERN_INFO "Out of diagmem for QDSP\n");
421 else {
422 APPEND_DEBUG('i');
423 smd_read(driver->chqdsp, buf, r);
424 APPEND_DEBUG('j');
425 write_ptr_qdsp->length = r;
426 *in_busy_qdsp_ptr = 1;
427 diag_device_write(buf, QDSP_DATA,
428 write_ptr_qdsp);
429 }
430 }
431 }
432}
433
434static void diag_print_mask_table(void)
435{
436/* Enable this to print mask table when updated */
437#ifdef MASK_DEBUG
438 int first;
439 int last;
440 uint8_t *ptr = driver->msg_masks;
441 int i = 0;
442
443 while (*(uint32_t *)(ptr + 4)) {
444 first = *(uint32_t *)ptr;
445 ptr += 4;
446 last = *(uint32_t *)ptr;
447 ptr += 4;
448 printk(KERN_INFO "SSID %d - %d\n", first, last);
449 for (i = 0 ; i <= last - first ; i++)
450 printk(KERN_INFO "MASK:%x\n", *((uint32_t *)ptr + i));
451 ptr += ((last - first) + 1)*4;
452
453 }
454#endif
455}
456
457static void diag_update_msg_mask(int start, int end , uint8_t *buf)
458{
459 int found = 0;
460 int first;
461 int last;
462 uint8_t *ptr = driver->msg_masks;
463 uint8_t *ptr_buffer_start = &(*(driver->msg_masks));
464 uint8_t *ptr_buffer_end = &(*(driver->msg_masks)) + MSG_MASK_SIZE;
465
466 mutex_lock(&driver->diagchar_mutex);
Shalabh Jain2c783cb2012-01-15 11:09:29 +0530467
Shalabh Jain321c8b52012-02-22 12:37:06 -0800468 /* First SSID can be zero : So check that last is non-zero */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469 while (*(uint32_t *)(ptr + 4)) {
470 first = *(uint32_t *)ptr;
471 ptr += 4;
472 last = *(uint32_t *)ptr;
473 ptr += 4;
474 if (start >= first && start <= last) {
475 ptr += (start - first)*4;
476 if (end <= last)
477 if (CHK_OVERFLOW(ptr_buffer_start, ptr,
478 ptr_buffer_end,
479 (((end - start)+1)*4)))
480 memcpy(ptr, buf , ((end - start)+1)*4);
481 else
482 printk(KERN_CRIT "Not enough"
483 " buffer space for"
484 " MSG_MASK\n");
485 else
486 printk(KERN_INFO "Unable to copy"
487 " mask change\n");
Shalabh Jain2c783cb2012-01-15 11:09:29 +0530488
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489 found = 1;
490 break;
491 } else {
492 ptr += ((last - first) + 1)*4;
493 }
494 }
495 /* Entry was not found - add new table */
496 if (!found) {
497 if (CHK_OVERFLOW(ptr_buffer_start, ptr, ptr_buffer_end,
498 8 + ((end - start) + 1)*4)) {
499 memcpy(ptr, &(start) , 4);
500 ptr += 4;
501 memcpy(ptr, &(end), 4);
502 ptr += 4;
503 memcpy(ptr, buf , ((end - start) + 1)*4);
504 } else
505 printk(KERN_CRIT " Not enough buffer"
506 " space for MSG_MASK\n");
507 }
508 mutex_unlock(&driver->diagchar_mutex);
509 diag_print_mask_table();
Shalabh Jain2c783cb2012-01-15 11:09:29 +0530510
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511}
512
Shalabh Jaina51f2592012-03-08 14:36:35 -0800513void diag_toggle_event_mask(int toggle)
514{
515 uint8_t *ptr = driver->event_masks;
516
517 mutex_lock(&driver->diagchar_mutex);
518 if (toggle)
519 memset(ptr, 0xFF, EVENT_MASK_SIZE);
520 else
521 memset(ptr, 0, EVENT_MASK_SIZE);
522 mutex_unlock(&driver->diagchar_mutex);
523}
524
Shalabh Jain321c8b52012-02-22 12:37:06 -0800525static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bytes)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700526{
527 uint8_t *ptr = driver->event_masks;
528 uint8_t *temp = buf + 2;
529
530 mutex_lock(&driver->diagchar_mutex);
531 if (!toggle)
532 memset(ptr, 0 , EVENT_MASK_SIZE);
533 else
534 if (CHK_OVERFLOW(ptr, ptr,
Shalabh Jain321c8b52012-02-22 12:37:06 -0800535 ptr+EVENT_MASK_SIZE, num_bytes))
536 memcpy(ptr, temp , num_bytes);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700537 else
538 printk(KERN_CRIT "Not enough buffer space "
539 "for EVENT_MASK\n");
540 mutex_unlock(&driver->diagchar_mutex);
541}
542
543static void diag_update_log_mask(int equip_id, uint8_t *buf, int num_items)
544{
545 uint8_t *temp = buf;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700546 int i = 0;
547 unsigned char *ptr_data;
Shalabh Jainfbf3bdc2012-03-16 21:02:50 -0700548 int offset = (sizeof(struct mask_info))*MAX_EQUIP_ID;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700549 struct mask_info *ptr = (struct mask_info *)driver->log_masks;
550
551 mutex_lock(&driver->diagchar_mutex);
552 /* Check if we already know index of this equipment ID */
553 for (i = 0; i < MAX_EQUIP_ID; i++) {
554 if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
555 offset = ptr->index;
556 break;
557 }
558 if ((ptr->equip_id == 0) && (ptr->index == 0)) {
Shalabh Jain321c8b52012-02-22 12:37:06 -0800559 /* Reached a null entry */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700560 ptr->equip_id = equip_id;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800561 ptr->num_items = num_items;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700562 ptr->index = driver->log_masks_length;
563 offset = driver->log_masks_length;
564 driver->log_masks_length += ((num_items+7)/8);
565 break;
566 }
567 ptr++;
568 }
569 ptr_data = driver->log_masks + offset;
570 if (CHK_OVERFLOW(driver->log_masks, ptr_data, driver->log_masks
571 + LOG_MASK_SIZE, (num_items+7)/8))
572 memcpy(ptr_data, temp , (num_items+7)/8);
573 else
574 printk(KERN_CRIT " Not enough buffer space for LOG_MASK\n");
575 mutex_unlock(&driver->diagchar_mutex);
576}
577
578static void diag_update_pkt_buffer(unsigned char *buf)
579{
580 unsigned char *ptr = driver->pkt_buf;
581 unsigned char *temp = buf;
582
583 mutex_lock(&driver->diagchar_mutex);
584 if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, driver->pkt_length))
585 memcpy(ptr, temp , driver->pkt_length);
586 else
587 printk(KERN_CRIT " Not enough buffer space for PKT_RESP\n");
588 mutex_unlock(&driver->diagchar_mutex);
589}
590
591void diag_update_userspace_clients(unsigned int type)
592{
593 int i;
594
595 mutex_lock(&driver->diagchar_mutex);
596 for (i = 0; i < driver->num_clients; i++)
597 if (driver->client_map[i].pid != 0)
598 driver->data_ready[i] |= type;
599 wake_up_interruptible(&driver->wait_q);
600 mutex_unlock(&driver->diagchar_mutex);
601}
602
603void diag_update_sleeping_process(int process_id)
604{
605 int i;
606
607 mutex_lock(&driver->diagchar_mutex);
608 for (i = 0; i < driver->num_clients; i++)
609 if (driver->client_map[i].pid == process_id) {
610 driver->data_ready[i] |= PKT_TYPE;
611 break;
612 }
613 wake_up_interruptible(&driver->wait_q);
614 mutex_unlock(&driver->diagchar_mutex);
615}
616
617void diag_send_data(struct diag_master_table entry, unsigned char *buf,
618 int len, int type)
619{
620 driver->pkt_length = len;
621 if (entry.process_id != NON_APPS_PROC && type != MODEM_DATA) {
622 diag_update_pkt_buffer(buf);
623 diag_update_sleeping_process(entry.process_id);
624 } else {
625 if (len > 0) {
Shalabh Jainc9f35092011-07-28 18:36:17 -0700626 if (entry.client_id == MODEM_PROC && driver->ch) {
Shalabh Jain10f5f432012-01-11 11:45:44 +0530627 if (chk_apps_master() &&
Shalabh Jainc9f35092011-07-28 18:36:17 -0700628 (int)(*(char *)buf) == MODE_CMD)
Dixon Petersonff425d12011-12-06 18:12:35 -0800629 if ((int)(*(char *)(buf+1)) ==
630 RESET_ID)
Shalabh Jainc9f35092011-07-28 18:36:17 -0700631 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632 smd_write(driver->ch, buf, len);
Shalabh Jainc9f35092011-07-28 18:36:17 -0700633 } else if (entry.client_id == QDSP_PROC &&
634 driver->chqdsp) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700635 smd_write(driver->chqdsp, buf, len);
Shalabh Jainc9f35092011-07-28 18:36:17 -0700636 } else if (entry.client_id == WCNSS_PROC &&
637 driver->ch_wcnss) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700638 smd_write(driver->ch_wcnss, buf, len);
Shalabh Jainc9f35092011-07-28 18:36:17 -0700639 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700640 pr_alert("diag: incorrect channel");
Shalabh Jainc9f35092011-07-28 18:36:17 -0700641 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700642 }
643 }
644}
645
Shalabh Jain321c8b52012-02-22 12:37:06 -0800646void diag_modem_mask_update_fn(struct work_struct *work)
647{
648 diag_send_msg_mask_update(driver->ch_cntl);
649 diag_send_log_mask_update(driver->ch_cntl);
650 diag_send_event_mask_update(driver->ch_cntl, diag_event_num_bytes);
651}
652
653void diag_qdsp_mask_update_fn(struct work_struct *work)
654{
655 diag_send_msg_mask_update(driver->chqdsp_cntl);
656 diag_send_log_mask_update(driver->chqdsp_cntl);
657 diag_send_event_mask_update(driver->chqdsp_cntl, diag_event_num_bytes);
658}
659
660void diag_wcnss_mask_update_fn(struct work_struct *work)
661{
662 diag_send_msg_mask_update(driver->ch_wcnss_cntl);
663 diag_send_log_mask_update(driver->ch_wcnss_cntl);
664 diag_send_event_mask_update(driver->ch_wcnss_cntl,
665 diag_event_num_bytes);
666}
667
668void diag_msg_mask_update_fn(struct work_struct *work)
669{
670 diag_send_msg_mask_update(driver->ch_cntl);
671 diag_send_msg_mask_update(driver->chqdsp_cntl);
672 diag_send_msg_mask_update(driver->ch_wcnss_cntl);
673}
674
675void diag_log_mask_update_fn(struct work_struct *work)
676{
677 diag_send_log_mask_update(driver->ch_cntl);
678 diag_send_log_mask_update(driver->chqdsp_cntl);
679 diag_send_log_mask_update(driver->ch_wcnss_cntl);
680}
681
682void diag_send_log_mask_update(smd_channel_t *ch)
683{
684 void *buf = driver->buf_log_mask_update;
685 int header_size = sizeof(struct diag_ctrl_log_mask);
686 struct mask_info *ptr = (struct mask_info *)driver->log_masks;
Shalabh Jainfbf3bdc2012-03-16 21:02:50 -0700687 int i, size;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800688
689 for (i = 0; i < MAX_EQUIP_ID; i++) {
Shalabh Jainfbf3bdc2012-03-16 21:02:50 -0700690 size = (ptr->num_items+7)/8;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800691 /* reached null entry */
692 if ((ptr->equip_id == 0) && (ptr->index == 0))
693 break;
694 driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
695 driver->log_mask->num_items = ptr->num_items;
696 driver->log_mask->data_len = 11 + size;
697 driver->log_mask->stream_id = 1; /* 2, if dual stream */
698 driver->log_mask->status = 3; /* status for valid mask */
699 driver->log_mask->equip_id = ptr->equip_id;
700 driver->log_mask->log_mask_size = size;
701 memcpy(buf, driver->log_mask, header_size);
702 memcpy(buf+header_size, driver->log_masks+ptr->index, size);
703 msleep(100);
704 if (ch)
705 smd_write(ch, buf, header_size + size);
706 ptr++;
707 }
708}
709
710void diag_send_event_mask_update(smd_channel_t *ch, int num_bytes)
711{
712 void *buf = driver->buf_event_mask_update;
713 int header_size = sizeof(struct diag_ctrl_event_mask);
714
715 /* send event mask update */
716 driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
717 driver->event_mask->data_len = 7 + num_bytes;
718 driver->event_mask->stream_id = 1; /* 2, if dual stream */
719 driver->event_mask->status = 3; /* status for valid mask */
720 driver->event_mask->event_config = diag_event_config; /* event config */
721 driver->event_mask->event_mask_size = num_bytes;
722 memcpy(buf, driver->event_mask, header_size);
723 memcpy(buf+header_size, driver->event_masks, num_bytes);
724 msleep(100);
725 if (ch)
726 smd_write(ch, buf, header_size + num_bytes);
727}
728
729void diag_send_msg_mask_update(smd_channel_t *ch)
730{
731 void *buf = driver->buf_msg_mask_update;
732 int first, last;
733 int header_size = sizeof(struct diag_ctrl_msg_mask);
734 uint8_t *ptr = driver->msg_masks;
735
736 while (*(uint32_t *)(ptr + 4)) {
737 first = *(uint32_t *)ptr;
738 ptr += 4;
739 last = *(uint32_t *)ptr;
740 ptr += 4;
741 /* send event mask update */
742 driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
743 driver->msg_mask->msg_mask_size = last - first + 1;
744 driver->msg_mask->data_len = 11 +
745 4 * (driver->msg_mask->msg_mask_size);
746 driver->msg_mask->stream_id = 1; /* 2, if dual stream */
747 driver->msg_mask->status = 3; /* status for valid mask */
748 driver->msg_mask->msg_mode = 0; /* Legcay mode */
749 driver->msg_mask->ssid_first = first;
750 driver->msg_mask->ssid_last = last;
751 memcpy(buf, driver->msg_mask, header_size);
752 memcpy(buf+header_size, ptr,
753 4 * (driver->msg_mask->msg_mask_size));
754 /* since mask updates are slow, so sleep needed as to
755 prevent modem running out of DSM items */
756 msleep(100);
757 if (ch)
758 smd_write(ch, buf,
759 header_size + 4*(driver->msg_mask->msg_mask_size));
760 ptr += ((last - first) + 1)*4;
761 }
762}
763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700764static int diag_process_apps_pkt(unsigned char *buf, int len)
765{
766 uint16_t subsys_cmd_code;
767 int subsys_id, ssid_first, ssid_last, ssid_range;
768 int packet_type = 1, i, cmd_code;
769 unsigned char *temp = buf;
770 int data_type;
771#if defined(CONFIG_DIAG_OVER_USB)
772 int payload_length;
773 unsigned char *ptr;
774#endif
775
Shalabh Jain321c8b52012-02-22 12:37:06 -0800776 /* Set log masks */
777 if (*buf == 0x73 && *(int *)(buf+4) == 3) {
778 buf += 8;
779 /* Read Equip ID and pass as first param below*/
780 diag_update_log_mask(*(int *)buf, buf+8, *(int *)(buf+4));
781 diag_update_userspace_clients(LOG_MASKS_TYPE);
782#if defined(CONFIG_DIAG_OVER_USB)
783 if (chk_apps_only()) {
784 driver->apps_rsp_buf[0] = 0x73;
785 *(int *)(driver->apps_rsp_buf + 4) = 0x3; /* op. ID */
786 *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success */
787 payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
788 for (i = 0; i < payload_length; i++)
789 *(int *)(driver->apps_rsp_buf+12+i) = *(buf+i);
790 queue_work(driver->diag_cntl_wq,
791 &(driver->diag_log_mask_update_work));
792 ENCODE_RSP_AND_SEND(12 + payload_length - 1);
793 return 0;
794 } else
795 buf = temp;
796#endif
797 } /* Check for set message mask */
798 else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
799 ssid_first = *(uint16_t *)(buf + 2);
800 ssid_last = *(uint16_t *)(buf + 4);
801 ssid_range = 4 * (ssid_last - ssid_first + 1);
802 diag_update_msg_mask(ssid_first, ssid_last , buf + 8);
803 diag_update_userspace_clients(MSG_MASKS_TYPE);
804#if defined(CONFIG_DIAG_OVER_USB)
805 if (chk_apps_only()) {
806 for (i = 0; i < 8 + ssid_range; i++)
807 *(driver->apps_rsp_buf + i) = *(buf+i);
808 *(driver->apps_rsp_buf + 6) = 0x1;
809 queue_work(driver->diag_cntl_wq,
810 &(driver->diag_msg_mask_update_work));
811 ENCODE_RSP_AND_SEND(8 + ssid_range - 1);
812 return 0;
813 } else
814 buf = temp;
815#endif
816 } else if (*buf == 0x82) { /* event mask change */
817 buf += 4;
818 diag_event_num_bytes = (*(uint16_t *)buf)/8+1;
819 diag_update_event_mask(buf, 1, (*(uint16_t *)buf)/8+1);
820 diag_update_userspace_clients(EVENT_MASKS_TYPE);
821#if defined(CONFIG_DIAG_OVER_USB)
822 if (chk_apps_only()) {
823 driver->apps_rsp_buf[0] = 0x82;
824 driver->apps_rsp_buf[1] = 0x0;
825 *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
826 *(uint16_t *)(driver->apps_rsp_buf + 4) =
827 EVENT_LAST_ID + 1;
Shalabh Jaina51f2592012-03-08 14:36:35 -0800828 memcpy(driver->apps_rsp_buf+6, driver->event_masks,
829 EVENT_LAST_ID/8+1);
Shalabh Jain321c8b52012-02-22 12:37:06 -0800830 /* cannot do this on work queue, as each event update
831 needs a num_bytes variable. Each queue_work call will
832 overwrite the previous input, as its the same struct */
833 diag_send_event_mask_update(driver->ch_cntl,
834 diag_event_num_bytes);
835 diag_send_event_mask_update(driver->chqdsp_cntl,
836 diag_event_num_bytes);
837 diag_send_event_mask_update(driver->ch_wcnss_cntl,
838 diag_event_num_bytes);
839 ENCODE_RSP_AND_SEND(6 + EVENT_LAST_ID/8);
840 return 0;
841 } else
842 buf = temp;
843#endif
844 } else if (*buf == 0x60) {
845 diag_event_config = *(buf+1);
Shalabh Jaina51f2592012-03-08 14:36:35 -0800846 diag_toggle_event_mask(*(buf+1));
847 diag_update_userspace_clients(EVENT_MASKS_TYPE);
Shalabh Jain321c8b52012-02-22 12:37:06 -0800848#if defined(CONFIG_DIAG_OVER_USB)
849 if (chk_apps_only()) {
850 driver->apps_rsp_buf[0] = 0x60;
851 driver->apps_rsp_buf[1] = 0x0;
852 driver->apps_rsp_buf[2] = 0x0;
853 diag_send_event_mask_update(driver->ch_cntl,
854 diag_event_num_bytes);
855 diag_send_event_mask_update(driver->chqdsp_cntl,
856 diag_event_num_bytes);
857 diag_send_event_mask_update(driver->ch_wcnss_cntl,
858 diag_event_num_bytes);
859 ENCODE_RSP_AND_SEND(2);
860 return 0;
861 }
862#endif
863 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700864 /* Check for registered clients and forward packet to apropriate proc */
865 cmd_code = (int)(*(char *)buf);
866 temp++;
867 subsys_id = (int)(*(char *)temp);
868 temp++;
869 subsys_cmd_code = *(uint16_t *)temp;
870 temp += 2;
871 data_type = APPS_DATA;
872 /* Dont send any command other than mode reset */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530873 if (chk_apps_master() && cmd_code == MODE_CMD) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700874 if (subsys_id != RESET_ID)
875 data_type = MODEM_DATA;
876 }
877
878 pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
Shalabh Jainfe02b0c2012-02-21 14:48:03 -0800879 for (i = 0; i < diag_max_reg; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700880 entry = driver->table[i];
881 if (entry.process_id != NO_PROCESS) {
882 if (entry.cmd_code == cmd_code && entry.subsys_id ==
883 subsys_id && entry.cmd_code_lo <=
884 subsys_cmd_code &&
885 entry.cmd_code_hi >= subsys_cmd_code) {
886 diag_send_data(entry, buf, len, data_type);
887 packet_type = 0;
888 } else if (entry.cmd_code == 255
889 && cmd_code == 75) {
890 if (entry.subsys_id ==
891 subsys_id &&
892 entry.cmd_code_lo <=
893 subsys_cmd_code &&
894 entry.cmd_code_hi >=
895 subsys_cmd_code) {
896 diag_send_data(entry, buf, len,
897 data_type);
898 packet_type = 0;
899 }
900 } else if (entry.cmd_code == 255 &&
901 entry.subsys_id == 255) {
902 if (entry.cmd_code_lo <=
903 cmd_code &&
904 entry.
905 cmd_code_hi >= cmd_code) {
906 diag_send_data(entry, buf, len,
907 data_type);
908 packet_type = 0;
909 }
910 }
911 }
912 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700913#if defined(CONFIG_DIAG_OVER_USB)
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700914 /* Check for Apps Only & get event mask request */
Shalabh Jain321c8b52012-02-22 12:37:06 -0800915 if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700916 driver->apps_rsp_buf[0] = 0x81;
917 driver->apps_rsp_buf[1] = 0x0;
918 *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
919 *(uint16_t *)(driver->apps_rsp_buf + 4) = EVENT_LAST_ID + 1;
920 for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
921 *(unsigned char *)(driver->apps_rsp_buf + 6 + i) = 0x0;
922 ENCODE_RSP_AND_SEND(6 + EVENT_LAST_ID/8);
923 return 0;
924 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700925 /* Get log ID range & Check for Apps Only */
926 else if (!(driver->ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700927 && (*buf == 0x73) && *(int *)(buf+4) == 1) {
928 driver->apps_rsp_buf[0] = 0x73;
929 *(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
930 *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success code */
931 *(int *)(driver->apps_rsp_buf + 12) = LOG_GET_ITEM_NUM(LOG_0);
932 *(int *)(driver->apps_rsp_buf + 16) = LOG_GET_ITEM_NUM(LOG_1);
933 *(int *)(driver->apps_rsp_buf + 20) = LOG_GET_ITEM_NUM(LOG_2);
934 *(int *)(driver->apps_rsp_buf + 24) = LOG_GET_ITEM_NUM(LOG_3);
935 *(int *)(driver->apps_rsp_buf + 28) = LOG_GET_ITEM_NUM(LOG_4);
936 *(int *)(driver->apps_rsp_buf + 32) = LOG_GET_ITEM_NUM(LOG_5);
937 *(int *)(driver->apps_rsp_buf + 36) = LOG_GET_ITEM_NUM(LOG_6);
938 *(int *)(driver->apps_rsp_buf + 40) = LOG_GET_ITEM_NUM(LOG_7);
939 *(int *)(driver->apps_rsp_buf + 44) = LOG_GET_ITEM_NUM(LOG_8);
940 *(int *)(driver->apps_rsp_buf + 48) = LOG_GET_ITEM_NUM(LOG_9);
941 *(int *)(driver->apps_rsp_buf + 52) = LOG_GET_ITEM_NUM(LOG_10);
942 *(int *)(driver->apps_rsp_buf + 56) = LOG_GET_ITEM_NUM(LOG_11);
943 *(int *)(driver->apps_rsp_buf + 60) = LOG_GET_ITEM_NUM(LOG_12);
944 *(int *)(driver->apps_rsp_buf + 64) = LOG_GET_ITEM_NUM(LOG_13);
945 *(int *)(driver->apps_rsp_buf + 68) = LOG_GET_ITEM_NUM(LOG_14);
946 *(int *)(driver->apps_rsp_buf + 72) = LOG_GET_ITEM_NUM(LOG_15);
947 ENCODE_RSP_AND_SEND(75);
948 return 0;
949 }
950 /* Respond to Get SSID Range request message */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700951 else if (!(driver->ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700952 && (*buf == 0x7d) && (*(buf+1) == 0x1)) {
953 driver->apps_rsp_buf[0] = 0x7d;
954 driver->apps_rsp_buf[1] = 0x1;
955 driver->apps_rsp_buf[2] = 0x1;
956 driver->apps_rsp_buf[3] = 0x0;
957 *(int *)(driver->apps_rsp_buf + 4) = MSG_MASK_TBL_CNT;
958 *(uint16_t *)(driver->apps_rsp_buf + 8) = MSG_SSID_0;
959 *(uint16_t *)(driver->apps_rsp_buf + 10) = MSG_SSID_0_LAST;
960 *(uint16_t *)(driver->apps_rsp_buf + 12) = MSG_SSID_1;
961 *(uint16_t *)(driver->apps_rsp_buf + 14) = MSG_SSID_1_LAST;
962 *(uint16_t *)(driver->apps_rsp_buf + 16) = MSG_SSID_2;
963 *(uint16_t *)(driver->apps_rsp_buf + 18) = MSG_SSID_2_LAST;
964 *(uint16_t *)(driver->apps_rsp_buf + 20) = MSG_SSID_3;
965 *(uint16_t *)(driver->apps_rsp_buf + 22) = MSG_SSID_3_LAST;
966 *(uint16_t *)(driver->apps_rsp_buf + 24) = MSG_SSID_4;
967 *(uint16_t *)(driver->apps_rsp_buf + 26) = MSG_SSID_4_LAST;
968 *(uint16_t *)(driver->apps_rsp_buf + 28) = MSG_SSID_5;
969 *(uint16_t *)(driver->apps_rsp_buf + 30) = MSG_SSID_5_LAST;
970 *(uint16_t *)(driver->apps_rsp_buf + 32) = MSG_SSID_6;
971 *(uint16_t *)(driver->apps_rsp_buf + 34) = MSG_SSID_6_LAST;
972 *(uint16_t *)(driver->apps_rsp_buf + 36) = MSG_SSID_7;
973 *(uint16_t *)(driver->apps_rsp_buf + 38) = MSG_SSID_7_LAST;
974 *(uint16_t *)(driver->apps_rsp_buf + 40) = MSG_SSID_8;
975 *(uint16_t *)(driver->apps_rsp_buf + 42) = MSG_SSID_8_LAST;
976 *(uint16_t *)(driver->apps_rsp_buf + 44) = MSG_SSID_9;
977 *(uint16_t *)(driver->apps_rsp_buf + 46) = MSG_SSID_9_LAST;
978 *(uint16_t *)(driver->apps_rsp_buf + 48) = MSG_SSID_10;
979 *(uint16_t *)(driver->apps_rsp_buf + 50) = MSG_SSID_10_LAST;
980 *(uint16_t *)(driver->apps_rsp_buf + 52) = MSG_SSID_11;
981 *(uint16_t *)(driver->apps_rsp_buf + 54) = MSG_SSID_11_LAST;
982 *(uint16_t *)(driver->apps_rsp_buf + 56) = MSG_SSID_12;
983 *(uint16_t *)(driver->apps_rsp_buf + 58) = MSG_SSID_12_LAST;
984 *(uint16_t *)(driver->apps_rsp_buf + 60) = MSG_SSID_13;
985 *(uint16_t *)(driver->apps_rsp_buf + 62) = MSG_SSID_13_LAST;
986 *(uint16_t *)(driver->apps_rsp_buf + 64) = MSG_SSID_14;
987 *(uint16_t *)(driver->apps_rsp_buf + 66) = MSG_SSID_14_LAST;
988 *(uint16_t *)(driver->apps_rsp_buf + 68) = MSG_SSID_15;
989 *(uint16_t *)(driver->apps_rsp_buf + 70) = MSG_SSID_15_LAST;
990 *(uint16_t *)(driver->apps_rsp_buf + 72) = MSG_SSID_16;
991 *(uint16_t *)(driver->apps_rsp_buf + 74) = MSG_SSID_16_LAST;
992 *(uint16_t *)(driver->apps_rsp_buf + 76) = MSG_SSID_17;
993 *(uint16_t *)(driver->apps_rsp_buf + 78) = MSG_SSID_17_LAST;
994 *(uint16_t *)(driver->apps_rsp_buf + 80) = MSG_SSID_18;
995 *(uint16_t *)(driver->apps_rsp_buf + 82) = MSG_SSID_18_LAST;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800996 *(uint16_t *)(driver->apps_rsp_buf + 84) = MSG_SSID_19;
997 *(uint16_t *)(driver->apps_rsp_buf + 86) = MSG_SSID_19_LAST;
998 *(uint16_t *)(driver->apps_rsp_buf + 88) = MSG_SSID_20;
999 *(uint16_t *)(driver->apps_rsp_buf + 90) = MSG_SSID_20_LAST;
1000 *(uint16_t *)(driver->apps_rsp_buf + 92) = MSG_SSID_21;
1001 *(uint16_t *)(driver->apps_rsp_buf + 94) = MSG_SSID_21_LAST;
1002 *(uint16_t *)(driver->apps_rsp_buf + 96) = MSG_SSID_22;
1003 *(uint16_t *)(driver->apps_rsp_buf + 98) = MSG_SSID_22_LAST;
1004 ENCODE_RSP_AND_SEND(99);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001005 return 0;
1006 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001007 /* Check for Apps Only Respond to Get Subsys Build mask */
1008 else if (!(driver->ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001009 && (*buf == 0x7d) && (*(buf+1) == 0x2)) {
1010 ssid_first = *(uint16_t *)(buf + 2);
1011 ssid_last = *(uint16_t *)(buf + 4);
1012 ssid_range = 4 * (ssid_last - ssid_first + 1);
1013 /* frame response */
1014 driver->apps_rsp_buf[0] = 0x7d;
1015 driver->apps_rsp_buf[1] = 0x2;
1016 *(uint16_t *)(driver->apps_rsp_buf + 2) = ssid_first;
1017 *(uint16_t *)(driver->apps_rsp_buf + 4) = ssid_last;
1018 driver->apps_rsp_buf[6] = 0x1;
1019 driver->apps_rsp_buf[7] = 0x0;
1020 ptr = driver->apps_rsp_buf + 8;
1021 /* bld time masks */
1022 switch (ssid_first) {
1023 case MSG_SSID_0:
1024 for (i = 0; i < ssid_range; i += 4)
1025 *(int *)(ptr + i) = msg_bld_masks_0[i/4];
1026 break;
1027 case MSG_SSID_1:
1028 for (i = 0; i < ssid_range; i += 4)
1029 *(int *)(ptr + i) = msg_bld_masks_1[i/4];
1030 break;
1031 case MSG_SSID_2:
1032 for (i = 0; i < ssid_range; i += 4)
1033 *(int *)(ptr + i) = msg_bld_masks_2[i/4];
1034 break;
1035 case MSG_SSID_3:
1036 for (i = 0; i < ssid_range; i += 4)
1037 *(int *)(ptr + i) = msg_bld_masks_3[i/4];
1038 break;
1039 case MSG_SSID_4:
1040 for (i = 0; i < ssid_range; i += 4)
1041 *(int *)(ptr + i) = msg_bld_masks_4[i/4];
1042 break;
1043 case MSG_SSID_5:
1044 for (i = 0; i < ssid_range; i += 4)
1045 *(int *)(ptr + i) = msg_bld_masks_5[i/4];
1046 break;
1047 case MSG_SSID_6:
1048 for (i = 0; i < ssid_range; i += 4)
1049 *(int *)(ptr + i) = msg_bld_masks_6[i/4];
1050 break;
1051 case MSG_SSID_7:
1052 for (i = 0; i < ssid_range; i += 4)
1053 *(int *)(ptr + i) = msg_bld_masks_7[i/4];
1054 break;
1055 case MSG_SSID_8:
1056 for (i = 0; i < ssid_range; i += 4)
1057 *(int *)(ptr + i) = msg_bld_masks_8[i/4];
1058 break;
1059 case MSG_SSID_9:
1060 for (i = 0; i < ssid_range; i += 4)
1061 *(int *)(ptr + i) = msg_bld_masks_9[i/4];
1062 break;
1063 case MSG_SSID_10:
1064 for (i = 0; i < ssid_range; i += 4)
1065 *(int *)(ptr + i) = msg_bld_masks_10[i/4];
1066 break;
1067 case MSG_SSID_11:
1068 for (i = 0; i < ssid_range; i += 4)
1069 *(int *)(ptr + i) = msg_bld_masks_11[i/4];
1070 break;
1071 case MSG_SSID_12:
1072 for (i = 0; i < ssid_range; i += 4)
1073 *(int *)(ptr + i) = msg_bld_masks_12[i/4];
1074 break;
1075 case MSG_SSID_13:
1076 for (i = 0; i < ssid_range; i += 4)
1077 *(int *)(ptr + i) = msg_bld_masks_13[i/4];
1078 break;
1079 case MSG_SSID_14:
1080 for (i = 0; i < ssid_range; i += 4)
1081 *(int *)(ptr + i) = msg_bld_masks_14[i/4];
1082 break;
1083 case MSG_SSID_15:
1084 for (i = 0; i < ssid_range; i += 4)
1085 *(int *)(ptr + i) = msg_bld_masks_15[i/4];
1086 break;
1087 case MSG_SSID_16:
1088 for (i = 0; i < ssid_range; i += 4)
1089 *(int *)(ptr + i) = msg_bld_masks_16[i/4];
1090 break;
1091 case MSG_SSID_17:
1092 for (i = 0; i < ssid_range; i += 4)
1093 *(int *)(ptr + i) = msg_bld_masks_17[i/4];
1094 break;
1095 case MSG_SSID_18:
1096 for (i = 0; i < ssid_range; i += 4)
1097 *(int *)(ptr + i) = msg_bld_masks_18[i/4];
1098 break;
Shalabh Jain321c8b52012-02-22 12:37:06 -08001099 case MSG_SSID_19:
1100 for (i = 0; i < ssid_range; i += 4)
1101 *(int *)(ptr + i) = msg_bld_masks_19[i/4];
1102 break;
1103 case MSG_SSID_20:
1104 for (i = 0; i < ssid_range; i += 4)
1105 *(int *)(ptr + i) = msg_bld_masks_20[i/4];
1106 break;
1107 case MSG_SSID_21:
1108 for (i = 0; i < ssid_range; i += 4)
1109 *(int *)(ptr + i) = msg_bld_masks_21[i/4];
1110 break;
1111 case MSG_SSID_22:
1112 for (i = 0; i < ssid_range; i += 4)
1113 *(int *)(ptr + i) = msg_bld_masks_22[i/4];
1114 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001115 }
1116 ENCODE_RSP_AND_SEND(8 + ssid_range - 1);
1117 return 0;
1118 }
1119 /* Check for download command */
Shalabh Jain10f5f432012-01-11 11:45:44 +05301120 else if ((cpu_is_msm8x60() || chk_apps_master()) && (*buf == 0x3A)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001121 /* send response back */
1122 driver->apps_rsp_buf[0] = *buf;
1123 ENCODE_RSP_AND_SEND(0);
1124 msleep(5000);
1125 /* call download API */
1126 msm_set_restart_mode(RESTART_DLOAD);
1127 printk(KERN_CRIT "diag: download mode set, Rebooting SoC..\n");
1128 kernel_restart(NULL);
1129 /* Not required, represents that command isnt sent to modem */
1130 return 0;
1131 }
Dixon Petersonb46bb992012-01-12 19:16:56 -08001132 /* Check for polling for Apps only DIAG */
1133 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1134 (*(buf+2) == 0x03)) {
Shalabh Jain3d29fc32012-02-09 17:15:59 -08001135 /* If no one has registered for polling */
Dixon Petersonb4618a42012-02-29 18:56:31 -08001136 if (chk_polling_response()) {
Dixon Petersonb46bb992012-01-12 19:16:56 -08001137 /* Respond to polling for Apps only DIAG */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138 for (i = 0; i < 3; i++)
1139 driver->apps_rsp_buf[i] = *(buf+i);
1140 for (i = 0; i < 13; i++)
1141 driver->apps_rsp_buf[i+3] = 0;
1142
1143 ENCODE_RSP_AND_SEND(15);
1144 return 0;
1145 }
Dixon Petersonb46bb992012-01-12 19:16:56 -08001146 }
1147 /* Check for ID for NO MODEM present */
Dixon Petersonb4618a42012-02-29 18:56:31 -08001148 else if (chk_polling_response()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001149 /* respond to 0x0 command */
Dixon Petersonb46bb992012-01-12 19:16:56 -08001150 if (*buf == 0x00) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151 for (i = 0; i < 55; i++)
1152 driver->apps_rsp_buf[i] = 0;
1153
1154 ENCODE_RSP_AND_SEND(54);
1155 return 0;
1156 }
1157 /* respond to 0x7c command */
1158 else if (*buf == 0x7c) {
1159 driver->apps_rsp_buf[0] = 0x7c;
1160 for (i = 1; i < 8; i++)
1161 driver->apps_rsp_buf[i] = 0;
1162 /* Tools ID for APQ 8060 */
1163 *(int *)(driver->apps_rsp_buf + 8) =
1164 chk_config_get_id();
1165 *(unsigned char *)(driver->apps_rsp_buf + 12) = '\0';
1166 *(unsigned char *)(driver->apps_rsp_buf + 13) = '\0';
1167 ENCODE_RSP_AND_SEND(13);
1168 return 0;
1169 }
1170 }
1171#endif
1172 return packet_type;
1173}
1174
1175#ifdef CONFIG_DIAG_OVER_USB
1176void diag_send_error_rsp(int index)
1177{
1178 int i;
Shalabh Jain1fedab92011-12-22 13:15:22 +05301179
1180 if (index > 490) {
1181 pr_err("diag: error response too huge, aborting\n");
1182 return;
1183 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184 driver->apps_rsp_buf[0] = 0x13; /* error code 13 */
1185 for (i = 0; i < index; i++)
1186 driver->apps_rsp_buf[i+1] = *(driver->hdlc_buf+i);
1187 ENCODE_RSP_AND_SEND(index - 3);
1188}
1189#else
1190static inline void diag_send_error_rsp(int index) {}
1191#endif
1192
1193void diag_process_hdlc(void *data, unsigned len)
1194{
1195 struct diag_hdlc_decode_type hdlc;
1196 int ret, type = 0;
1197 pr_debug("diag: HDLC decode fn, len of data %d\n", len);
1198 hdlc.dest_ptr = driver->hdlc_buf;
1199 hdlc.dest_size = USB_MAX_OUT_BUF;
1200 hdlc.src_ptr = data;
1201 hdlc.src_size = len;
1202 hdlc.src_idx = 0;
1203 hdlc.dest_idx = 0;
1204 hdlc.escaping = 0;
1205
1206 ret = diag_hdlc_decode(&hdlc);
1207
1208 if (ret)
1209 type = diag_process_apps_pkt(driver->hdlc_buf,
1210 hdlc.dest_idx - 3);
1211 else if (driver->debug_flag) {
1212 printk(KERN_ERR "Packet dropped due to bad HDLC coding/CRC"
1213 " errors or partial packet received, packet"
1214 " length = %d\n", len);
1215 print_hex_dump(KERN_DEBUG, "Dropped Packet Data: ", 16, 1,
1216 DUMP_PREFIX_ADDRESS, data, len, 1);
1217 driver->debug_flag = 0;
1218 }
1219 /* send error responses from APPS for Central Routing */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001220 if (type == 1 && chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221 diag_send_error_rsp(hdlc.dest_idx);
1222 type = 0;
1223 }
1224 /* implies this packet is NOT meant for apps */
1225 if (!(driver->ch) && type == 1) {
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001226 if (chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227 diag_send_error_rsp(hdlc.dest_idx);
1228 } else { /* APQ 8060, Let Q6 respond */
1229 if (driver->chqdsp)
1230 smd_write(driver->chqdsp, driver->hdlc_buf,
1231 hdlc.dest_idx - 3);
1232 }
1233 type = 0;
1234 }
1235
1236#ifdef DIAG_DEBUG
1237 pr_debug("diag: hdlc.dest_idx = %d", hdlc.dest_idx);
1238 for (i = 0; i < hdlc.dest_idx; i++)
1239 printk(KERN_DEBUG "\t%x", *(((unsigned char *)
1240 driver->hdlc_buf)+i));
1241#endif /* DIAG DEBUG */
1242 /* ignore 2 bytes for CRC, one for 7E and send */
1243 if ((driver->ch) && (ret) && (type) && (hdlc.dest_idx > 3)) {
1244 APPEND_DEBUG('g');
1245 smd_write(driver->ch, driver->hdlc_buf, hdlc.dest_idx - 3);
1246 APPEND_DEBUG('h');
1247#ifdef DIAG_DEBUG
1248 printk(KERN_INFO "writing data to SMD, pkt length %d\n", len);
1249 print_hex_dump(KERN_DEBUG, "Written Packet Data to SMD: ", 16,
1250 1, DUMP_PREFIX_ADDRESS, data, len, 1);
1251#endif /* DIAG DEBUG */
1252 }
1253}
1254
1255#ifdef CONFIG_DIAG_OVER_USB
Shalabh Jain8e9750a2011-09-09 13:06:29 -07001256/* 2+1 for modem ; 2 for LPASS ; 1 for WCNSS */
1257#define N_LEGACY_WRITE (driver->poolsize + 6)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001258#define N_LEGACY_READ 1
1259
1260int diagfwd_connect(void)
1261{
1262 int err;
1263
1264 printk(KERN_DEBUG "diag: USB connected\n");
1265 err = usb_diag_alloc_req(driver->legacy_ch, N_LEGACY_WRITE,
1266 N_LEGACY_READ);
1267 if (err)
1268 printk(KERN_ERR "diag: unable to alloc USB req on legacy ch");
1269
1270 driver->usb_connected = 1;
1271 driver->in_busy_1 = 0;
1272 driver->in_busy_2 = 0;
1273 driver->in_busy_qdsp_1 = 0;
1274 driver->in_busy_qdsp_2 = 0;
Ashay Jaiswal29620122012-03-21 12:02:36 +05301275 driver->in_busy_wcnss_1 = 0;
1276 driver->in_busy_wcnss_2 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001277
1278 /* Poll SMD channels to check for data*/
1279 queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
1280 queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
1281 queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_work));
Shalabh Jaincf5f20e2011-08-22 12:29:52 -07001282 /* Poll SMD CNTL channels to check for data */
Shalabh Jain4e1bd312012-02-16 19:33:05 -08001283 diag_smd_cntl_notify(NULL, SMD_EVENT_DATA);
1284 diag_smd_qdsp_cntl_notify(NULL, SMD_EVENT_DATA);
1285 diag_smd_wcnss_cntl_notify(NULL, SMD_EVENT_DATA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001286 /* Poll USB channel to check for data*/
1287 queue_work(driver->diag_wq, &(driver->diag_read_work));
1288#ifdef CONFIG_DIAG_SDIO_PIPE
1289 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
1290 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1291 diagfwd_connect_sdio();
1292 else
1293 printk(KERN_INFO "diag: No USB MDM ch");
1294 }
1295#endif
1296 return 0;
1297}
1298
1299int diagfwd_disconnect(void)
1300{
1301 printk(KERN_DEBUG "diag: USB disconnected\n");
1302 driver->usb_connected = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001303 driver->debug_flag = 1;
1304 usb_diag_free_req(driver->legacy_ch);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001305 if (driver->logging_mode == USB_MODE) {
1306 driver->in_busy_1 = 1;
1307 driver->in_busy_2 = 1;
1308 driver->in_busy_qdsp_1 = 1;
1309 driver->in_busy_qdsp_2 = 1;
Ashay Jaiswal29620122012-03-21 12:02:36 +05301310 driver->in_busy_wcnss_1 = 1;
1311 driver->in_busy_wcnss_2 = 1;
Shalabh Jain69890aa2011-10-10 12:59:16 -07001312 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313#ifdef CONFIG_DIAG_SDIO_PIPE
1314 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
1315 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1316 diagfwd_disconnect_sdio();
1317#endif
1318 /* TBD - notify and flow control SMD */
1319 return 0;
1320}
1321
1322int diagfwd_write_complete(struct diag_request *diag_write_ptr)
1323{
1324 unsigned char *buf = diag_write_ptr->buf;
1325 /*Determine if the write complete is for data from modem/apps/q6 */
1326 /* Need a context variable here instead */
1327 if (buf == (void *)driver->buf_in_1) {
1328 driver->in_busy_1 = 0;
1329 APPEND_DEBUG('o');
1330 queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
1331 } else if (buf == (void *)driver->buf_in_2) {
1332 driver->in_busy_2 = 0;
1333 APPEND_DEBUG('O');
1334 queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
1335 } else if (buf == (void *)driver->buf_in_qdsp_1) {
1336 driver->in_busy_qdsp_1 = 0;
1337 APPEND_DEBUG('p');
1338 queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
1339 } else if (buf == (void *)driver->buf_in_qdsp_2) {
1340 driver->in_busy_qdsp_2 = 0;
1341 APPEND_DEBUG('P');
1342 queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
Ashay Jaiswal29620122012-03-21 12:02:36 +05301343 } else if (buf == driver->buf_in_wcnss_1) {
1344 driver->in_busy_wcnss_1 = 0;
1345 APPEND_DEBUG('r');
1346 queue_work(driver->diag_wq,
1347 &(driver->diag_read_smd_wcnss_work));
1348 } else if (buf == driver->buf_in_wcnss_2) {
1349 driver->in_busy_wcnss_2 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001350 APPEND_DEBUG('R');
1351 queue_work(driver->diag_wq,
1352 &(driver->diag_read_smd_wcnss_work));
1353 }
1354#ifdef CONFIG_DIAG_SDIO_PIPE
1355 else if (buf == (void *)driver->buf_in_sdio)
1356 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -08001357 machine_is_msm8x60_fusn_ffa())
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001358 diagfwd_write_complete_sdio();
1359 else
1360 pr_err("diag: Incorrect buffer pointer while WRITE");
1361#endif
1362 else {
1363 diagmem_free(driver, (unsigned char *)buf, POOL_TYPE_HDLC);
1364 diagmem_free(driver, (unsigned char *)diag_write_ptr,
1365 POOL_TYPE_WRITE_STRUCT);
1366 APPEND_DEBUG('q');
1367 }
1368 return 0;
1369}
1370
1371int diagfwd_read_complete(struct diag_request *diag_read_ptr)
1372{
1373 int status = diag_read_ptr->status;
1374 unsigned char *buf = diag_read_ptr->buf;
1375
1376 /* Determine if the read complete is for data on legacy/mdm ch */
1377 if (buf == (void *)driver->usb_buf_out) {
1378 driver->read_len_legacy = diag_read_ptr->actual;
1379 APPEND_DEBUG('s');
1380#ifdef DIAG_DEBUG
1381 printk(KERN_INFO "read data from USB, pkt length %d",
1382 diag_read_ptr->actual);
1383 print_hex_dump(KERN_DEBUG, "Read Packet Data from USB: ", 16, 1,
1384 DUMP_PREFIX_ADDRESS, diag_read_ptr->buf,
1385 diag_read_ptr->actual, 1);
1386#endif /* DIAG DEBUG */
1387 if (driver->logging_mode == USB_MODE) {
1388 if (status != -ECONNRESET && status != -ESHUTDOWN)
1389 queue_work(driver->diag_wq,
1390 &(driver->diag_proc_hdlc_work));
1391 else
1392 queue_work(driver->diag_wq,
1393 &(driver->diag_read_work));
1394 }
1395 }
1396#ifdef CONFIG_DIAG_SDIO_PIPE
1397 else if (buf == (void *)driver->usb_buf_mdm_out) {
1398 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -08001399 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001400 driver->read_len_mdm = diag_read_ptr->actual;
1401 diagfwd_read_complete_sdio();
1402 } else
1403 pr_err("diag: Incorrect buffer pointer while READ");
1404 }
1405#endif
1406 else
1407 printk(KERN_ERR "diag: Unknown buffer ptr from USB");
1408
1409 return 0;
1410}
1411
1412void diag_read_work_fn(struct work_struct *work)
1413{
1414 APPEND_DEBUG('d');
1415 driver->usb_read_ptr->buf = driver->usb_buf_out;
1416 driver->usb_read_ptr->length = USB_MAX_OUT_BUF;
1417 usb_diag_read(driver->legacy_ch, driver->usb_read_ptr);
1418 APPEND_DEBUG('e');
1419}
1420
1421void diag_process_hdlc_fn(struct work_struct *work)
1422{
1423 APPEND_DEBUG('D');
1424 diag_process_hdlc(driver->usb_buf_out, driver->read_len_legacy);
1425 diag_read_work_fn(work);
1426 APPEND_DEBUG('E');
1427}
1428
1429void diag_usb_legacy_notifier(void *priv, unsigned event,
1430 struct diag_request *d_req)
1431{
1432 switch (event) {
1433 case USB_DIAG_CONNECT:
1434 diagfwd_connect();
1435 break;
1436 case USB_DIAG_DISCONNECT:
1437 diagfwd_disconnect();
1438 break;
1439 case USB_DIAG_READ_DONE:
1440 diagfwd_read_complete(d_req);
1441 break;
1442 case USB_DIAG_WRITE_DONE:
1443 diagfwd_write_complete(d_req);
1444 break;
1445 default:
1446 printk(KERN_ERR "Unknown event from USB diag\n");
1447 break;
1448 }
1449}
1450
1451#endif /* DIAG OVER USB */
1452
1453static void diag_smd_notify(void *ctxt, unsigned event)
1454{
Shalabh Jainc2ec8292011-10-14 12:34:55 -07001455 if (event == SMD_EVENT_CLOSE) {
1456 pr_info("diag: clean modem registration\n");
1457 diag_clear_reg(MODEM_PROC);
Shalabh Jaineefee052011-11-08 23:46:03 -08001458 driver->ch = 0;
1459 return;
1460 } else if (event == SMD_EVENT_OPEN) {
1461 driver->ch = ch_temp;
1462 }
1463 queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001464}
1465
1466#if defined(CONFIG_MSM_N_WAY_SMD)
1467static void diag_smd_qdsp_notify(void *ctxt, unsigned event)
1468{
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001469 if (event == SMD_EVENT_CLOSE) {
1470 pr_info("diag: clean lpass registration\n");
1471 diag_clear_reg(QDSP_PROC);
1472 driver->chqdsp = 0;
1473 return;
1474 } else if (event == SMD_EVENT_OPEN) {
1475 driver->chqdsp = chqdsp_temp;
1476 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477 queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
1478}
1479#endif
1480
1481static void diag_smd_wcnss_notify(void *ctxt, unsigned event)
1482{
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001483 if (event == SMD_EVENT_CLOSE) {
1484 pr_info("diag: clean wcnss registration\n");
1485 diag_clear_reg(WCNSS_PROC);
1486 driver->ch_wcnss = 0;
1487 return;
1488 } else if (event == SMD_EVENT_OPEN) {
1489 driver->ch_wcnss = ch_wcnss_temp;
1490 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_work));
1492}
1493
1494static int diag_smd_probe(struct platform_device *pdev)
1495{
1496 int r = 0;
1497
Shalabh Jaineefee052011-11-08 23:46:03 -08001498 if (pdev->id == SMD_APPS_MODEM) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001499 r = smd_open("DIAG", &driver->ch, driver, diag_smd_notify);
Shalabh Jaineefee052011-11-08 23:46:03 -08001500 ch_temp = driver->ch;
1501 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502#if defined(CONFIG_MSM_N_WAY_SMD)
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001503 if (pdev->id == SMD_APPS_QDSP) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001504 r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP
1505 , &driver->chqdsp, driver, diag_smd_qdsp_notify);
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001506 chqdsp_temp = driver->chqdsp;
1507 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001508#endif
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001509 if (pdev->id == SMD_APPS_WCNSS) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001510 r = smd_named_open_on_edge("APPS_RIVA_DATA", SMD_APPS_WCNSS
1511 , &driver->ch_wcnss, driver, diag_smd_wcnss_notify);
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001512 ch_wcnss_temp = driver->ch_wcnss;
1513 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001514 pm_runtime_set_active(&pdev->dev);
1515 pm_runtime_enable(&pdev->dev);
1516 pr_debug("diag: open SMD port, Id = %d, r = %d\n", pdev->id, r);
1517
1518 return 0;
1519}
1520
1521static int diagfwd_runtime_suspend(struct device *dev)
1522{
1523 dev_dbg(dev, "pm_runtime: suspending...\n");
1524 return 0;
1525}
1526
1527static int diagfwd_runtime_resume(struct device *dev)
1528{
1529 dev_dbg(dev, "pm_runtime: resuming...\n");
1530 return 0;
1531}
1532
1533static const struct dev_pm_ops diagfwd_dev_pm_ops = {
1534 .runtime_suspend = diagfwd_runtime_suspend,
1535 .runtime_resume = diagfwd_runtime_resume,
1536};
1537
1538static struct platform_driver msm_smd_ch1_driver = {
1539
1540 .probe = diag_smd_probe,
1541 .driver = {
1542 .name = "DIAG",
1543 .owner = THIS_MODULE,
1544 .pm = &diagfwd_dev_pm_ops,
1545 },
1546};
1547
1548static struct platform_driver diag_smd_lite_driver = {
1549
1550 .probe = diag_smd_probe,
1551 .driver = {
1552 .name = "APPS_RIVA_DATA",
1553 .owner = THIS_MODULE,
1554 .pm = &diagfwd_dev_pm_ops,
1555 },
1556};
1557
1558void diagfwd_init(void)
1559{
1560 diag_debug_buf_idx = 0;
1561 driver->read_len_legacy = 0;
Dixon Petersonb4618a42012-02-29 18:56:31 -08001562 driver->use_device_tree = has_device_tree();
Shalabh Jain321c8b52012-02-22 12:37:06 -08001563
1564 if (driver->event_mask == NULL) {
1565 driver->event_mask = kzalloc(sizeof(
1566 struct diag_ctrl_event_mask), GFP_KERNEL);
1567 if (driver->event_mask == NULL)
1568 goto err;
1569 }
1570 if (driver->msg_mask == NULL) {
1571 driver->msg_mask = kzalloc(sizeof(
1572 struct diag_ctrl_msg_mask), GFP_KERNEL);
1573 if (driver->msg_mask == NULL)
1574 goto err;
1575 }
1576 if (driver->log_mask == NULL) {
1577 driver->log_mask = kzalloc(sizeof(
1578 struct diag_ctrl_log_mask), GFP_KERNEL);
1579 if (driver->log_mask == NULL)
1580 goto err;
1581 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001582 if (driver->buf_in_1 == NULL) {
1583 driver->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1584 if (driver->buf_in_1 == NULL)
1585 goto err;
1586 }
1587 if (driver->buf_in_2 == NULL) {
1588 driver->buf_in_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1589 if (driver->buf_in_2 == NULL)
1590 goto err;
1591 }
1592 if (driver->buf_in_qdsp_1 == NULL) {
1593 driver->buf_in_qdsp_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1594 if (driver->buf_in_qdsp_1 == NULL)
1595 goto err;
1596 }
1597 if (driver->buf_in_qdsp_2 == NULL) {
1598 driver->buf_in_qdsp_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1599 if (driver->buf_in_qdsp_2 == NULL)
1600 goto err;
1601 }
Ashay Jaiswal29620122012-03-21 12:02:36 +05301602 if (driver->buf_in_wcnss_1 == NULL) {
1603 driver->buf_in_wcnss_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1604 if (driver->buf_in_wcnss_1 == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 goto err;
1606 }
Ashay Jaiswal29620122012-03-21 12:02:36 +05301607 if (driver->buf_in_wcnss_2 == NULL) {
1608 driver->buf_in_wcnss_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1609 if (driver->buf_in_wcnss_2 == NULL)
1610 goto err;
1611 }
1612
Shalabh Jain321c8b52012-02-22 12:37:06 -08001613 if (driver->buf_msg_mask_update == NULL) {
1614 driver->buf_msg_mask_update = kzalloc(APPS_BUF_SIZE,
1615 GFP_KERNEL);
1616 if (driver->buf_msg_mask_update == NULL)
1617 goto err;
1618 }
1619 if (driver->buf_log_mask_update == NULL) {
1620 driver->buf_log_mask_update = kzalloc(APPS_BUF_SIZE,
1621 GFP_KERNEL);
1622 if (driver->buf_log_mask_update == NULL)
1623 goto err;
1624 }
1625 if (driver->buf_event_mask_update == NULL) {
1626 driver->buf_event_mask_update = kzalloc(APPS_BUF_SIZE,
1627 GFP_KERNEL);
1628 if (driver->buf_event_mask_update == NULL)
1629 goto err;
1630 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001631 if (driver->usb_buf_out == NULL &&
1632 (driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
1633 GFP_KERNEL)) == NULL)
1634 goto err;
1635 if (driver->hdlc_buf == NULL
1636 && (driver->hdlc_buf = kzalloc(HDLC_MAX, GFP_KERNEL)) == NULL)
1637 goto err;
Shalabh Jain69890aa2011-10-10 12:59:16 -07001638 if (driver->user_space_data == NULL)
1639 driver->user_space_data = kzalloc(USER_SPACE_DATA, GFP_KERNEL);
1640 if (driver->user_space_data == NULL)
1641 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001642 if (driver->msg_masks == NULL
1643 && (driver->msg_masks = kzalloc(MSG_MASK_SIZE,
1644 GFP_KERNEL)) == NULL)
1645 goto err;
1646 if (driver->log_masks == NULL &&
1647 (driver->log_masks = kzalloc(LOG_MASK_SIZE, GFP_KERNEL)) == NULL)
1648 goto err;
Shalabh Jainfbf3bdc2012-03-16 21:02:50 -07001649 driver->log_masks_length = (sizeof(struct mask_info))*MAX_EQUIP_ID;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001650 if (driver->event_masks == NULL &&
1651 (driver->event_masks = kzalloc(EVENT_MASK_SIZE,
1652 GFP_KERNEL)) == NULL)
1653 goto err;
1654 if (driver->client_map == NULL &&
1655 (driver->client_map = kzalloc
1656 ((driver->num_clients) * sizeof(struct diag_client_map),
1657 GFP_KERNEL)) == NULL)
1658 goto err;
1659 if (driver->buf_tbl == NULL)
1660 driver->buf_tbl = kzalloc(buf_tbl_size *
1661 sizeof(struct diag_write_device), GFP_KERNEL);
1662 if (driver->buf_tbl == NULL)
1663 goto err;
1664 if (driver->data_ready == NULL &&
1665 (driver->data_ready = kzalloc(driver->num_clients * sizeof(int)
1666 , GFP_KERNEL)) == NULL)
1667 goto err;
1668 if (driver->table == NULL &&
Shalabh Jainfe02b0c2012-02-21 14:48:03 -08001669 (driver->table = kzalloc(diag_max_reg*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670 sizeof(struct diag_master_table),
1671 GFP_KERNEL)) == NULL)
1672 goto err;
1673 if (driver->write_ptr_1 == NULL) {
1674 driver->write_ptr_1 = kzalloc(
1675 sizeof(struct diag_request), GFP_KERNEL);
1676 if (driver->write_ptr_1 == NULL)
1677 goto err;
1678 }
1679 if (driver->write_ptr_2 == NULL) {
1680 driver->write_ptr_2 = kzalloc(
1681 sizeof(struct diag_request), GFP_KERNEL);
1682 if (driver->write_ptr_2 == NULL)
1683 goto err;
1684 }
1685 if (driver->write_ptr_qdsp_1 == NULL) {
1686 driver->write_ptr_qdsp_1 = kzalloc(
1687 sizeof(struct diag_request), GFP_KERNEL);
1688 if (driver->write_ptr_qdsp_1 == NULL)
1689 goto err;
1690 }
1691 if (driver->write_ptr_qdsp_2 == NULL) {
1692 driver->write_ptr_qdsp_2 = kzalloc(
1693 sizeof(struct diag_request), GFP_KERNEL);
1694 if (driver->write_ptr_qdsp_2 == NULL)
1695 goto err;
1696 }
Ashay Jaiswal29620122012-03-21 12:02:36 +05301697 if (driver->write_ptr_wcnss_1 == NULL) {
1698 driver->write_ptr_wcnss_1 = kzalloc(
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699 sizeof(struct diag_request), GFP_KERNEL);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301700 if (driver->write_ptr_wcnss_1 == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001701 goto err;
1702 }
Ashay Jaiswal29620122012-03-21 12:02:36 +05301703 if (driver->write_ptr_wcnss_2 == NULL) {
1704 driver->write_ptr_wcnss_2 = kzalloc(
1705 sizeof(struct diag_request), GFP_KERNEL);
1706 if (driver->write_ptr_wcnss_2 == NULL)
1707 goto err;
1708 }
1709
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001710 if (driver->usb_read_ptr == NULL) {
1711 driver->usb_read_ptr = kzalloc(
1712 sizeof(struct diag_request), GFP_KERNEL);
1713 if (driver->usb_read_ptr == NULL)
1714 goto err;
1715 }
1716 if (driver->pkt_buf == NULL &&
1717 (driver->pkt_buf = kzalloc(PKT_SIZE,
1718 GFP_KERNEL)) == NULL)
1719 goto err;
1720 if (driver->apps_rsp_buf == NULL) {
Shalabh Jain321c8b52012-02-22 12:37:06 -08001721 driver->apps_rsp_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001722 if (driver->apps_rsp_buf == NULL)
1723 goto err;
1724 }
1725 driver->diag_wq = create_singlethread_workqueue("diag_wq");
1726#ifdef CONFIG_DIAG_OVER_USB
1727 INIT_WORK(&(driver->diag_proc_hdlc_work), diag_process_hdlc_fn);
1728 INIT_WORK(&(driver->diag_read_work), diag_read_work_fn);
Shalabh Jain321c8b52012-02-22 12:37:06 -08001729 INIT_WORK(&(driver->diag_msg_mask_update_work),
1730 diag_msg_mask_update_fn);
1731 INIT_WORK(&(driver->diag_log_mask_update_work),
1732 diag_log_mask_update_fn);
1733 INIT_WORK(&(driver->diag_modem_mask_update_work),
1734 diag_modem_mask_update_fn);
1735 INIT_WORK(&(driver->diag_qdsp_mask_update_work),
1736 diag_qdsp_mask_update_fn);
1737 INIT_WORK(&(driver->diag_wcnss_mask_update_work),
1738 diag_wcnss_mask_update_fn);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001739 driver->legacy_ch = usb_diag_open(DIAG_LEGACY, driver,
1740 diag_usb_legacy_notifier);
1741 if (IS_ERR(driver->legacy_ch)) {
1742 printk(KERN_ERR "Unable to open USB diag legacy channel\n");
1743 goto err;
1744 }
1745#endif
1746 platform_driver_register(&msm_smd_ch1_driver);
1747 platform_driver_register(&diag_smd_lite_driver);
1748
1749 return;
1750err:
1751 pr_err("diag: Could not initialize diag buffers");
Shalabh Jain321c8b52012-02-22 12:37:06 -08001752 kfree(driver->event_mask);
1753 kfree(driver->log_mask);
1754 kfree(driver->msg_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755 kfree(driver->buf_in_1);
1756 kfree(driver->buf_in_2);
1757 kfree(driver->buf_in_qdsp_1);
1758 kfree(driver->buf_in_qdsp_2);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301759 kfree(driver->buf_in_wcnss_1);
1760 kfree(driver->buf_in_wcnss_2);
Shalabh Jain321c8b52012-02-22 12:37:06 -08001761 kfree(driver->buf_msg_mask_update);
1762 kfree(driver->buf_log_mask_update);
1763 kfree(driver->buf_event_mask_update);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001764 kfree(driver->usb_buf_out);
1765 kfree(driver->hdlc_buf);
1766 kfree(driver->msg_masks);
1767 kfree(driver->log_masks);
1768 kfree(driver->event_masks);
1769 kfree(driver->client_map);
1770 kfree(driver->buf_tbl);
1771 kfree(driver->data_ready);
1772 kfree(driver->table);
1773 kfree(driver->pkt_buf);
1774 kfree(driver->write_ptr_1);
1775 kfree(driver->write_ptr_2);
1776 kfree(driver->write_ptr_qdsp_1);
1777 kfree(driver->write_ptr_qdsp_2);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301778 kfree(driver->write_ptr_wcnss_1);
1779 kfree(driver->write_ptr_wcnss_2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001780 kfree(driver->usb_read_ptr);
1781 kfree(driver->apps_rsp_buf);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001782 kfree(driver->user_space_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001783 if (driver->diag_wq)
1784 destroy_workqueue(driver->diag_wq);
1785}
1786
1787void diagfwd_exit(void)
1788{
1789 smd_close(driver->ch);
1790 smd_close(driver->chqdsp);
1791 smd_close(driver->ch_wcnss);
1792 driver->ch = 0; /* SMD can make this NULL */
1793 driver->chqdsp = 0;
1794 driver->ch_wcnss = 0;
1795#ifdef CONFIG_DIAG_OVER_USB
1796 if (driver->usb_connected)
1797 usb_diag_free_req(driver->legacy_ch);
1798 usb_diag_close(driver->legacy_ch);
1799#endif
1800 platform_driver_unregister(&msm_smd_ch1_driver);
1801 platform_driver_unregister(&diag_smd_lite_driver);
Shalabh Jain321c8b52012-02-22 12:37:06 -08001802 kfree(driver->event_mask);
1803 kfree(driver->log_mask);
1804 kfree(driver->msg_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001805 kfree(driver->buf_in_1);
1806 kfree(driver->buf_in_2);
1807 kfree(driver->buf_in_qdsp_1);
1808 kfree(driver->buf_in_qdsp_2);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301809 kfree(driver->buf_in_wcnss_1);
1810 kfree(driver->buf_in_wcnss_2);
Shalabh Jain321c8b52012-02-22 12:37:06 -08001811 kfree(driver->buf_msg_mask_update);
1812 kfree(driver->buf_log_mask_update);
1813 kfree(driver->buf_event_mask_update);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001814 kfree(driver->usb_buf_out);
1815 kfree(driver->hdlc_buf);
1816 kfree(driver->msg_masks);
1817 kfree(driver->log_masks);
1818 kfree(driver->event_masks);
1819 kfree(driver->client_map);
1820 kfree(driver->buf_tbl);
1821 kfree(driver->data_ready);
1822 kfree(driver->table);
1823 kfree(driver->pkt_buf);
1824 kfree(driver->write_ptr_1);
1825 kfree(driver->write_ptr_2);
1826 kfree(driver->write_ptr_qdsp_1);
1827 kfree(driver->write_ptr_qdsp_2);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301828 kfree(driver->write_ptr_wcnss_1);
1829 kfree(driver->write_ptr_wcnss_2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001830 kfree(driver->usb_read_ptr);
1831 kfree(driver->apps_rsp_buf);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001832 kfree(driver->user_space_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001833 destroy_workqueue(driver->diag_wq);
1834}