blob: bc9d3fa7436e357be01440ad7486e9efdf123f2e [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 Jain737fca72012-11-14 21:53:43 -080043#include "diagfwd_bridge.h"
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070044
Shalabh Jain6a2ca7c2012-04-10 14:35:15 -070045#define MODE_CMD 41
46#define RESET_ID 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070047
48int diag_debug_buf_idx;
49unsigned char diag_debug_buf[1024];
50static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
51struct diag_master_table entry;
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{
Dixon Peterson66fb11b2012-12-04 20:30:54 -080057 struct diag_smd_info *data = &(driver->smd_data[SMD_MODEM_INDEX]);
Dixon Petersond6a20a92012-09-27 15:58:50 -070058 send.state = DIAG_STATE_START;
59 send.pkt = driver->apps_rsp_buf;
60 send.last = (void *)(driver->apps_rsp_buf + buf_length);
61 send.terminate = 1;
Dixon Peterson66fb11b2012-12-04 20:30:54 -080062 if (!data->in_busy_1) {
63 enc.dest = data->buf_in_1;
64 enc.dest_last = (void *)(data->buf_in_1 + APPS_BUF_SIZE - 1);
Dixon Petersond6a20a92012-09-27 15:58:50 -070065 diag_hdlc_encode(&send, &enc);
Dixon Peterson66fb11b2012-12-04 20:30:54 -080066 data->write_ptr_1->buf = data->buf_in_1;
67 data->write_ptr_1->length = (int)(enc.dest -
68 (void *)(data->buf_in_1));
69 data->in_busy_1 = 1;
70 diag_device_write(data->buf_in_1, MODEM_DATA,
71 data->write_ptr_1);
Dixon Petersond6a20a92012-09-27 15:58:50 -070072 memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);
73 }
74}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070075
Dixon Petersonb4618a42012-02-29 18:56:31 -080076/* Determine if this device uses a device tree */
77#ifdef CONFIG_OF
78static int has_device_tree(void)
79{
80 struct device_node *node;
81
82 node = of_find_node_by_path("/");
83 if (node) {
84 of_node_put(node);
85 return 1;
86 }
87 return 0;
88}
89#else
90static int has_device_tree(void)
91{
92 return 0;
93}
94#endif
95
Shalabh Jainfb8e3c12011-10-19 17:29:42 -070096int chk_config_get_id(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070097{
Shalabh Jain482bf122011-12-06 03:54:47 -080098 /* For all Fusion targets, Modem will always be present */
99 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
100 return 0;
101
Dixon Petersonb4618a42012-02-29 18:56:31 -0800102 if (driver->use_device_tree) {
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700103 if (machine_is_msm8974())
Dixon Petersonb4618a42012-02-29 18:56:31 -0800104 return MSM8974_TOOLS_ID;
105 else
106 return 0;
107 } else {
108 switch (socinfo_get_msm_cpu()) {
109 case MSM_CPU_8X60:
110 return APQ8060_TOOLS_ID;
111 case MSM_CPU_8960:
Stepan Moskovchenko9c749262012-07-09 19:30:44 -0700112 case MSM_CPU_8960AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800113 return AO8960_TOOLS_ID;
114 case MSM_CPU_8064:
Jay Chokshi11abd8b2012-09-20 14:35:17 -0700115 case MSM_CPU_8064AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800116 return APQ8064_TOOLS_ID;
117 case MSM_CPU_8930:
Stepan Moskovchenko0df9bb22012-07-06 18:19:15 -0700118 case MSM_CPU_8930AA:
Stepan Moskovchenkoecb0d9b2012-10-16 18:35:34 -0700119 case MSM_CPU_8930AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800120 return MSM8930_TOOLS_ID;
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700121 case MSM_CPU_8974:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800122 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:
Stepan Moskovchenko9c749262012-07-09 19:30:44 -0700142 case MSM_CPU_8960AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800143 case MSM_CPU_8064:
Jay Chokshi11abd8b2012-09-20 14:35:17 -0700144 case MSM_CPU_8064AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800145 case MSM_CPU_8930:
Stepan Moskovchenko0df9bb22012-07-06 18:19:15 -0700146 case MSM_CPU_8930AA:
Stepan Moskovchenkoecb0d9b2012-10-16 18:35:34 -0700147 case MSM_CPU_8930AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800148 case MSM_CPU_8627:
149 case MSM_CPU_9615:
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700150 case MSM_CPU_8974:
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700151 return 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152 default:
153 return 0;
154 }
155}
156
Shalabh Jain10f5f432012-01-11 11:45:44 +0530157/*
158 * This will return TRUE for targets which support apps as master.
159 * Thus, SW DLOAD and Mode Reset are supported on apps processor.
160 * This applies to 8960 and newer targets.
161 */
162int chk_apps_master(void)
163{
Dixon Petersonb4618a42012-02-29 18:56:31 -0800164 if (driver->use_device_tree)
165 return 1;
Stepan Moskovchenko5b9e7762012-09-21 20:32:17 -0700166 else if (soc_class_is_msm8960() || soc_class_is_msm8930() ||
167 soc_class_is_apq8064() || cpu_is_msm9615())
Dixon Petersonb4618a42012-02-29 18:56:31 -0800168 return 1;
169 else
170 return 0;
171}
172
Dixon Peterson29aebee2012-04-06 12:44:08 -0700173int chk_polling_response(void)
Dixon Petersonb4618a42012-02-29 18:56:31 -0800174{
175 if (!(driver->polling_reg_flag) && chk_apps_master())
176 /*
177 * If the apps processor is master and no other processor
178 * has registered to respond for polling
179 */
180 return 1;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800181 else if (!(driver->smd_data[SMD_MODEM_INDEX].ch) &&
182 !(chk_apps_master()))
Dixon Petersonb4618a42012-02-29 18:56:31 -0800183 /*
184 * If the apps processor is not the master and the modem
185 * is not up
186 */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530187 return 1;
188 else
189 return 0;
190}
191
Dixon Peterson743a11e2012-07-30 17:42:20 -0700192/*
193 * This function should be called if you feel that the logging process may
194 * need to be woken up. For instance, if the logging mode is MEMORY_DEVICE MODE
195 * and while trying to read data from a SMD data channel there are no buffers
196 * available to read the data into, then this function should be called to
197 * determine if the logging process needs to be woken up.
198 */
199void chk_logging_wakeup(void)
200{
201 int i;
202
203 /* Find the index of the logging process */
204 for (i = 0; i < driver->num_clients; i++)
205 if (driver->client_map[i].pid ==
206 driver->logging_process_id)
207 break;
208
209 if (i < driver->num_clients) {
210 /* At very high logging rates a race condition can
211 * occur where the buffers containing the data from
212 * an smd channel are all in use, but the data_ready
213 * flag is cleared. In this case, the buffers never
214 * have their data read/logged. Detect and remedy this
215 * situation.
216 */
Shalabh Jain84e30342012-10-16 16:16:08 -0700217 if ((driver->data_ready[i] & USER_SPACE_DATA_TYPE) == 0) {
218 driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
Dixon Peterson743a11e2012-07-30 17:42:20 -0700219 pr_debug("diag: Force wakeup of logging process\n");
220 wake_up_interruptible(&driver->wait_q);
221 }
222 }
223}
224
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800225/* Process the data read from the smd data channel */
226int diag_process_smd_read_data(struct diag_smd_info *smd_info, void *buf,
227 int total_recd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229 struct diag_request *write_ptr_modem = NULL;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800230 int *in_busy_ptr = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800232 if (smd_info->buf_in_1 == buf) {
233 write_ptr_modem = smd_info->write_ptr_1;
234 in_busy_ptr = &smd_info->in_busy_1;
235 } else if (smd_info->buf_in_2 == buf) {
236 write_ptr_modem = smd_info->write_ptr_2;
237 in_busy_ptr = &smd_info->in_busy_2;
238 } else {
239 pr_err("diag: In %s, no match for in_busy_1\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700240 }
241
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800242 if (write_ptr_modem) {
243 int data_type;
244 switch (smd_info->peripheral) {
245 case MODEM_PROC:
246 data_type = MODEM_DATA;
247 break;
248 case LPASS_PROC:
249 data_type = LPASS_DATA;
250 break;
251 case WCNSS_PROC:
252 data_type = WCNSS_DATA;
253 break;
254 default:
255 pr_err("diag: In %s, unknown peripheral type: %d\n",
256 __func__, smd_info->peripheral);
257 return 0;
258 }
259 write_ptr_modem->length = total_recd;
260 *in_busy_ptr = 1;
261 diag_device_write(buf, data_type, write_ptr_modem);
262 }
263
264 return 0;
265}
266
267void diag_smd_send_req(struct diag_smd_info *smd_info)
268{
269 void *buf = NULL, *temp_buf = NULL;
270 int total_recd = 0, r = 0, pkt_len;
271 int loop_count = 0;
272 int notify = 0;
273
274 if (!smd_info) {
275 pr_err("diag: In %s, no smd info. Not able to read.\n",
276 __func__);
277 return;
278 }
279
280 if (!smd_info->in_busy_1)
281 buf = smd_info->buf_in_1;
282 else if ((smd_info->type == SMD_DATA_TYPE) && !smd_info->in_busy_2)
283 buf = smd_info->buf_in_2;
284
285 if (smd_info->ch && buf) {
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700286 temp_buf = buf;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800287 pkt_len = smd_cur_packet_size(smd_info->ch);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700289 while (pkt_len && (pkt_len != total_recd)) {
290 loop_count++;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800291 r = smd_read_avail(smd_info->ch);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700292 pr_debug("diag: In %s, received pkt %d %d\n",
293 __func__, r, total_recd);
294 if (!r) {
295 /* Nothing to read from SMD */
296 wait_event(driver->smd_wait_q,
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800297 ((smd_info->ch == 0) ||
298 smd_read_avail(smd_info->ch)));
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700299 /* If the smd channel is open */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800300 if (smd_info->ch) {
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700301 pr_debug("diag: In %s, return from wait_event\n",
302 __func__);
303 continue;
304 } else {
305 pr_debug("diag: In %s, return from wait_event ch closed\n",
306 __func__);
307 return;
308 }
309 }
310 total_recd += r;
311 if (total_recd > IN_BUF_SIZE) {
312 if (total_recd < MAX_IN_BUF_SIZE) {
313 pr_err("diag: In %s, SMD sending in packets up to %d bytes\n",
314 __func__, total_recd);
315 buf = krealloc(buf, total_recd,
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800316 GFP_KERNEL);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700317 } else {
318 pr_err("diag: In %s, SMD sending in packets more than %d bytes\n",
319 __func__, MAX_IN_BUF_SIZE);
320 return;
321 }
322 }
323 if (pkt_len < r) {
324 pr_err("diag: In %s, SMD sending incorrect pkt\n",
325 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700326 return;
327 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800328 if (pkt_len > r) {
329 pr_err("diag: In %s, SMD sending partial pkt %d %d %d %d %d %d\n",
330 __func__, pkt_len, r, total_recd, loop_count,
331 smd_info->peripheral, smd_info->type);
332 }
333
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700334 /* keep reading for complete packet */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800335 smd_read(smd_info->ch, temp_buf, r);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700336 temp_buf += r;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337 }
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700338
339 if (total_recd > 0) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800340 if (!buf) {
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700341 pr_err("diag: Out of diagmem for Modem\n");
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800342 } else if (smd_info->process_smd_read_data) {
343 notify = smd_info->process_smd_read_data(
344 smd_info, buf, total_recd);
345 /* Poll SMD channels to check for data */
346 if (notify)
347 diag_smd_notify(smd_info,
348 SMD_EVENT_DATA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700349 }
350 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800351 } else if (smd_info->ch && !buf &&
Dixon Peterson743a11e2012-07-30 17:42:20 -0700352 (driver->logging_mode == MEMORY_DEVICE_MODE)) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800353 chk_logging_wakeup();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354 }
355}
356
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800357void diag_read_smd_work_fn(struct work_struct *work)
358{
359 struct diag_smd_info *smd_info = container_of(work,
360 struct diag_smd_info,
361 diag_read_smd_work);
362 diag_smd_send_req(smd_info);
363}
364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700365int diag_device_write(void *buf, int proc_num, struct diag_request *write_ptr)
366{
367 int i, err = 0;
368
369 if (driver->logging_mode == MEMORY_DEVICE_MODE) {
370 if (proc_num == APPS_DATA) {
371 for (i = 0; i < driver->poolsize_write_struct; i++)
372 if (driver->buf_tbl[i].length == 0) {
373 driver->buf_tbl[i].buf = buf;
374 driver->buf_tbl[i].length =
375 driver->used;
376#ifdef DIAG_DEBUG
377 pr_debug("diag: ENQUEUE buf ptr"
378 " and length is %x , %d\n",
379 (unsigned int)(driver->buf_
380 tbl[i].buf), driver->buf_tbl[i].length);
381#endif
382 break;
383 }
384 }
Dixon Peterson938f8602012-08-17 20:02:57 -0700385
Shalabh Jain737fca72012-11-14 21:53:43 -0800386#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Dixon Peterson938f8602012-08-17 20:02:57 -0700387 else if (proc_num == HSIC_DATA) {
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700388 unsigned long flags;
389 int foundIndex = -1;
390
391 spin_lock_irqsave(&driver->hsic_spinlock, flags);
Dixon Peterson938f8602012-08-17 20:02:57 -0700392 for (i = 0; i < driver->poolsize_hsic_write; i++) {
393 if (driver->hsic_buf_tbl[i].length == 0) {
394 driver->hsic_buf_tbl[i].buf = buf;
395 driver->hsic_buf_tbl[i].length =
Shalabh Jain737fca72012-11-14 21:53:43 -0800396 diag_bridge[HSIC].write_len;
Dixon Peterson938f8602012-08-17 20:02:57 -0700397 driver->num_hsic_buf_tbl_entries++;
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700398 foundIndex = i;
Dixon Peterson938f8602012-08-17 20:02:57 -0700399 break;
400 }
401 }
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700402 spin_unlock_irqrestore(&driver->hsic_spinlock, flags);
403 if (foundIndex == -1)
404 err = -1;
405 else
406 pr_debug("diag: ENQUEUE HSIC buf ptr and length is %x , %d\n",
407 (unsigned int)buf,
Shalabh Jain737fca72012-11-14 21:53:43 -0800408 diag_bridge[HSIC].write_len);
Dixon Peterson938f8602012-08-17 20:02:57 -0700409 }
410#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411 for (i = 0; i < driver->num_clients; i++)
412 if (driver->client_map[i].pid ==
413 driver->logging_process_id)
414 break;
415 if (i < driver->num_clients) {
Shalabh Jain84e30342012-10-16 16:16:08 -0700416 driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700417 pr_debug("diag: wake up logging process\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700418 wake_up_interruptible(&driver->wait_q);
419 } else
420 return -EINVAL;
421 } else if (driver->logging_mode == NO_LOGGING_MODE) {
422 if (proc_num == MODEM_DATA) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800423 driver->smd_data[SMD_MODEM_INDEX].in_busy_1 = 0;
424 driver->smd_data[SMD_MODEM_INDEX].in_busy_2 = 0;
425 queue_work(driver->diag_wq,
426 &(driver->smd_data[SMD_MODEM_INDEX].
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427 diag_read_smd_work));
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -0700428 } else if (proc_num == LPASS_DATA) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800429 driver->smd_data[SMD_LPASS_INDEX].in_busy_1 = 0;
430 driver->smd_data[SMD_LPASS_INDEX].in_busy_2 = 0;
431 queue_work(driver->diag_wq,
432 &(driver->smd_data[SMD_LPASS_INDEX].
433 diag_read_smd_work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434 } else if (proc_num == WCNSS_DATA) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800435 driver->smd_data[SMD_WCNSS_INDEX].in_busy_1 = 0;
436 driver->smd_data[SMD_WCNSS_INDEX].in_busy_2 = 0;
437 queue_work(driver->diag_wq,
438 &(driver->smd_data[SMD_WCNSS_INDEX].
439 diag_read_smd_work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 }
Shalabh Jain482bf122011-12-06 03:54:47 -0800441#ifdef CONFIG_DIAG_SDIO_PIPE
442 else if (proc_num == SDIO_DATA) {
443 driver->in_busy_sdio = 0;
444 queue_work(driver->diag_sdio_wq,
445 &(driver->diag_read_sdio_work));
446 }
447#endif
Shalabh Jain737fca72012-11-14 21:53:43 -0800448#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700449 else if (proc_num == HSIC_DATA) {
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700450 if (driver->hsic_ch)
Shalabh Jain737fca72012-11-14 21:53:43 -0800451 queue_work(diag_bridge[HSIC].wq,
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700452 &(driver->diag_read_hsic_work));
453 }
454#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700455 err = -1;
456 }
457#ifdef CONFIG_DIAG_OVER_USB
458 else if (driver->logging_mode == USB_MODE) {
459 if (proc_num == APPS_DATA) {
460 driver->write_ptr_svc = (struct diag_request *)
461 (diagmem_alloc(driver, sizeof(struct diag_request),
462 POOL_TYPE_WRITE_STRUCT));
463 if (driver->write_ptr_svc) {
464 driver->write_ptr_svc->length = driver->used;
465 driver->write_ptr_svc->buf = buf;
466 err = usb_diag_write(driver->legacy_ch,
467 driver->write_ptr_svc);
468 } else
469 err = -1;
470 } else if (proc_num == MODEM_DATA) {
471 write_ptr->buf = buf;
472#ifdef DIAG_DEBUG
473 printk(KERN_INFO "writing data to USB,"
474 "pkt length %d\n", write_ptr->length);
475 print_hex_dump(KERN_DEBUG, "Written Packet Data to"
476 " USB: ", 16, 1, DUMP_PREFIX_ADDRESS,
477 buf, write_ptr->length, 1);
478#endif /* DIAG DEBUG */
479 err = usb_diag_write(driver->legacy_ch, write_ptr);
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -0700480 } else if (proc_num == LPASS_DATA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700481 write_ptr->buf = buf;
482 err = usb_diag_write(driver->legacy_ch, write_ptr);
483 } else if (proc_num == WCNSS_DATA) {
484 write_ptr->buf = buf;
485 err = usb_diag_write(driver->legacy_ch, write_ptr);
486 }
487#ifdef CONFIG_DIAG_SDIO_PIPE
488 else if (proc_num == SDIO_DATA) {
489 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -0800490 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700491 write_ptr->buf = buf;
492 err = usb_diag_write(driver->mdm_ch, write_ptr);
493 } else
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800494 pr_err("diag: Incorrect sdio data "
495 "while USB write\n");
496 }
497#endif
Shalabh Jain737fca72012-11-14 21:53:43 -0800498#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800499 else if (proc_num == HSIC_DATA) {
500 if (driver->hsic_device_enabled) {
Dixon Peterson938f8602012-08-17 20:02:57 -0700501 struct diag_request *write_ptr_mdm;
502 write_ptr_mdm = (struct diag_request *)
503 diagmem_alloc(driver,
504 sizeof(struct diag_request),
505 POOL_TYPE_HSIC_WRITE);
506 if (write_ptr_mdm) {
507 write_ptr_mdm->buf = buf;
508 write_ptr_mdm->length =
Shalabh Jain737fca72012-11-14 21:53:43 -0800509 diag_bridge[HSIC].write_len;
510 write_ptr_mdm->context = (void *)HSIC;
511 err = usb_diag_write(
512 diag_bridge[HSIC].ch, write_ptr_mdm);
Dixon Peterson938f8602012-08-17 20:02:57 -0700513 /* Return to the pool immediately */
514 if (err) {
515 diagmem_free(driver,
516 write_ptr_mdm,
517 POOL_TYPE_HSIC_WRITE);
Dixon Peterson6beff2d2012-09-13 18:51:47 -0700518 pr_err_ratelimited("diag: HSIC write failure, err: %d\n",
519 err);
Dixon Peterson938f8602012-08-17 20:02:57 -0700520 }
521 } else {
522 pr_err("diag: allocate write fail\n");
523 err = -1;
524 }
525 } else {
Shalabh Jain737fca72012-11-14 21:53:43 -0800526 pr_err("diag: Incorrect HSIC data "
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800527 "while USB write\n");
Dixon Peterson938f8602012-08-17 20:02:57 -0700528 err = -1;
529 }
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700530 } else if (proc_num == SMUX_DATA) {
531 write_ptr->buf = buf;
Shalabh Jain737fca72012-11-14 21:53:43 -0800532 write_ptr->context = (void *)SMUX;
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700533 pr_debug("diag: writing SMUX data\n");
Shalabh Jain737fca72012-11-14 21:53:43 -0800534 err = usb_diag_write(diag_bridge[SMUX].ch,
535 write_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700536 }
537#endif
538 APPEND_DEBUG('d');
539 }
540#endif /* DIAG OVER USB */
541 return err;
542}
543
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700544static void diag_update_pkt_buffer(unsigned char *buf)
545{
546 unsigned char *ptr = driver->pkt_buf;
547 unsigned char *temp = buf;
548
549 mutex_lock(&driver->diagchar_mutex);
550 if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, driver->pkt_length))
551 memcpy(ptr, temp , driver->pkt_length);
552 else
553 printk(KERN_CRIT " Not enough buffer space for PKT_RESP\n");
554 mutex_unlock(&driver->diagchar_mutex);
555}
556
557void diag_update_userspace_clients(unsigned int type)
558{
559 int i;
560
561 mutex_lock(&driver->diagchar_mutex);
562 for (i = 0; i < driver->num_clients; i++)
563 if (driver->client_map[i].pid != 0)
564 driver->data_ready[i] |= type;
565 wake_up_interruptible(&driver->wait_q);
566 mutex_unlock(&driver->diagchar_mutex);
567}
568
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700569void diag_update_sleeping_process(int process_id, int data_type)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700570{
571 int i;
572
573 mutex_lock(&driver->diagchar_mutex);
574 for (i = 0; i < driver->num_clients; i++)
575 if (driver->client_map[i].pid == process_id) {
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700576 driver->data_ready[i] |= data_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700577 break;
578 }
579 wake_up_interruptible(&driver->wait_q);
580 mutex_unlock(&driver->diagchar_mutex);
581}
582
583void diag_send_data(struct diag_master_table entry, unsigned char *buf,
584 int len, int type)
585{
586 driver->pkt_length = len;
587 if (entry.process_id != NON_APPS_PROC && type != MODEM_DATA) {
588 diag_update_pkt_buffer(buf);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700589 diag_update_sleeping_process(entry.process_id, PKT_TYPE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700590 } else {
591 if (len > 0) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800592 if (entry.client_id == MODEM_PROC &&
593 driver->smd_data[SMD_MODEM_INDEX].ch) {
Shalabh Jain10f5f432012-01-11 11:45:44 +0530594 if (chk_apps_master() &&
Shalabh Jainc9f35092011-07-28 18:36:17 -0700595 (int)(*(char *)buf) == MODE_CMD)
Dixon Petersonff425d12011-12-06 18:12:35 -0800596 if ((int)(*(char *)(buf+1)) ==
597 RESET_ID)
Shalabh Jainc9f35092011-07-28 18:36:17 -0700598 return;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800599 smd_write(driver->smd_data[SMD_MODEM_INDEX].ch,
600 buf, len);
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -0700601 } else if (entry.client_id == LPASS_PROC &&
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800602 driver->smd_data[SMD_LPASS_INDEX].ch) {
603 smd_write(driver->smd_data[SMD_LPASS_INDEX].ch,
604 buf, len);
Shalabh Jainc9f35092011-07-28 18:36:17 -0700605 } else if (entry.client_id == WCNSS_PROC &&
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800606 driver->smd_data[SMD_WCNSS_INDEX].ch) {
607 smd_write(driver->smd_data[SMD_WCNSS_INDEX].ch,
608 buf, len);
Shalabh Jainc9f35092011-07-28 18:36:17 -0700609 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610 pr_alert("diag: incorrect channel");
Shalabh Jainc9f35092011-07-28 18:36:17 -0700611 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700612 }
613 }
614}
615
616static int diag_process_apps_pkt(unsigned char *buf, int len)
617{
618 uint16_t subsys_cmd_code;
619 int subsys_id, ssid_first, ssid_last, ssid_range;
Shalabh Jain3fd986f2012-05-30 18:42:26 -0700620 int packet_type = 1, i, cmd_code;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621 unsigned char *temp = buf;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700622 int data_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700623#if defined(CONFIG_DIAG_OVER_USB)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700624 unsigned char *ptr;
625#endif
626
Dixon Petersond6a20a92012-09-27 15:58:50 -0700627 /* Check if the command is a supported mask command */
628 if (diag_process_apps_masks(buf, len) == 0)
629 return 0;
630
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700631 /* Check for registered clients and forward packet to apropriate proc */
632 cmd_code = (int)(*(char *)buf);
633 temp++;
634 subsys_id = (int)(*(char *)temp);
635 temp++;
636 subsys_cmd_code = *(uint16_t *)temp;
637 temp += 2;
638 data_type = APPS_DATA;
639 /* Dont send any command other than mode reset */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530640 if (chk_apps_master() && cmd_code == MODE_CMD) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700641 if (subsys_id != RESET_ID)
642 data_type = MODEM_DATA;
643 }
644
645 pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
Shalabh Jainfe02b0c2012-02-21 14:48:03 -0800646 for (i = 0; i < diag_max_reg; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700647 entry = driver->table[i];
648 if (entry.process_id != NO_PROCESS) {
649 if (entry.cmd_code == cmd_code && entry.subsys_id ==
650 subsys_id && entry.cmd_code_lo <=
651 subsys_cmd_code &&
652 entry.cmd_code_hi >= subsys_cmd_code) {
653 diag_send_data(entry, buf, len, data_type);
654 packet_type = 0;
655 } else if (entry.cmd_code == 255
656 && cmd_code == 75) {
657 if (entry.subsys_id ==
658 subsys_id &&
659 entry.cmd_code_lo <=
660 subsys_cmd_code &&
661 entry.cmd_code_hi >=
662 subsys_cmd_code) {
663 diag_send_data(entry, buf, len,
664 data_type);
665 packet_type = 0;
666 }
667 } else if (entry.cmd_code == 255 &&
668 entry.subsys_id == 255) {
669 if (entry.cmd_code_lo <=
670 cmd_code &&
671 entry.
672 cmd_code_hi >= cmd_code) {
673 diag_send_data(entry, buf, len,
674 data_type);
675 packet_type = 0;
676 }
677 }
678 }
679 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700680#if defined(CONFIG_DIAG_OVER_USB)
Dixon Petersona2dd7352012-05-21 17:37:10 -0700681 /* Check for the command/respond msg for the maximum packet length */
682 if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
683 (*(uint16_t *)(buf+2) == 0x0055)) {
684 for (i = 0; i < 4; i++)
685 *(driver->apps_rsp_buf+i) = *(buf+i);
686 *(uint32_t *)(driver->apps_rsp_buf+4) = PKT_SIZE;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700687 encode_rsp_and_send(7);
Dixon Petersona2dd7352012-05-21 17:37:10 -0700688 return 0;
689 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700690 /* Check for Apps Only & get event mask request */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800691 else if (!(driver->smd_data[SMD_MODEM_INDEX].ch) && chk_apps_only() &&
692 *buf == 0x81) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700693 driver->apps_rsp_buf[0] = 0x81;
694 driver->apps_rsp_buf[1] = 0x0;
695 *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
696 *(uint16_t *)(driver->apps_rsp_buf + 4) = EVENT_LAST_ID + 1;
697 for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
698 *(unsigned char *)(driver->apps_rsp_buf + 6 + i) = 0x0;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700699 encode_rsp_and_send(6 + EVENT_LAST_ID/8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700700 return 0;
701 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700702 /* Get log ID range & Check for Apps Only */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800703 else if (!(driver->smd_data[SMD_MODEM_INDEX].ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700704 && (*buf == 0x73) && *(int *)(buf+4) == 1) {
705 driver->apps_rsp_buf[0] = 0x73;
706 *(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
707 *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success code */
708 *(int *)(driver->apps_rsp_buf + 12) = LOG_GET_ITEM_NUM(LOG_0);
709 *(int *)(driver->apps_rsp_buf + 16) = LOG_GET_ITEM_NUM(LOG_1);
710 *(int *)(driver->apps_rsp_buf + 20) = LOG_GET_ITEM_NUM(LOG_2);
711 *(int *)(driver->apps_rsp_buf + 24) = LOG_GET_ITEM_NUM(LOG_3);
712 *(int *)(driver->apps_rsp_buf + 28) = LOG_GET_ITEM_NUM(LOG_4);
713 *(int *)(driver->apps_rsp_buf + 32) = LOG_GET_ITEM_NUM(LOG_5);
714 *(int *)(driver->apps_rsp_buf + 36) = LOG_GET_ITEM_NUM(LOG_6);
715 *(int *)(driver->apps_rsp_buf + 40) = LOG_GET_ITEM_NUM(LOG_7);
716 *(int *)(driver->apps_rsp_buf + 44) = LOG_GET_ITEM_NUM(LOG_8);
717 *(int *)(driver->apps_rsp_buf + 48) = LOG_GET_ITEM_NUM(LOG_9);
718 *(int *)(driver->apps_rsp_buf + 52) = LOG_GET_ITEM_NUM(LOG_10);
719 *(int *)(driver->apps_rsp_buf + 56) = LOG_GET_ITEM_NUM(LOG_11);
720 *(int *)(driver->apps_rsp_buf + 60) = LOG_GET_ITEM_NUM(LOG_12);
721 *(int *)(driver->apps_rsp_buf + 64) = LOG_GET_ITEM_NUM(LOG_13);
722 *(int *)(driver->apps_rsp_buf + 68) = LOG_GET_ITEM_NUM(LOG_14);
723 *(int *)(driver->apps_rsp_buf + 72) = LOG_GET_ITEM_NUM(LOG_15);
Dixon Petersond6a20a92012-09-27 15:58:50 -0700724 encode_rsp_and_send(75);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700725 return 0;
726 }
727 /* Respond to Get SSID Range request message */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800728 else if (!(driver->smd_data[SMD_MODEM_INDEX].ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700729 && (*buf == 0x7d) && (*(buf+1) == 0x1)) {
730 driver->apps_rsp_buf[0] = 0x7d;
731 driver->apps_rsp_buf[1] = 0x1;
732 driver->apps_rsp_buf[2] = 0x1;
733 driver->apps_rsp_buf[3] = 0x0;
Shalabh Jain44b79b72012-06-15 13:39:27 -0700734 /* -1 to un-account for OEM SSID range */
735 *(int *)(driver->apps_rsp_buf + 4) = MSG_MASK_TBL_CNT - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700736 *(uint16_t *)(driver->apps_rsp_buf + 8) = MSG_SSID_0;
737 *(uint16_t *)(driver->apps_rsp_buf + 10) = MSG_SSID_0_LAST;
738 *(uint16_t *)(driver->apps_rsp_buf + 12) = MSG_SSID_1;
739 *(uint16_t *)(driver->apps_rsp_buf + 14) = MSG_SSID_1_LAST;
740 *(uint16_t *)(driver->apps_rsp_buf + 16) = MSG_SSID_2;
741 *(uint16_t *)(driver->apps_rsp_buf + 18) = MSG_SSID_2_LAST;
742 *(uint16_t *)(driver->apps_rsp_buf + 20) = MSG_SSID_3;
743 *(uint16_t *)(driver->apps_rsp_buf + 22) = MSG_SSID_3_LAST;
744 *(uint16_t *)(driver->apps_rsp_buf + 24) = MSG_SSID_4;
745 *(uint16_t *)(driver->apps_rsp_buf + 26) = MSG_SSID_4_LAST;
746 *(uint16_t *)(driver->apps_rsp_buf + 28) = MSG_SSID_5;
747 *(uint16_t *)(driver->apps_rsp_buf + 30) = MSG_SSID_5_LAST;
748 *(uint16_t *)(driver->apps_rsp_buf + 32) = MSG_SSID_6;
749 *(uint16_t *)(driver->apps_rsp_buf + 34) = MSG_SSID_6_LAST;
750 *(uint16_t *)(driver->apps_rsp_buf + 36) = MSG_SSID_7;
751 *(uint16_t *)(driver->apps_rsp_buf + 38) = MSG_SSID_7_LAST;
752 *(uint16_t *)(driver->apps_rsp_buf + 40) = MSG_SSID_8;
753 *(uint16_t *)(driver->apps_rsp_buf + 42) = MSG_SSID_8_LAST;
754 *(uint16_t *)(driver->apps_rsp_buf + 44) = MSG_SSID_9;
755 *(uint16_t *)(driver->apps_rsp_buf + 46) = MSG_SSID_9_LAST;
756 *(uint16_t *)(driver->apps_rsp_buf + 48) = MSG_SSID_10;
757 *(uint16_t *)(driver->apps_rsp_buf + 50) = MSG_SSID_10_LAST;
758 *(uint16_t *)(driver->apps_rsp_buf + 52) = MSG_SSID_11;
759 *(uint16_t *)(driver->apps_rsp_buf + 54) = MSG_SSID_11_LAST;
760 *(uint16_t *)(driver->apps_rsp_buf + 56) = MSG_SSID_12;
761 *(uint16_t *)(driver->apps_rsp_buf + 58) = MSG_SSID_12_LAST;
762 *(uint16_t *)(driver->apps_rsp_buf + 60) = MSG_SSID_13;
763 *(uint16_t *)(driver->apps_rsp_buf + 62) = MSG_SSID_13_LAST;
764 *(uint16_t *)(driver->apps_rsp_buf + 64) = MSG_SSID_14;
765 *(uint16_t *)(driver->apps_rsp_buf + 66) = MSG_SSID_14_LAST;
766 *(uint16_t *)(driver->apps_rsp_buf + 68) = MSG_SSID_15;
767 *(uint16_t *)(driver->apps_rsp_buf + 70) = MSG_SSID_15_LAST;
768 *(uint16_t *)(driver->apps_rsp_buf + 72) = MSG_SSID_16;
769 *(uint16_t *)(driver->apps_rsp_buf + 74) = MSG_SSID_16_LAST;
770 *(uint16_t *)(driver->apps_rsp_buf + 76) = MSG_SSID_17;
771 *(uint16_t *)(driver->apps_rsp_buf + 78) = MSG_SSID_17_LAST;
772 *(uint16_t *)(driver->apps_rsp_buf + 80) = MSG_SSID_18;
773 *(uint16_t *)(driver->apps_rsp_buf + 82) = MSG_SSID_18_LAST;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800774 *(uint16_t *)(driver->apps_rsp_buf + 84) = MSG_SSID_19;
775 *(uint16_t *)(driver->apps_rsp_buf + 86) = MSG_SSID_19_LAST;
776 *(uint16_t *)(driver->apps_rsp_buf + 88) = MSG_SSID_20;
777 *(uint16_t *)(driver->apps_rsp_buf + 90) = MSG_SSID_20_LAST;
778 *(uint16_t *)(driver->apps_rsp_buf + 92) = MSG_SSID_21;
779 *(uint16_t *)(driver->apps_rsp_buf + 94) = MSG_SSID_21_LAST;
780 *(uint16_t *)(driver->apps_rsp_buf + 96) = MSG_SSID_22;
781 *(uint16_t *)(driver->apps_rsp_buf + 98) = MSG_SSID_22_LAST;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700782 encode_rsp_and_send(99);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700783 return 0;
784 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700785 /* Check for Apps Only Respond to Get Subsys Build mask */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800786 else if (!(driver->smd_data[SMD_MODEM_INDEX].ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787 && (*buf == 0x7d) && (*(buf+1) == 0x2)) {
788 ssid_first = *(uint16_t *)(buf + 2);
789 ssid_last = *(uint16_t *)(buf + 4);
790 ssid_range = 4 * (ssid_last - ssid_first + 1);
791 /* frame response */
792 driver->apps_rsp_buf[0] = 0x7d;
793 driver->apps_rsp_buf[1] = 0x2;
794 *(uint16_t *)(driver->apps_rsp_buf + 2) = ssid_first;
795 *(uint16_t *)(driver->apps_rsp_buf + 4) = ssid_last;
796 driver->apps_rsp_buf[6] = 0x1;
797 driver->apps_rsp_buf[7] = 0x0;
798 ptr = driver->apps_rsp_buf + 8;
799 /* bld time masks */
800 switch (ssid_first) {
801 case MSG_SSID_0:
802 for (i = 0; i < ssid_range; i += 4)
803 *(int *)(ptr + i) = msg_bld_masks_0[i/4];
804 break;
805 case MSG_SSID_1:
806 for (i = 0; i < ssid_range; i += 4)
807 *(int *)(ptr + i) = msg_bld_masks_1[i/4];
808 break;
809 case MSG_SSID_2:
810 for (i = 0; i < ssid_range; i += 4)
811 *(int *)(ptr + i) = msg_bld_masks_2[i/4];
812 break;
813 case MSG_SSID_3:
814 for (i = 0; i < ssid_range; i += 4)
815 *(int *)(ptr + i) = msg_bld_masks_3[i/4];
816 break;
817 case MSG_SSID_4:
818 for (i = 0; i < ssid_range; i += 4)
819 *(int *)(ptr + i) = msg_bld_masks_4[i/4];
820 break;
821 case MSG_SSID_5:
822 for (i = 0; i < ssid_range; i += 4)
823 *(int *)(ptr + i) = msg_bld_masks_5[i/4];
824 break;
825 case MSG_SSID_6:
826 for (i = 0; i < ssid_range; i += 4)
827 *(int *)(ptr + i) = msg_bld_masks_6[i/4];
828 break;
829 case MSG_SSID_7:
830 for (i = 0; i < ssid_range; i += 4)
831 *(int *)(ptr + i) = msg_bld_masks_7[i/4];
832 break;
833 case MSG_SSID_8:
834 for (i = 0; i < ssid_range; i += 4)
835 *(int *)(ptr + i) = msg_bld_masks_8[i/4];
836 break;
837 case MSG_SSID_9:
838 for (i = 0; i < ssid_range; i += 4)
839 *(int *)(ptr + i) = msg_bld_masks_9[i/4];
840 break;
841 case MSG_SSID_10:
842 for (i = 0; i < ssid_range; i += 4)
843 *(int *)(ptr + i) = msg_bld_masks_10[i/4];
844 break;
845 case MSG_SSID_11:
846 for (i = 0; i < ssid_range; i += 4)
847 *(int *)(ptr + i) = msg_bld_masks_11[i/4];
848 break;
849 case MSG_SSID_12:
850 for (i = 0; i < ssid_range; i += 4)
851 *(int *)(ptr + i) = msg_bld_masks_12[i/4];
852 break;
853 case MSG_SSID_13:
854 for (i = 0; i < ssid_range; i += 4)
855 *(int *)(ptr + i) = msg_bld_masks_13[i/4];
856 break;
857 case MSG_SSID_14:
858 for (i = 0; i < ssid_range; i += 4)
859 *(int *)(ptr + i) = msg_bld_masks_14[i/4];
860 break;
861 case MSG_SSID_15:
862 for (i = 0; i < ssid_range; i += 4)
863 *(int *)(ptr + i) = msg_bld_masks_15[i/4];
864 break;
865 case MSG_SSID_16:
866 for (i = 0; i < ssid_range; i += 4)
867 *(int *)(ptr + i) = msg_bld_masks_16[i/4];
868 break;
869 case MSG_SSID_17:
870 for (i = 0; i < ssid_range; i += 4)
871 *(int *)(ptr + i) = msg_bld_masks_17[i/4];
872 break;
873 case MSG_SSID_18:
874 for (i = 0; i < ssid_range; i += 4)
875 *(int *)(ptr + i) = msg_bld_masks_18[i/4];
876 break;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800877 case MSG_SSID_19:
878 for (i = 0; i < ssid_range; i += 4)
879 *(int *)(ptr + i) = msg_bld_masks_19[i/4];
880 break;
881 case MSG_SSID_20:
882 for (i = 0; i < ssid_range; i += 4)
883 *(int *)(ptr + i) = msg_bld_masks_20[i/4];
884 break;
885 case MSG_SSID_21:
886 for (i = 0; i < ssid_range; i += 4)
887 *(int *)(ptr + i) = msg_bld_masks_21[i/4];
888 break;
889 case MSG_SSID_22:
890 for (i = 0; i < ssid_range; i += 4)
891 *(int *)(ptr + i) = msg_bld_masks_22[i/4];
892 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700893 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700894 encode_rsp_and_send(8 + ssid_range - 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700895 return 0;
896 }
897 /* Check for download command */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530898 else if ((cpu_is_msm8x60() || chk_apps_master()) && (*buf == 0x3A)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700899 /* send response back */
900 driver->apps_rsp_buf[0] = *buf;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700901 encode_rsp_and_send(0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700902 msleep(5000);
903 /* call download API */
904 msm_set_restart_mode(RESTART_DLOAD);
905 printk(KERN_CRIT "diag: download mode set, Rebooting SoC..\n");
906 kernel_restart(NULL);
907 /* Not required, represents that command isnt sent to modem */
908 return 0;
909 }
Dixon Petersonb46bb992012-01-12 19:16:56 -0800910 /* Check for polling for Apps only DIAG */
911 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
912 (*(buf+2) == 0x03)) {
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800913 /* If no one has registered for polling */
Dixon Petersonb4618a42012-02-29 18:56:31 -0800914 if (chk_polling_response()) {
Dixon Petersonb46bb992012-01-12 19:16:56 -0800915 /* Respond to polling for Apps only DIAG */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700916 for (i = 0; i < 3; i++)
917 driver->apps_rsp_buf[i] = *(buf+i);
918 for (i = 0; i < 13; i++)
919 driver->apps_rsp_buf[i+3] = 0;
920
Dixon Petersond6a20a92012-09-27 15:58:50 -0700921 encode_rsp_and_send(15);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700922 return 0;
923 }
Dixon Petersonb46bb992012-01-12 19:16:56 -0800924 }
925 /* Check for ID for NO MODEM present */
Dixon Petersonb4618a42012-02-29 18:56:31 -0800926 else if (chk_polling_response()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700927 /* respond to 0x0 command */
Dixon Petersonb46bb992012-01-12 19:16:56 -0800928 if (*buf == 0x00) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700929 for (i = 0; i < 55; i++)
930 driver->apps_rsp_buf[i] = 0;
931
Dixon Petersond6a20a92012-09-27 15:58:50 -0700932 encode_rsp_and_send(54);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700933 return 0;
934 }
935 /* respond to 0x7c command */
936 else if (*buf == 0x7c) {
937 driver->apps_rsp_buf[0] = 0x7c;
938 for (i = 1; i < 8; i++)
939 driver->apps_rsp_buf[i] = 0;
940 /* Tools ID for APQ 8060 */
941 *(int *)(driver->apps_rsp_buf + 8) =
942 chk_config_get_id();
943 *(unsigned char *)(driver->apps_rsp_buf + 12) = '\0';
944 *(unsigned char *)(driver->apps_rsp_buf + 13) = '\0';
Dixon Petersond6a20a92012-09-27 15:58:50 -0700945 encode_rsp_and_send(13);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700946 return 0;
947 }
948 }
949#endif
Dixon Petersond6a20a92012-09-27 15:58:50 -0700950 return packet_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700951}
952
953#ifdef CONFIG_DIAG_OVER_USB
954void diag_send_error_rsp(int index)
955{
956 int i;
Shalabh Jain1fedab92011-12-22 13:15:22 +0530957
958 if (index > 490) {
959 pr_err("diag: error response too huge, aborting\n");
960 return;
961 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700962 driver->apps_rsp_buf[0] = 0x13; /* error code 13 */
963 for (i = 0; i < index; i++)
964 driver->apps_rsp_buf[i+1] = *(driver->hdlc_buf+i);
Dixon Petersond6a20a92012-09-27 15:58:50 -0700965 encode_rsp_and_send(index - 3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966}
967#else
968static inline void diag_send_error_rsp(int index) {}
969#endif
970
971void diag_process_hdlc(void *data, unsigned len)
972{
973 struct diag_hdlc_decode_type hdlc;
974 int ret, type = 0;
975 pr_debug("diag: HDLC decode fn, len of data %d\n", len);
976 hdlc.dest_ptr = driver->hdlc_buf;
977 hdlc.dest_size = USB_MAX_OUT_BUF;
978 hdlc.src_ptr = data;
979 hdlc.src_size = len;
980 hdlc.src_idx = 0;
981 hdlc.dest_idx = 0;
982 hdlc.escaping = 0;
983
984 ret = diag_hdlc_decode(&hdlc);
985
986 if (ret)
987 type = diag_process_apps_pkt(driver->hdlc_buf,
988 hdlc.dest_idx - 3);
989 else if (driver->debug_flag) {
990 printk(KERN_ERR "Packet dropped due to bad HDLC coding/CRC"
991 " errors or partial packet received, packet"
992 " length = %d\n", len);
993 print_hex_dump(KERN_DEBUG, "Dropped Packet Data: ", 16, 1,
994 DUMP_PREFIX_ADDRESS, data, len, 1);
995 driver->debug_flag = 0;
996 }
997 /* send error responses from APPS for Central Routing */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700998 if (type == 1 && chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700999 diag_send_error_rsp(hdlc.dest_idx);
1000 type = 0;
1001 }
1002 /* implies this packet is NOT meant for apps */
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001003 if (!(driver->smd_data[SMD_MODEM_INDEX].ch) && type == 1) {
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001004 if (chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001005 diag_send_error_rsp(hdlc.dest_idx);
1006 } else { /* APQ 8060, Let Q6 respond */
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001007 if (driver->smd_data[SMD_LPASS_INDEX].ch)
1008 smd_write(driver->smd_data[SMD_LPASS_INDEX].ch,
1009 driver->hdlc_buf,
1010 hdlc.dest_idx - 3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001011 }
1012 type = 0;
1013 }
1014
1015#ifdef DIAG_DEBUG
1016 pr_debug("diag: hdlc.dest_idx = %d", hdlc.dest_idx);
1017 for (i = 0; i < hdlc.dest_idx; i++)
1018 printk(KERN_DEBUG "\t%x", *(((unsigned char *)
1019 driver->hdlc_buf)+i));
1020#endif /* DIAG DEBUG */
1021 /* ignore 2 bytes for CRC, one for 7E and send */
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001022 if ((driver->smd_data[SMD_MODEM_INDEX].ch) && (ret) && (type) &&
1023 (hdlc.dest_idx > 3)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001024 APPEND_DEBUG('g');
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001025 smd_write(driver->smd_data[SMD_MODEM_INDEX].ch,
1026 driver->hdlc_buf, hdlc.dest_idx - 3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001027 APPEND_DEBUG('h');
1028#ifdef DIAG_DEBUG
1029 printk(KERN_INFO "writing data to SMD, pkt length %d\n", len);
1030 print_hex_dump(KERN_DEBUG, "Written Packet Data to SMD: ", 16,
1031 1, DUMP_PREFIX_ADDRESS, data, len, 1);
1032#endif /* DIAG DEBUG */
1033 }
1034}
1035
1036#ifdef CONFIG_DIAG_OVER_USB
Shalabh Jain8e9750a2011-09-09 13:06:29 -07001037/* 2+1 for modem ; 2 for LPASS ; 1 for WCNSS */
1038#define N_LEGACY_WRITE (driver->poolsize + 6)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001039#define N_LEGACY_READ 1
1040
1041int diagfwd_connect(void)
1042{
1043 int err;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001044 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001045
1046 printk(KERN_DEBUG "diag: USB connected\n");
1047 err = usb_diag_alloc_req(driver->legacy_ch, N_LEGACY_WRITE,
1048 N_LEGACY_READ);
1049 if (err)
1050 printk(KERN_ERR "diag: unable to alloc USB req on legacy ch");
1051
1052 driver->usb_connected = 1;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001053 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1054 driver->smd_data[i].in_busy_1 = 0;
1055 driver->smd_data[i].in_busy_2 = 0;
1056 /* Poll SMD data channels to check for data */
1057 queue_work(driver->diag_wq,
1058 &(driver->smd_data[i].diag_read_smd_work));
1059 /* Poll SMD CNTL channels to check for data */
1060 diag_smd_notify(&(driver->smd_cntl[i]), SMD_EVENT_DATA);
1061 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001062
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001063 /* Poll USB channel to check for data*/
1064 queue_work(driver->diag_wq, &(driver->diag_read_work));
1065#ifdef CONFIG_DIAG_SDIO_PIPE
1066 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
1067 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1068 diagfwd_connect_sdio();
1069 else
1070 printk(KERN_INFO "diag: No USB MDM ch");
1071 }
1072#endif
1073 return 0;
1074}
1075
1076int diagfwd_disconnect(void)
1077{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001078 int i;
1079
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001080 printk(KERN_DEBUG "diag: USB disconnected\n");
1081 driver->usb_connected = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001082 driver->debug_flag = 1;
1083 usb_diag_free_req(driver->legacy_ch);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001084 if (driver->logging_mode == USB_MODE) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001085 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1086 driver->smd_data[i].in_busy_1 = 1;
1087 driver->smd_data[i].in_busy_2 = 1;
1088 }
Shalabh Jain69890aa2011-10-10 12:59:16 -07001089 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001090#ifdef CONFIG_DIAG_SDIO_PIPE
1091 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
1092 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1093 diagfwd_disconnect_sdio();
1094#endif
1095 /* TBD - notify and flow control SMD */
1096 return 0;
1097}
1098
1099int diagfwd_write_complete(struct diag_request *diag_write_ptr)
1100{
1101 unsigned char *buf = diag_write_ptr->buf;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001102 int found_it = 0;
1103 int i;
1104
1105 /* Determine if the write complete is for data from modem/apps/q6 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001106 /* Need a context variable here instead */
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001107 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1108 struct diag_smd_info *data = &(driver->smd_data[i]);
1109 if (buf == (void *)data->buf_in_1) {
1110 data->in_busy_1 = 0;
1111 queue_work(driver->diag_wq,
1112 &(data->diag_read_smd_work));
1113 found_it = 1;
1114 break;
1115 } else if (buf == (void *)data->buf_in_2) {
1116 data->in_busy_2 = 0;
1117 queue_work(driver->diag_wq,
1118 &(data->diag_read_smd_work));
1119 found_it = 1;
1120 break;
1121 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122 }
1123#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001124 if (!found_it) {
1125 if (buf == (void *)driver->buf_in_sdio) {
1126 if (machine_is_msm8x60_fusion() ||
1127 machine_is_msm8x60_fusn_ffa())
1128 diagfwd_write_complete_sdio();
1129 else
1130 pr_err("diag: Incorrect buffer pointer while WRITE");
1131 found_it = 1;
1132 }
1133 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001134#endif
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001135 if (!found_it) {
1136 diagmem_free(driver, (unsigned char *)buf,
1137 POOL_TYPE_HDLC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138 diagmem_free(driver, (unsigned char *)diag_write_ptr,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001139 POOL_TYPE_WRITE_STRUCT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 }
1141 return 0;
1142}
1143
1144int diagfwd_read_complete(struct diag_request *diag_read_ptr)
1145{
1146 int status = diag_read_ptr->status;
1147 unsigned char *buf = diag_read_ptr->buf;
1148
1149 /* Determine if the read complete is for data on legacy/mdm ch */
1150 if (buf == (void *)driver->usb_buf_out) {
1151 driver->read_len_legacy = diag_read_ptr->actual;
1152 APPEND_DEBUG('s');
1153#ifdef DIAG_DEBUG
1154 printk(KERN_INFO "read data from USB, pkt length %d",
1155 diag_read_ptr->actual);
1156 print_hex_dump(KERN_DEBUG, "Read Packet Data from USB: ", 16, 1,
1157 DUMP_PREFIX_ADDRESS, diag_read_ptr->buf,
1158 diag_read_ptr->actual, 1);
1159#endif /* DIAG DEBUG */
1160 if (driver->logging_mode == USB_MODE) {
1161 if (status != -ECONNRESET && status != -ESHUTDOWN)
1162 queue_work(driver->diag_wq,
1163 &(driver->diag_proc_hdlc_work));
1164 else
1165 queue_work(driver->diag_wq,
1166 &(driver->diag_read_work));
1167 }
1168 }
1169#ifdef CONFIG_DIAG_SDIO_PIPE
1170 else if (buf == (void *)driver->usb_buf_mdm_out) {
1171 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -08001172 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001173 driver->read_len_mdm = diag_read_ptr->actual;
1174 diagfwd_read_complete_sdio();
1175 } else
1176 pr_err("diag: Incorrect buffer pointer while READ");
1177 }
1178#endif
1179 else
1180 printk(KERN_ERR "diag: Unknown buffer ptr from USB");
1181
1182 return 0;
1183}
1184
1185void diag_read_work_fn(struct work_struct *work)
1186{
1187 APPEND_DEBUG('d');
1188 driver->usb_read_ptr->buf = driver->usb_buf_out;
1189 driver->usb_read_ptr->length = USB_MAX_OUT_BUF;
1190 usb_diag_read(driver->legacy_ch, driver->usb_read_ptr);
1191 APPEND_DEBUG('e');
1192}
1193
1194void diag_process_hdlc_fn(struct work_struct *work)
1195{
1196 APPEND_DEBUG('D');
1197 diag_process_hdlc(driver->usb_buf_out, driver->read_len_legacy);
1198 diag_read_work_fn(work);
1199 APPEND_DEBUG('E');
1200}
1201
1202void diag_usb_legacy_notifier(void *priv, unsigned event,
1203 struct diag_request *d_req)
1204{
1205 switch (event) {
1206 case USB_DIAG_CONNECT:
1207 diagfwd_connect();
1208 break;
1209 case USB_DIAG_DISCONNECT:
1210 diagfwd_disconnect();
1211 break;
1212 case USB_DIAG_READ_DONE:
1213 diagfwd_read_complete(d_req);
1214 break;
1215 case USB_DIAG_WRITE_DONE:
1216 diagfwd_write_complete(d_req);
1217 break;
1218 default:
1219 printk(KERN_ERR "Unknown event from USB diag\n");
1220 break;
1221 }
1222}
1223
1224#endif /* DIAG OVER USB */
1225
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001226void diag_smd_notify(void *ctxt, unsigned event)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001228 struct diag_smd_info *smd_info = (struct diag_smd_info *)ctxt;
1229 if (!smd_info)
Shalabh Jaineefee052011-11-08 23:46:03 -08001230 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001231
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001232 if (event == SMD_EVENT_CLOSE) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001233 smd_info->ch = 0;
Shalabh Jainc70b3b62012-08-31 19:11:20 -07001234 wake_up(&driver->smd_wait_q);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001235 if (smd_info->type == SMD_DATA_TYPE) {
1236 smd_info->notify_context = event;
1237 queue_work(driver->diag_cntl_wq,
1238 &(smd_info->diag_notify_update_smd_work));
1239 } else if (smd_info->type == SMD_DCI_TYPE) {
1240 /* Notify the clients of the close */
1241 diag_dci_notify_client(smd_info->peripheral_mask,
1242 DIAG_STATUS_CLOSED);
1243 }
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001244 return;
1245 } else if (event == SMD_EVENT_OPEN) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001246 if (smd_info->ch_save)
1247 smd_info->ch = smd_info->ch_save;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001248
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001249 if (smd_info->type == SMD_CNTL_TYPE) {
1250 smd_info->notify_context = event;
1251 queue_work(driver->diag_cntl_wq,
1252 &(smd_info->diag_notify_update_smd_work));
1253 } else if (smd_info->type == SMD_DCI_TYPE) {
1254 smd_info->notify_context = event;
1255 queue_work(driver->diag_dci_wq,
1256 &(smd_info->diag_notify_update_smd_work));
1257 /* Notify the clients of the open */
1258 diag_dci_notify_client(smd_info->peripheral_mask,
1259 DIAG_STATUS_OPEN);
1260 }
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001261 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001262
Shalabh Jainc70b3b62012-08-31 19:11:20 -07001263 wake_up(&driver->smd_wait_q);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001264
1265 if (smd_info->type == SMD_DCI_TYPE)
1266 queue_work(driver->diag_dci_wq,
1267 &(smd_info->diag_read_smd_work));
1268 else
1269 queue_work(driver->diag_wq, &(smd_info->diag_read_smd_work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270}
1271
1272static int diag_smd_probe(struct platform_device *pdev)
1273{
1274 int r = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001275 int index = -1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276
Shalabh Jaineefee052011-11-08 23:46:03 -08001277 if (pdev->id == SMD_APPS_MODEM) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001278 index = SMD_MODEM_INDEX;
1279 r = smd_open("DIAG", &driver->smd_data[index].ch,
1280 &driver->smd_data[index],
1281 diag_smd_notify);
1282 driver->smd_data[index].ch_save =
1283 driver->smd_data[index].ch;
Shalabh Jaineefee052011-11-08 23:46:03 -08001284 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001285#if defined(CONFIG_MSM_N_WAY_SMD)
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001286 if (pdev->id == SMD_APPS_QDSP) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001287 index = SMD_LPASS_INDEX;
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001288 r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001289 &driver->smd_data[index].ch,
1290 &driver->smd_data[index],
1291 diag_smd_notify);
1292 driver->smd_data[index].ch_save =
1293 driver->smd_data[index].ch;
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001294 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001295#endif
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001296 if (pdev->id == SMD_APPS_WCNSS) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001297 index = SMD_WCNSS_INDEX;
1298 r = smd_named_open_on_edge("APPS_RIVA_DATA",
1299 SMD_APPS_WCNSS,
1300 &driver->smd_data[index].ch,
1301 &driver->smd_data[index],
1302 diag_smd_notify);
1303 driver->smd_data[index].ch_save =
1304 driver->smd_data[index].ch;
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001305 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001307 pm_runtime_set_active(&pdev->dev);
1308 pm_runtime_enable(&pdev->dev);
1309 pr_debug("diag: open SMD port, Id = %d, r = %d\n", pdev->id, r);
1310
1311 return 0;
1312}
1313
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001314static int diag_smd_runtime_suspend(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001315{
1316 dev_dbg(dev, "pm_runtime: suspending...\n");
1317 return 0;
1318}
1319
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001320static int diag_smd_runtime_resume(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001321{
1322 dev_dbg(dev, "pm_runtime: resuming...\n");
1323 return 0;
1324}
1325
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001326static const struct dev_pm_ops diag_smd_dev_pm_ops = {
1327 .runtime_suspend = diag_smd_runtime_suspend,
1328 .runtime_resume = diag_smd_runtime_resume,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001329};
1330
1331static struct platform_driver msm_smd_ch1_driver = {
1332
1333 .probe = diag_smd_probe,
1334 .driver = {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001335 .name = "DIAG",
1336 .owner = THIS_MODULE,
1337 .pm = &diag_smd_dev_pm_ops,
1338 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001339};
1340
1341static struct platform_driver diag_smd_lite_driver = {
1342
1343 .probe = diag_smd_probe,
1344 .driver = {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001345 .name = "APPS_RIVA_DATA",
1346 .owner = THIS_MODULE,
1347 .pm = &diag_smd_dev_pm_ops,
1348 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001349};
1350
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001351void diag_smd_destructor(struct diag_smd_info *smd_info)
1352{
1353 if (smd_info->ch)
1354 smd_close(smd_info->ch);
1355
1356 smd_info->ch = 0;
1357 smd_info->ch_save = 0;
1358 kfree(smd_info->buf_in_1);
1359 kfree(smd_info->buf_in_2);
1360 kfree(smd_info->write_ptr_1);
1361 kfree(smd_info->write_ptr_2);
1362}
1363
1364int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral,
1365 int type, uint16_t peripheral_mask)
1366{
1367 smd_info->peripheral = peripheral;
1368 smd_info->type = type;
1369 smd_info->peripheral_mask = peripheral_mask;
1370
1371 smd_info->ch = 0;
1372 smd_info->ch_save = 0;
1373
1374 if (smd_info->buf_in_1 == NULL) {
1375 smd_info->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1376 if (smd_info->buf_in_1 == NULL)
1377 goto err;
1378 kmemleak_not_leak(smd_info->buf_in_1);
1379 }
1380
1381 if (smd_info->write_ptr_1 == NULL) {
1382 smd_info->write_ptr_1 = kzalloc(sizeof(struct diag_request),
1383 GFP_KERNEL);
1384 if (smd_info->write_ptr_1 == NULL)
1385 goto err;
1386 kmemleak_not_leak(smd_info->write_ptr_1);
1387 }
1388
1389 /* The smd data type needs two buffers */
1390 if (smd_info->type == SMD_DATA_TYPE) {
1391 if (smd_info->buf_in_2 == NULL) {
1392 smd_info->buf_in_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1393 if (smd_info->buf_in_2 == NULL)
1394 goto err;
1395 kmemleak_not_leak(smd_info->buf_in_2);
1396 }
1397 if (smd_info->write_ptr_2 == NULL) {
1398 smd_info->write_ptr_2 =
1399 kzalloc(sizeof(struct diag_request),
1400 GFP_KERNEL);
1401 if (smd_info->write_ptr_2 == NULL)
1402 goto err;
1403 kmemleak_not_leak(smd_info->write_ptr_2);
1404 }
1405 }
1406
1407 INIT_WORK(&(smd_info->diag_read_smd_work), diag_read_smd_work_fn);
1408
1409 /*
1410 * The update function assigned to the diag_notify_update_smd_work
1411 * work_struct is meant to be used for updating that is not to
1412 * be done in the context of the smd notify function. The
1413 * notify_context variable can be used for passing additional
1414 * information to the update function.
1415 */
1416 smd_info->notify_context = 0;
1417 if (type == SMD_DATA_TYPE)
1418 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
1419 diag_clean_reg_fn);
1420 else if (type == SMD_CNTL_TYPE)
1421 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
1422 diag_mask_update_fn);
1423 else if (type == SMD_DCI_TYPE)
1424 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
1425 diag_update_smd_dci_work_fn);
1426 else {
1427 pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
1428 goto err;
1429 }
1430
1431 /*
1432 * Set function ptr for function to call to process the data that
1433 * was just read from the smd channel
1434 */
1435 if (type == SMD_DATA_TYPE)
1436 smd_info->process_smd_read_data = diag_process_smd_read_data;
1437 else if (type == SMD_CNTL_TYPE)
1438 smd_info->process_smd_read_data =
1439 diag_process_smd_cntl_read_data;
1440 else if (type == SMD_DCI_TYPE)
1441 smd_info->process_smd_read_data =
1442 diag_process_smd_dci_read_data;
1443 else {
1444 pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
1445 goto err;
1446 }
1447
1448 return 1;
1449err:
1450 kfree(smd_info->buf_in_1);
1451 kfree(smd_info->buf_in_2);
1452 kfree(smd_info->write_ptr_1);
1453 kfree(smd_info->write_ptr_2);
1454
1455 return 0;
1456}
1457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458void diagfwd_init(void)
1459{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001460 int success;
1461 int i;
1462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001463 diag_debug_buf_idx = 0;
1464 driver->read_len_legacy = 0;
Dixon Petersonb4618a42012-02-29 18:56:31 -08001465 driver->use_device_tree = has_device_tree();
Shalabh Jaina06c6d72012-04-30 13:40:35 -07001466 mutex_init(&driver->diag_cntl_mutex);
Shalabh Jain321c8b52012-02-22 12:37:06 -08001467
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001468 success = diag_smd_constructor(&driver->smd_data[SMD_MODEM_INDEX],
1469 MODEM_PROC, SMD_DATA_TYPE, DIAG_CON_MPSS);
1470 if (!success)
1471 goto err;
1472
1473 success = diag_smd_constructor(&driver->smd_data[SMD_LPASS_INDEX],
1474 LPASS_PROC, SMD_DATA_TYPE, DIAG_CON_LPASS);
1475 if (!success)
1476 goto err;
1477
1478 success = diag_smd_constructor(&driver->smd_data[SMD_WCNSS_INDEX],
1479 WCNSS_PROC, SMD_DATA_TYPE, DIAG_CON_WCNSS);
1480 if (!success)
1481 goto err;
1482
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001483 if (driver->usb_buf_out == NULL &&
1484 (driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
1485 GFP_KERNEL)) == NULL)
1486 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001487 kmemleak_not_leak(driver->usb_buf_out);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488 if (driver->hdlc_buf == NULL
1489 && (driver->hdlc_buf = kzalloc(HDLC_MAX, GFP_KERNEL)) == NULL)
1490 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001491 kmemleak_not_leak(driver->hdlc_buf);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001492 if (driver->user_space_data == NULL)
1493 driver->user_space_data = kzalloc(USER_SPACE_DATA, GFP_KERNEL);
1494 if (driver->user_space_data == NULL)
1495 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001496 kmemleak_not_leak(driver->user_space_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497 if (driver->client_map == NULL &&
1498 (driver->client_map = kzalloc
1499 ((driver->num_clients) * sizeof(struct diag_client_map),
1500 GFP_KERNEL)) == NULL)
1501 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001502 kmemleak_not_leak(driver->client_map);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001503 if (driver->buf_tbl == NULL)
1504 driver->buf_tbl = kzalloc(buf_tbl_size *
1505 sizeof(struct diag_write_device), GFP_KERNEL);
1506 if (driver->buf_tbl == NULL)
1507 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001508 kmemleak_not_leak(driver->buf_tbl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001509 if (driver->data_ready == NULL &&
1510 (driver->data_ready = kzalloc(driver->num_clients * sizeof(int)
1511 , GFP_KERNEL)) == NULL)
1512 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001513 kmemleak_not_leak(driver->data_ready);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001514 if (driver->table == NULL &&
Shalabh Jainfe02b0c2012-02-21 14:48:03 -08001515 (driver->table = kzalloc(diag_max_reg*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516 sizeof(struct diag_master_table),
1517 GFP_KERNEL)) == NULL)
1518 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001519 kmemleak_not_leak(driver->table);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001521 if (driver->usb_read_ptr == NULL) {
1522 driver->usb_read_ptr = kzalloc(
1523 sizeof(struct diag_request), GFP_KERNEL);
1524 if (driver->usb_read_ptr == NULL)
1525 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001526 kmemleak_not_leak(driver->usb_read_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001527 }
1528 if (driver->pkt_buf == NULL &&
1529 (driver->pkt_buf = kzalloc(PKT_SIZE,
1530 GFP_KERNEL)) == NULL)
1531 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001532 kmemleak_not_leak(driver->pkt_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533 if (driver->apps_rsp_buf == NULL) {
Shalabh Jain321c8b52012-02-22 12:37:06 -08001534 driver->apps_rsp_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001535 if (driver->apps_rsp_buf == NULL)
1536 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001537 kmemleak_not_leak(driver->apps_rsp_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001538 }
1539 driver->diag_wq = create_singlethread_workqueue("diag_wq");
1540#ifdef CONFIG_DIAG_OVER_USB
1541 INIT_WORK(&(driver->diag_proc_hdlc_work), diag_process_hdlc_fn);
1542 INIT_WORK(&(driver->diag_read_work), diag_read_work_fn);
1543 driver->legacy_ch = usb_diag_open(DIAG_LEGACY, driver,
1544 diag_usb_legacy_notifier);
1545 if (IS_ERR(driver->legacy_ch)) {
1546 printk(KERN_ERR "Unable to open USB diag legacy channel\n");
1547 goto err;
1548 }
1549#endif
1550 platform_driver_register(&msm_smd_ch1_driver);
1551 platform_driver_register(&diag_smd_lite_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001552 return;
1553err:
Dixon Petersond6a20a92012-09-27 15:58:50 -07001554 pr_err("diag: Could not initialize diag buffers");
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001555
1556 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
1557 diag_smd_destructor(&driver->smd_data[i]);
1558
Dixon Petersond6a20a92012-09-27 15:58:50 -07001559 kfree(driver->buf_msg_mask_update);
1560 kfree(driver->buf_log_mask_update);
1561 kfree(driver->buf_event_mask_update);
1562 kfree(driver->usb_buf_out);
1563 kfree(driver->hdlc_buf);
1564 kfree(driver->client_map);
1565 kfree(driver->buf_tbl);
1566 kfree(driver->data_ready);
1567 kfree(driver->table);
1568 kfree(driver->pkt_buf);
Dixon Petersond6a20a92012-09-27 15:58:50 -07001569 kfree(driver->usb_read_ptr);
1570 kfree(driver->apps_rsp_buf);
1571 kfree(driver->user_space_data);
1572 if (driver->diag_wq)
1573 destroy_workqueue(driver->diag_wq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001574}
1575
1576void diagfwd_exit(void)
1577{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001578 int i;
1579
1580 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
1581 diag_smd_destructor(&driver->smd_data[i]);
1582
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001583#ifdef CONFIG_DIAG_OVER_USB
1584 if (driver->usb_connected)
1585 usb_diag_free_req(driver->legacy_ch);
1586 usb_diag_close(driver->legacy_ch);
1587#endif
1588 platform_driver_unregister(&msm_smd_ch1_driver);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001589 platform_driver_unregister(&msm_diag_dci_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001590 platform_driver_unregister(&diag_smd_lite_driver);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001591
Shalabh Jain321c8b52012-02-22 12:37:06 -08001592 kfree(driver->buf_msg_mask_update);
1593 kfree(driver->buf_log_mask_update);
1594 kfree(driver->buf_event_mask_update);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595 kfree(driver->usb_buf_out);
1596 kfree(driver->hdlc_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001597 kfree(driver->client_map);
1598 kfree(driver->buf_tbl);
1599 kfree(driver->data_ready);
1600 kfree(driver->table);
1601 kfree(driver->pkt_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001602 kfree(driver->usb_read_ptr);
1603 kfree(driver->apps_rsp_buf);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001604 kfree(driver->user_space_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 destroy_workqueue(driver->diag_wq);
1606}