blob: a77d825d4770239f4106cc2a70219c33584d8f77 [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 Jain321c8b52012-02-22 12:37:06 -0800513static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bytes)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700514{
515 uint8_t *ptr = driver->event_masks;
516 uint8_t *temp = buf + 2;
517
518 mutex_lock(&driver->diagchar_mutex);
519 if (!toggle)
520 memset(ptr, 0 , EVENT_MASK_SIZE);
521 else
522 if (CHK_OVERFLOW(ptr, ptr,
Shalabh Jain321c8b52012-02-22 12:37:06 -0800523 ptr+EVENT_MASK_SIZE, num_bytes))
524 memcpy(ptr, temp , num_bytes);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700525 else
526 printk(KERN_CRIT "Not enough buffer space "
527 "for EVENT_MASK\n");
528 mutex_unlock(&driver->diagchar_mutex);
529}
530
531static void diag_update_log_mask(int equip_id, uint8_t *buf, int num_items)
532{
533 uint8_t *temp = buf;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534 int i = 0;
535 unsigned char *ptr_data;
Shalabh Jainfbf3bdc2012-03-16 21:02:50 -0700536 int offset = (sizeof(struct mask_info))*MAX_EQUIP_ID;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700537 struct mask_info *ptr = (struct mask_info *)driver->log_masks;
538
539 mutex_lock(&driver->diagchar_mutex);
540 /* Check if we already know index of this equipment ID */
541 for (i = 0; i < MAX_EQUIP_ID; i++) {
542 if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
543 offset = ptr->index;
544 break;
545 }
546 if ((ptr->equip_id == 0) && (ptr->index == 0)) {
Shalabh Jain321c8b52012-02-22 12:37:06 -0800547 /* Reached a null entry */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700548 ptr->equip_id = equip_id;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800549 ptr->num_items = num_items;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550 ptr->index = driver->log_masks_length;
551 offset = driver->log_masks_length;
552 driver->log_masks_length += ((num_items+7)/8);
553 break;
554 }
555 ptr++;
556 }
557 ptr_data = driver->log_masks + offset;
558 if (CHK_OVERFLOW(driver->log_masks, ptr_data, driver->log_masks
559 + LOG_MASK_SIZE, (num_items+7)/8))
560 memcpy(ptr_data, temp , (num_items+7)/8);
561 else
562 printk(KERN_CRIT " Not enough buffer space for LOG_MASK\n");
563 mutex_unlock(&driver->diagchar_mutex);
564}
565
566static void diag_update_pkt_buffer(unsigned char *buf)
567{
568 unsigned char *ptr = driver->pkt_buf;
569 unsigned char *temp = buf;
570
571 mutex_lock(&driver->diagchar_mutex);
572 if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, driver->pkt_length))
573 memcpy(ptr, temp , driver->pkt_length);
574 else
575 printk(KERN_CRIT " Not enough buffer space for PKT_RESP\n");
576 mutex_unlock(&driver->diagchar_mutex);
577}
578
579void diag_update_userspace_clients(unsigned int type)
580{
581 int i;
582
583 mutex_lock(&driver->diagchar_mutex);
584 for (i = 0; i < driver->num_clients; i++)
585 if (driver->client_map[i].pid != 0)
586 driver->data_ready[i] |= type;
587 wake_up_interruptible(&driver->wait_q);
588 mutex_unlock(&driver->diagchar_mutex);
589}
590
591void diag_update_sleeping_process(int process_id)
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 == process_id) {
598 driver->data_ready[i] |= PKT_TYPE;
599 break;
600 }
601 wake_up_interruptible(&driver->wait_q);
602 mutex_unlock(&driver->diagchar_mutex);
603}
604
605void diag_send_data(struct diag_master_table entry, unsigned char *buf,
606 int len, int type)
607{
608 driver->pkt_length = len;
609 if (entry.process_id != NON_APPS_PROC && type != MODEM_DATA) {
610 diag_update_pkt_buffer(buf);
611 diag_update_sleeping_process(entry.process_id);
612 } else {
613 if (len > 0) {
Shalabh Jainc9f35092011-07-28 18:36:17 -0700614 if (entry.client_id == MODEM_PROC && driver->ch) {
Shalabh Jain10f5f432012-01-11 11:45:44 +0530615 if (chk_apps_master() &&
Shalabh Jainc9f35092011-07-28 18:36:17 -0700616 (int)(*(char *)buf) == MODE_CMD)
Dixon Petersonff425d12011-12-06 18:12:35 -0800617 if ((int)(*(char *)(buf+1)) ==
618 RESET_ID)
Shalabh Jainc9f35092011-07-28 18:36:17 -0700619 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 smd_write(driver->ch, buf, len);
Shalabh Jainc9f35092011-07-28 18:36:17 -0700621 } else if (entry.client_id == QDSP_PROC &&
622 driver->chqdsp) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700623 smd_write(driver->chqdsp, buf, len);
Shalabh Jainc9f35092011-07-28 18:36:17 -0700624 } else if (entry.client_id == WCNSS_PROC &&
625 driver->ch_wcnss) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700626 smd_write(driver->ch_wcnss, buf, len);
Shalabh Jainc9f35092011-07-28 18:36:17 -0700627 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700628 pr_alert("diag: incorrect channel");
Shalabh Jainc9f35092011-07-28 18:36:17 -0700629 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700630 }
631 }
632}
633
Shalabh Jain321c8b52012-02-22 12:37:06 -0800634void diag_modem_mask_update_fn(struct work_struct *work)
635{
636 diag_send_msg_mask_update(driver->ch_cntl);
637 diag_send_log_mask_update(driver->ch_cntl);
638 diag_send_event_mask_update(driver->ch_cntl, diag_event_num_bytes);
639}
640
641void diag_qdsp_mask_update_fn(struct work_struct *work)
642{
643 diag_send_msg_mask_update(driver->chqdsp_cntl);
644 diag_send_log_mask_update(driver->chqdsp_cntl);
645 diag_send_event_mask_update(driver->chqdsp_cntl, diag_event_num_bytes);
646}
647
648void diag_wcnss_mask_update_fn(struct work_struct *work)
649{
650 diag_send_msg_mask_update(driver->ch_wcnss_cntl);
651 diag_send_log_mask_update(driver->ch_wcnss_cntl);
652 diag_send_event_mask_update(driver->ch_wcnss_cntl,
653 diag_event_num_bytes);
654}
655
656void diag_msg_mask_update_fn(struct work_struct *work)
657{
658 diag_send_msg_mask_update(driver->ch_cntl);
659 diag_send_msg_mask_update(driver->chqdsp_cntl);
660 diag_send_msg_mask_update(driver->ch_wcnss_cntl);
661}
662
663void diag_log_mask_update_fn(struct work_struct *work)
664{
665 diag_send_log_mask_update(driver->ch_cntl);
666 diag_send_log_mask_update(driver->chqdsp_cntl);
667 diag_send_log_mask_update(driver->ch_wcnss_cntl);
668}
669
670void diag_send_log_mask_update(smd_channel_t *ch)
671{
672 void *buf = driver->buf_log_mask_update;
673 int header_size = sizeof(struct diag_ctrl_log_mask);
674 struct mask_info *ptr = (struct mask_info *)driver->log_masks;
Shalabh Jainfbf3bdc2012-03-16 21:02:50 -0700675 int i, size;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800676
677 for (i = 0; i < MAX_EQUIP_ID; i++) {
Shalabh Jainfbf3bdc2012-03-16 21:02:50 -0700678 size = (ptr->num_items+7)/8;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800679 /* reached null entry */
680 if ((ptr->equip_id == 0) && (ptr->index == 0))
681 break;
682 driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
683 driver->log_mask->num_items = ptr->num_items;
684 driver->log_mask->data_len = 11 + size;
685 driver->log_mask->stream_id = 1; /* 2, if dual stream */
686 driver->log_mask->status = 3; /* status for valid mask */
687 driver->log_mask->equip_id = ptr->equip_id;
688 driver->log_mask->log_mask_size = size;
689 memcpy(buf, driver->log_mask, header_size);
690 memcpy(buf+header_size, driver->log_masks+ptr->index, size);
691 msleep(100);
692 if (ch)
693 smd_write(ch, buf, header_size + size);
694 ptr++;
695 }
696}
697
698void diag_send_event_mask_update(smd_channel_t *ch, int num_bytes)
699{
700 void *buf = driver->buf_event_mask_update;
701 int header_size = sizeof(struct diag_ctrl_event_mask);
702
703 /* send event mask update */
704 driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
705 driver->event_mask->data_len = 7 + num_bytes;
706 driver->event_mask->stream_id = 1; /* 2, if dual stream */
707 driver->event_mask->status = 3; /* status for valid mask */
708 driver->event_mask->event_config = diag_event_config; /* event config */
709 driver->event_mask->event_mask_size = num_bytes;
710 memcpy(buf, driver->event_mask, header_size);
711 memcpy(buf+header_size, driver->event_masks, num_bytes);
712 msleep(100);
713 if (ch)
714 smd_write(ch, buf, header_size + num_bytes);
715}
716
717void diag_send_msg_mask_update(smd_channel_t *ch)
718{
719 void *buf = driver->buf_msg_mask_update;
720 int first, last;
721 int header_size = sizeof(struct diag_ctrl_msg_mask);
722 uint8_t *ptr = driver->msg_masks;
723
724 while (*(uint32_t *)(ptr + 4)) {
725 first = *(uint32_t *)ptr;
726 ptr += 4;
727 last = *(uint32_t *)ptr;
728 ptr += 4;
729 /* send event mask update */
730 driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
731 driver->msg_mask->msg_mask_size = last - first + 1;
732 driver->msg_mask->data_len = 11 +
733 4 * (driver->msg_mask->msg_mask_size);
734 driver->msg_mask->stream_id = 1; /* 2, if dual stream */
735 driver->msg_mask->status = 3; /* status for valid mask */
736 driver->msg_mask->msg_mode = 0; /* Legcay mode */
737 driver->msg_mask->ssid_first = first;
738 driver->msg_mask->ssid_last = last;
739 memcpy(buf, driver->msg_mask, header_size);
740 memcpy(buf+header_size, ptr,
741 4 * (driver->msg_mask->msg_mask_size));
742 /* since mask updates are slow, so sleep needed as to
743 prevent modem running out of DSM items */
744 msleep(100);
745 if (ch)
746 smd_write(ch, buf,
747 header_size + 4*(driver->msg_mask->msg_mask_size));
748 ptr += ((last - first) + 1)*4;
749 }
750}
751
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700752static int diag_process_apps_pkt(unsigned char *buf, int len)
753{
754 uint16_t subsys_cmd_code;
755 int subsys_id, ssid_first, ssid_last, ssid_range;
756 int packet_type = 1, i, cmd_code;
757 unsigned char *temp = buf;
758 int data_type;
759#if defined(CONFIG_DIAG_OVER_USB)
760 int payload_length;
761 unsigned char *ptr;
762#endif
763
Shalabh Jain321c8b52012-02-22 12:37:06 -0800764 /* Set log masks */
765 if (*buf == 0x73 && *(int *)(buf+4) == 3) {
766 buf += 8;
767 /* Read Equip ID and pass as first param below*/
768 diag_update_log_mask(*(int *)buf, buf+8, *(int *)(buf+4));
769 diag_update_userspace_clients(LOG_MASKS_TYPE);
770#if defined(CONFIG_DIAG_OVER_USB)
771 if (chk_apps_only()) {
772 driver->apps_rsp_buf[0] = 0x73;
773 *(int *)(driver->apps_rsp_buf + 4) = 0x3; /* op. ID */
774 *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success */
775 payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
776 for (i = 0; i < payload_length; i++)
777 *(int *)(driver->apps_rsp_buf+12+i) = *(buf+i);
778 queue_work(driver->diag_cntl_wq,
779 &(driver->diag_log_mask_update_work));
780 ENCODE_RSP_AND_SEND(12 + payload_length - 1);
781 return 0;
782 } else
783 buf = temp;
784#endif
785 } /* Check for set message mask */
786 else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
787 ssid_first = *(uint16_t *)(buf + 2);
788 ssid_last = *(uint16_t *)(buf + 4);
789 ssid_range = 4 * (ssid_last - ssid_first + 1);
790 diag_update_msg_mask(ssid_first, ssid_last , buf + 8);
791 diag_update_userspace_clients(MSG_MASKS_TYPE);
792#if defined(CONFIG_DIAG_OVER_USB)
793 if (chk_apps_only()) {
794 for (i = 0; i < 8 + ssid_range; i++)
795 *(driver->apps_rsp_buf + i) = *(buf+i);
796 *(driver->apps_rsp_buf + 6) = 0x1;
797 queue_work(driver->diag_cntl_wq,
798 &(driver->diag_msg_mask_update_work));
799 ENCODE_RSP_AND_SEND(8 + ssid_range - 1);
800 return 0;
801 } else
802 buf = temp;
803#endif
804 } else if (*buf == 0x82) { /* event mask change */
805 buf += 4;
806 diag_event_num_bytes = (*(uint16_t *)buf)/8+1;
807 diag_update_event_mask(buf, 1, (*(uint16_t *)buf)/8+1);
808 diag_update_userspace_clients(EVENT_MASKS_TYPE);
809#if defined(CONFIG_DIAG_OVER_USB)
810 if (chk_apps_only()) {
811 driver->apps_rsp_buf[0] = 0x82;
812 driver->apps_rsp_buf[1] = 0x0;
813 *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
814 *(uint16_t *)(driver->apps_rsp_buf + 4) =
815 EVENT_LAST_ID + 1;
816 for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
817 *(unsigned char *)(driver->apps_rsp_buf + 6 + i)
818 = 0x0;
819 /* cannot do this on work queue, as each event update
820 needs a num_bytes variable. Each queue_work call will
821 overwrite the previous input, as its the same struct */
822 diag_send_event_mask_update(driver->ch_cntl,
823 diag_event_num_bytes);
824 diag_send_event_mask_update(driver->chqdsp_cntl,
825 diag_event_num_bytes);
826 diag_send_event_mask_update(driver->ch_wcnss_cntl,
827 diag_event_num_bytes);
828 ENCODE_RSP_AND_SEND(6 + EVENT_LAST_ID/8);
829 return 0;
830 } else
831 buf = temp;
832#endif
833 } else if (*buf == 0x60) {
834 diag_event_config = *(buf+1);
835#if defined(CONFIG_DIAG_OVER_USB)
836 if (chk_apps_only()) {
837 driver->apps_rsp_buf[0] = 0x60;
838 driver->apps_rsp_buf[1] = 0x0;
839 driver->apps_rsp_buf[2] = 0x0;
840 diag_send_event_mask_update(driver->ch_cntl,
841 diag_event_num_bytes);
842 diag_send_event_mask_update(driver->chqdsp_cntl,
843 diag_event_num_bytes);
844 diag_send_event_mask_update(driver->ch_wcnss_cntl,
845 diag_event_num_bytes);
846 ENCODE_RSP_AND_SEND(2);
847 return 0;
848 }
849#endif
850 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700851 /* Check for registered clients and forward packet to apropriate proc */
852 cmd_code = (int)(*(char *)buf);
853 temp++;
854 subsys_id = (int)(*(char *)temp);
855 temp++;
856 subsys_cmd_code = *(uint16_t *)temp;
857 temp += 2;
858 data_type = APPS_DATA;
859 /* Dont send any command other than mode reset */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530860 if (chk_apps_master() && cmd_code == MODE_CMD) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700861 if (subsys_id != RESET_ID)
862 data_type = MODEM_DATA;
863 }
864
865 pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
Shalabh Jainfe02b0c2012-02-21 14:48:03 -0800866 for (i = 0; i < diag_max_reg; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700867 entry = driver->table[i];
868 if (entry.process_id != NO_PROCESS) {
869 if (entry.cmd_code == cmd_code && entry.subsys_id ==
870 subsys_id && entry.cmd_code_lo <=
871 subsys_cmd_code &&
872 entry.cmd_code_hi >= subsys_cmd_code) {
873 diag_send_data(entry, buf, len, data_type);
874 packet_type = 0;
875 } else if (entry.cmd_code == 255
876 && cmd_code == 75) {
877 if (entry.subsys_id ==
878 subsys_id &&
879 entry.cmd_code_lo <=
880 subsys_cmd_code &&
881 entry.cmd_code_hi >=
882 subsys_cmd_code) {
883 diag_send_data(entry, buf, len,
884 data_type);
885 packet_type = 0;
886 }
887 } else if (entry.cmd_code == 255 &&
888 entry.subsys_id == 255) {
889 if (entry.cmd_code_lo <=
890 cmd_code &&
891 entry.
892 cmd_code_hi >= cmd_code) {
893 diag_send_data(entry, buf, len,
894 data_type);
895 packet_type = 0;
896 }
897 }
898 }
899 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900#if defined(CONFIG_DIAG_OVER_USB)
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700901 /* Check for Apps Only & get event mask request */
Shalabh Jain321c8b52012-02-22 12:37:06 -0800902 if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903 driver->apps_rsp_buf[0] = 0x81;
904 driver->apps_rsp_buf[1] = 0x0;
905 *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
906 *(uint16_t *)(driver->apps_rsp_buf + 4) = EVENT_LAST_ID + 1;
907 for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
908 *(unsigned char *)(driver->apps_rsp_buf + 6 + i) = 0x0;
909 ENCODE_RSP_AND_SEND(6 + EVENT_LAST_ID/8);
910 return 0;
911 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700912 /* Get log ID range & Check for Apps Only */
913 else if (!(driver->ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700914 && (*buf == 0x73) && *(int *)(buf+4) == 1) {
915 driver->apps_rsp_buf[0] = 0x73;
916 *(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
917 *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success code */
918 *(int *)(driver->apps_rsp_buf + 12) = LOG_GET_ITEM_NUM(LOG_0);
919 *(int *)(driver->apps_rsp_buf + 16) = LOG_GET_ITEM_NUM(LOG_1);
920 *(int *)(driver->apps_rsp_buf + 20) = LOG_GET_ITEM_NUM(LOG_2);
921 *(int *)(driver->apps_rsp_buf + 24) = LOG_GET_ITEM_NUM(LOG_3);
922 *(int *)(driver->apps_rsp_buf + 28) = LOG_GET_ITEM_NUM(LOG_4);
923 *(int *)(driver->apps_rsp_buf + 32) = LOG_GET_ITEM_NUM(LOG_5);
924 *(int *)(driver->apps_rsp_buf + 36) = LOG_GET_ITEM_NUM(LOG_6);
925 *(int *)(driver->apps_rsp_buf + 40) = LOG_GET_ITEM_NUM(LOG_7);
926 *(int *)(driver->apps_rsp_buf + 44) = LOG_GET_ITEM_NUM(LOG_8);
927 *(int *)(driver->apps_rsp_buf + 48) = LOG_GET_ITEM_NUM(LOG_9);
928 *(int *)(driver->apps_rsp_buf + 52) = LOG_GET_ITEM_NUM(LOG_10);
929 *(int *)(driver->apps_rsp_buf + 56) = LOG_GET_ITEM_NUM(LOG_11);
930 *(int *)(driver->apps_rsp_buf + 60) = LOG_GET_ITEM_NUM(LOG_12);
931 *(int *)(driver->apps_rsp_buf + 64) = LOG_GET_ITEM_NUM(LOG_13);
932 *(int *)(driver->apps_rsp_buf + 68) = LOG_GET_ITEM_NUM(LOG_14);
933 *(int *)(driver->apps_rsp_buf + 72) = LOG_GET_ITEM_NUM(LOG_15);
934 ENCODE_RSP_AND_SEND(75);
935 return 0;
936 }
937 /* Respond to Get SSID Range request message */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700938 else if (!(driver->ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700939 && (*buf == 0x7d) && (*(buf+1) == 0x1)) {
940 driver->apps_rsp_buf[0] = 0x7d;
941 driver->apps_rsp_buf[1] = 0x1;
942 driver->apps_rsp_buf[2] = 0x1;
943 driver->apps_rsp_buf[3] = 0x0;
944 *(int *)(driver->apps_rsp_buf + 4) = MSG_MASK_TBL_CNT;
945 *(uint16_t *)(driver->apps_rsp_buf + 8) = MSG_SSID_0;
946 *(uint16_t *)(driver->apps_rsp_buf + 10) = MSG_SSID_0_LAST;
947 *(uint16_t *)(driver->apps_rsp_buf + 12) = MSG_SSID_1;
948 *(uint16_t *)(driver->apps_rsp_buf + 14) = MSG_SSID_1_LAST;
949 *(uint16_t *)(driver->apps_rsp_buf + 16) = MSG_SSID_2;
950 *(uint16_t *)(driver->apps_rsp_buf + 18) = MSG_SSID_2_LAST;
951 *(uint16_t *)(driver->apps_rsp_buf + 20) = MSG_SSID_3;
952 *(uint16_t *)(driver->apps_rsp_buf + 22) = MSG_SSID_3_LAST;
953 *(uint16_t *)(driver->apps_rsp_buf + 24) = MSG_SSID_4;
954 *(uint16_t *)(driver->apps_rsp_buf + 26) = MSG_SSID_4_LAST;
955 *(uint16_t *)(driver->apps_rsp_buf + 28) = MSG_SSID_5;
956 *(uint16_t *)(driver->apps_rsp_buf + 30) = MSG_SSID_5_LAST;
957 *(uint16_t *)(driver->apps_rsp_buf + 32) = MSG_SSID_6;
958 *(uint16_t *)(driver->apps_rsp_buf + 34) = MSG_SSID_6_LAST;
959 *(uint16_t *)(driver->apps_rsp_buf + 36) = MSG_SSID_7;
960 *(uint16_t *)(driver->apps_rsp_buf + 38) = MSG_SSID_7_LAST;
961 *(uint16_t *)(driver->apps_rsp_buf + 40) = MSG_SSID_8;
962 *(uint16_t *)(driver->apps_rsp_buf + 42) = MSG_SSID_8_LAST;
963 *(uint16_t *)(driver->apps_rsp_buf + 44) = MSG_SSID_9;
964 *(uint16_t *)(driver->apps_rsp_buf + 46) = MSG_SSID_9_LAST;
965 *(uint16_t *)(driver->apps_rsp_buf + 48) = MSG_SSID_10;
966 *(uint16_t *)(driver->apps_rsp_buf + 50) = MSG_SSID_10_LAST;
967 *(uint16_t *)(driver->apps_rsp_buf + 52) = MSG_SSID_11;
968 *(uint16_t *)(driver->apps_rsp_buf + 54) = MSG_SSID_11_LAST;
969 *(uint16_t *)(driver->apps_rsp_buf + 56) = MSG_SSID_12;
970 *(uint16_t *)(driver->apps_rsp_buf + 58) = MSG_SSID_12_LAST;
971 *(uint16_t *)(driver->apps_rsp_buf + 60) = MSG_SSID_13;
972 *(uint16_t *)(driver->apps_rsp_buf + 62) = MSG_SSID_13_LAST;
973 *(uint16_t *)(driver->apps_rsp_buf + 64) = MSG_SSID_14;
974 *(uint16_t *)(driver->apps_rsp_buf + 66) = MSG_SSID_14_LAST;
975 *(uint16_t *)(driver->apps_rsp_buf + 68) = MSG_SSID_15;
976 *(uint16_t *)(driver->apps_rsp_buf + 70) = MSG_SSID_15_LAST;
977 *(uint16_t *)(driver->apps_rsp_buf + 72) = MSG_SSID_16;
978 *(uint16_t *)(driver->apps_rsp_buf + 74) = MSG_SSID_16_LAST;
979 *(uint16_t *)(driver->apps_rsp_buf + 76) = MSG_SSID_17;
980 *(uint16_t *)(driver->apps_rsp_buf + 78) = MSG_SSID_17_LAST;
981 *(uint16_t *)(driver->apps_rsp_buf + 80) = MSG_SSID_18;
982 *(uint16_t *)(driver->apps_rsp_buf + 82) = MSG_SSID_18_LAST;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800983 *(uint16_t *)(driver->apps_rsp_buf + 84) = MSG_SSID_19;
984 *(uint16_t *)(driver->apps_rsp_buf + 86) = MSG_SSID_19_LAST;
985 *(uint16_t *)(driver->apps_rsp_buf + 88) = MSG_SSID_20;
986 *(uint16_t *)(driver->apps_rsp_buf + 90) = MSG_SSID_20_LAST;
987 *(uint16_t *)(driver->apps_rsp_buf + 92) = MSG_SSID_21;
988 *(uint16_t *)(driver->apps_rsp_buf + 94) = MSG_SSID_21_LAST;
989 *(uint16_t *)(driver->apps_rsp_buf + 96) = MSG_SSID_22;
990 *(uint16_t *)(driver->apps_rsp_buf + 98) = MSG_SSID_22_LAST;
991 ENCODE_RSP_AND_SEND(99);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700992 return 0;
993 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700994 /* Check for Apps Only Respond to Get Subsys Build mask */
995 else if (!(driver->ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700996 && (*buf == 0x7d) && (*(buf+1) == 0x2)) {
997 ssid_first = *(uint16_t *)(buf + 2);
998 ssid_last = *(uint16_t *)(buf + 4);
999 ssid_range = 4 * (ssid_last - ssid_first + 1);
1000 /* frame response */
1001 driver->apps_rsp_buf[0] = 0x7d;
1002 driver->apps_rsp_buf[1] = 0x2;
1003 *(uint16_t *)(driver->apps_rsp_buf + 2) = ssid_first;
1004 *(uint16_t *)(driver->apps_rsp_buf + 4) = ssid_last;
1005 driver->apps_rsp_buf[6] = 0x1;
1006 driver->apps_rsp_buf[7] = 0x0;
1007 ptr = driver->apps_rsp_buf + 8;
1008 /* bld time masks */
1009 switch (ssid_first) {
1010 case MSG_SSID_0:
1011 for (i = 0; i < ssid_range; i += 4)
1012 *(int *)(ptr + i) = msg_bld_masks_0[i/4];
1013 break;
1014 case MSG_SSID_1:
1015 for (i = 0; i < ssid_range; i += 4)
1016 *(int *)(ptr + i) = msg_bld_masks_1[i/4];
1017 break;
1018 case MSG_SSID_2:
1019 for (i = 0; i < ssid_range; i += 4)
1020 *(int *)(ptr + i) = msg_bld_masks_2[i/4];
1021 break;
1022 case MSG_SSID_3:
1023 for (i = 0; i < ssid_range; i += 4)
1024 *(int *)(ptr + i) = msg_bld_masks_3[i/4];
1025 break;
1026 case MSG_SSID_4:
1027 for (i = 0; i < ssid_range; i += 4)
1028 *(int *)(ptr + i) = msg_bld_masks_4[i/4];
1029 break;
1030 case MSG_SSID_5:
1031 for (i = 0; i < ssid_range; i += 4)
1032 *(int *)(ptr + i) = msg_bld_masks_5[i/4];
1033 break;
1034 case MSG_SSID_6:
1035 for (i = 0; i < ssid_range; i += 4)
1036 *(int *)(ptr + i) = msg_bld_masks_6[i/4];
1037 break;
1038 case MSG_SSID_7:
1039 for (i = 0; i < ssid_range; i += 4)
1040 *(int *)(ptr + i) = msg_bld_masks_7[i/4];
1041 break;
1042 case MSG_SSID_8:
1043 for (i = 0; i < ssid_range; i += 4)
1044 *(int *)(ptr + i) = msg_bld_masks_8[i/4];
1045 break;
1046 case MSG_SSID_9:
1047 for (i = 0; i < ssid_range; i += 4)
1048 *(int *)(ptr + i) = msg_bld_masks_9[i/4];
1049 break;
1050 case MSG_SSID_10:
1051 for (i = 0; i < ssid_range; i += 4)
1052 *(int *)(ptr + i) = msg_bld_masks_10[i/4];
1053 break;
1054 case MSG_SSID_11:
1055 for (i = 0; i < ssid_range; i += 4)
1056 *(int *)(ptr + i) = msg_bld_masks_11[i/4];
1057 break;
1058 case MSG_SSID_12:
1059 for (i = 0; i < ssid_range; i += 4)
1060 *(int *)(ptr + i) = msg_bld_masks_12[i/4];
1061 break;
1062 case MSG_SSID_13:
1063 for (i = 0; i < ssid_range; i += 4)
1064 *(int *)(ptr + i) = msg_bld_masks_13[i/4];
1065 break;
1066 case MSG_SSID_14:
1067 for (i = 0; i < ssid_range; i += 4)
1068 *(int *)(ptr + i) = msg_bld_masks_14[i/4];
1069 break;
1070 case MSG_SSID_15:
1071 for (i = 0; i < ssid_range; i += 4)
1072 *(int *)(ptr + i) = msg_bld_masks_15[i/4];
1073 break;
1074 case MSG_SSID_16:
1075 for (i = 0; i < ssid_range; i += 4)
1076 *(int *)(ptr + i) = msg_bld_masks_16[i/4];
1077 break;
1078 case MSG_SSID_17:
1079 for (i = 0; i < ssid_range; i += 4)
1080 *(int *)(ptr + i) = msg_bld_masks_17[i/4];
1081 break;
1082 case MSG_SSID_18:
1083 for (i = 0; i < ssid_range; i += 4)
1084 *(int *)(ptr + i) = msg_bld_masks_18[i/4];
1085 break;
Shalabh Jain321c8b52012-02-22 12:37:06 -08001086 case MSG_SSID_19:
1087 for (i = 0; i < ssid_range; i += 4)
1088 *(int *)(ptr + i) = msg_bld_masks_19[i/4];
1089 break;
1090 case MSG_SSID_20:
1091 for (i = 0; i < ssid_range; i += 4)
1092 *(int *)(ptr + i) = msg_bld_masks_20[i/4];
1093 break;
1094 case MSG_SSID_21:
1095 for (i = 0; i < ssid_range; i += 4)
1096 *(int *)(ptr + i) = msg_bld_masks_21[i/4];
1097 break;
1098 case MSG_SSID_22:
1099 for (i = 0; i < ssid_range; i += 4)
1100 *(int *)(ptr + i) = msg_bld_masks_22[i/4];
1101 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001102 }
1103 ENCODE_RSP_AND_SEND(8 + ssid_range - 1);
1104 return 0;
1105 }
1106 /* Check for download command */
Shalabh Jain10f5f432012-01-11 11:45:44 +05301107 else if ((cpu_is_msm8x60() || chk_apps_master()) && (*buf == 0x3A)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001108 /* send response back */
1109 driver->apps_rsp_buf[0] = *buf;
1110 ENCODE_RSP_AND_SEND(0);
1111 msleep(5000);
1112 /* call download API */
1113 msm_set_restart_mode(RESTART_DLOAD);
1114 printk(KERN_CRIT "diag: download mode set, Rebooting SoC..\n");
1115 kernel_restart(NULL);
1116 /* Not required, represents that command isnt sent to modem */
1117 return 0;
1118 }
Dixon Petersonb46bb992012-01-12 19:16:56 -08001119 /* Check for polling for Apps only DIAG */
1120 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1121 (*(buf+2) == 0x03)) {
Shalabh Jain3d29fc32012-02-09 17:15:59 -08001122 /* If no one has registered for polling */
Dixon Petersonb4618a42012-02-29 18:56:31 -08001123 if (chk_polling_response()) {
Dixon Petersonb46bb992012-01-12 19:16:56 -08001124 /* Respond to polling for Apps only DIAG */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 for (i = 0; i < 3; i++)
1126 driver->apps_rsp_buf[i] = *(buf+i);
1127 for (i = 0; i < 13; i++)
1128 driver->apps_rsp_buf[i+3] = 0;
1129
1130 ENCODE_RSP_AND_SEND(15);
1131 return 0;
1132 }
Dixon Petersonb46bb992012-01-12 19:16:56 -08001133 }
1134 /* Check for ID for NO MODEM present */
Dixon Petersonb4618a42012-02-29 18:56:31 -08001135 else if (chk_polling_response()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001136 /* respond to 0x0 command */
Dixon Petersonb46bb992012-01-12 19:16:56 -08001137 if (*buf == 0x00) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138 for (i = 0; i < 55; i++)
1139 driver->apps_rsp_buf[i] = 0;
1140
1141 ENCODE_RSP_AND_SEND(54);
1142 return 0;
1143 }
1144 /* respond to 0x7c command */
1145 else if (*buf == 0x7c) {
1146 driver->apps_rsp_buf[0] = 0x7c;
1147 for (i = 1; i < 8; i++)
1148 driver->apps_rsp_buf[i] = 0;
1149 /* Tools ID for APQ 8060 */
1150 *(int *)(driver->apps_rsp_buf + 8) =
1151 chk_config_get_id();
1152 *(unsigned char *)(driver->apps_rsp_buf + 12) = '\0';
1153 *(unsigned char *)(driver->apps_rsp_buf + 13) = '\0';
1154 ENCODE_RSP_AND_SEND(13);
1155 return 0;
1156 }
1157 }
1158#endif
1159 return packet_type;
1160}
1161
1162#ifdef CONFIG_DIAG_OVER_USB
1163void diag_send_error_rsp(int index)
1164{
1165 int i;
Shalabh Jain1fedab92011-12-22 13:15:22 +05301166
1167 if (index > 490) {
1168 pr_err("diag: error response too huge, aborting\n");
1169 return;
1170 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001171 driver->apps_rsp_buf[0] = 0x13; /* error code 13 */
1172 for (i = 0; i < index; i++)
1173 driver->apps_rsp_buf[i+1] = *(driver->hdlc_buf+i);
1174 ENCODE_RSP_AND_SEND(index - 3);
1175}
1176#else
1177static inline void diag_send_error_rsp(int index) {}
1178#endif
1179
1180void diag_process_hdlc(void *data, unsigned len)
1181{
1182 struct diag_hdlc_decode_type hdlc;
1183 int ret, type = 0;
1184 pr_debug("diag: HDLC decode fn, len of data %d\n", len);
1185 hdlc.dest_ptr = driver->hdlc_buf;
1186 hdlc.dest_size = USB_MAX_OUT_BUF;
1187 hdlc.src_ptr = data;
1188 hdlc.src_size = len;
1189 hdlc.src_idx = 0;
1190 hdlc.dest_idx = 0;
1191 hdlc.escaping = 0;
1192
1193 ret = diag_hdlc_decode(&hdlc);
1194
1195 if (ret)
1196 type = diag_process_apps_pkt(driver->hdlc_buf,
1197 hdlc.dest_idx - 3);
1198 else if (driver->debug_flag) {
1199 printk(KERN_ERR "Packet dropped due to bad HDLC coding/CRC"
1200 " errors or partial packet received, packet"
1201 " length = %d\n", len);
1202 print_hex_dump(KERN_DEBUG, "Dropped Packet Data: ", 16, 1,
1203 DUMP_PREFIX_ADDRESS, data, len, 1);
1204 driver->debug_flag = 0;
1205 }
1206 /* send error responses from APPS for Central Routing */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001207 if (type == 1 && chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208 diag_send_error_rsp(hdlc.dest_idx);
1209 type = 0;
1210 }
1211 /* implies this packet is NOT meant for apps */
1212 if (!(driver->ch) && type == 1) {
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001213 if (chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001214 diag_send_error_rsp(hdlc.dest_idx);
1215 } else { /* APQ 8060, Let Q6 respond */
1216 if (driver->chqdsp)
1217 smd_write(driver->chqdsp, driver->hdlc_buf,
1218 hdlc.dest_idx - 3);
1219 }
1220 type = 0;
1221 }
1222
1223#ifdef DIAG_DEBUG
1224 pr_debug("diag: hdlc.dest_idx = %d", hdlc.dest_idx);
1225 for (i = 0; i < hdlc.dest_idx; i++)
1226 printk(KERN_DEBUG "\t%x", *(((unsigned char *)
1227 driver->hdlc_buf)+i));
1228#endif /* DIAG DEBUG */
1229 /* ignore 2 bytes for CRC, one for 7E and send */
1230 if ((driver->ch) && (ret) && (type) && (hdlc.dest_idx > 3)) {
1231 APPEND_DEBUG('g');
1232 smd_write(driver->ch, driver->hdlc_buf, hdlc.dest_idx - 3);
1233 APPEND_DEBUG('h');
1234#ifdef DIAG_DEBUG
1235 printk(KERN_INFO "writing data to SMD, pkt length %d\n", len);
1236 print_hex_dump(KERN_DEBUG, "Written Packet Data to SMD: ", 16,
1237 1, DUMP_PREFIX_ADDRESS, data, len, 1);
1238#endif /* DIAG DEBUG */
1239 }
1240}
1241
1242#ifdef CONFIG_DIAG_OVER_USB
Shalabh Jain8e9750a2011-09-09 13:06:29 -07001243/* 2+1 for modem ; 2 for LPASS ; 1 for WCNSS */
1244#define N_LEGACY_WRITE (driver->poolsize + 6)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001245#define N_LEGACY_READ 1
1246
1247int diagfwd_connect(void)
1248{
1249 int err;
1250
1251 printk(KERN_DEBUG "diag: USB connected\n");
1252 err = usb_diag_alloc_req(driver->legacy_ch, N_LEGACY_WRITE,
1253 N_LEGACY_READ);
1254 if (err)
1255 printk(KERN_ERR "diag: unable to alloc USB req on legacy ch");
1256
1257 driver->usb_connected = 1;
1258 driver->in_busy_1 = 0;
1259 driver->in_busy_2 = 0;
1260 driver->in_busy_qdsp_1 = 0;
1261 driver->in_busy_qdsp_2 = 0;
Ashay Jaiswal29620122012-03-21 12:02:36 +05301262 driver->in_busy_wcnss_1 = 0;
1263 driver->in_busy_wcnss_2 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264
1265 /* Poll SMD channels to check for data*/
1266 queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
1267 queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
1268 queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_work));
Shalabh Jaincf5f20e2011-08-22 12:29:52 -07001269 /* Poll SMD CNTL channels to check for data */
Shalabh Jain4e1bd312012-02-16 19:33:05 -08001270 diag_smd_cntl_notify(NULL, SMD_EVENT_DATA);
1271 diag_smd_qdsp_cntl_notify(NULL, SMD_EVENT_DATA);
1272 diag_smd_wcnss_cntl_notify(NULL, SMD_EVENT_DATA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273 /* Poll USB channel to check for data*/
1274 queue_work(driver->diag_wq, &(driver->diag_read_work));
1275#ifdef CONFIG_DIAG_SDIO_PIPE
1276 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
1277 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1278 diagfwd_connect_sdio();
1279 else
1280 printk(KERN_INFO "diag: No USB MDM ch");
1281 }
1282#endif
1283 return 0;
1284}
1285
1286int diagfwd_disconnect(void)
1287{
1288 printk(KERN_DEBUG "diag: USB disconnected\n");
1289 driver->usb_connected = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001290 driver->debug_flag = 1;
1291 usb_diag_free_req(driver->legacy_ch);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001292 if (driver->logging_mode == USB_MODE) {
1293 driver->in_busy_1 = 1;
1294 driver->in_busy_2 = 1;
1295 driver->in_busy_qdsp_1 = 1;
1296 driver->in_busy_qdsp_2 = 1;
Ashay Jaiswal29620122012-03-21 12:02:36 +05301297 driver->in_busy_wcnss_1 = 1;
1298 driver->in_busy_wcnss_2 = 1;
Shalabh Jain69890aa2011-10-10 12:59:16 -07001299 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300#ifdef CONFIG_DIAG_SDIO_PIPE
1301 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
1302 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1303 diagfwd_disconnect_sdio();
1304#endif
1305 /* TBD - notify and flow control SMD */
1306 return 0;
1307}
1308
1309int diagfwd_write_complete(struct diag_request *diag_write_ptr)
1310{
1311 unsigned char *buf = diag_write_ptr->buf;
1312 /*Determine if the write complete is for data from modem/apps/q6 */
1313 /* Need a context variable here instead */
1314 if (buf == (void *)driver->buf_in_1) {
1315 driver->in_busy_1 = 0;
1316 APPEND_DEBUG('o');
1317 queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
1318 } else if (buf == (void *)driver->buf_in_2) {
1319 driver->in_busy_2 = 0;
1320 APPEND_DEBUG('O');
1321 queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
1322 } else if (buf == (void *)driver->buf_in_qdsp_1) {
1323 driver->in_busy_qdsp_1 = 0;
1324 APPEND_DEBUG('p');
1325 queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
1326 } else if (buf == (void *)driver->buf_in_qdsp_2) {
1327 driver->in_busy_qdsp_2 = 0;
1328 APPEND_DEBUG('P');
1329 queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
Ashay Jaiswal29620122012-03-21 12:02:36 +05301330 } else if (buf == driver->buf_in_wcnss_1) {
1331 driver->in_busy_wcnss_1 = 0;
1332 APPEND_DEBUG('r');
1333 queue_work(driver->diag_wq,
1334 &(driver->diag_read_smd_wcnss_work));
1335 } else if (buf == driver->buf_in_wcnss_2) {
1336 driver->in_busy_wcnss_2 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001337 APPEND_DEBUG('R');
1338 queue_work(driver->diag_wq,
1339 &(driver->diag_read_smd_wcnss_work));
1340 }
1341#ifdef CONFIG_DIAG_SDIO_PIPE
1342 else if (buf == (void *)driver->buf_in_sdio)
1343 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -08001344 machine_is_msm8x60_fusn_ffa())
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001345 diagfwd_write_complete_sdio();
1346 else
1347 pr_err("diag: Incorrect buffer pointer while WRITE");
1348#endif
1349 else {
1350 diagmem_free(driver, (unsigned char *)buf, POOL_TYPE_HDLC);
1351 diagmem_free(driver, (unsigned char *)diag_write_ptr,
1352 POOL_TYPE_WRITE_STRUCT);
1353 APPEND_DEBUG('q');
1354 }
1355 return 0;
1356}
1357
1358int diagfwd_read_complete(struct diag_request *diag_read_ptr)
1359{
1360 int status = diag_read_ptr->status;
1361 unsigned char *buf = diag_read_ptr->buf;
1362
1363 /* Determine if the read complete is for data on legacy/mdm ch */
1364 if (buf == (void *)driver->usb_buf_out) {
1365 driver->read_len_legacy = diag_read_ptr->actual;
1366 APPEND_DEBUG('s');
1367#ifdef DIAG_DEBUG
1368 printk(KERN_INFO "read data from USB, pkt length %d",
1369 diag_read_ptr->actual);
1370 print_hex_dump(KERN_DEBUG, "Read Packet Data from USB: ", 16, 1,
1371 DUMP_PREFIX_ADDRESS, diag_read_ptr->buf,
1372 diag_read_ptr->actual, 1);
1373#endif /* DIAG DEBUG */
1374 if (driver->logging_mode == USB_MODE) {
1375 if (status != -ECONNRESET && status != -ESHUTDOWN)
1376 queue_work(driver->diag_wq,
1377 &(driver->diag_proc_hdlc_work));
1378 else
1379 queue_work(driver->diag_wq,
1380 &(driver->diag_read_work));
1381 }
1382 }
1383#ifdef CONFIG_DIAG_SDIO_PIPE
1384 else if (buf == (void *)driver->usb_buf_mdm_out) {
1385 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -08001386 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001387 driver->read_len_mdm = diag_read_ptr->actual;
1388 diagfwd_read_complete_sdio();
1389 } else
1390 pr_err("diag: Incorrect buffer pointer while READ");
1391 }
1392#endif
1393 else
1394 printk(KERN_ERR "diag: Unknown buffer ptr from USB");
1395
1396 return 0;
1397}
1398
1399void diag_read_work_fn(struct work_struct *work)
1400{
1401 APPEND_DEBUG('d');
1402 driver->usb_read_ptr->buf = driver->usb_buf_out;
1403 driver->usb_read_ptr->length = USB_MAX_OUT_BUF;
1404 usb_diag_read(driver->legacy_ch, driver->usb_read_ptr);
1405 APPEND_DEBUG('e');
1406}
1407
1408void diag_process_hdlc_fn(struct work_struct *work)
1409{
1410 APPEND_DEBUG('D');
1411 diag_process_hdlc(driver->usb_buf_out, driver->read_len_legacy);
1412 diag_read_work_fn(work);
1413 APPEND_DEBUG('E');
1414}
1415
1416void diag_usb_legacy_notifier(void *priv, unsigned event,
1417 struct diag_request *d_req)
1418{
1419 switch (event) {
1420 case USB_DIAG_CONNECT:
1421 diagfwd_connect();
1422 break;
1423 case USB_DIAG_DISCONNECT:
1424 diagfwd_disconnect();
1425 break;
1426 case USB_DIAG_READ_DONE:
1427 diagfwd_read_complete(d_req);
1428 break;
1429 case USB_DIAG_WRITE_DONE:
1430 diagfwd_write_complete(d_req);
1431 break;
1432 default:
1433 printk(KERN_ERR "Unknown event from USB diag\n");
1434 break;
1435 }
1436}
1437
1438#endif /* DIAG OVER USB */
1439
1440static void diag_smd_notify(void *ctxt, unsigned event)
1441{
Shalabh Jainc2ec8292011-10-14 12:34:55 -07001442 if (event == SMD_EVENT_CLOSE) {
1443 pr_info("diag: clean modem registration\n");
1444 diag_clear_reg(MODEM_PROC);
Shalabh Jaineefee052011-11-08 23:46:03 -08001445 driver->ch = 0;
1446 return;
1447 } else if (event == SMD_EVENT_OPEN) {
1448 driver->ch = ch_temp;
1449 }
1450 queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451}
1452
1453#if defined(CONFIG_MSM_N_WAY_SMD)
1454static void diag_smd_qdsp_notify(void *ctxt, unsigned event)
1455{
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001456 if (event == SMD_EVENT_CLOSE) {
1457 pr_info("diag: clean lpass registration\n");
1458 diag_clear_reg(QDSP_PROC);
1459 driver->chqdsp = 0;
1460 return;
1461 } else if (event == SMD_EVENT_OPEN) {
1462 driver->chqdsp = chqdsp_temp;
1463 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001464 queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
1465}
1466#endif
1467
1468static void diag_smd_wcnss_notify(void *ctxt, unsigned event)
1469{
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001470 if (event == SMD_EVENT_CLOSE) {
1471 pr_info("diag: clean wcnss registration\n");
1472 diag_clear_reg(WCNSS_PROC);
1473 driver->ch_wcnss = 0;
1474 return;
1475 } else if (event == SMD_EVENT_OPEN) {
1476 driver->ch_wcnss = ch_wcnss_temp;
1477 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478 queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_work));
1479}
1480
1481static int diag_smd_probe(struct platform_device *pdev)
1482{
1483 int r = 0;
1484
Shalabh Jaineefee052011-11-08 23:46:03 -08001485 if (pdev->id == SMD_APPS_MODEM) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486 r = smd_open("DIAG", &driver->ch, driver, diag_smd_notify);
Shalabh Jaineefee052011-11-08 23:46:03 -08001487 ch_temp = driver->ch;
1488 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001489#if defined(CONFIG_MSM_N_WAY_SMD)
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001490 if (pdev->id == SMD_APPS_QDSP) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP
1492 , &driver->chqdsp, driver, diag_smd_qdsp_notify);
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001493 chqdsp_temp = driver->chqdsp;
1494 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001495#endif
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001496 if (pdev->id == SMD_APPS_WCNSS) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497 r = smd_named_open_on_edge("APPS_RIVA_DATA", SMD_APPS_WCNSS
1498 , &driver->ch_wcnss, driver, diag_smd_wcnss_notify);
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001499 ch_wcnss_temp = driver->ch_wcnss;
1500 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001501 pm_runtime_set_active(&pdev->dev);
1502 pm_runtime_enable(&pdev->dev);
1503 pr_debug("diag: open SMD port, Id = %d, r = %d\n", pdev->id, r);
1504
1505 return 0;
1506}
1507
1508static int diagfwd_runtime_suspend(struct device *dev)
1509{
1510 dev_dbg(dev, "pm_runtime: suspending...\n");
1511 return 0;
1512}
1513
1514static int diagfwd_runtime_resume(struct device *dev)
1515{
1516 dev_dbg(dev, "pm_runtime: resuming...\n");
1517 return 0;
1518}
1519
1520static const struct dev_pm_ops diagfwd_dev_pm_ops = {
1521 .runtime_suspend = diagfwd_runtime_suspend,
1522 .runtime_resume = diagfwd_runtime_resume,
1523};
1524
1525static struct platform_driver msm_smd_ch1_driver = {
1526
1527 .probe = diag_smd_probe,
1528 .driver = {
1529 .name = "DIAG",
1530 .owner = THIS_MODULE,
1531 .pm = &diagfwd_dev_pm_ops,
1532 },
1533};
1534
1535static struct platform_driver diag_smd_lite_driver = {
1536
1537 .probe = diag_smd_probe,
1538 .driver = {
1539 .name = "APPS_RIVA_DATA",
1540 .owner = THIS_MODULE,
1541 .pm = &diagfwd_dev_pm_ops,
1542 },
1543};
1544
1545void diagfwd_init(void)
1546{
1547 diag_debug_buf_idx = 0;
1548 driver->read_len_legacy = 0;
Dixon Petersonb4618a42012-02-29 18:56:31 -08001549 driver->use_device_tree = has_device_tree();
Shalabh Jain321c8b52012-02-22 12:37:06 -08001550
1551 if (driver->event_mask == NULL) {
1552 driver->event_mask = kzalloc(sizeof(
1553 struct diag_ctrl_event_mask), GFP_KERNEL);
1554 if (driver->event_mask == NULL)
1555 goto err;
1556 }
1557 if (driver->msg_mask == NULL) {
1558 driver->msg_mask = kzalloc(sizeof(
1559 struct diag_ctrl_msg_mask), GFP_KERNEL);
1560 if (driver->msg_mask == NULL)
1561 goto err;
1562 }
1563 if (driver->log_mask == NULL) {
1564 driver->log_mask = kzalloc(sizeof(
1565 struct diag_ctrl_log_mask), GFP_KERNEL);
1566 if (driver->log_mask == NULL)
1567 goto err;
1568 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 if (driver->buf_in_1 == NULL) {
1570 driver->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1571 if (driver->buf_in_1 == NULL)
1572 goto err;
1573 }
1574 if (driver->buf_in_2 == NULL) {
1575 driver->buf_in_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1576 if (driver->buf_in_2 == NULL)
1577 goto err;
1578 }
1579 if (driver->buf_in_qdsp_1 == NULL) {
1580 driver->buf_in_qdsp_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1581 if (driver->buf_in_qdsp_1 == NULL)
1582 goto err;
1583 }
1584 if (driver->buf_in_qdsp_2 == NULL) {
1585 driver->buf_in_qdsp_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1586 if (driver->buf_in_qdsp_2 == NULL)
1587 goto err;
1588 }
Ashay Jaiswal29620122012-03-21 12:02:36 +05301589 if (driver->buf_in_wcnss_1 == NULL) {
1590 driver->buf_in_wcnss_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1591 if (driver->buf_in_wcnss_1 == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001592 goto err;
1593 }
Ashay Jaiswal29620122012-03-21 12:02:36 +05301594 if (driver->buf_in_wcnss_2 == NULL) {
1595 driver->buf_in_wcnss_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1596 if (driver->buf_in_wcnss_2 == NULL)
1597 goto err;
1598 }
1599
Shalabh Jain321c8b52012-02-22 12:37:06 -08001600 if (driver->buf_msg_mask_update == NULL) {
1601 driver->buf_msg_mask_update = kzalloc(APPS_BUF_SIZE,
1602 GFP_KERNEL);
1603 if (driver->buf_msg_mask_update == NULL)
1604 goto err;
1605 }
1606 if (driver->buf_log_mask_update == NULL) {
1607 driver->buf_log_mask_update = kzalloc(APPS_BUF_SIZE,
1608 GFP_KERNEL);
1609 if (driver->buf_log_mask_update == NULL)
1610 goto err;
1611 }
1612 if (driver->buf_event_mask_update == NULL) {
1613 driver->buf_event_mask_update = kzalloc(APPS_BUF_SIZE,
1614 GFP_KERNEL);
1615 if (driver->buf_event_mask_update == NULL)
1616 goto err;
1617 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001618 if (driver->usb_buf_out == NULL &&
1619 (driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
1620 GFP_KERNEL)) == NULL)
1621 goto err;
1622 if (driver->hdlc_buf == NULL
1623 && (driver->hdlc_buf = kzalloc(HDLC_MAX, GFP_KERNEL)) == NULL)
1624 goto err;
Shalabh Jain69890aa2011-10-10 12:59:16 -07001625 if (driver->user_space_data == NULL)
1626 driver->user_space_data = kzalloc(USER_SPACE_DATA, GFP_KERNEL);
1627 if (driver->user_space_data == NULL)
1628 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001629 if (driver->msg_masks == NULL
1630 && (driver->msg_masks = kzalloc(MSG_MASK_SIZE,
1631 GFP_KERNEL)) == NULL)
1632 goto err;
1633 if (driver->log_masks == NULL &&
1634 (driver->log_masks = kzalloc(LOG_MASK_SIZE, GFP_KERNEL)) == NULL)
1635 goto err;
Shalabh Jainfbf3bdc2012-03-16 21:02:50 -07001636 driver->log_masks_length = (sizeof(struct mask_info))*MAX_EQUIP_ID;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001637 if (driver->event_masks == NULL &&
1638 (driver->event_masks = kzalloc(EVENT_MASK_SIZE,
1639 GFP_KERNEL)) == NULL)
1640 goto err;
1641 if (driver->client_map == NULL &&
1642 (driver->client_map = kzalloc
1643 ((driver->num_clients) * sizeof(struct diag_client_map),
1644 GFP_KERNEL)) == NULL)
1645 goto err;
1646 if (driver->buf_tbl == NULL)
1647 driver->buf_tbl = kzalloc(buf_tbl_size *
1648 sizeof(struct diag_write_device), GFP_KERNEL);
1649 if (driver->buf_tbl == NULL)
1650 goto err;
1651 if (driver->data_ready == NULL &&
1652 (driver->data_ready = kzalloc(driver->num_clients * sizeof(int)
1653 , GFP_KERNEL)) == NULL)
1654 goto err;
1655 if (driver->table == NULL &&
Shalabh Jainfe02b0c2012-02-21 14:48:03 -08001656 (driver->table = kzalloc(diag_max_reg*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001657 sizeof(struct diag_master_table),
1658 GFP_KERNEL)) == NULL)
1659 goto err;
1660 if (driver->write_ptr_1 == NULL) {
1661 driver->write_ptr_1 = kzalloc(
1662 sizeof(struct diag_request), GFP_KERNEL);
1663 if (driver->write_ptr_1 == NULL)
1664 goto err;
1665 }
1666 if (driver->write_ptr_2 == NULL) {
1667 driver->write_ptr_2 = kzalloc(
1668 sizeof(struct diag_request), GFP_KERNEL);
1669 if (driver->write_ptr_2 == NULL)
1670 goto err;
1671 }
1672 if (driver->write_ptr_qdsp_1 == NULL) {
1673 driver->write_ptr_qdsp_1 = kzalloc(
1674 sizeof(struct diag_request), GFP_KERNEL);
1675 if (driver->write_ptr_qdsp_1 == NULL)
1676 goto err;
1677 }
1678 if (driver->write_ptr_qdsp_2 == NULL) {
1679 driver->write_ptr_qdsp_2 = kzalloc(
1680 sizeof(struct diag_request), GFP_KERNEL);
1681 if (driver->write_ptr_qdsp_2 == NULL)
1682 goto err;
1683 }
Ashay Jaiswal29620122012-03-21 12:02:36 +05301684 if (driver->write_ptr_wcnss_1 == NULL) {
1685 driver->write_ptr_wcnss_1 = kzalloc(
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001686 sizeof(struct diag_request), GFP_KERNEL);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301687 if (driver->write_ptr_wcnss_1 == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001688 goto err;
1689 }
Ashay Jaiswal29620122012-03-21 12:02:36 +05301690 if (driver->write_ptr_wcnss_2 == NULL) {
1691 driver->write_ptr_wcnss_2 = kzalloc(
1692 sizeof(struct diag_request), GFP_KERNEL);
1693 if (driver->write_ptr_wcnss_2 == NULL)
1694 goto err;
1695 }
1696
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001697 if (driver->usb_read_ptr == NULL) {
1698 driver->usb_read_ptr = kzalloc(
1699 sizeof(struct diag_request), GFP_KERNEL);
1700 if (driver->usb_read_ptr == NULL)
1701 goto err;
1702 }
1703 if (driver->pkt_buf == NULL &&
1704 (driver->pkt_buf = kzalloc(PKT_SIZE,
1705 GFP_KERNEL)) == NULL)
1706 goto err;
1707 if (driver->apps_rsp_buf == NULL) {
Shalabh Jain321c8b52012-02-22 12:37:06 -08001708 driver->apps_rsp_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001709 if (driver->apps_rsp_buf == NULL)
1710 goto err;
1711 }
1712 driver->diag_wq = create_singlethread_workqueue("diag_wq");
1713#ifdef CONFIG_DIAG_OVER_USB
1714 INIT_WORK(&(driver->diag_proc_hdlc_work), diag_process_hdlc_fn);
1715 INIT_WORK(&(driver->diag_read_work), diag_read_work_fn);
Shalabh Jain321c8b52012-02-22 12:37:06 -08001716 INIT_WORK(&(driver->diag_msg_mask_update_work),
1717 diag_msg_mask_update_fn);
1718 INIT_WORK(&(driver->diag_log_mask_update_work),
1719 diag_log_mask_update_fn);
1720 INIT_WORK(&(driver->diag_modem_mask_update_work),
1721 diag_modem_mask_update_fn);
1722 INIT_WORK(&(driver->diag_qdsp_mask_update_work),
1723 diag_qdsp_mask_update_fn);
1724 INIT_WORK(&(driver->diag_wcnss_mask_update_work),
1725 diag_wcnss_mask_update_fn);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001726 driver->legacy_ch = usb_diag_open(DIAG_LEGACY, driver,
1727 diag_usb_legacy_notifier);
1728 if (IS_ERR(driver->legacy_ch)) {
1729 printk(KERN_ERR "Unable to open USB diag legacy channel\n");
1730 goto err;
1731 }
1732#endif
1733 platform_driver_register(&msm_smd_ch1_driver);
1734 platform_driver_register(&diag_smd_lite_driver);
1735
1736 return;
1737err:
1738 pr_err("diag: Could not initialize diag buffers");
Shalabh Jain321c8b52012-02-22 12:37:06 -08001739 kfree(driver->event_mask);
1740 kfree(driver->log_mask);
1741 kfree(driver->msg_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001742 kfree(driver->buf_in_1);
1743 kfree(driver->buf_in_2);
1744 kfree(driver->buf_in_qdsp_1);
1745 kfree(driver->buf_in_qdsp_2);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301746 kfree(driver->buf_in_wcnss_1);
1747 kfree(driver->buf_in_wcnss_2);
Shalabh Jain321c8b52012-02-22 12:37:06 -08001748 kfree(driver->buf_msg_mask_update);
1749 kfree(driver->buf_log_mask_update);
1750 kfree(driver->buf_event_mask_update);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001751 kfree(driver->usb_buf_out);
1752 kfree(driver->hdlc_buf);
1753 kfree(driver->msg_masks);
1754 kfree(driver->log_masks);
1755 kfree(driver->event_masks);
1756 kfree(driver->client_map);
1757 kfree(driver->buf_tbl);
1758 kfree(driver->data_ready);
1759 kfree(driver->table);
1760 kfree(driver->pkt_buf);
1761 kfree(driver->write_ptr_1);
1762 kfree(driver->write_ptr_2);
1763 kfree(driver->write_ptr_qdsp_1);
1764 kfree(driver->write_ptr_qdsp_2);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301765 kfree(driver->write_ptr_wcnss_1);
1766 kfree(driver->write_ptr_wcnss_2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001767 kfree(driver->usb_read_ptr);
1768 kfree(driver->apps_rsp_buf);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001769 kfree(driver->user_space_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001770 if (driver->diag_wq)
1771 destroy_workqueue(driver->diag_wq);
1772}
1773
1774void diagfwd_exit(void)
1775{
1776 smd_close(driver->ch);
1777 smd_close(driver->chqdsp);
1778 smd_close(driver->ch_wcnss);
1779 driver->ch = 0; /* SMD can make this NULL */
1780 driver->chqdsp = 0;
1781 driver->ch_wcnss = 0;
1782#ifdef CONFIG_DIAG_OVER_USB
1783 if (driver->usb_connected)
1784 usb_diag_free_req(driver->legacy_ch);
1785 usb_diag_close(driver->legacy_ch);
1786#endif
1787 platform_driver_unregister(&msm_smd_ch1_driver);
1788 platform_driver_unregister(&diag_smd_lite_driver);
Shalabh Jain321c8b52012-02-22 12:37:06 -08001789 kfree(driver->event_mask);
1790 kfree(driver->log_mask);
1791 kfree(driver->msg_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001792 kfree(driver->buf_in_1);
1793 kfree(driver->buf_in_2);
1794 kfree(driver->buf_in_qdsp_1);
1795 kfree(driver->buf_in_qdsp_2);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301796 kfree(driver->buf_in_wcnss_1);
1797 kfree(driver->buf_in_wcnss_2);
Shalabh Jain321c8b52012-02-22 12:37:06 -08001798 kfree(driver->buf_msg_mask_update);
1799 kfree(driver->buf_log_mask_update);
1800 kfree(driver->buf_event_mask_update);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001801 kfree(driver->usb_buf_out);
1802 kfree(driver->hdlc_buf);
1803 kfree(driver->msg_masks);
1804 kfree(driver->log_masks);
1805 kfree(driver->event_masks);
1806 kfree(driver->client_map);
1807 kfree(driver->buf_tbl);
1808 kfree(driver->data_ready);
1809 kfree(driver->table);
1810 kfree(driver->pkt_buf);
1811 kfree(driver->write_ptr_1);
1812 kfree(driver->write_ptr_2);
1813 kfree(driver->write_ptr_qdsp_1);
1814 kfree(driver->write_ptr_qdsp_2);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301815 kfree(driver->write_ptr_wcnss_1);
1816 kfree(driver->write_ptr_wcnss_2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001817 kfree(driver->usb_read_ptr);
1818 kfree(driver->apps_rsp_buf);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001819 kfree(driver->user_space_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001820 destroy_workqueue(driver->diag_wq);
1821}