blob: b27ab54137cdfc1782f66f2b26dd008a8481b1d3 [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>
Dixon Peterson6beff2d2012-09-13 18:51:47 -070019#include <linux/ratelimit.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070020#include <linux/workqueue.h>
21#include <linux/pm_runtime.h>
22#include <linux/diagchar.h>
23#include <linux/delay.h>
24#include <linux/reboot.h>
Dixon Petersonb4618a42012-02-29 18:56:31 -080025#include <linux/of.h>
Dixon Petersoncc0bea772012-04-11 20:45:37 -070026#include <linux/kmemleak.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027#ifdef CONFIG_DIAG_OVER_USB
28#include <mach/usbdiag.h>
29#endif
30#include <mach/msm_smd.h>
31#include <mach/socinfo.h>
32#include <mach/restart.h>
33#include "diagmem.h"
34#include "diagchar.h"
35#include "diagfwd.h"
36#include "diagfwd_cntl.h"
37#include "diagchar_hdlc.h"
38#ifdef CONFIG_DIAG_SDIO_PIPE
39#include "diagfwd_sdio.h"
40#endif
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070041#include "diag_dci.h"
Dixon Petersond6a20a92012-09-27 15:58:50 -070042#include "diag_masks.h"
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070043
Shalabh Jain6a2ca7c2012-04-10 14:35:15 -070044#define MODE_CMD 41
45#define RESET_ID 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046
47int diag_debug_buf_idx;
48unsigned char diag_debug_buf[1024];
49static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
50struct diag_master_table entry;
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -070051smd_channel_t *ch_temp = NULL, *chlpass_temp = NULL, *ch_wcnss_temp = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
53struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
Shalabh Jain6a2ca7c2012-04-10 14:35:15 -070054
Dixon Petersond6a20a92012-09-27 15:58:50 -070055void encode_rsp_and_send(int buf_length)
56{
57 send.state = DIAG_STATE_START;
58 send.pkt = driver->apps_rsp_buf;
59 send.last = (void *)(driver->apps_rsp_buf + buf_length);
60 send.terminate = 1;
61 if (!driver->in_busy_1) {
62 enc.dest = driver->buf_in_1;
63 enc.dest_last = (void *)(driver->buf_in_1 + APPS_BUF_SIZE - 1);
64 diag_hdlc_encode(&send, &enc);
65 driver->write_ptr_1->buf = driver->buf_in_1;
66 driver->write_ptr_1->length = (int)(enc.dest -
67 (void *)(driver->buf_in_1));
68 driver->in_busy_1 = 1;
69 diag_device_write(driver->buf_in_1, MODEM_DATA,
70 driver->write_ptr_1);
71 memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);
72 }
73}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070074
Dixon Petersonb4618a42012-02-29 18:56:31 -080075/* Determine if this device uses a device tree */
76#ifdef CONFIG_OF
77static int has_device_tree(void)
78{
79 struct device_node *node;
80
81 node = of_find_node_by_path("/");
82 if (node) {
83 of_node_put(node);
84 return 1;
85 }
86 return 0;
87}
88#else
89static int has_device_tree(void)
90{
91 return 0;
92}
93#endif
94
Shalabh Jainfb8e3c12011-10-19 17:29:42 -070095int chk_config_get_id(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070096{
Shalabh Jain482bf122011-12-06 03:54:47 -080097 /* For all Fusion targets, Modem will always be present */
98 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
99 return 0;
100
Dixon Petersonb4618a42012-02-29 18:56:31 -0800101 if (driver->use_device_tree) {
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700102 if (machine_is_msm8974())
Dixon Petersonb4618a42012-02-29 18:56:31 -0800103 return MSM8974_TOOLS_ID;
104 else
105 return 0;
106 } else {
107 switch (socinfo_get_msm_cpu()) {
108 case MSM_CPU_8X60:
109 return APQ8060_TOOLS_ID;
110 case MSM_CPU_8960:
Stepan Moskovchenko9c749262012-07-09 19:30:44 -0700111 case MSM_CPU_8960AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800112 return AO8960_TOOLS_ID;
113 case MSM_CPU_8064:
Jay Chokshi11abd8b2012-09-20 14:35:17 -0700114 case MSM_CPU_8064AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800115 return APQ8064_TOOLS_ID;
116 case MSM_CPU_8930:
Stepan Moskovchenko0df9bb22012-07-06 18:19:15 -0700117 case MSM_CPU_8930AA:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800118 return MSM8930_TOOLS_ID;
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700119 case MSM_CPU_8974:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800120 return MSM8974_TOOLS_ID;
121 case MSM_CPU_8625:
122 return MSM8625_TOOLS_ID;
123 default:
124 return 0;
125 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700126 }
127}
128
129/*
Shalabh Jain321c8b52012-02-22 12:37:06 -0800130 * This will return TRUE for targets which support apps only mode and hence SSR.
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700131 * This applies to 8960 and newer targets.
132 */
133int chk_apps_only(void)
134{
Dixon Petersonb4618a42012-02-29 18:56:31 -0800135 if (driver->use_device_tree)
136 return 1;
137
138 switch (socinfo_get_msm_cpu()) {
139 case MSM_CPU_8960:
Stepan Moskovchenko9c749262012-07-09 19:30:44 -0700140 case MSM_CPU_8960AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800141 case MSM_CPU_8064:
Jay Chokshi11abd8b2012-09-20 14:35:17 -0700142 case MSM_CPU_8064AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800143 case MSM_CPU_8930:
Stepan Moskovchenko0df9bb22012-07-06 18:19:15 -0700144 case MSM_CPU_8930AA:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800145 case MSM_CPU_8627:
146 case MSM_CPU_9615:
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700147 case MSM_CPU_8974:
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700148 return 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149 default:
150 return 0;
151 }
152}
153
Shalabh Jain10f5f432012-01-11 11:45:44 +0530154/*
155 * This will return TRUE for targets which support apps as master.
156 * Thus, SW DLOAD and Mode Reset are supported on apps processor.
157 * This applies to 8960 and newer targets.
158 */
159int chk_apps_master(void)
160{
Dixon Petersonb4618a42012-02-29 18:56:31 -0800161 if (driver->use_device_tree)
162 return 1;
Stepan Moskovchenko0df9bb22012-07-06 18:19:15 -0700163 else if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
Stepan Moskovchenko9c749262012-07-09 19:30:44 -0700164 cpu_is_msm9615() || cpu_is_apq8064() || cpu_is_msm8627() ||
Jay Chokshi11abd8b2012-09-20 14:35:17 -0700165 cpu_is_msm8960ab() || cpu_is_apq8064ab())
Dixon Petersonb4618a42012-02-29 18:56:31 -0800166 return 1;
167 else
168 return 0;
169}
170
Dixon Peterson29aebee2012-04-06 12:44:08 -0700171int chk_polling_response(void)
Dixon Petersonb4618a42012-02-29 18:56:31 -0800172{
173 if (!(driver->polling_reg_flag) && chk_apps_master())
174 /*
175 * If the apps processor is master and no other processor
176 * has registered to respond for polling
177 */
178 return 1;
179 else if (!(driver->ch) && !(chk_apps_master()))
180 /*
181 * If the apps processor is not the master and the modem
182 * is not up
183 */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530184 return 1;
185 else
186 return 0;
187}
188
Dixon Peterson743a11e2012-07-30 17:42:20 -0700189/*
190 * This function should be called if you feel that the logging process may
191 * need to be woken up. For instance, if the logging mode is MEMORY_DEVICE MODE
192 * and while trying to read data from a SMD data channel there are no buffers
193 * available to read the data into, then this function should be called to
194 * determine if the logging process needs to be woken up.
195 */
196void chk_logging_wakeup(void)
197{
198 int i;
199
200 /* Find the index of the logging process */
201 for (i = 0; i < driver->num_clients; i++)
202 if (driver->client_map[i].pid ==
203 driver->logging_process_id)
204 break;
205
206 if (i < driver->num_clients) {
207 /* At very high logging rates a race condition can
208 * occur where the buffers containing the data from
209 * an smd channel are all in use, but the data_ready
210 * flag is cleared. In this case, the buffers never
211 * have their data read/logged. Detect and remedy this
212 * situation.
213 */
Shalabh Jain84e30342012-10-16 16:16:08 -0700214 if ((driver->data_ready[i] & USER_SPACE_DATA_TYPE) == 0) {
215 driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
Dixon Peterson743a11e2012-07-30 17:42:20 -0700216 pr_debug("diag: Force wakeup of logging process\n");
217 wake_up_interruptible(&driver->wait_q);
218 }
219 }
220}
221
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700222void __diag_smd_send_req(void)
223{
224 void *buf = NULL;
225 int *in_busy_ptr = NULL;
226 struct diag_request *write_ptr_modem = NULL;
227
228 if (!driver->in_busy_1) {
229 buf = driver->buf_in_1;
230 write_ptr_modem = driver->write_ptr_1;
231 in_busy_ptr = &(driver->in_busy_1);
232 } else if (!driver->in_busy_2) {
233 buf = driver->buf_in_2;
234 write_ptr_modem = driver->write_ptr_2;
235 in_busy_ptr = &(driver->in_busy_2);
236 }
237
238 if (driver->ch && buf) {
239 int r = smd_read_avail(driver->ch);
240
241 if (r > IN_BUF_SIZE) {
242 if (r < MAX_IN_BUF_SIZE) {
243 pr_err("diag: SMD sending in "
244 "packets upto %d bytes", r);
245 buf = krealloc(buf, r, GFP_KERNEL);
246 } else {
247 pr_err("diag: SMD sending in "
248 "packets more than %d bytes", MAX_IN_BUF_SIZE);
249 return;
250 }
251 }
252 if (r > 0) {
253 if (!buf)
254 pr_info("Out of diagmem for Modem\n");
255 else {
256 APPEND_DEBUG('i');
257 smd_read(driver->ch, buf, r);
258 APPEND_DEBUG('j');
259 write_ptr_modem->length = r;
260 *in_busy_ptr = 1;
261 diag_device_write(buf, MODEM_DATA,
262 write_ptr_modem);
263 }
264 }
Dixon Peterson743a11e2012-07-30 17:42:20 -0700265 } else if (driver->ch && !buf &&
266 (driver->logging_mode == MEMORY_DEVICE_MODE)) {
267 chk_logging_wakeup();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 }
269}
270
271int diag_device_write(void *buf, int proc_num, struct diag_request *write_ptr)
272{
273 int i, err = 0;
274
275 if (driver->logging_mode == MEMORY_DEVICE_MODE) {
276 if (proc_num == APPS_DATA) {
277 for (i = 0; i < driver->poolsize_write_struct; i++)
278 if (driver->buf_tbl[i].length == 0) {
279 driver->buf_tbl[i].buf = buf;
280 driver->buf_tbl[i].length =
281 driver->used;
282#ifdef DIAG_DEBUG
283 pr_debug("diag: ENQUEUE buf ptr"
284 " and length is %x , %d\n",
285 (unsigned int)(driver->buf_
286 tbl[i].buf), driver->buf_tbl[i].length);
287#endif
288 break;
289 }
290 }
Dixon Peterson938f8602012-08-17 20:02:57 -0700291
292#ifdef CONFIG_DIAG_BRIDGE_CODE
293 else if (proc_num == HSIC_DATA) {
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700294 unsigned long flags;
295 int foundIndex = -1;
296
297 spin_lock_irqsave(&driver->hsic_spinlock, flags);
Dixon Peterson938f8602012-08-17 20:02:57 -0700298 for (i = 0; i < driver->poolsize_hsic_write; i++) {
299 if (driver->hsic_buf_tbl[i].length == 0) {
300 driver->hsic_buf_tbl[i].buf = buf;
301 driver->hsic_buf_tbl[i].length =
302 driver->write_len_mdm;
303 driver->num_hsic_buf_tbl_entries++;
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700304 foundIndex = i;
Dixon Peterson938f8602012-08-17 20:02:57 -0700305 break;
306 }
307 }
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700308 spin_unlock_irqrestore(&driver->hsic_spinlock, flags);
309 if (foundIndex == -1)
310 err = -1;
311 else
312 pr_debug("diag: ENQUEUE HSIC buf ptr and length is %x , %d\n",
313 (unsigned int)buf,
314 driver->write_len_mdm);
Dixon Peterson938f8602012-08-17 20:02:57 -0700315 }
316#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317 for (i = 0; i < driver->num_clients; i++)
318 if (driver->client_map[i].pid ==
319 driver->logging_process_id)
320 break;
321 if (i < driver->num_clients) {
Shalabh Jain84e30342012-10-16 16:16:08 -0700322 driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700323 pr_debug("diag: wake up logging process\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324 wake_up_interruptible(&driver->wait_q);
325 } else
326 return -EINVAL;
327 } else if (driver->logging_mode == NO_LOGGING_MODE) {
328 if (proc_num == MODEM_DATA) {
329 driver->in_busy_1 = 0;
330 driver->in_busy_2 = 0;
331 queue_work(driver->diag_wq, &(driver->
332 diag_read_smd_work));
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -0700333 } else if (proc_num == LPASS_DATA) {
334 driver->in_busy_lpass_1 = 0;
335 driver->in_busy_lpass_2 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700336 queue_work(driver->diag_wq, &(driver->
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -0700337 diag_read_smd_lpass_work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700338 } else if (proc_num == WCNSS_DATA) {
Ashay Jaiswal29620122012-03-21 12:02:36 +0530339 driver->in_busy_wcnss_1 = 0;
340 driver->in_busy_wcnss_2 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341 queue_work(driver->diag_wq, &(driver->
342 diag_read_smd_wcnss_work));
343 }
Shalabh Jain482bf122011-12-06 03:54:47 -0800344#ifdef CONFIG_DIAG_SDIO_PIPE
345 else if (proc_num == SDIO_DATA) {
346 driver->in_busy_sdio = 0;
347 queue_work(driver->diag_sdio_wq,
348 &(driver->diag_read_sdio_work));
349 }
350#endif
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700351#ifdef CONFIG_DIAG_BRIDGE_CODE
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700352 else if (proc_num == HSIC_DATA) {
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700353 if (driver->hsic_ch)
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700354 queue_work(driver->diag_bridge_wq,
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700355 &(driver->diag_read_hsic_work));
356 }
357#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700358 err = -1;
359 }
360#ifdef CONFIG_DIAG_OVER_USB
361 else if (driver->logging_mode == USB_MODE) {
362 if (proc_num == APPS_DATA) {
363 driver->write_ptr_svc = (struct diag_request *)
364 (diagmem_alloc(driver, sizeof(struct diag_request),
365 POOL_TYPE_WRITE_STRUCT));
366 if (driver->write_ptr_svc) {
367 driver->write_ptr_svc->length = driver->used;
368 driver->write_ptr_svc->buf = buf;
369 err = usb_diag_write(driver->legacy_ch,
370 driver->write_ptr_svc);
371 } else
372 err = -1;
373 } else if (proc_num == MODEM_DATA) {
374 write_ptr->buf = buf;
375#ifdef DIAG_DEBUG
376 printk(KERN_INFO "writing data to USB,"
377 "pkt length %d\n", write_ptr->length);
378 print_hex_dump(KERN_DEBUG, "Written Packet Data to"
379 " USB: ", 16, 1, DUMP_PREFIX_ADDRESS,
380 buf, write_ptr->length, 1);
381#endif /* DIAG DEBUG */
382 err = usb_diag_write(driver->legacy_ch, write_ptr);
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -0700383 } else if (proc_num == LPASS_DATA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384 write_ptr->buf = buf;
385 err = usb_diag_write(driver->legacy_ch, write_ptr);
386 } else if (proc_num == WCNSS_DATA) {
387 write_ptr->buf = buf;
388 err = usb_diag_write(driver->legacy_ch, write_ptr);
389 }
390#ifdef CONFIG_DIAG_SDIO_PIPE
391 else if (proc_num == SDIO_DATA) {
392 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -0800393 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700394 write_ptr->buf = buf;
395 err = usb_diag_write(driver->mdm_ch, write_ptr);
396 } else
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800397 pr_err("diag: Incorrect sdio data "
398 "while USB write\n");
399 }
400#endif
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700401#ifdef CONFIG_DIAG_BRIDGE_CODE
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800402 else if (proc_num == HSIC_DATA) {
403 if (driver->hsic_device_enabled) {
Dixon Peterson938f8602012-08-17 20:02:57 -0700404 struct diag_request *write_ptr_mdm;
405 write_ptr_mdm = (struct diag_request *)
406 diagmem_alloc(driver,
407 sizeof(struct diag_request),
408 POOL_TYPE_HSIC_WRITE);
409 if (write_ptr_mdm) {
410 write_ptr_mdm->buf = buf;
411 write_ptr_mdm->length =
412 driver->write_len_mdm;
413 err = usb_diag_write(driver->mdm_ch,
414 write_ptr_mdm);
415 /* Return to the pool immediately */
416 if (err) {
417 diagmem_free(driver,
418 write_ptr_mdm,
419 POOL_TYPE_HSIC_WRITE);
Dixon Peterson6beff2d2012-09-13 18:51:47 -0700420 pr_err_ratelimited("diag: HSIC write failure, err: %d\n",
421 err);
Dixon Peterson938f8602012-08-17 20:02:57 -0700422 }
423 } else {
424 pr_err("diag: allocate write fail\n");
425 err = -1;
426 }
427 } else {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800428 pr_err("diag: Incorrect hsic data "
429 "while USB write\n");
Dixon Peterson938f8602012-08-17 20:02:57 -0700430 err = -1;
431 }
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700432 } else if (proc_num == SMUX_DATA) {
433 write_ptr->buf = buf;
434 pr_debug("diag: writing SMUX data\n");
435 err = usb_diag_write(driver->mdm_ch, write_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700436 }
437#endif
438 APPEND_DEBUG('d');
439 }
440#endif /* DIAG OVER USB */
441 return err;
442}
443
444void __diag_smd_wcnss_send_req(void)
445{
Ashay Jaiswal29620122012-03-21 12:02:36 +0530446 void *buf = NULL;
447 int *in_busy_wcnss_ptr = NULL;
448 struct diag_request *write_ptr_wcnss = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700449
Ashay Jaiswal29620122012-03-21 12:02:36 +0530450 if (!driver->in_busy_wcnss_1) {
451 buf = driver->buf_in_wcnss_1;
452 write_ptr_wcnss = driver->write_ptr_wcnss_1;
453 in_busy_wcnss_ptr = &(driver->in_busy_wcnss_1);
454 } else if (!driver->in_busy_wcnss_2) {
455 buf = driver->buf_in_wcnss_2;
456 write_ptr_wcnss = driver->write_ptr_wcnss_2;
457 in_busy_wcnss_ptr = &(driver->in_busy_wcnss_2);
458 }
459
460 if (driver->ch_wcnss && buf) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700461 int r = smd_read_avail(driver->ch_wcnss);
462 if (r > IN_BUF_SIZE) {
463 if (r < MAX_IN_BUF_SIZE) {
464 pr_err("diag: wcnss packets > %d bytes", r);
465 buf = krealloc(buf, r, GFP_KERNEL);
466 } else {
467 pr_err("diag: wcnss pkt > %d", MAX_IN_BUF_SIZE);
468 return;
469 }
470 }
471 if (r > 0) {
472 if (!buf) {
473 pr_err("Out of diagmem for wcnss\n");
474 } else {
475 APPEND_DEBUG('i');
476 smd_read(driver->ch_wcnss, buf, r);
477 APPEND_DEBUG('j');
478 write_ptr_wcnss->length = r;
479 *in_busy_wcnss_ptr = 1;
480 diag_device_write(buf, WCNSS_DATA,
481 write_ptr_wcnss);
482 }
483 }
Dixon Peterson743a11e2012-07-30 17:42:20 -0700484 } else if (driver->ch_wcnss && !buf &&
485 (driver->logging_mode == MEMORY_DEVICE_MODE)) {
486 chk_logging_wakeup();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700487 }
488}
489
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -0700490void __diag_smd_lpass_send_req(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700491{
492 void *buf = NULL;
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -0700493 int *in_busy_lpass_ptr = NULL;
494 struct diag_request *write_ptr_lpass = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700495
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -0700496 if (!driver->in_busy_lpass_1) {
497 buf = driver->buf_in_lpass_1;
498 write_ptr_lpass = driver->write_ptr_lpass_1;
499 in_busy_lpass_ptr = &(driver->in_busy_lpass_1);
500 } else if (!driver->in_busy_lpass_2) {
501 buf = driver->buf_in_lpass_2;
502 write_ptr_lpass = driver->write_ptr_lpass_2;
503 in_busy_lpass_ptr = &(driver->in_busy_lpass_2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504 }
505
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -0700506 if (driver->chlpass && buf) {
507 int r = smd_read_avail(driver->chlpass);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508
509 if (r > IN_BUF_SIZE) {
510 if (r < MAX_IN_BUF_SIZE) {
511 pr_err("diag: SMD sending in "
512 "packets upto %d bytes", r);
513 buf = krealloc(buf, r, GFP_KERNEL);
514 } else {
515 pr_err("diag: SMD sending in "
516 "packets more than %d bytes", MAX_IN_BUF_SIZE);
517 return;
518 }
519 }
520 if (r > 0) {
521 if (!buf)
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -0700522 printk(KERN_INFO "Out of diagmem for LPASS\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700523 else {
524 APPEND_DEBUG('i');
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -0700525 smd_read(driver->chlpass, buf, r);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700526 APPEND_DEBUG('j');
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -0700527 write_ptr_lpass->length = r;
528 *in_busy_lpass_ptr = 1;
529 diag_device_write(buf, LPASS_DATA,
530 write_ptr_lpass);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700531 }
532 }
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -0700533 } else if (driver->chlpass && !buf &&
Dixon Peterson743a11e2012-07-30 17:42:20 -0700534 (driver->logging_mode == MEMORY_DEVICE_MODE)) {
535 chk_logging_wakeup();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700536 }
537}
538
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700539static void diag_update_pkt_buffer(unsigned char *buf)
540{
541 unsigned char *ptr = driver->pkt_buf;
542 unsigned char *temp = buf;
543
544 mutex_lock(&driver->diagchar_mutex);
545 if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, driver->pkt_length))
546 memcpy(ptr, temp , driver->pkt_length);
547 else
548 printk(KERN_CRIT " Not enough buffer space for PKT_RESP\n");
549 mutex_unlock(&driver->diagchar_mutex);
550}
551
552void diag_update_userspace_clients(unsigned int type)
553{
554 int i;
555
556 mutex_lock(&driver->diagchar_mutex);
557 for (i = 0; i < driver->num_clients; i++)
558 if (driver->client_map[i].pid != 0)
559 driver->data_ready[i] |= type;
560 wake_up_interruptible(&driver->wait_q);
561 mutex_unlock(&driver->diagchar_mutex);
562}
563
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700564void diag_update_sleeping_process(int process_id, int data_type)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700565{
566 int i;
567
568 mutex_lock(&driver->diagchar_mutex);
569 for (i = 0; i < driver->num_clients; i++)
570 if (driver->client_map[i].pid == process_id) {
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700571 driver->data_ready[i] |= data_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700572 break;
573 }
574 wake_up_interruptible(&driver->wait_q);
575 mutex_unlock(&driver->diagchar_mutex);
576}
577
578void diag_send_data(struct diag_master_table entry, unsigned char *buf,
579 int len, int type)
580{
581 driver->pkt_length = len;
582 if (entry.process_id != NON_APPS_PROC && type != MODEM_DATA) {
583 diag_update_pkt_buffer(buf);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700584 diag_update_sleeping_process(entry.process_id, PKT_TYPE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585 } else {
586 if (len > 0) {
Shalabh Jainc9f35092011-07-28 18:36:17 -0700587 if (entry.client_id == MODEM_PROC && driver->ch) {
Shalabh Jain10f5f432012-01-11 11:45:44 +0530588 if (chk_apps_master() &&
Shalabh Jainc9f35092011-07-28 18:36:17 -0700589 (int)(*(char *)buf) == MODE_CMD)
Dixon Petersonff425d12011-12-06 18:12:35 -0800590 if ((int)(*(char *)(buf+1)) ==
591 RESET_ID)
Shalabh Jainc9f35092011-07-28 18:36:17 -0700592 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700593 smd_write(driver->ch, buf, len);
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -0700594 } else if (entry.client_id == LPASS_PROC &&
595 driver->chlpass) {
596 smd_write(driver->chlpass, buf, len);
Shalabh Jainc9f35092011-07-28 18:36:17 -0700597 } else if (entry.client_id == WCNSS_PROC &&
598 driver->ch_wcnss) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599 smd_write(driver->ch_wcnss, buf, len);
Shalabh Jainc9f35092011-07-28 18:36:17 -0700600 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700601 pr_alert("diag: incorrect channel");
Shalabh Jainc9f35092011-07-28 18:36:17 -0700602 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700603 }
604 }
605}
606
607static int diag_process_apps_pkt(unsigned char *buf, int len)
608{
609 uint16_t subsys_cmd_code;
610 int subsys_id, ssid_first, ssid_last, ssid_range;
Shalabh Jain3fd986f2012-05-30 18:42:26 -0700611 int packet_type = 1, i, cmd_code;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700612 unsigned char *temp = buf;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700613 int data_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700614#if defined(CONFIG_DIAG_OVER_USB)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700615 unsigned char *ptr;
616#endif
617
Dixon Petersond6a20a92012-09-27 15:58:50 -0700618 /* Check if the command is a supported mask command */
619 if (diag_process_apps_masks(buf, len) == 0)
620 return 0;
621
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700622 /* Check for registered clients and forward packet to apropriate proc */
623 cmd_code = (int)(*(char *)buf);
624 temp++;
625 subsys_id = (int)(*(char *)temp);
626 temp++;
627 subsys_cmd_code = *(uint16_t *)temp;
628 temp += 2;
629 data_type = APPS_DATA;
630 /* Dont send any command other than mode reset */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530631 if (chk_apps_master() && cmd_code == MODE_CMD) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632 if (subsys_id != RESET_ID)
633 data_type = MODEM_DATA;
634 }
635
636 pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
Shalabh Jainfe02b0c2012-02-21 14:48:03 -0800637 for (i = 0; i < diag_max_reg; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700638 entry = driver->table[i];
639 if (entry.process_id != NO_PROCESS) {
640 if (entry.cmd_code == cmd_code && entry.subsys_id ==
641 subsys_id && entry.cmd_code_lo <=
642 subsys_cmd_code &&
643 entry.cmd_code_hi >= subsys_cmd_code) {
644 diag_send_data(entry, buf, len, data_type);
645 packet_type = 0;
646 } else if (entry.cmd_code == 255
647 && cmd_code == 75) {
648 if (entry.subsys_id ==
649 subsys_id &&
650 entry.cmd_code_lo <=
651 subsys_cmd_code &&
652 entry.cmd_code_hi >=
653 subsys_cmd_code) {
654 diag_send_data(entry, buf, len,
655 data_type);
656 packet_type = 0;
657 }
658 } else if (entry.cmd_code == 255 &&
659 entry.subsys_id == 255) {
660 if (entry.cmd_code_lo <=
661 cmd_code &&
662 entry.
663 cmd_code_hi >= cmd_code) {
664 diag_send_data(entry, buf, len,
665 data_type);
666 packet_type = 0;
667 }
668 }
669 }
670 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700671#if defined(CONFIG_DIAG_OVER_USB)
Dixon Petersona2dd7352012-05-21 17:37:10 -0700672 /* Check for the command/respond msg for the maximum packet length */
673 if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
674 (*(uint16_t *)(buf+2) == 0x0055)) {
675 for (i = 0; i < 4; i++)
676 *(driver->apps_rsp_buf+i) = *(buf+i);
677 *(uint32_t *)(driver->apps_rsp_buf+4) = PKT_SIZE;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700678 encode_rsp_and_send(7);
Dixon Petersona2dd7352012-05-21 17:37:10 -0700679 return 0;
680 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700681 /* Check for Apps Only & get event mask request */
Dixon Petersona2dd7352012-05-21 17:37:10 -0700682 else if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700683 driver->apps_rsp_buf[0] = 0x81;
684 driver->apps_rsp_buf[1] = 0x0;
685 *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
686 *(uint16_t *)(driver->apps_rsp_buf + 4) = EVENT_LAST_ID + 1;
687 for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
688 *(unsigned char *)(driver->apps_rsp_buf + 6 + i) = 0x0;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700689 encode_rsp_and_send(6 + EVENT_LAST_ID/8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690 return 0;
691 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700692 /* Get log ID range & Check for Apps Only */
693 else if (!(driver->ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700694 && (*buf == 0x73) && *(int *)(buf+4) == 1) {
695 driver->apps_rsp_buf[0] = 0x73;
696 *(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
697 *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success code */
698 *(int *)(driver->apps_rsp_buf + 12) = LOG_GET_ITEM_NUM(LOG_0);
699 *(int *)(driver->apps_rsp_buf + 16) = LOG_GET_ITEM_NUM(LOG_1);
700 *(int *)(driver->apps_rsp_buf + 20) = LOG_GET_ITEM_NUM(LOG_2);
701 *(int *)(driver->apps_rsp_buf + 24) = LOG_GET_ITEM_NUM(LOG_3);
702 *(int *)(driver->apps_rsp_buf + 28) = LOG_GET_ITEM_NUM(LOG_4);
703 *(int *)(driver->apps_rsp_buf + 32) = LOG_GET_ITEM_NUM(LOG_5);
704 *(int *)(driver->apps_rsp_buf + 36) = LOG_GET_ITEM_NUM(LOG_6);
705 *(int *)(driver->apps_rsp_buf + 40) = LOG_GET_ITEM_NUM(LOG_7);
706 *(int *)(driver->apps_rsp_buf + 44) = LOG_GET_ITEM_NUM(LOG_8);
707 *(int *)(driver->apps_rsp_buf + 48) = LOG_GET_ITEM_NUM(LOG_9);
708 *(int *)(driver->apps_rsp_buf + 52) = LOG_GET_ITEM_NUM(LOG_10);
709 *(int *)(driver->apps_rsp_buf + 56) = LOG_GET_ITEM_NUM(LOG_11);
710 *(int *)(driver->apps_rsp_buf + 60) = LOG_GET_ITEM_NUM(LOG_12);
711 *(int *)(driver->apps_rsp_buf + 64) = LOG_GET_ITEM_NUM(LOG_13);
712 *(int *)(driver->apps_rsp_buf + 68) = LOG_GET_ITEM_NUM(LOG_14);
713 *(int *)(driver->apps_rsp_buf + 72) = LOG_GET_ITEM_NUM(LOG_15);
Dixon Petersond6a20a92012-09-27 15:58:50 -0700714 encode_rsp_and_send(75);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700715 return 0;
716 }
717 /* Respond to Get SSID Range request message */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700718 else if (!(driver->ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700719 && (*buf == 0x7d) && (*(buf+1) == 0x1)) {
720 driver->apps_rsp_buf[0] = 0x7d;
721 driver->apps_rsp_buf[1] = 0x1;
722 driver->apps_rsp_buf[2] = 0x1;
723 driver->apps_rsp_buf[3] = 0x0;
Shalabh Jain44b79b72012-06-15 13:39:27 -0700724 /* -1 to un-account for OEM SSID range */
725 *(int *)(driver->apps_rsp_buf + 4) = MSG_MASK_TBL_CNT - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700726 *(uint16_t *)(driver->apps_rsp_buf + 8) = MSG_SSID_0;
727 *(uint16_t *)(driver->apps_rsp_buf + 10) = MSG_SSID_0_LAST;
728 *(uint16_t *)(driver->apps_rsp_buf + 12) = MSG_SSID_1;
729 *(uint16_t *)(driver->apps_rsp_buf + 14) = MSG_SSID_1_LAST;
730 *(uint16_t *)(driver->apps_rsp_buf + 16) = MSG_SSID_2;
731 *(uint16_t *)(driver->apps_rsp_buf + 18) = MSG_SSID_2_LAST;
732 *(uint16_t *)(driver->apps_rsp_buf + 20) = MSG_SSID_3;
733 *(uint16_t *)(driver->apps_rsp_buf + 22) = MSG_SSID_3_LAST;
734 *(uint16_t *)(driver->apps_rsp_buf + 24) = MSG_SSID_4;
735 *(uint16_t *)(driver->apps_rsp_buf + 26) = MSG_SSID_4_LAST;
736 *(uint16_t *)(driver->apps_rsp_buf + 28) = MSG_SSID_5;
737 *(uint16_t *)(driver->apps_rsp_buf + 30) = MSG_SSID_5_LAST;
738 *(uint16_t *)(driver->apps_rsp_buf + 32) = MSG_SSID_6;
739 *(uint16_t *)(driver->apps_rsp_buf + 34) = MSG_SSID_6_LAST;
740 *(uint16_t *)(driver->apps_rsp_buf + 36) = MSG_SSID_7;
741 *(uint16_t *)(driver->apps_rsp_buf + 38) = MSG_SSID_7_LAST;
742 *(uint16_t *)(driver->apps_rsp_buf + 40) = MSG_SSID_8;
743 *(uint16_t *)(driver->apps_rsp_buf + 42) = MSG_SSID_8_LAST;
744 *(uint16_t *)(driver->apps_rsp_buf + 44) = MSG_SSID_9;
745 *(uint16_t *)(driver->apps_rsp_buf + 46) = MSG_SSID_9_LAST;
746 *(uint16_t *)(driver->apps_rsp_buf + 48) = MSG_SSID_10;
747 *(uint16_t *)(driver->apps_rsp_buf + 50) = MSG_SSID_10_LAST;
748 *(uint16_t *)(driver->apps_rsp_buf + 52) = MSG_SSID_11;
749 *(uint16_t *)(driver->apps_rsp_buf + 54) = MSG_SSID_11_LAST;
750 *(uint16_t *)(driver->apps_rsp_buf + 56) = MSG_SSID_12;
751 *(uint16_t *)(driver->apps_rsp_buf + 58) = MSG_SSID_12_LAST;
752 *(uint16_t *)(driver->apps_rsp_buf + 60) = MSG_SSID_13;
753 *(uint16_t *)(driver->apps_rsp_buf + 62) = MSG_SSID_13_LAST;
754 *(uint16_t *)(driver->apps_rsp_buf + 64) = MSG_SSID_14;
755 *(uint16_t *)(driver->apps_rsp_buf + 66) = MSG_SSID_14_LAST;
756 *(uint16_t *)(driver->apps_rsp_buf + 68) = MSG_SSID_15;
757 *(uint16_t *)(driver->apps_rsp_buf + 70) = MSG_SSID_15_LAST;
758 *(uint16_t *)(driver->apps_rsp_buf + 72) = MSG_SSID_16;
759 *(uint16_t *)(driver->apps_rsp_buf + 74) = MSG_SSID_16_LAST;
760 *(uint16_t *)(driver->apps_rsp_buf + 76) = MSG_SSID_17;
761 *(uint16_t *)(driver->apps_rsp_buf + 78) = MSG_SSID_17_LAST;
762 *(uint16_t *)(driver->apps_rsp_buf + 80) = MSG_SSID_18;
763 *(uint16_t *)(driver->apps_rsp_buf + 82) = MSG_SSID_18_LAST;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800764 *(uint16_t *)(driver->apps_rsp_buf + 84) = MSG_SSID_19;
765 *(uint16_t *)(driver->apps_rsp_buf + 86) = MSG_SSID_19_LAST;
766 *(uint16_t *)(driver->apps_rsp_buf + 88) = MSG_SSID_20;
767 *(uint16_t *)(driver->apps_rsp_buf + 90) = MSG_SSID_20_LAST;
768 *(uint16_t *)(driver->apps_rsp_buf + 92) = MSG_SSID_21;
769 *(uint16_t *)(driver->apps_rsp_buf + 94) = MSG_SSID_21_LAST;
770 *(uint16_t *)(driver->apps_rsp_buf + 96) = MSG_SSID_22;
771 *(uint16_t *)(driver->apps_rsp_buf + 98) = MSG_SSID_22_LAST;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700772 encode_rsp_and_send(99);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700773 return 0;
774 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700775 /* Check for Apps Only Respond to Get Subsys Build mask */
776 else if (!(driver->ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700777 && (*buf == 0x7d) && (*(buf+1) == 0x2)) {
778 ssid_first = *(uint16_t *)(buf + 2);
779 ssid_last = *(uint16_t *)(buf + 4);
780 ssid_range = 4 * (ssid_last - ssid_first + 1);
781 /* frame response */
782 driver->apps_rsp_buf[0] = 0x7d;
783 driver->apps_rsp_buf[1] = 0x2;
784 *(uint16_t *)(driver->apps_rsp_buf + 2) = ssid_first;
785 *(uint16_t *)(driver->apps_rsp_buf + 4) = ssid_last;
786 driver->apps_rsp_buf[6] = 0x1;
787 driver->apps_rsp_buf[7] = 0x0;
788 ptr = driver->apps_rsp_buf + 8;
789 /* bld time masks */
790 switch (ssid_first) {
791 case MSG_SSID_0:
792 for (i = 0; i < ssid_range; i += 4)
793 *(int *)(ptr + i) = msg_bld_masks_0[i/4];
794 break;
795 case MSG_SSID_1:
796 for (i = 0; i < ssid_range; i += 4)
797 *(int *)(ptr + i) = msg_bld_masks_1[i/4];
798 break;
799 case MSG_SSID_2:
800 for (i = 0; i < ssid_range; i += 4)
801 *(int *)(ptr + i) = msg_bld_masks_2[i/4];
802 break;
803 case MSG_SSID_3:
804 for (i = 0; i < ssid_range; i += 4)
805 *(int *)(ptr + i) = msg_bld_masks_3[i/4];
806 break;
807 case MSG_SSID_4:
808 for (i = 0; i < ssid_range; i += 4)
809 *(int *)(ptr + i) = msg_bld_masks_4[i/4];
810 break;
811 case MSG_SSID_5:
812 for (i = 0; i < ssid_range; i += 4)
813 *(int *)(ptr + i) = msg_bld_masks_5[i/4];
814 break;
815 case MSG_SSID_6:
816 for (i = 0; i < ssid_range; i += 4)
817 *(int *)(ptr + i) = msg_bld_masks_6[i/4];
818 break;
819 case MSG_SSID_7:
820 for (i = 0; i < ssid_range; i += 4)
821 *(int *)(ptr + i) = msg_bld_masks_7[i/4];
822 break;
823 case MSG_SSID_8:
824 for (i = 0; i < ssid_range; i += 4)
825 *(int *)(ptr + i) = msg_bld_masks_8[i/4];
826 break;
827 case MSG_SSID_9:
828 for (i = 0; i < ssid_range; i += 4)
829 *(int *)(ptr + i) = msg_bld_masks_9[i/4];
830 break;
831 case MSG_SSID_10:
832 for (i = 0; i < ssid_range; i += 4)
833 *(int *)(ptr + i) = msg_bld_masks_10[i/4];
834 break;
835 case MSG_SSID_11:
836 for (i = 0; i < ssid_range; i += 4)
837 *(int *)(ptr + i) = msg_bld_masks_11[i/4];
838 break;
839 case MSG_SSID_12:
840 for (i = 0; i < ssid_range; i += 4)
841 *(int *)(ptr + i) = msg_bld_masks_12[i/4];
842 break;
843 case MSG_SSID_13:
844 for (i = 0; i < ssid_range; i += 4)
845 *(int *)(ptr + i) = msg_bld_masks_13[i/4];
846 break;
847 case MSG_SSID_14:
848 for (i = 0; i < ssid_range; i += 4)
849 *(int *)(ptr + i) = msg_bld_masks_14[i/4];
850 break;
851 case MSG_SSID_15:
852 for (i = 0; i < ssid_range; i += 4)
853 *(int *)(ptr + i) = msg_bld_masks_15[i/4];
854 break;
855 case MSG_SSID_16:
856 for (i = 0; i < ssid_range; i += 4)
857 *(int *)(ptr + i) = msg_bld_masks_16[i/4];
858 break;
859 case MSG_SSID_17:
860 for (i = 0; i < ssid_range; i += 4)
861 *(int *)(ptr + i) = msg_bld_masks_17[i/4];
862 break;
863 case MSG_SSID_18:
864 for (i = 0; i < ssid_range; i += 4)
865 *(int *)(ptr + i) = msg_bld_masks_18[i/4];
866 break;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800867 case MSG_SSID_19:
868 for (i = 0; i < ssid_range; i += 4)
869 *(int *)(ptr + i) = msg_bld_masks_19[i/4];
870 break;
871 case MSG_SSID_20:
872 for (i = 0; i < ssid_range; i += 4)
873 *(int *)(ptr + i) = msg_bld_masks_20[i/4];
874 break;
875 case MSG_SSID_21:
876 for (i = 0; i < ssid_range; i += 4)
877 *(int *)(ptr + i) = msg_bld_masks_21[i/4];
878 break;
879 case MSG_SSID_22:
880 for (i = 0; i < ssid_range; i += 4)
881 *(int *)(ptr + i) = msg_bld_masks_22[i/4];
882 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700883 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700884 encode_rsp_and_send(8 + ssid_range - 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700885 return 0;
886 }
887 /* Check for download command */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530888 else if ((cpu_is_msm8x60() || chk_apps_master()) && (*buf == 0x3A)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700889 /* send response back */
890 driver->apps_rsp_buf[0] = *buf;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700891 encode_rsp_and_send(0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892 msleep(5000);
893 /* call download API */
894 msm_set_restart_mode(RESTART_DLOAD);
895 printk(KERN_CRIT "diag: download mode set, Rebooting SoC..\n");
896 kernel_restart(NULL);
897 /* Not required, represents that command isnt sent to modem */
898 return 0;
899 }
Dixon Petersonb46bb992012-01-12 19:16:56 -0800900 /* Check for polling for Apps only DIAG */
901 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
902 (*(buf+2) == 0x03)) {
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800903 /* If no one has registered for polling */
Dixon Petersonb4618a42012-02-29 18:56:31 -0800904 if (chk_polling_response()) {
Dixon Petersonb46bb992012-01-12 19:16:56 -0800905 /* Respond to polling for Apps only DIAG */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700906 for (i = 0; i < 3; i++)
907 driver->apps_rsp_buf[i] = *(buf+i);
908 for (i = 0; i < 13; i++)
909 driver->apps_rsp_buf[i+3] = 0;
910
Dixon Petersond6a20a92012-09-27 15:58:50 -0700911 encode_rsp_and_send(15);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700912 return 0;
913 }
Dixon Petersonb46bb992012-01-12 19:16:56 -0800914 }
915 /* Check for ID for NO MODEM present */
Dixon Petersonb4618a42012-02-29 18:56:31 -0800916 else if (chk_polling_response()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700917 /* respond to 0x0 command */
Dixon Petersonb46bb992012-01-12 19:16:56 -0800918 if (*buf == 0x00) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700919 for (i = 0; i < 55; i++)
920 driver->apps_rsp_buf[i] = 0;
921
Dixon Petersond6a20a92012-09-27 15:58:50 -0700922 encode_rsp_and_send(54);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700923 return 0;
924 }
925 /* respond to 0x7c command */
926 else if (*buf == 0x7c) {
927 driver->apps_rsp_buf[0] = 0x7c;
928 for (i = 1; i < 8; i++)
929 driver->apps_rsp_buf[i] = 0;
930 /* Tools ID for APQ 8060 */
931 *(int *)(driver->apps_rsp_buf + 8) =
932 chk_config_get_id();
933 *(unsigned char *)(driver->apps_rsp_buf + 12) = '\0';
934 *(unsigned char *)(driver->apps_rsp_buf + 13) = '\0';
Dixon Petersond6a20a92012-09-27 15:58:50 -0700935 encode_rsp_and_send(13);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700936 return 0;
937 }
938 }
939#endif
Dixon Petersond6a20a92012-09-27 15:58:50 -0700940 return packet_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700941}
942
943#ifdef CONFIG_DIAG_OVER_USB
944void diag_send_error_rsp(int index)
945{
946 int i;
Shalabh Jain1fedab92011-12-22 13:15:22 +0530947
948 if (index > 490) {
949 pr_err("diag: error response too huge, aborting\n");
950 return;
951 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700952 driver->apps_rsp_buf[0] = 0x13; /* error code 13 */
953 for (i = 0; i < index; i++)
954 driver->apps_rsp_buf[i+1] = *(driver->hdlc_buf+i);
Dixon Petersond6a20a92012-09-27 15:58:50 -0700955 encode_rsp_and_send(index - 3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700956}
957#else
958static inline void diag_send_error_rsp(int index) {}
959#endif
960
961void diag_process_hdlc(void *data, unsigned len)
962{
963 struct diag_hdlc_decode_type hdlc;
964 int ret, type = 0;
965 pr_debug("diag: HDLC decode fn, len of data %d\n", len);
966 hdlc.dest_ptr = driver->hdlc_buf;
967 hdlc.dest_size = USB_MAX_OUT_BUF;
968 hdlc.src_ptr = data;
969 hdlc.src_size = len;
970 hdlc.src_idx = 0;
971 hdlc.dest_idx = 0;
972 hdlc.escaping = 0;
973
974 ret = diag_hdlc_decode(&hdlc);
975
976 if (ret)
977 type = diag_process_apps_pkt(driver->hdlc_buf,
978 hdlc.dest_idx - 3);
979 else if (driver->debug_flag) {
980 printk(KERN_ERR "Packet dropped due to bad HDLC coding/CRC"
981 " errors or partial packet received, packet"
982 " length = %d\n", len);
983 print_hex_dump(KERN_DEBUG, "Dropped Packet Data: ", 16, 1,
984 DUMP_PREFIX_ADDRESS, data, len, 1);
985 driver->debug_flag = 0;
986 }
987 /* send error responses from APPS for Central Routing */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700988 if (type == 1 && chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700989 diag_send_error_rsp(hdlc.dest_idx);
990 type = 0;
991 }
992 /* implies this packet is NOT meant for apps */
993 if (!(driver->ch) && type == 1) {
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700994 if (chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700995 diag_send_error_rsp(hdlc.dest_idx);
996 } else { /* APQ 8060, Let Q6 respond */
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -0700997 if (driver->chlpass)
998 smd_write(driver->chlpass, driver->hdlc_buf,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700999 hdlc.dest_idx - 3);
1000 }
1001 type = 0;
1002 }
1003
1004#ifdef DIAG_DEBUG
1005 pr_debug("diag: hdlc.dest_idx = %d", hdlc.dest_idx);
1006 for (i = 0; i < hdlc.dest_idx; i++)
1007 printk(KERN_DEBUG "\t%x", *(((unsigned char *)
1008 driver->hdlc_buf)+i));
1009#endif /* DIAG DEBUG */
1010 /* ignore 2 bytes for CRC, one for 7E and send */
1011 if ((driver->ch) && (ret) && (type) && (hdlc.dest_idx > 3)) {
1012 APPEND_DEBUG('g');
1013 smd_write(driver->ch, driver->hdlc_buf, hdlc.dest_idx - 3);
1014 APPEND_DEBUG('h');
1015#ifdef DIAG_DEBUG
1016 printk(KERN_INFO "writing data to SMD, pkt length %d\n", len);
1017 print_hex_dump(KERN_DEBUG, "Written Packet Data to SMD: ", 16,
1018 1, DUMP_PREFIX_ADDRESS, data, len, 1);
1019#endif /* DIAG DEBUG */
1020 }
1021}
1022
1023#ifdef CONFIG_DIAG_OVER_USB
Shalabh Jain8e9750a2011-09-09 13:06:29 -07001024/* 2+1 for modem ; 2 for LPASS ; 1 for WCNSS */
1025#define N_LEGACY_WRITE (driver->poolsize + 6)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026#define N_LEGACY_READ 1
1027
1028int diagfwd_connect(void)
1029{
1030 int err;
1031
1032 printk(KERN_DEBUG "diag: USB connected\n");
1033 err = usb_diag_alloc_req(driver->legacy_ch, N_LEGACY_WRITE,
1034 N_LEGACY_READ);
1035 if (err)
1036 printk(KERN_ERR "diag: unable to alloc USB req on legacy ch");
1037
1038 driver->usb_connected = 1;
1039 driver->in_busy_1 = 0;
1040 driver->in_busy_2 = 0;
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001041 driver->in_busy_lpass_1 = 0;
1042 driver->in_busy_lpass_2 = 0;
Ashay Jaiswal29620122012-03-21 12:02:36 +05301043 driver->in_busy_wcnss_1 = 0;
1044 driver->in_busy_wcnss_2 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001045
1046 /* Poll SMD channels to check for data*/
1047 queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001048 queue_work(driver->diag_wq, &(driver->diag_read_smd_lpass_work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001049 queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_work));
Shalabh Jaincf5f20e2011-08-22 12:29:52 -07001050 /* Poll SMD CNTL channels to check for data */
Shalabh Jain4e1bd312012-02-16 19:33:05 -08001051 diag_smd_cntl_notify(NULL, SMD_EVENT_DATA);
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001052 diag_smd_lpass_cntl_notify(NULL, SMD_EVENT_DATA);
Shalabh Jain4e1bd312012-02-16 19:33:05 -08001053 diag_smd_wcnss_cntl_notify(NULL, SMD_EVENT_DATA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001054 /* Poll USB channel to check for data*/
1055 queue_work(driver->diag_wq, &(driver->diag_read_work));
1056#ifdef CONFIG_DIAG_SDIO_PIPE
1057 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
1058 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1059 diagfwd_connect_sdio();
1060 else
1061 printk(KERN_INFO "diag: No USB MDM ch");
1062 }
1063#endif
1064 return 0;
1065}
1066
1067int diagfwd_disconnect(void)
1068{
1069 printk(KERN_DEBUG "diag: USB disconnected\n");
1070 driver->usb_connected = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001071 driver->debug_flag = 1;
1072 usb_diag_free_req(driver->legacy_ch);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001073 if (driver->logging_mode == USB_MODE) {
1074 driver->in_busy_1 = 1;
1075 driver->in_busy_2 = 1;
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001076 driver->in_busy_lpass_1 = 1;
1077 driver->in_busy_lpass_2 = 1;
Ashay Jaiswal29620122012-03-21 12:02:36 +05301078 driver->in_busy_wcnss_1 = 1;
1079 driver->in_busy_wcnss_2 = 1;
Shalabh Jain69890aa2011-10-10 12:59:16 -07001080 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081#ifdef CONFIG_DIAG_SDIO_PIPE
1082 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
1083 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1084 diagfwd_disconnect_sdio();
1085#endif
1086 /* TBD - notify and flow control SMD */
1087 return 0;
1088}
1089
1090int diagfwd_write_complete(struct diag_request *diag_write_ptr)
1091{
1092 unsigned char *buf = diag_write_ptr->buf;
1093 /*Determine if the write complete is for data from modem/apps/q6 */
1094 /* Need a context variable here instead */
1095 if (buf == (void *)driver->buf_in_1) {
1096 driver->in_busy_1 = 0;
1097 APPEND_DEBUG('o');
1098 queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
1099 } else if (buf == (void *)driver->buf_in_2) {
1100 driver->in_busy_2 = 0;
1101 APPEND_DEBUG('O');
1102 queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001103 } else if (buf == (void *)driver->buf_in_lpass_1) {
1104 driver->in_busy_lpass_1 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 APPEND_DEBUG('p');
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001106 queue_work(driver->diag_wq,
1107 &(driver->diag_read_smd_lpass_work));
1108 } else if (buf == (void *)driver->buf_in_lpass_2) {
1109 driver->in_busy_lpass_2 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001110 APPEND_DEBUG('P');
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001111 queue_work(driver->diag_wq,
1112 &(driver->diag_read_smd_lpass_work));
Ashay Jaiswal29620122012-03-21 12:02:36 +05301113 } else if (buf == driver->buf_in_wcnss_1) {
1114 driver->in_busy_wcnss_1 = 0;
1115 APPEND_DEBUG('r');
1116 queue_work(driver->diag_wq,
1117 &(driver->diag_read_smd_wcnss_work));
1118 } else if (buf == driver->buf_in_wcnss_2) {
1119 driver->in_busy_wcnss_2 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001120 APPEND_DEBUG('R');
1121 queue_work(driver->diag_wq,
1122 &(driver->diag_read_smd_wcnss_work));
1123 }
1124#ifdef CONFIG_DIAG_SDIO_PIPE
1125 else if (buf == (void *)driver->buf_in_sdio)
1126 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -08001127 machine_is_msm8x60_fusn_ffa())
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001128 diagfwd_write_complete_sdio();
1129 else
1130 pr_err("diag: Incorrect buffer pointer while WRITE");
1131#endif
1132 else {
1133 diagmem_free(driver, (unsigned char *)buf, POOL_TYPE_HDLC);
1134 diagmem_free(driver, (unsigned char *)diag_write_ptr,
1135 POOL_TYPE_WRITE_STRUCT);
1136 APPEND_DEBUG('q');
1137 }
1138 return 0;
1139}
1140
1141int diagfwd_read_complete(struct diag_request *diag_read_ptr)
1142{
1143 int status = diag_read_ptr->status;
1144 unsigned char *buf = diag_read_ptr->buf;
1145
1146 /* Determine if the read complete is for data on legacy/mdm ch */
1147 if (buf == (void *)driver->usb_buf_out) {
1148 driver->read_len_legacy = diag_read_ptr->actual;
1149 APPEND_DEBUG('s');
1150#ifdef DIAG_DEBUG
1151 printk(KERN_INFO "read data from USB, pkt length %d",
1152 diag_read_ptr->actual);
1153 print_hex_dump(KERN_DEBUG, "Read Packet Data from USB: ", 16, 1,
1154 DUMP_PREFIX_ADDRESS, diag_read_ptr->buf,
1155 diag_read_ptr->actual, 1);
1156#endif /* DIAG DEBUG */
1157 if (driver->logging_mode == USB_MODE) {
1158 if (status != -ECONNRESET && status != -ESHUTDOWN)
1159 queue_work(driver->diag_wq,
1160 &(driver->diag_proc_hdlc_work));
1161 else
1162 queue_work(driver->diag_wq,
1163 &(driver->diag_read_work));
1164 }
1165 }
1166#ifdef CONFIG_DIAG_SDIO_PIPE
1167 else if (buf == (void *)driver->usb_buf_mdm_out) {
1168 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -08001169 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170 driver->read_len_mdm = diag_read_ptr->actual;
1171 diagfwd_read_complete_sdio();
1172 } else
1173 pr_err("diag: Incorrect buffer pointer while READ");
1174 }
1175#endif
1176 else
1177 printk(KERN_ERR "diag: Unknown buffer ptr from USB");
1178
1179 return 0;
1180}
1181
1182void diag_read_work_fn(struct work_struct *work)
1183{
1184 APPEND_DEBUG('d');
1185 driver->usb_read_ptr->buf = driver->usb_buf_out;
1186 driver->usb_read_ptr->length = USB_MAX_OUT_BUF;
1187 usb_diag_read(driver->legacy_ch, driver->usb_read_ptr);
1188 APPEND_DEBUG('e');
1189}
1190
1191void diag_process_hdlc_fn(struct work_struct *work)
1192{
1193 APPEND_DEBUG('D');
1194 diag_process_hdlc(driver->usb_buf_out, driver->read_len_legacy);
1195 diag_read_work_fn(work);
1196 APPEND_DEBUG('E');
1197}
1198
1199void diag_usb_legacy_notifier(void *priv, unsigned event,
1200 struct diag_request *d_req)
1201{
1202 switch (event) {
1203 case USB_DIAG_CONNECT:
1204 diagfwd_connect();
1205 break;
1206 case USB_DIAG_DISCONNECT:
1207 diagfwd_disconnect();
1208 break;
1209 case USB_DIAG_READ_DONE:
1210 diagfwd_read_complete(d_req);
1211 break;
1212 case USB_DIAG_WRITE_DONE:
1213 diagfwd_write_complete(d_req);
1214 break;
1215 default:
1216 printk(KERN_ERR "Unknown event from USB diag\n");
1217 break;
1218 }
1219}
1220
1221#endif /* DIAG OVER USB */
1222
1223static void diag_smd_notify(void *ctxt, unsigned event)
1224{
Shalabh Jainc2ec8292011-10-14 12:34:55 -07001225 if (event == SMD_EVENT_CLOSE) {
Shalabh Jain7b20eab2012-06-19 17:50:58 -07001226 queue_work(driver->diag_cntl_wq,
1227 &(driver->diag_clean_modem_reg_work));
Shalabh Jaineefee052011-11-08 23:46:03 -08001228 driver->ch = 0;
1229 return;
1230 } else if (event == SMD_EVENT_OPEN) {
Shalabh Jainaeaab622012-06-04 18:01:02 -07001231 if (ch_temp)
1232 driver->ch = ch_temp;
Shalabh Jaineefee052011-11-08 23:46:03 -08001233 }
1234 queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001235}
1236
1237#if defined(CONFIG_MSM_N_WAY_SMD)
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001238static void diag_smd_lpass_notify(void *ctxt, unsigned event)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239{
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001240 if (event == SMD_EVENT_CLOSE) {
Shalabh Jain7b20eab2012-06-19 17:50:58 -07001241 queue_work(driver->diag_cntl_wq,
1242 &(driver->diag_clean_lpass_reg_work));
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001243 driver->chlpass = 0;
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001244 return;
1245 } else if (event == SMD_EVENT_OPEN) {
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001246 if (chlpass_temp)
1247 driver->chlpass = chlpass_temp;
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001248 }
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001249 queue_work(driver->diag_wq, &(driver->diag_read_smd_lpass_work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001250}
1251#endif
1252
1253static void diag_smd_wcnss_notify(void *ctxt, unsigned event)
1254{
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001255 if (event == SMD_EVENT_CLOSE) {
Shalabh Jain7b20eab2012-06-19 17:50:58 -07001256 queue_work(driver->diag_cntl_wq,
1257 &(driver->diag_clean_wcnss_reg_work));
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001258 driver->ch_wcnss = 0;
1259 return;
1260 } else if (event == SMD_EVENT_OPEN) {
Shalabh Jainaeaab622012-06-04 18:01:02 -07001261 if (ch_wcnss_temp)
1262 driver->ch_wcnss = ch_wcnss_temp;
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001263 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264 queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_work));
1265}
1266
1267static int diag_smd_probe(struct platform_device *pdev)
1268{
1269 int r = 0;
1270
Shalabh Jaineefee052011-11-08 23:46:03 -08001271 if (pdev->id == SMD_APPS_MODEM) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272 r = smd_open("DIAG", &driver->ch, driver, diag_smd_notify);
Shalabh Jaineefee052011-11-08 23:46:03 -08001273 ch_temp = driver->ch;
1274 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001275#if defined(CONFIG_MSM_N_WAY_SMD)
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001276 if (pdev->id == SMD_APPS_QDSP) {
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001277 r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP,
1278 &driver->chlpass, driver, diag_smd_lpass_notify);
1279 chlpass_temp = driver->chlpass;
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001280 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281#endif
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001282 if (pdev->id == SMD_APPS_WCNSS) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001283 r = smd_named_open_on_edge("APPS_RIVA_DATA", SMD_APPS_WCNSS
1284 , &driver->ch_wcnss, driver, diag_smd_wcnss_notify);
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001285 ch_wcnss_temp = driver->ch_wcnss;
1286 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001287 pm_runtime_set_active(&pdev->dev);
1288 pm_runtime_enable(&pdev->dev);
1289 pr_debug("diag: open SMD port, Id = %d, r = %d\n", pdev->id, r);
1290
1291 return 0;
1292}
1293
1294static int diagfwd_runtime_suspend(struct device *dev)
1295{
1296 dev_dbg(dev, "pm_runtime: suspending...\n");
1297 return 0;
1298}
1299
1300static int diagfwd_runtime_resume(struct device *dev)
1301{
1302 dev_dbg(dev, "pm_runtime: resuming...\n");
1303 return 0;
1304}
1305
1306static const struct dev_pm_ops diagfwd_dev_pm_ops = {
1307 .runtime_suspend = diagfwd_runtime_suspend,
1308 .runtime_resume = diagfwd_runtime_resume,
1309};
1310
1311static struct platform_driver msm_smd_ch1_driver = {
1312
1313 .probe = diag_smd_probe,
1314 .driver = {
1315 .name = "DIAG",
1316 .owner = THIS_MODULE,
1317 .pm = &diagfwd_dev_pm_ops,
1318 },
1319};
1320
1321static struct platform_driver diag_smd_lite_driver = {
1322
1323 .probe = diag_smd_probe,
1324 .driver = {
1325 .name = "APPS_RIVA_DATA",
1326 .owner = THIS_MODULE,
1327 .pm = &diagfwd_dev_pm_ops,
1328 },
1329};
1330
1331void diagfwd_init(void)
1332{
1333 diag_debug_buf_idx = 0;
1334 driver->read_len_legacy = 0;
Dixon Petersonb4618a42012-02-29 18:56:31 -08001335 driver->use_device_tree = has_device_tree();
Shalabh Jaina06c6d72012-04-30 13:40:35 -07001336 mutex_init(&driver->diag_cntl_mutex);
Shalabh Jain321c8b52012-02-22 12:37:06 -08001337
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338 if (driver->buf_in_1 == NULL) {
1339 driver->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1340 if (driver->buf_in_1 == NULL)
1341 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001342 kmemleak_not_leak(driver->buf_in_1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001343 }
1344 if (driver->buf_in_2 == NULL) {
1345 driver->buf_in_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1346 if (driver->buf_in_2 == NULL)
1347 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001348 kmemleak_not_leak(driver->buf_in_2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001349 }
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001350 if (driver->buf_in_lpass_1 == NULL) {
1351 driver->buf_in_lpass_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1352 if (driver->buf_in_lpass_1 == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001353 goto err;
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001354 kmemleak_not_leak(driver->buf_in_lpass_1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001355 }
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001356 if (driver->buf_in_lpass_2 == NULL) {
1357 driver->buf_in_lpass_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1358 if (driver->buf_in_lpass_2 == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001359 goto err;
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001360 kmemleak_not_leak(driver->buf_in_lpass_2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001361 }
Ashay Jaiswal29620122012-03-21 12:02:36 +05301362 if (driver->buf_in_wcnss_1 == NULL) {
1363 driver->buf_in_wcnss_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1364 if (driver->buf_in_wcnss_1 == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001365 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001366 kmemleak_not_leak(driver->buf_in_wcnss_1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001367 }
Ashay Jaiswal29620122012-03-21 12:02:36 +05301368 if (driver->buf_in_wcnss_2 == NULL) {
1369 driver->buf_in_wcnss_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1370 if (driver->buf_in_wcnss_2 == NULL)
1371 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001372 kmemleak_not_leak(driver->buf_in_wcnss_2);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301373 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374 if (driver->usb_buf_out == NULL &&
1375 (driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
1376 GFP_KERNEL)) == NULL)
1377 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001378 kmemleak_not_leak(driver->usb_buf_out);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001379 if (driver->hdlc_buf == NULL
1380 && (driver->hdlc_buf = kzalloc(HDLC_MAX, GFP_KERNEL)) == NULL)
1381 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001382 kmemleak_not_leak(driver->hdlc_buf);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001383 if (driver->user_space_data == NULL)
1384 driver->user_space_data = kzalloc(USER_SPACE_DATA, GFP_KERNEL);
1385 if (driver->user_space_data == NULL)
1386 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001387 kmemleak_not_leak(driver->user_space_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001388 if (driver->client_map == NULL &&
1389 (driver->client_map = kzalloc
1390 ((driver->num_clients) * sizeof(struct diag_client_map),
1391 GFP_KERNEL)) == NULL)
1392 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001393 kmemleak_not_leak(driver->client_map);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001394 if (driver->buf_tbl == NULL)
1395 driver->buf_tbl = kzalloc(buf_tbl_size *
1396 sizeof(struct diag_write_device), GFP_KERNEL);
1397 if (driver->buf_tbl == NULL)
1398 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001399 kmemleak_not_leak(driver->buf_tbl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001400 if (driver->data_ready == NULL &&
1401 (driver->data_ready = kzalloc(driver->num_clients * sizeof(int)
1402 , GFP_KERNEL)) == NULL)
1403 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001404 kmemleak_not_leak(driver->data_ready);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001405 if (driver->table == NULL &&
Shalabh Jainfe02b0c2012-02-21 14:48:03 -08001406 (driver->table = kzalloc(diag_max_reg*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001407 sizeof(struct diag_master_table),
1408 GFP_KERNEL)) == NULL)
1409 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001410 kmemleak_not_leak(driver->table);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001411 if (driver->write_ptr_1 == NULL) {
1412 driver->write_ptr_1 = kzalloc(
1413 sizeof(struct diag_request), GFP_KERNEL);
1414 if (driver->write_ptr_1 == NULL)
1415 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001416 kmemleak_not_leak(driver->write_ptr_1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001417 }
1418 if (driver->write_ptr_2 == NULL) {
1419 driver->write_ptr_2 = kzalloc(
1420 sizeof(struct diag_request), GFP_KERNEL);
1421 if (driver->write_ptr_2 == NULL)
1422 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001423 kmemleak_not_leak(driver->write_ptr_2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001424 }
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001425 if (driver->write_ptr_lpass_1 == NULL) {
1426 driver->write_ptr_lpass_1 = kzalloc(
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001427 sizeof(struct diag_request), GFP_KERNEL);
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001428 if (driver->write_ptr_lpass_1 == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001429 goto err;
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001430 kmemleak_not_leak(driver->write_ptr_lpass_1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001431 }
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001432 if (driver->write_ptr_lpass_2 == NULL) {
1433 driver->write_ptr_lpass_2 = kzalloc(
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434 sizeof(struct diag_request), GFP_KERNEL);
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001435 if (driver->write_ptr_lpass_2 == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436 goto err;
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001437 kmemleak_not_leak(driver->write_ptr_lpass_2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001438 }
Ashay Jaiswal29620122012-03-21 12:02:36 +05301439 if (driver->write_ptr_wcnss_1 == NULL) {
1440 driver->write_ptr_wcnss_1 = kzalloc(
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001441 sizeof(struct diag_request), GFP_KERNEL);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301442 if (driver->write_ptr_wcnss_1 == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001443 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001444 kmemleak_not_leak(driver->write_ptr_wcnss_1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445 }
Ashay Jaiswal29620122012-03-21 12:02:36 +05301446 if (driver->write_ptr_wcnss_2 == NULL) {
1447 driver->write_ptr_wcnss_2 = kzalloc(
1448 sizeof(struct diag_request), GFP_KERNEL);
1449 if (driver->write_ptr_wcnss_2 == NULL)
1450 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001451 kmemleak_not_leak(driver->write_ptr_wcnss_2);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301452 }
1453
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001454 if (driver->usb_read_ptr == NULL) {
1455 driver->usb_read_ptr = kzalloc(
1456 sizeof(struct diag_request), GFP_KERNEL);
1457 if (driver->usb_read_ptr == NULL)
1458 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001459 kmemleak_not_leak(driver->usb_read_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001460 }
1461 if (driver->pkt_buf == NULL &&
1462 (driver->pkt_buf = kzalloc(PKT_SIZE,
1463 GFP_KERNEL)) == NULL)
1464 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001465 kmemleak_not_leak(driver->pkt_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001466 if (driver->apps_rsp_buf == NULL) {
Shalabh Jain321c8b52012-02-22 12:37:06 -08001467 driver->apps_rsp_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001468 if (driver->apps_rsp_buf == NULL)
1469 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001470 kmemleak_not_leak(driver->apps_rsp_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001471 }
1472 driver->diag_wq = create_singlethread_workqueue("diag_wq");
1473#ifdef CONFIG_DIAG_OVER_USB
1474 INIT_WORK(&(driver->diag_proc_hdlc_work), diag_process_hdlc_fn);
1475 INIT_WORK(&(driver->diag_read_work), diag_read_work_fn);
1476 driver->legacy_ch = usb_diag_open(DIAG_LEGACY, driver,
1477 diag_usb_legacy_notifier);
1478 if (IS_ERR(driver->legacy_ch)) {
1479 printk(KERN_ERR "Unable to open USB diag legacy channel\n");
1480 goto err;
1481 }
1482#endif
1483 platform_driver_register(&msm_smd_ch1_driver);
1484 platform_driver_register(&diag_smd_lite_driver);
1485
1486 return;
1487err:
Dixon Petersond6a20a92012-09-27 15:58:50 -07001488 pr_err("diag: Could not initialize diag buffers");
1489 kfree(driver->buf_in_1);
1490 kfree(driver->buf_in_2);
1491 kfree(driver->buf_in_lpass_1);
1492 kfree(driver->buf_in_lpass_2);
1493 kfree(driver->buf_in_wcnss_1);
1494 kfree(driver->buf_in_wcnss_2);
1495 kfree(driver->buf_msg_mask_update);
1496 kfree(driver->buf_log_mask_update);
1497 kfree(driver->buf_event_mask_update);
1498 kfree(driver->usb_buf_out);
1499 kfree(driver->hdlc_buf);
1500 kfree(driver->client_map);
1501 kfree(driver->buf_tbl);
1502 kfree(driver->data_ready);
1503 kfree(driver->table);
1504 kfree(driver->pkt_buf);
1505 kfree(driver->write_ptr_1);
1506 kfree(driver->write_ptr_2);
1507 kfree(driver->write_ptr_lpass_1);
1508 kfree(driver->write_ptr_lpass_2);
1509 kfree(driver->write_ptr_wcnss_1);
1510 kfree(driver->write_ptr_wcnss_2);
1511 kfree(driver->usb_read_ptr);
1512 kfree(driver->apps_rsp_buf);
1513 kfree(driver->user_space_data);
1514 if (driver->diag_wq)
1515 destroy_workqueue(driver->diag_wq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516}
1517
1518void diagfwd_exit(void)
1519{
1520 smd_close(driver->ch);
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001521 smd_close(driver->chlpass);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522 smd_close(driver->ch_wcnss);
1523 driver->ch = 0; /* SMD can make this NULL */
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001524 driver->chlpass = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001525 driver->ch_wcnss = 0;
1526#ifdef CONFIG_DIAG_OVER_USB
1527 if (driver->usb_connected)
1528 usb_diag_free_req(driver->legacy_ch);
1529 usb_diag_close(driver->legacy_ch);
1530#endif
1531 platform_driver_unregister(&msm_smd_ch1_driver);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001532 platform_driver_unregister(&msm_diag_dci_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533 platform_driver_unregister(&diag_smd_lite_driver);
1534 kfree(driver->buf_in_1);
1535 kfree(driver->buf_in_2);
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001536 kfree(driver->buf_in_lpass_1);
1537 kfree(driver->buf_in_lpass_2);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301538 kfree(driver->buf_in_wcnss_1);
1539 kfree(driver->buf_in_wcnss_2);
Shalabh Jain321c8b52012-02-22 12:37:06 -08001540 kfree(driver->buf_msg_mask_update);
1541 kfree(driver->buf_log_mask_update);
1542 kfree(driver->buf_event_mask_update);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001543 kfree(driver->usb_buf_out);
1544 kfree(driver->hdlc_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545 kfree(driver->client_map);
1546 kfree(driver->buf_tbl);
1547 kfree(driver->data_ready);
1548 kfree(driver->table);
1549 kfree(driver->pkt_buf);
1550 kfree(driver->write_ptr_1);
1551 kfree(driver->write_ptr_2);
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001552 kfree(driver->write_ptr_lpass_1);
1553 kfree(driver->write_ptr_lpass_2);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301554 kfree(driver->write_ptr_wcnss_1);
1555 kfree(driver->write_ptr_wcnss_2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001556 kfree(driver->usb_read_ptr);
1557 kfree(driver->apps_rsp_buf);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001558 kfree(driver->user_space_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001559 destroy_workqueue(driver->diag_wq);
1560}