blob: 1a7b2f8a003e34400a43b511a4619d5cd96bf456 [file] [log] [blame]
Shalabh Jainb0037c02013-01-18 12:47:40 -08001/* Copyright (c) 2008-2013, The Linux Foundation. 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"
Shalabh Jainb0037c02013-01-18 12:47:40 -080037#include "diagfwd_hsic.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038#include "diagchar_hdlc.h"
39#ifdef CONFIG_DIAG_SDIO_PIPE
40#include "diagfwd_sdio.h"
41#endif
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070042#include "diag_dci.h"
Dixon Petersond6a20a92012-09-27 15:58:50 -070043#include "diag_masks.h"
Shalabh Jain737fca72012-11-14 21:53:43 -080044#include "diagfwd_bridge.h"
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070045
Shalabh Jain6a2ca7c2012-04-10 14:35:15 -070046#define MODE_CMD 41
47#define RESET_ID 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070048
Dixon Peterson15a6ecb2013-06-25 12:36:33 -070049#define STM_CMD_VERSION_OFFSET 4
50#define STM_CMD_MASK_OFFSET 5
51#define STM_CMD_DATA_OFFSET 6
52#define STM_CMD_NUM_BYTES 7
53
54#define STM_RSP_VALID_INDEX 7
55#define STM_RSP_SUPPORTED_INDEX 8
56#define STM_RSP_SMD_COMPLY_INDEX 9
57#define STM_RSP_NUM_BYTES 10
58
Dixon Petersond2309b42013-08-28 21:00:05 -070059#define SMD_DRAIN_BUF_SIZE 4096
60
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061int diag_debug_buf_idx;
62unsigned char diag_debug_buf[1024];
Dixon Petersona6d98092013-05-16 12:26:26 -070063/* Number of entries in table of buffers */
64static unsigned int buf_tbl_size = 10;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065struct diag_master_table entry;
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -080066int wrap_enabled;
67uint16_t wrap_count;
Shalabh Jain6a2ca7c2012-04-10 14:35:15 -070068
Dixon Petersond6a20a92012-09-27 15:58:50 -070069void encode_rsp_and_send(int buf_length)
70{
Dixon Peterson9ce39c62013-02-21 13:00:52 -080071 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
72 struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
Dixon Petersoneecbadb2012-12-10 21:59:28 -080073 struct diag_smd_info *data = &(driver->smd_data[MODEM_DATA]);
Ravi Aravamudhancc9946862013-07-15 13:31:11 -070074
75 if (buf_length > APPS_BUF_SIZE) {
76 pr_err("diag: In %s, invalid len %d, permissible len %d\n",
77 __func__, buf_length, APPS_BUF_SIZE);
78 return;
79 }
80
Dixon Petersond6a20a92012-09-27 15:58:50 -070081 send.state = DIAG_STATE_START;
82 send.pkt = driver->apps_rsp_buf;
83 send.last = (void *)(driver->apps_rsp_buf + buf_length);
84 send.terminate = 1;
Dixon Peterson66fb11b2012-12-04 20:30:54 -080085 if (!data->in_busy_1) {
86 enc.dest = data->buf_in_1;
87 enc.dest_last = (void *)(data->buf_in_1 + APPS_BUF_SIZE - 1);
Dixon Petersond6a20a92012-09-27 15:58:50 -070088 diag_hdlc_encode(&send, &enc);
Dixon Peterson66fb11b2012-12-04 20:30:54 -080089 data->write_ptr_1->buf = data->buf_in_1;
90 data->write_ptr_1->length = (int)(enc.dest -
91 (void *)(data->buf_in_1));
92 data->in_busy_1 = 1;
Dixon Petersoneecbadb2012-12-10 21:59:28 -080093 diag_device_write(data->buf_in_1, data->peripheral,
Dixon Peterson66fb11b2012-12-04 20:30:54 -080094 data->write_ptr_1);
Dixon Petersond6a20a92012-09-27 15:58:50 -070095 memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);
96 }
97}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098
Dixon Petersonb4618a42012-02-29 18:56:31 -080099/* Determine if this device uses a device tree */
100#ifdef CONFIG_OF
101static int has_device_tree(void)
102{
103 struct device_node *node;
104
105 node = of_find_node_by_path("/");
106 if (node) {
107 of_node_put(node);
108 return 1;
109 }
110 return 0;
111}
112#else
113static int has_device_tree(void)
114{
115 return 0;
116}
117#endif
118
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700119int chk_config_get_id(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700120{
Shashank Mittal24771632013-02-06 19:34:57 -0800121 /* For all Fusion targets, Modem will always be present */
Shalabh Jain482bf122011-12-06 03:54:47 -0800122 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
123 return 0;
124
Dixon Petersonb4618a42012-02-29 18:56:31 -0800125 if (driver->use_device_tree) {
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700126 if (machine_is_msm8974())
Dixon Petersonb4618a42012-02-29 18:56:31 -0800127 return MSM8974_TOOLS_ID;
128 else
129 return 0;
130 } else {
131 switch (socinfo_get_msm_cpu()) {
132 case MSM_CPU_8X60:
133 return APQ8060_TOOLS_ID;
134 case MSM_CPU_8960:
Stepan Moskovchenko9c749262012-07-09 19:30:44 -0700135 case MSM_CPU_8960AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800136 return AO8960_TOOLS_ID;
137 case MSM_CPU_8064:
Jay Chokshi11abd8b2012-09-20 14:35:17 -0700138 case MSM_CPU_8064AB:
Shashank Mittal24771632013-02-06 19:34:57 -0800139 case MSM_CPU_8064AA:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800140 return APQ8064_TOOLS_ID;
141 case MSM_CPU_8930:
Stepan Moskovchenko0df9bb22012-07-06 18:19:15 -0700142 case MSM_CPU_8930AA:
Stepan Moskovchenkoecb0d9b2012-10-16 18:35:34 -0700143 case MSM_CPU_8930AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800144 return MSM8930_TOOLS_ID;
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700145 case MSM_CPU_8974:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800146 return MSM8974_TOOLS_ID;
147 case MSM_CPU_8625:
148 return MSM8625_TOOLS_ID;
149 default:
150 return 0;
151 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700152 }
153}
154
155/*
Shalabh Jain321c8b52012-02-22 12:37:06 -0800156 * This will return TRUE for targets which support apps only mode and hence SSR.
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700157 * This applies to 8960 and newer targets.
158 */
159int chk_apps_only(void)
160{
Dixon Petersonb4618a42012-02-29 18:56:31 -0800161 if (driver->use_device_tree)
162 return 1;
163
164 switch (socinfo_get_msm_cpu()) {
165 case MSM_CPU_8960:
Stepan Moskovchenko9c749262012-07-09 19:30:44 -0700166 case MSM_CPU_8960AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800167 case MSM_CPU_8064:
Jay Chokshi11abd8b2012-09-20 14:35:17 -0700168 case MSM_CPU_8064AB:
Shashank Mittal24771632013-02-06 19:34:57 -0800169 case MSM_CPU_8064AA:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800170 case MSM_CPU_8930:
Stepan Moskovchenko0df9bb22012-07-06 18:19:15 -0700171 case MSM_CPU_8930AA:
Stepan Moskovchenkoecb0d9b2012-10-16 18:35:34 -0700172 case MSM_CPU_8930AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800173 case MSM_CPU_8627:
174 case MSM_CPU_9615:
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700175 case MSM_CPU_8974:
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700176 return 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700177 default:
178 return 0;
179 }
180}
181
Shalabh Jain10f5f432012-01-11 11:45:44 +0530182/*
183 * This will return TRUE for targets which support apps as master.
184 * Thus, SW DLOAD and Mode Reset are supported on apps processor.
185 * This applies to 8960 and newer targets.
186 */
187int chk_apps_master(void)
188{
Dixon Petersonb4618a42012-02-29 18:56:31 -0800189 if (driver->use_device_tree)
190 return 1;
Stepan Moskovchenko5b9e7762012-09-21 20:32:17 -0700191 else if (soc_class_is_msm8960() || soc_class_is_msm8930() ||
192 soc_class_is_apq8064() || cpu_is_msm9615())
Dixon Petersonb4618a42012-02-29 18:56:31 -0800193 return 1;
194 else
195 return 0;
196}
197
Dixon Peterson29aebee2012-04-06 12:44:08 -0700198int chk_polling_response(void)
Dixon Petersonb4618a42012-02-29 18:56:31 -0800199{
200 if (!(driver->polling_reg_flag) && chk_apps_master())
201 /*
202 * If the apps processor is master and no other processor
203 * has registered to respond for polling
204 */
205 return 1;
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -0700206 else if (!((driver->smd_data[MODEM_DATA].ch) &&
207 (driver->rcvd_feature_mask[MODEM_DATA])) &&
208 (chk_apps_master()))
Dixon Petersonb4618a42012-02-29 18:56:31 -0800209 /*
210 * If the apps processor is not the master and the modem
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -0700211 * is not up or we did not receive the feature masks from Modem
Dixon Petersonb4618a42012-02-29 18:56:31 -0800212 */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530213 return 1;
214 else
215 return 0;
216}
217
Dixon Peterson743a11e2012-07-30 17:42:20 -0700218/*
219 * This function should be called if you feel that the logging process may
220 * need to be woken up. For instance, if the logging mode is MEMORY_DEVICE MODE
221 * and while trying to read data from a SMD data channel there are no buffers
222 * available to read the data into, then this function should be called to
223 * determine if the logging process needs to be woken up.
224 */
225void chk_logging_wakeup(void)
226{
227 int i;
228
229 /* Find the index of the logging process */
230 for (i = 0; i < driver->num_clients; i++)
231 if (driver->client_map[i].pid ==
232 driver->logging_process_id)
233 break;
234
235 if (i < driver->num_clients) {
236 /* At very high logging rates a race condition can
237 * occur where the buffers containing the data from
238 * an smd channel are all in use, but the data_ready
239 * flag is cleared. In this case, the buffers never
240 * have their data read/logged. Detect and remedy this
241 * situation.
242 */
Shalabh Jain84e30342012-10-16 16:16:08 -0700243 if ((driver->data_ready[i] & USER_SPACE_DATA_TYPE) == 0) {
244 driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
Dixon Peterson743a11e2012-07-30 17:42:20 -0700245 pr_debug("diag: Force wakeup of logging process\n");
246 wake_up_interruptible(&driver->wait_q);
247 }
248 }
249}
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800250int diag_add_hdlc_encoding(struct diag_smd_info *smd_info, void *buf,
251 int total_recd, uint8_t *encode_buf,
252 int *encoded_length)
253{
254 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
255 struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
256 struct data_header {
257 uint8_t control_char;
258 uint8_t version;
259 uint16_t length;
260 };
261 struct data_header *header;
262 int header_size = sizeof(struct data_header);
263 uint8_t *end_control_char;
264 uint8_t *payload;
265 uint8_t *temp_buf;
266 uint8_t *temp_encode_buf;
267 int src_pkt_len;
268 int encoded_pkt_length;
269 int max_size;
270 int total_processed = 0;
271 int bytes_remaining;
272 int success = 1;
273
274 temp_buf = buf;
275 temp_encode_buf = encode_buf;
276 bytes_remaining = *encoded_length;
277 while (total_processed < total_recd) {
278 header = (struct data_header *)temp_buf;
279 /* Perform initial error checking */
280 if (header->control_char != CONTROL_CHAR ||
281 header->version != 1) {
282 success = 0;
283 break;
284 }
285 payload = temp_buf + header_size;
286 end_control_char = payload + header->length;
287 if (*end_control_char != CONTROL_CHAR) {
288 success = 0;
289 break;
290 }
291
292 max_size = 2 * header->length + 3;
293 if (bytes_remaining < max_size) {
294 pr_err("diag: In %s, Not enough room to encode remaining data for peripheral: %d, bytes available: %d, max_size: %d\n",
295 __func__, smd_info->peripheral,
296 bytes_remaining, max_size);
297 success = 0;
298 break;
299 }
300
301 /* Prepare for encoding the data */
302 send.state = DIAG_STATE_START;
303 send.pkt = payload;
304 send.last = (void *)(payload + header->length - 1);
305 send.terminate = 1;
306
307 enc.dest = temp_encode_buf;
308 enc.dest_last = (void *)(temp_encode_buf + max_size);
309 enc.crc = 0;
310 diag_hdlc_encode(&send, &enc);
311
312 /* Prepare for next packet */
313 src_pkt_len = (header_size + header->length + 1);
314 total_processed += src_pkt_len;
315 temp_buf += src_pkt_len;
316
317 encoded_pkt_length = (uint8_t *)enc.dest - temp_encode_buf;
318 bytes_remaining -= encoded_pkt_length;
319 temp_encode_buf = enc.dest;
320 }
321
322 *encoded_length = (int)(temp_encode_buf - encode_buf);
323
324 return success;
325}
326
327static int check_bufsize_for_encoding(struct diag_smd_info *smd_info, void *buf,
328 int total_recd)
329{
330 int buf_size = IN_BUF_SIZE;
331 int max_size = 2 * total_recd + 3;
332 unsigned char *temp_buf;
333
334 if (max_size > IN_BUF_SIZE) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700335 if (max_size > MAX_IN_BUF_SIZE) {
336 pr_err_ratelimited("diag: In %s, SMD sending packet of %d bytes that may expand to %d bytes, peripheral: %d\n",
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800337 __func__, total_recd, max_size,
338 smd_info->peripheral);
Dixon Petersond2309b42013-08-28 21:00:05 -0700339 max_size = MAX_IN_BUF_SIZE;
340 }
341 if (buf == smd_info->buf_in_1_raw) {
342 /* Only realloc if we need to increase the size */
343 if (smd_info->buf_in_1_size < max_size) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800344 temp_buf = krealloc(smd_info->buf_in_1,
Dixon Petersond2309b42013-08-28 21:00:05 -0700345 max_size, GFP_KERNEL);
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800346 if (temp_buf) {
347 smd_info->buf_in_1 = temp_buf;
Dixon Petersond2309b42013-08-28 21:00:05 -0700348 smd_info->buf_in_1_size = max_size;
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800349 }
350 }
Dixon Petersond2309b42013-08-28 21:00:05 -0700351 buf_size = smd_info->buf_in_1_size;
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800352 } else {
Dixon Petersond2309b42013-08-28 21:00:05 -0700353 /* Only realloc if we need to increase the size */
354 if (smd_info->buf_in_2_size < max_size) {
355 temp_buf = krealloc(smd_info->buf_in_2,
356 max_size, GFP_KERNEL);
357 if (temp_buf) {
358 smd_info->buf_in_2 = temp_buf;
359 smd_info->buf_in_2_size = max_size;
360 }
361 }
362 buf_size = smd_info->buf_in_2_size;
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800363 }
364 }
365
366 return buf_size;
367}
Dixon Peterson743a11e2012-07-30 17:42:20 -0700368
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800369void process_lock_enabling(struct diag_nrt_wake_lock *lock, int real_time)
370{
371 unsigned long read_lock_flags;
372
373 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
374 if (real_time)
375 lock->enabled = 0;
376 else
377 lock->enabled = 1;
378 lock->ref_count = 0;
379 lock->copy_count = 0;
380 wake_unlock(&lock->read_lock);
381 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
382}
383
384void process_lock_on_notify(struct diag_nrt_wake_lock *lock)
385{
386 unsigned long read_lock_flags;
387
388 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
389 /*
390 * Do not work with ref_count here in case
391 * of spurious interrupt
392 */
393 if (lock->enabled)
394 wake_lock(&lock->read_lock);
395 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
396}
397
398void process_lock_on_read(struct diag_nrt_wake_lock *lock, int pkt_len)
399{
400 unsigned long read_lock_flags;
401
402 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
403 if (lock->enabled) {
404 if (pkt_len > 0) {
405 /*
406 * We have an data that is read that
407 * needs to be processed, make sure the
408 * processor does not go to sleep
409 */
410 lock->ref_count++;
411 if (!wake_lock_active(&lock->read_lock))
412 wake_lock(&lock->read_lock);
413 } else {
414 /*
415 * There was no data associated with the
416 * read from the smd, unlock the wake lock
417 * if it is not needed.
418 */
419 if (lock->ref_count < 1) {
420 if (wake_lock_active(&lock->read_lock))
421 wake_unlock(&lock->read_lock);
422 lock->ref_count = 0;
423 lock->copy_count = 0;
424 }
425 }
426 }
427 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
428}
429
430void process_lock_on_copy(struct diag_nrt_wake_lock *lock)
431{
432 unsigned long read_lock_flags;
433
434 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
435 if (lock->enabled)
436 lock->copy_count++;
437 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
438}
439
440void process_lock_on_copy_complete(struct diag_nrt_wake_lock *lock)
441{
442 unsigned long read_lock_flags;
443
444 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
445 if (lock->enabled) {
446 lock->ref_count -= lock->copy_count;
447 if (lock->ref_count < 1) {
448 wake_unlock(&lock->read_lock);
449 lock->ref_count = 0;
450 }
451 lock->copy_count = 0;
452 }
453 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
454}
455
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800456/* Process the data read from the smd data channel */
457int diag_process_smd_read_data(struct diag_smd_info *smd_info, void *buf,
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800458 int total_recd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700459{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460 struct diag_request *write_ptr_modem = NULL;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800461 int *in_busy_ptr = 0;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800462 int err = 0;
463
464 /*
465 * Do not process data on command channel if the
466 * channel is not designated to do so
467 */
468 if ((smd_info->type == SMD_CMD_TYPE) &&
469 !driver->separate_cmdrsp[smd_info->peripheral]) {
470 /* This print is for debugging */
471 pr_err("diag, In %s, received data on non-designated command channel: %d\n",
472 __func__, smd_info->peripheral);
473 return 0;
474 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800476 /* If the data is already hdlc encoded */
477 if (!smd_info->encode_hdlc) {
478 if (smd_info->buf_in_1 == buf) {
479 write_ptr_modem = smd_info->write_ptr_1;
480 in_busy_ptr = &smd_info->in_busy_1;
481 } else if (smd_info->buf_in_2 == buf) {
482 write_ptr_modem = smd_info->write_ptr_2;
483 in_busy_ptr = &smd_info->in_busy_2;
484 } else {
485 pr_err("diag: In %s, no match for in_busy_1, peripheral: %d\n",
486 __func__, smd_info->peripheral);
487 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800489 if (write_ptr_modem) {
490 write_ptr_modem->length = total_recd;
491 *in_busy_ptr = 1;
492 err = diag_device_write(buf, smd_info->peripheral,
493 write_ptr_modem);
494 if (err) {
495 /* Free up the buffer for future use */
496 *in_busy_ptr = 0;
497 pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
498 __func__, err);
499 }
500 }
501 } else {
502 /* The data is raw and needs to be hdlc encoded */
503 if (smd_info->buf_in_1_raw == buf) {
504 write_ptr_modem = smd_info->write_ptr_1;
505 in_busy_ptr = &smd_info->in_busy_1;
506 } else if (smd_info->buf_in_2_raw == buf) {
507 write_ptr_modem = smd_info->write_ptr_2;
508 in_busy_ptr = &smd_info->in_busy_2;
509 } else {
510 pr_err("diag: In %s, no match for in_busy_1, peripheral: %d\n",
511 __func__, smd_info->peripheral);
512 }
513
514 if (write_ptr_modem) {
515 int success = 0;
516 int write_length = 0;
517 unsigned char *write_buf = NULL;
518
519 write_length = check_bufsize_for_encoding(smd_info, buf,
520 total_recd);
521 if (write_length) {
522 write_buf = (buf == smd_info->buf_in_1_raw) ?
523 smd_info->buf_in_1 : smd_info->buf_in_2;
524 success = diag_add_hdlc_encoding(smd_info, buf,
525 total_recd, write_buf,
526 &write_length);
527 if (success) {
528 write_ptr_modem->length = write_length;
529 *in_busy_ptr = 1;
530 err = diag_device_write(write_buf,
531 smd_info->peripheral,
532 write_ptr_modem);
533 if (err) {
534 /*
535 * Free up the buffer for
536 * future use
537 */
538 *in_busy_ptr = 0;
539 pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
540 __func__, err);
541 }
542 }
543 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800544 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800545 }
546
547 return 0;
548}
549
Dixon Petersond2309b42013-08-28 21:00:05 -0700550static int diag_smd_resize_buf(struct diag_smd_info *smd_info, void **buf,
551 unsigned int *buf_size,
552 unsigned int requested_size)
553{
554 int success = 0;
555 void *temp_buf = NULL;
556 unsigned int new_buf_size = requested_size;
557
558 if (!smd_info)
559 return success;
560
561 if (requested_size <= MAX_IN_BUF_SIZE) {
562 pr_debug("diag: In %s, SMD peripheral: %d sending in packets up to %d bytes\n",
563 __func__, smd_info->peripheral, requested_size);
564 } else {
565 pr_err_ratelimited("diag: In %s, SMD peripheral: %d, Packet size sent: %d, Max size supported (%d) exceeded. Data beyond max size will be lost\n",
566 __func__, smd_info->peripheral, requested_size,
567 MAX_IN_BUF_SIZE);
568 new_buf_size = MAX_IN_BUF_SIZE;
569 }
570
571 /* Only resize if the buffer can be increased in size */
572 if (new_buf_size <= *buf_size) {
573 success = 1;
574 return success;
575 }
576
577 temp_buf = krealloc(*buf, new_buf_size, GFP_KERNEL);
578
579 if (temp_buf) {
580 /* Match the buffer and reset the pointer and size */
581 if (smd_info->encode_hdlc) {
582 /*
583 * This smd channel is supporting HDLC encoding
584 * on the apps
585 */
586 void *temp_hdlc = NULL;
587 if (*buf == smd_info->buf_in_1_raw) {
588 smd_info->buf_in_1_raw = temp_buf;
589 smd_info->buf_in_1_raw_size = new_buf_size;
590 temp_hdlc = krealloc(smd_info->buf_in_1,
591 MAX_IN_BUF_SIZE,
592 GFP_KERNEL);
593 if (temp_hdlc) {
594 smd_info->buf_in_1 = temp_hdlc;
595 smd_info->buf_in_1_size =
596 MAX_IN_BUF_SIZE;
597 }
598 } else if (*buf == smd_info->buf_in_2_raw) {
599 smd_info->buf_in_2_raw = temp_buf;
600 smd_info->buf_in_2_raw_size = new_buf_size;
601 temp_hdlc = krealloc(smd_info->buf_in_2,
602 MAX_IN_BUF_SIZE,
603 GFP_KERNEL);
604 if (temp_hdlc) {
605 smd_info->buf_in_2 = temp_hdlc;
606 smd_info->buf_in_2_size =
607 MAX_IN_BUF_SIZE;
608 }
609 }
610 } else {
611 if (*buf == smd_info->buf_in_1) {
612 smd_info->buf_in_1 = temp_buf;
613 smd_info->buf_in_1_size = new_buf_size;
614 } else if (*buf == smd_info->buf_in_2) {
615 smd_info->buf_in_2 = temp_buf;
616 smd_info->buf_in_2_size = new_buf_size;
617 }
618 }
619 *buf = temp_buf;
620 *buf_size = new_buf_size;
621 success = 1;
622 } else {
623 pr_err_ratelimited("diag: In %s, SMD peripheral: %d. packet size sent: %d, resize to support failed. Data beyond %d will be lost\n",
624 __func__, smd_info->peripheral, requested_size,
625 *buf_size);
626 }
627
628 return success;
629}
630
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800631void diag_smd_send_req(struct diag_smd_info *smd_info)
632{
633 void *buf = NULL, *temp_buf = NULL;
634 int total_recd = 0, r = 0, pkt_len;
635 int loop_count = 0;
636 int notify = 0;
Dixon Petersond2309b42013-08-28 21:00:05 -0700637 int buf_size = 0;
638 int resize_success = 0;
639 int buf_full = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800640
641 if (!smd_info) {
642 pr_err("diag: In %s, no smd info. Not able to read.\n",
643 __func__);
644 return;
645 }
646
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800647 /* Determine the buffer to read the data into. */
648 if (smd_info->type == SMD_DATA_TYPE) {
649 /* If the data is raw and not hdlc encoded */
650 if (smd_info->encode_hdlc) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700651 if (!smd_info->in_busy_1) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800652 buf = smd_info->buf_in_1_raw;
Dixon Petersond2309b42013-08-28 21:00:05 -0700653 buf_size = smd_info->buf_in_1_raw_size;
654 } else if (!smd_info->in_busy_2) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800655 buf = smd_info->buf_in_2_raw;
Dixon Petersond2309b42013-08-28 21:00:05 -0700656 buf_size = smd_info->buf_in_2_raw_size;
657 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800658 } else {
Dixon Petersond2309b42013-08-28 21:00:05 -0700659 if (!smd_info->in_busy_1) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800660 buf = smd_info->buf_in_1;
Dixon Petersond2309b42013-08-28 21:00:05 -0700661 buf_size = smd_info->buf_in_1_size;
662 } else if (!smd_info->in_busy_2) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800663 buf = smd_info->buf_in_2;
Dixon Petersond2309b42013-08-28 21:00:05 -0700664 buf_size = smd_info->buf_in_2_size;
665 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800666 }
667 } else if (smd_info->type == SMD_CMD_TYPE) {
668 /* If the data is raw and not hdlc encoded */
669 if (smd_info->encode_hdlc) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700670 if (!smd_info->in_busy_1) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800671 buf = smd_info->buf_in_1_raw;
Dixon Petersond2309b42013-08-28 21:00:05 -0700672 buf_size = smd_info->buf_in_1_raw_size;
673 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800674 } else {
Dixon Petersond2309b42013-08-28 21:00:05 -0700675 if (!smd_info->in_busy_1) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800676 buf = smd_info->buf_in_1;
Dixon Petersond2309b42013-08-28 21:00:05 -0700677 buf_size = smd_info->buf_in_1_size;
678 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800679 }
680 } else if (!smd_info->in_busy_1) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800681 buf = smd_info->buf_in_1;
Dixon Petersond2309b42013-08-28 21:00:05 -0700682 buf_size = smd_info->buf_in_1_size;
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800683 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800684
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700685 if (!buf && (smd_info->type == SMD_DCI_TYPE ||
686 smd_info->type == SMD_DCI_CMD_TYPE))
687 diag_dci_try_deactivate_wakeup_source(smd_info->ch);
688
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800689 if (smd_info->ch && buf) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800690 pkt_len = smd_cur_packet_size(smd_info->ch);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700691
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700692 if (pkt_len == 0 && (smd_info->type == SMD_DCI_TYPE ||
693 smd_info->type == SMD_DCI_CMD_TYPE))
694 diag_dci_try_deactivate_wakeup_source(smd_info->ch);
695
Dixon Petersond2309b42013-08-28 21:00:05 -0700696 if (pkt_len > buf_size)
697 resize_success = diag_smd_resize_buf(smd_info, &buf,
698 &buf_size, pkt_len);
699 temp_buf = buf;
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700700 while (pkt_len && (pkt_len != total_recd)) {
701 loop_count++;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800702 r = smd_read_avail(smd_info->ch);
Dixon Petersond2309b42013-08-28 21:00:05 -0700703 pr_debug("diag: In %s, SMD peripheral: %d, received pkt %d %d\n",
704 __func__, smd_info->peripheral, r, total_recd);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700705 if (!r) {
706 /* Nothing to read from SMD */
707 wait_event(driver->smd_wait_q,
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800708 ((smd_info->ch == 0) ||
709 smd_read_avail(smd_info->ch)));
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700710 /* If the smd channel is open */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800711 if (smd_info->ch) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700712 pr_debug("diag: In %s, SMD peripheral: %d, return from wait_event\n",
713 __func__, smd_info->peripheral);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700714 continue;
715 } else {
Dixon Petersond2309b42013-08-28 21:00:05 -0700716 pr_debug("diag: In %s, SMD peripheral: %d, return from wait_event ch closed\n",
717 __func__, smd_info->peripheral);
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700718 goto fail_return;
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700719 }
720 }
Dixon Petersond2309b42013-08-28 21:00:05 -0700721
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700722 if (pkt_len < r) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700723 pr_err("diag: In %s, SMD peripheral: %d, sending incorrect pkt\n",
724 __func__, smd_info->peripheral);
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700725 goto fail_return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700726 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800727 if (pkt_len > r) {
Dixon Peterson6dba7572013-04-12 18:45:16 -0700728 pr_debug("diag: In %s, SMD sending partial pkt %d %d %d %d %d %d\n",
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800729 __func__, pkt_len, r, total_recd, loop_count,
730 smd_info->peripheral, smd_info->type);
731 }
732
Dixon Petersond2309b42013-08-28 21:00:05 -0700733 /* Protect from going beyond the end of the buffer */
734 if (total_recd < buf_size) {
735 if (total_recd + r > buf_size) {
736 r = buf_size - total_recd;
737 buf_full = 1;
738 }
739
740 total_recd += r;
741
742 /* Keep reading for complete packet */
743 smd_read(smd_info->ch, temp_buf, r);
744 temp_buf += r;
745 } else {
746 /*
747 * This block handles the very rare case of a
748 * packet that is greater in length than what
749 * we can support. In this case, we
750 * incrementally drain the remaining portion
751 * of the packet that will not fit in the
752 * buffer, so that the entire packet is read
753 * from the smd.
754 */
755 int drain_bytes = (r > SMD_DRAIN_BUF_SIZE) ?
756 SMD_DRAIN_BUF_SIZE : r;
757 unsigned char *drain_buf = kzalloc(drain_bytes,
758 GFP_KERNEL);
759 if (drain_buf) {
760 total_recd += drain_bytes;
761 smd_read(smd_info->ch, drain_buf,
762 drain_bytes);
763 kfree(drain_buf);
764 } else {
765 pr_err("diag: In %s, SMD peripheral: %d, unable to allocate drain buffer\n",
766 __func__, smd_info->peripheral);
767 break;
768 }
769 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700770 }
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800771 if (!driver->real_time_mode && smd_info->type == SMD_DATA_TYPE)
772 process_lock_on_read(&smd_info->nrt_lock, pkt_len);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700773
774 if (total_recd > 0) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800775 if (!buf) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700776 pr_err("diag: In %s, SMD peripheral: %d, Out of diagmem for Modem\n",
777 __func__, smd_info->peripheral);
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800778 } else if (smd_info->process_smd_read_data) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700779 /*
780 * If the buffer was totally filled, reset
781 * total_recd appropriately
782 */
783 if (buf_full)
784 total_recd = buf_size;
785
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800786 notify = smd_info->process_smd_read_data(
787 smd_info, buf, total_recd);
788 /* Poll SMD channels to check for data */
789 if (notify)
790 diag_smd_notify(smd_info,
791 SMD_EVENT_DATA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792 }
793 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800794 } else if (smd_info->ch && !buf &&
Dixon Peterson743a11e2012-07-30 17:42:20 -0700795 (driver->logging_mode == MEMORY_DEVICE_MODE)) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800796 chk_logging_wakeup();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700797 }
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700798 return;
799
800fail_return:
801 if (smd_info->type == SMD_DCI_TYPE ||
802 smd_info->type == SMD_DCI_CMD_TYPE)
803 diag_dci_try_deactivate_wakeup_source(smd_info->ch);
804 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805}
806
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800807void diag_read_smd_work_fn(struct work_struct *work)
808{
809 struct diag_smd_info *smd_info = container_of(work,
810 struct diag_smd_info,
811 diag_read_smd_work);
812 diag_smd_send_req(smd_info);
813}
814
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800815int diag_device_write(void *buf, int data_type, struct diag_request *write_ptr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700816{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800817 int i, err = 0, index;
818 index = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700819
820 if (driver->logging_mode == MEMORY_DEVICE_MODE) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800821 if (data_type == APPS_DATA) {
Dixon Petersona6d98092013-05-16 12:26:26 -0700822 for (i = 0; i < driver->buf_tbl_size; i++)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700823 if (driver->buf_tbl[i].length == 0) {
824 driver->buf_tbl[i].buf = buf;
825 driver->buf_tbl[i].length =
826 driver->used;
827#ifdef DIAG_DEBUG
828 pr_debug("diag: ENQUEUE buf ptr"
829 " and length is %x , %d\n",
830 (unsigned int)(driver->buf_
831 tbl[i].buf), driver->buf_tbl[i].length);
832#endif
833 break;
834 }
835 }
Dixon Peterson938f8602012-08-17 20:02:57 -0700836
Shalabh Jain737fca72012-11-14 21:53:43 -0800837#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Shalabh Jainb0037c02013-01-18 12:47:40 -0800838 else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700839 unsigned long flags;
840 int foundIndex = -1;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800841 index = data_type - HSIC_DATA;
842 spin_lock_irqsave(&diag_hsic[index].hsic_spinlock,
843 flags);
844 for (i = 0; i < diag_hsic[index].poolsize_hsic_write;
845 i++) {
846 if (diag_hsic[index].hsic_buf_tbl[i].length
847 == 0) {
848 diag_hsic[index].hsic_buf_tbl[i].buf
849 = buf;
850 diag_hsic[index].hsic_buf_tbl[i].length
851 = diag_bridge[index].write_len;
852 diag_hsic[index].
853 num_hsic_buf_tbl_entries++;
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700854 foundIndex = i;
Dixon Peterson938f8602012-08-17 20:02:57 -0700855 break;
856 }
857 }
Shalabh Jainb0037c02013-01-18 12:47:40 -0800858 spin_unlock_irqrestore(&diag_hsic[index].hsic_spinlock,
859 flags);
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700860 if (foundIndex == -1)
861 err = -1;
862 else
Shalabh Jainb0037c02013-01-18 12:47:40 -0800863 pr_debug("diag: ENQUEUE HSIC buf ptr and length is %x , %d, ch %d\n",
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700864 (unsigned int)buf,
Shalabh Jainb0037c02013-01-18 12:47:40 -0800865 diag_bridge[index].write_len, index);
Dixon Peterson938f8602012-08-17 20:02:57 -0700866 }
867#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700868 for (i = 0; i < driver->num_clients; i++)
869 if (driver->client_map[i].pid ==
870 driver->logging_process_id)
871 break;
872 if (i < driver->num_clients) {
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700873 pr_debug("diag: wake up logging process\n");
Dixon Petersonbba99ca2013-07-10 17:25:20 -0700874 driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700875 wake_up_interruptible(&driver->wait_q);
876 } else
877 return -EINVAL;
878 } else if (driver->logging_mode == NO_LOGGING_MODE) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800879 if ((data_type >= MODEM_DATA) && (data_type <= WCNSS_DATA)) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800880 driver->smd_data[data_type].in_busy_1 = 0;
881 driver->smd_data[data_type].in_busy_2 = 0;
Dixon Petersonbba99ca2013-07-10 17:25:20 -0700882 queue_work(driver->smd_data[data_type].wq,
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800883 &(driver->smd_data[data_type].
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800884 diag_read_smd_work));
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800885 if (data_type == MODEM_DATA &&
886 driver->separate_cmdrsp[data_type]) {
887 driver->smd_cmd[data_type].in_busy_1 = 0;
888 driver->smd_cmd[data_type].in_busy_2 = 0;
889 queue_work(driver->diag_wq,
890 &(driver->smd_cmd[data_type].
891 diag_read_smd_work));
892 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700893 }
Shalabh Jain482bf122011-12-06 03:54:47 -0800894#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800895 else if (data_type == SDIO_DATA) {
Shalabh Jain482bf122011-12-06 03:54:47 -0800896 driver->in_busy_sdio = 0;
897 queue_work(driver->diag_sdio_wq,
898 &(driver->diag_read_sdio_work));
899 }
900#endif
Shalabh Jain737fca72012-11-14 21:53:43 -0800901#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Shalabh Jainb0037c02013-01-18 12:47:40 -0800902 else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
903 index = data_type - HSIC_DATA;
904 if (diag_hsic[index].hsic_ch)
905 queue_work(diag_bridge[index].wq,
906 &(diag_hsic[index].
907 diag_read_hsic_work));
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700908 }
909#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910 err = -1;
911 }
912#ifdef CONFIG_DIAG_OVER_USB
913 else if (driver->logging_mode == USB_MODE) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800914 if (data_type == APPS_DATA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700915 driver->write_ptr_svc = (struct diag_request *)
916 (diagmem_alloc(driver, sizeof(struct diag_request),
917 POOL_TYPE_WRITE_STRUCT));
918 if (driver->write_ptr_svc) {
919 driver->write_ptr_svc->length = driver->used;
920 driver->write_ptr_svc->buf = buf;
921 err = usb_diag_write(driver->legacy_ch,
922 driver->write_ptr_svc);
Ravi Aravamudhand995a7f2013-07-03 13:06:15 -0700923 /* Free the buffer if write failed */
924 if (err) {
925 diagmem_free(driver,
926 (unsigned char *)driver->
927 write_ptr_svc,
928 POOL_TYPE_WRITE_STRUCT);
929 }
930 } else {
931 err = -ENOMEM;
932 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800933 } else if ((data_type >= MODEM_DATA) &&
934 (data_type <= WCNSS_DATA)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700935 write_ptr->buf = buf;
936#ifdef DIAG_DEBUG
937 printk(KERN_INFO "writing data to USB,"
938 "pkt length %d\n", write_ptr->length);
939 print_hex_dump(KERN_DEBUG, "Written Packet Data to"
940 " USB: ", 16, 1, DUMP_PREFIX_ADDRESS,
941 buf, write_ptr->length, 1);
942#endif /* DIAG DEBUG */
943 err = usb_diag_write(driver->legacy_ch, write_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700944 }
945#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800946 else if (data_type == SDIO_DATA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700947 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -0800948 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700949 write_ptr->buf = buf;
950 err = usb_diag_write(driver->mdm_ch, write_ptr);
951 } else
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800952 pr_err("diag: Incorrect sdio data "
953 "while USB write\n");
954 }
955#endif
Shalabh Jain737fca72012-11-14 21:53:43 -0800956#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Shalabh Jainb0037c02013-01-18 12:47:40 -0800957 else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
958 index = data_type - HSIC_DATA;
959 if (diag_hsic[index].hsic_device_enabled) {
Dixon Peterson938f8602012-08-17 20:02:57 -0700960 struct diag_request *write_ptr_mdm;
961 write_ptr_mdm = (struct diag_request *)
962 diagmem_alloc(driver,
963 sizeof(struct diag_request),
Shalabh Jainb0037c02013-01-18 12:47:40 -0800964 index +
Dixon Peterson938f8602012-08-17 20:02:57 -0700965 POOL_TYPE_HSIC_WRITE);
966 if (write_ptr_mdm) {
967 write_ptr_mdm->buf = buf;
968 write_ptr_mdm->length =
Shalabh Jainb0037c02013-01-18 12:47:40 -0800969 diag_bridge[index].write_len;
970 write_ptr_mdm->context = (void *)index;
Shalabh Jain737fca72012-11-14 21:53:43 -0800971 err = usb_diag_write(
Shalabh Jainb0037c02013-01-18 12:47:40 -0800972 diag_bridge[index].ch, write_ptr_mdm);
Dixon Peterson938f8602012-08-17 20:02:57 -0700973 /* Return to the pool immediately */
974 if (err) {
975 diagmem_free(driver,
976 write_ptr_mdm,
Shalabh Jainb0037c02013-01-18 12:47:40 -0800977 index +
Dixon Peterson938f8602012-08-17 20:02:57 -0700978 POOL_TYPE_HSIC_WRITE);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800979 pr_err_ratelimited("diag: HSIC write failure, err: %d, ch %d\n",
980 err, index);
Dixon Peterson938f8602012-08-17 20:02:57 -0700981 }
982 } else {
983 pr_err("diag: allocate write fail\n");
984 err = -1;
985 }
986 } else {
Shalabh Jain737fca72012-11-14 21:53:43 -0800987 pr_err("diag: Incorrect HSIC data "
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800988 "while USB write\n");
Dixon Peterson938f8602012-08-17 20:02:57 -0700989 err = -1;
990 }
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800991 } else if (data_type == SMUX_DATA) {
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700992 write_ptr->buf = buf;
Shalabh Jain737fca72012-11-14 21:53:43 -0800993 write_ptr->context = (void *)SMUX;
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700994 pr_debug("diag: writing SMUX data\n");
Shalabh Jain737fca72012-11-14 21:53:43 -0800995 err = usb_diag_write(diag_bridge[SMUX].ch,
996 write_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700997 }
998#endif
999 APPEND_DEBUG('d');
1000 }
1001#endif /* DIAG OVER USB */
1002 return err;
1003}
1004
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001005static void diag_update_pkt_buffer(unsigned char *buf)
1006{
1007 unsigned char *ptr = driver->pkt_buf;
1008 unsigned char *temp = buf;
1009
1010 mutex_lock(&driver->diagchar_mutex);
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001011 if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, driver->pkt_length)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012 memcpy(ptr, temp , driver->pkt_length);
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001013 driver->in_busy_pktdata = 1;
1014 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001015 printk(KERN_CRIT " Not enough buffer space for PKT_RESP\n");
1016 mutex_unlock(&driver->diagchar_mutex);
1017}
1018
1019void diag_update_userspace_clients(unsigned int type)
1020{
1021 int i;
1022
1023 mutex_lock(&driver->diagchar_mutex);
1024 for (i = 0; i < driver->num_clients; i++)
1025 if (driver->client_map[i].pid != 0)
1026 driver->data_ready[i] |= type;
1027 wake_up_interruptible(&driver->wait_q);
1028 mutex_unlock(&driver->diagchar_mutex);
1029}
1030
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001031void diag_update_sleeping_process(int process_id, int data_type)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032{
1033 int i;
1034
1035 mutex_lock(&driver->diagchar_mutex);
1036 for (i = 0; i < driver->num_clients; i++)
1037 if (driver->client_map[i].pid == process_id) {
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001038 driver->data_ready[i] |= data_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001039 break;
1040 }
1041 wake_up_interruptible(&driver->wait_q);
1042 mutex_unlock(&driver->diagchar_mutex);
1043}
1044
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001045static int diag_check_mode_reset(unsigned char *buf)
1046{
1047 int is_mode_reset = 0;
1048 if (chk_apps_master() && (int)(*(char *)buf) == MODE_CMD)
1049 if ((int)(*(char *)(buf+1)) == RESET_ID)
1050 is_mode_reset = 1;
1051 return is_mode_reset;
1052}
1053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001054void diag_send_data(struct diag_master_table entry, unsigned char *buf,
1055 int len, int type)
1056{
1057 driver->pkt_length = len;
Dixon Petersoncf8b6292013-05-07 19:01:29 -07001058
1059 /* If the process_id corresponds to an apps process */
1060 if (entry.process_id != NON_APPS_PROC) {
1061 /* If the message is to be sent to the apps process */
1062 if (type != MODEM_DATA) {
1063 diag_update_pkt_buffer(buf);
1064 diag_update_sleeping_process(entry.process_id,
1065 PKT_TYPE);
1066 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001067 } else {
1068 if (len > 0) {
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001069 if (entry.client_id < NUM_SMD_DATA_CHANNELS) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001070 struct diag_smd_info *smd_info;
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001071 int index = entry.client_id;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001072 /*
1073 * Mode reset should work even if
1074 * modem is down
1075 */
1076 if ((index == MODEM_DATA) &&
1077 diag_check_mode_reset(buf)) {
1078 return;
1079 }
1080 smd_info = (driver->separate_cmdrsp[index] &&
1081 index < NUM_SMD_CMD_CHANNELS) ?
1082 &driver->smd_cmd[index] :
1083 &driver->smd_data[index];
1084
1085 if (smd_info->ch) {
1086 mutex_lock(&smd_info->smd_ch_mutex);
1087 smd_write(smd_info->ch, buf, len);
1088 mutex_unlock(&smd_info->smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001089 } else {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001090 pr_err("diag: In %s, smd channel %d not open, peripheral: %d, type: %d\n",
1091 __func__, index,
1092 smd_info->peripheral,
1093 smd_info->type);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001094 }
Shalabh Jainc9f35092011-07-28 18:36:17 -07001095 } else {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001096 pr_alert("diag: In %s, incorrect channel: %d",
1097 __func__, entry.client_id);
Shalabh Jainc9f35092011-07-28 18:36:17 -07001098 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099 }
1100 }
1101}
1102
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07001103void diag_process_stm_mask(uint8_t cmd, uint8_t data_mask, int data_type,
1104 uint8_t *rsp_supported, uint8_t *rsp_smd_comply)
1105{
1106 int status = 0;
1107 if (data_type >= MODEM_DATA && data_type <= WCNSS_DATA) {
1108 if (driver->peripheral_supports_stm[data_type]) {
1109 status = diag_send_stm_state(
1110 &driver->smd_cntl[data_type], cmd);
1111 if (status == 1)
1112 *rsp_smd_comply |= data_mask;
1113 *rsp_supported |= data_mask;
1114 } else if (driver->smd_cntl[data_type].ch) {
1115 *rsp_smd_comply |= data_mask;
1116 }
1117 if ((*rsp_smd_comply & data_mask) &&
1118 (*rsp_supported & data_mask))
1119 driver->stm_state[data_type] = cmd;
1120
1121 driver->stm_state_requested[data_type] = cmd;
1122 } else if (data_type == APPS_DATA) {
1123 *rsp_supported |= data_mask;
1124 *rsp_smd_comply |= data_mask;
1125 driver->stm_state[data_type] = cmd;
1126 driver->stm_state_requested[data_type] = cmd;
1127 }
1128}
1129
1130int diag_process_stm_cmd(unsigned char *buf)
1131{
1132 uint8_t version = *(buf+STM_CMD_VERSION_OFFSET);
1133 uint8_t mask = *(buf+STM_CMD_MASK_OFFSET);
1134 uint8_t cmd = *(buf+STM_CMD_DATA_OFFSET);
1135 uint8_t rsp_supported = 0;
1136 uint8_t rsp_smd_comply = 0;
1137 int valid_command = 1;
1138 int i;
1139
1140 /* Check if command is valid */
1141 if ((version != 1) || (mask == 0) || (0 != (mask >> 4)) ||
1142 (cmd != ENABLE_STM && cmd != DISABLE_STM)) {
1143 valid_command = 0;
1144 } else {
1145 if (mask & DIAG_STM_MODEM)
1146 diag_process_stm_mask(cmd, DIAG_STM_MODEM, MODEM_DATA,
1147 &rsp_supported, &rsp_smd_comply);
1148
1149 if (mask & DIAG_STM_LPASS)
1150 diag_process_stm_mask(cmd, DIAG_STM_LPASS, LPASS_DATA,
1151 &rsp_supported, &rsp_smd_comply);
1152
1153 if (mask & DIAG_STM_WCNSS)
1154 diag_process_stm_mask(cmd, DIAG_STM_WCNSS, WCNSS_DATA,
1155 &rsp_supported, &rsp_smd_comply);
1156
1157 if (mask & DIAG_STM_APPS)
1158 diag_process_stm_mask(cmd, DIAG_STM_APPS, APPS_DATA,
1159 &rsp_supported, &rsp_smd_comply);
1160 }
1161
1162 for (i = 0; i < STM_CMD_NUM_BYTES; i++)
1163 driver->apps_rsp_buf[i] = *(buf+i);
1164
1165 driver->apps_rsp_buf[STM_RSP_VALID_INDEX] = valid_command;
1166 driver->apps_rsp_buf[STM_RSP_SUPPORTED_INDEX] = rsp_supported;
1167 driver->apps_rsp_buf[STM_RSP_SMD_COMPLY_INDEX] = rsp_smd_comply;
1168
1169 encode_rsp_and_send(STM_RSP_NUM_BYTES-1);
1170
1171 return 0;
1172}
1173
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07001174int diag_apps_responds()
1175{
1176 if (chk_apps_only()) {
1177 if (driver->smd_data[MODEM_DATA].ch &&
1178 driver->rcvd_feature_mask[MODEM_DATA]) {
1179 return 0;
1180 }
1181 return 1;
1182 }
1183 return 0;
1184}
1185
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001186int diag_process_apps_pkt(unsigned char *buf, int len)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001187{
1188 uint16_t subsys_cmd_code;
1189 int subsys_id, ssid_first, ssid_last, ssid_range;
Shalabh Jain3fd986f2012-05-30 18:42:26 -07001190 int packet_type = 1, i, cmd_code;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001191 unsigned char *temp = buf;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001192 int data_type;
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001193 int mask_ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001194#if defined(CONFIG_DIAG_OVER_USB)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195 unsigned char *ptr;
1196#endif
1197
Dixon Petersond6a20a92012-09-27 15:58:50 -07001198 /* Check if the command is a supported mask command */
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001199 mask_ret = diag_process_apps_masks(buf, len);
1200 if (mask_ret <= 0)
1201 return mask_ret;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001202
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203 /* Check for registered clients and forward packet to apropriate proc */
1204 cmd_code = (int)(*(char *)buf);
1205 temp++;
1206 subsys_id = (int)(*(char *)temp);
1207 temp++;
1208 subsys_cmd_code = *(uint16_t *)temp;
1209 temp += 2;
1210 data_type = APPS_DATA;
1211 /* Dont send any command other than mode reset */
Shalabh Jain10f5f432012-01-11 11:45:44 +05301212 if (chk_apps_master() && cmd_code == MODE_CMD) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001213 if (subsys_id != RESET_ID)
1214 data_type = MODEM_DATA;
1215 }
1216
1217 pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
Shalabh Jainfe02b0c2012-02-21 14:48:03 -08001218 for (i = 0; i < diag_max_reg; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001219 entry = driver->table[i];
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07001220 if (entry.process_id != NO_PROCESS &&
1221 driver->rcvd_feature_mask[entry.client_id]) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222 if (entry.cmd_code == cmd_code && entry.subsys_id ==
1223 subsys_id && entry.cmd_code_lo <=
1224 subsys_cmd_code &&
1225 entry.cmd_code_hi >= subsys_cmd_code) {
1226 diag_send_data(entry, buf, len, data_type);
1227 packet_type = 0;
1228 } else if (entry.cmd_code == 255
1229 && cmd_code == 75) {
1230 if (entry.subsys_id ==
1231 subsys_id &&
1232 entry.cmd_code_lo <=
1233 subsys_cmd_code &&
1234 entry.cmd_code_hi >=
1235 subsys_cmd_code) {
1236 diag_send_data(entry, buf, len,
1237 data_type);
1238 packet_type = 0;
1239 }
1240 } else if (entry.cmd_code == 255 &&
1241 entry.subsys_id == 255) {
1242 if (entry.cmd_code_lo <=
1243 cmd_code &&
1244 entry.
1245 cmd_code_hi >= cmd_code) {
1246 diag_send_data(entry, buf, len,
1247 data_type);
1248 packet_type = 0;
1249 }
1250 }
1251 }
1252 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001253#if defined(CONFIG_DIAG_OVER_USB)
Dixon Petersona2dd7352012-05-21 17:37:10 -07001254 /* Check for the command/respond msg for the maximum packet length */
1255 if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
1256 (*(uint16_t *)(buf+2) == 0x0055)) {
1257 for (i = 0; i < 4; i++)
1258 *(driver->apps_rsp_buf+i) = *(buf+i);
1259 *(uint32_t *)(driver->apps_rsp_buf+4) = PKT_SIZE;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001260 encode_rsp_and_send(7);
Dixon Petersona2dd7352012-05-21 17:37:10 -07001261 return 0;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07001262 } else if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
1263 (*(uint16_t *)(buf+2) == 0x020E)) {
1264 return diag_process_stm_cmd(buf);
Dixon Petersona2dd7352012-05-21 17:37:10 -07001265 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001266 /* Check for Apps Only & get event mask request */
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07001267 else if (diag_apps_responds() && *buf == 0x81) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001268 driver->apps_rsp_buf[0] = 0x81;
1269 driver->apps_rsp_buf[1] = 0x0;
1270 *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
1271 *(uint16_t *)(driver->apps_rsp_buf + 4) = EVENT_LAST_ID + 1;
1272 for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
1273 *(unsigned char *)(driver->apps_rsp_buf + 6 + i) = 0x0;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001274 encode_rsp_and_send(6 + EVENT_LAST_ID/8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001275 return 0;
1276 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001277 /* Get log ID range & Check for Apps Only */
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07001278 else if (diag_apps_responds() && (*buf == 0x73) &&
1279 *(int *)(buf+4) == 1) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001280 driver->apps_rsp_buf[0] = 0x73;
1281 *(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
1282 *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success code */
1283 *(int *)(driver->apps_rsp_buf + 12) = LOG_GET_ITEM_NUM(LOG_0);
1284 *(int *)(driver->apps_rsp_buf + 16) = LOG_GET_ITEM_NUM(LOG_1);
1285 *(int *)(driver->apps_rsp_buf + 20) = LOG_GET_ITEM_NUM(LOG_2);
1286 *(int *)(driver->apps_rsp_buf + 24) = LOG_GET_ITEM_NUM(LOG_3);
1287 *(int *)(driver->apps_rsp_buf + 28) = LOG_GET_ITEM_NUM(LOG_4);
1288 *(int *)(driver->apps_rsp_buf + 32) = LOG_GET_ITEM_NUM(LOG_5);
1289 *(int *)(driver->apps_rsp_buf + 36) = LOG_GET_ITEM_NUM(LOG_6);
1290 *(int *)(driver->apps_rsp_buf + 40) = LOG_GET_ITEM_NUM(LOG_7);
1291 *(int *)(driver->apps_rsp_buf + 44) = LOG_GET_ITEM_NUM(LOG_8);
1292 *(int *)(driver->apps_rsp_buf + 48) = LOG_GET_ITEM_NUM(LOG_9);
1293 *(int *)(driver->apps_rsp_buf + 52) = LOG_GET_ITEM_NUM(LOG_10);
1294 *(int *)(driver->apps_rsp_buf + 56) = LOG_GET_ITEM_NUM(LOG_11);
1295 *(int *)(driver->apps_rsp_buf + 60) = LOG_GET_ITEM_NUM(LOG_12);
1296 *(int *)(driver->apps_rsp_buf + 64) = LOG_GET_ITEM_NUM(LOG_13);
1297 *(int *)(driver->apps_rsp_buf + 68) = LOG_GET_ITEM_NUM(LOG_14);
1298 *(int *)(driver->apps_rsp_buf + 72) = LOG_GET_ITEM_NUM(LOG_15);
Dixon Petersond6a20a92012-09-27 15:58:50 -07001299 encode_rsp_and_send(75);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300 return 0;
1301 }
1302 /* Respond to Get SSID Range request message */
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07001303 else if (diag_apps_responds() && (*buf == 0x7d) &&
1304 (*(buf+1) == 0x1)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001305 driver->apps_rsp_buf[0] = 0x7d;
1306 driver->apps_rsp_buf[1] = 0x1;
1307 driver->apps_rsp_buf[2] = 0x1;
1308 driver->apps_rsp_buf[3] = 0x0;
Shalabh Jain44b79b72012-06-15 13:39:27 -07001309 /* -1 to un-account for OEM SSID range */
1310 *(int *)(driver->apps_rsp_buf + 4) = MSG_MASK_TBL_CNT - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001311 *(uint16_t *)(driver->apps_rsp_buf + 8) = MSG_SSID_0;
1312 *(uint16_t *)(driver->apps_rsp_buf + 10) = MSG_SSID_0_LAST;
1313 *(uint16_t *)(driver->apps_rsp_buf + 12) = MSG_SSID_1;
1314 *(uint16_t *)(driver->apps_rsp_buf + 14) = MSG_SSID_1_LAST;
1315 *(uint16_t *)(driver->apps_rsp_buf + 16) = MSG_SSID_2;
1316 *(uint16_t *)(driver->apps_rsp_buf + 18) = MSG_SSID_2_LAST;
1317 *(uint16_t *)(driver->apps_rsp_buf + 20) = MSG_SSID_3;
1318 *(uint16_t *)(driver->apps_rsp_buf + 22) = MSG_SSID_3_LAST;
1319 *(uint16_t *)(driver->apps_rsp_buf + 24) = MSG_SSID_4;
1320 *(uint16_t *)(driver->apps_rsp_buf + 26) = MSG_SSID_4_LAST;
1321 *(uint16_t *)(driver->apps_rsp_buf + 28) = MSG_SSID_5;
1322 *(uint16_t *)(driver->apps_rsp_buf + 30) = MSG_SSID_5_LAST;
1323 *(uint16_t *)(driver->apps_rsp_buf + 32) = MSG_SSID_6;
1324 *(uint16_t *)(driver->apps_rsp_buf + 34) = MSG_SSID_6_LAST;
1325 *(uint16_t *)(driver->apps_rsp_buf + 36) = MSG_SSID_7;
1326 *(uint16_t *)(driver->apps_rsp_buf + 38) = MSG_SSID_7_LAST;
1327 *(uint16_t *)(driver->apps_rsp_buf + 40) = MSG_SSID_8;
1328 *(uint16_t *)(driver->apps_rsp_buf + 42) = MSG_SSID_8_LAST;
1329 *(uint16_t *)(driver->apps_rsp_buf + 44) = MSG_SSID_9;
1330 *(uint16_t *)(driver->apps_rsp_buf + 46) = MSG_SSID_9_LAST;
1331 *(uint16_t *)(driver->apps_rsp_buf + 48) = MSG_SSID_10;
1332 *(uint16_t *)(driver->apps_rsp_buf + 50) = MSG_SSID_10_LAST;
1333 *(uint16_t *)(driver->apps_rsp_buf + 52) = MSG_SSID_11;
1334 *(uint16_t *)(driver->apps_rsp_buf + 54) = MSG_SSID_11_LAST;
1335 *(uint16_t *)(driver->apps_rsp_buf + 56) = MSG_SSID_12;
1336 *(uint16_t *)(driver->apps_rsp_buf + 58) = MSG_SSID_12_LAST;
1337 *(uint16_t *)(driver->apps_rsp_buf + 60) = MSG_SSID_13;
1338 *(uint16_t *)(driver->apps_rsp_buf + 62) = MSG_SSID_13_LAST;
1339 *(uint16_t *)(driver->apps_rsp_buf + 64) = MSG_SSID_14;
1340 *(uint16_t *)(driver->apps_rsp_buf + 66) = MSG_SSID_14_LAST;
1341 *(uint16_t *)(driver->apps_rsp_buf + 68) = MSG_SSID_15;
1342 *(uint16_t *)(driver->apps_rsp_buf + 70) = MSG_SSID_15_LAST;
1343 *(uint16_t *)(driver->apps_rsp_buf + 72) = MSG_SSID_16;
1344 *(uint16_t *)(driver->apps_rsp_buf + 74) = MSG_SSID_16_LAST;
1345 *(uint16_t *)(driver->apps_rsp_buf + 76) = MSG_SSID_17;
1346 *(uint16_t *)(driver->apps_rsp_buf + 78) = MSG_SSID_17_LAST;
1347 *(uint16_t *)(driver->apps_rsp_buf + 80) = MSG_SSID_18;
1348 *(uint16_t *)(driver->apps_rsp_buf + 82) = MSG_SSID_18_LAST;
Shalabh Jain321c8b52012-02-22 12:37:06 -08001349 *(uint16_t *)(driver->apps_rsp_buf + 84) = MSG_SSID_19;
1350 *(uint16_t *)(driver->apps_rsp_buf + 86) = MSG_SSID_19_LAST;
1351 *(uint16_t *)(driver->apps_rsp_buf + 88) = MSG_SSID_20;
1352 *(uint16_t *)(driver->apps_rsp_buf + 90) = MSG_SSID_20_LAST;
1353 *(uint16_t *)(driver->apps_rsp_buf + 92) = MSG_SSID_21;
1354 *(uint16_t *)(driver->apps_rsp_buf + 94) = MSG_SSID_21_LAST;
1355 *(uint16_t *)(driver->apps_rsp_buf + 96) = MSG_SSID_22;
1356 *(uint16_t *)(driver->apps_rsp_buf + 98) = MSG_SSID_22_LAST;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001357 encode_rsp_and_send(99);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001358 return 0;
1359 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001360 /* Check for Apps Only Respond to Get Subsys Build mask */
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07001361 else if (diag_apps_responds() && (*buf == 0x7d) &&
1362 (*(buf+1) == 0x2)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001363 ssid_first = *(uint16_t *)(buf + 2);
1364 ssid_last = *(uint16_t *)(buf + 4);
1365 ssid_range = 4 * (ssid_last - ssid_first + 1);
1366 /* frame response */
1367 driver->apps_rsp_buf[0] = 0x7d;
1368 driver->apps_rsp_buf[1] = 0x2;
1369 *(uint16_t *)(driver->apps_rsp_buf + 2) = ssid_first;
1370 *(uint16_t *)(driver->apps_rsp_buf + 4) = ssid_last;
1371 driver->apps_rsp_buf[6] = 0x1;
1372 driver->apps_rsp_buf[7] = 0x0;
1373 ptr = driver->apps_rsp_buf + 8;
1374 /* bld time masks */
1375 switch (ssid_first) {
1376 case MSG_SSID_0:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001377 if (ssid_range > sizeof(msg_bld_masks_0)) {
1378 pr_warning("diag: truncating ssid range for ssid 0");
1379 ssid_range = sizeof(msg_bld_masks_0);
1380 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001381 for (i = 0; i < ssid_range; i += 4)
1382 *(int *)(ptr + i) = msg_bld_masks_0[i/4];
1383 break;
1384 case MSG_SSID_1:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001385 if (ssid_range > sizeof(msg_bld_masks_1)) {
1386 pr_warning("diag: truncating ssid range for ssid 1");
1387 ssid_range = sizeof(msg_bld_masks_1);
1388 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001389 for (i = 0; i < ssid_range; i += 4)
1390 *(int *)(ptr + i) = msg_bld_masks_1[i/4];
1391 break;
1392 case MSG_SSID_2:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001393 if (ssid_range > sizeof(msg_bld_masks_2)) {
1394 pr_warning("diag: truncating ssid range for ssid 2");
1395 ssid_range = sizeof(msg_bld_masks_2);
1396 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001397 for (i = 0; i < ssid_range; i += 4)
1398 *(int *)(ptr + i) = msg_bld_masks_2[i/4];
1399 break;
1400 case MSG_SSID_3:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001401 if (ssid_range > sizeof(msg_bld_masks_3)) {
1402 pr_warning("diag: truncating ssid range for ssid 3");
1403 ssid_range = sizeof(msg_bld_masks_3);
1404 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001405 for (i = 0; i < ssid_range; i += 4)
1406 *(int *)(ptr + i) = msg_bld_masks_3[i/4];
1407 break;
1408 case MSG_SSID_4:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001409 if (ssid_range > sizeof(msg_bld_masks_4)) {
1410 pr_warning("diag: truncating ssid range for ssid 4");
1411 ssid_range = sizeof(msg_bld_masks_4);
1412 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001413 for (i = 0; i < ssid_range; i += 4)
1414 *(int *)(ptr + i) = msg_bld_masks_4[i/4];
1415 break;
1416 case MSG_SSID_5:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001417 if (ssid_range > sizeof(msg_bld_masks_5)) {
1418 pr_warning("diag: truncating ssid range for ssid 5");
1419 ssid_range = sizeof(msg_bld_masks_5);
1420 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001421 for (i = 0; i < ssid_range; i += 4)
1422 *(int *)(ptr + i) = msg_bld_masks_5[i/4];
1423 break;
1424 case MSG_SSID_6:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001425 if (ssid_range > sizeof(msg_bld_masks_6)) {
1426 pr_warning("diag: truncating ssid range for ssid 6");
1427 ssid_range = sizeof(msg_bld_masks_6);
1428 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001429 for (i = 0; i < ssid_range; i += 4)
1430 *(int *)(ptr + i) = msg_bld_masks_6[i/4];
1431 break;
1432 case MSG_SSID_7:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001433 if (ssid_range > sizeof(msg_bld_masks_7)) {
1434 pr_warning("diag: truncating ssid range for ssid 7");
1435 ssid_range = sizeof(msg_bld_masks_7);
1436 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001437 for (i = 0; i < ssid_range; i += 4)
1438 *(int *)(ptr + i) = msg_bld_masks_7[i/4];
1439 break;
1440 case MSG_SSID_8:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001441 if (ssid_range > sizeof(msg_bld_masks_8)) {
1442 pr_warning("diag: truncating ssid range for ssid 8");
1443 ssid_range = sizeof(msg_bld_masks_8);
1444 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445 for (i = 0; i < ssid_range; i += 4)
1446 *(int *)(ptr + i) = msg_bld_masks_8[i/4];
1447 break;
1448 case MSG_SSID_9:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001449 if (ssid_range > sizeof(msg_bld_masks_9)) {
1450 pr_warning("diag: truncating ssid range for ssid 9");
1451 ssid_range = sizeof(msg_bld_masks_9);
1452 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 for (i = 0; i < ssid_range; i += 4)
1454 *(int *)(ptr + i) = msg_bld_masks_9[i/4];
1455 break;
1456 case MSG_SSID_10:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001457 if (ssid_range > sizeof(msg_bld_masks_10)) {
1458 pr_warning("diag: truncating ssid range for ssid 10");
1459 ssid_range = sizeof(msg_bld_masks_10);
1460 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001461 for (i = 0; i < ssid_range; i += 4)
1462 *(int *)(ptr + i) = msg_bld_masks_10[i/4];
1463 break;
1464 case MSG_SSID_11:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001465 if (ssid_range > sizeof(msg_bld_masks_11)) {
1466 pr_warning("diag: truncating ssid range for ssid 11");
1467 ssid_range = sizeof(msg_bld_masks_11);
1468 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001469 for (i = 0; i < ssid_range; i += 4)
1470 *(int *)(ptr + i) = msg_bld_masks_11[i/4];
1471 break;
1472 case MSG_SSID_12:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001473 if (ssid_range > sizeof(msg_bld_masks_12)) {
1474 pr_warning("diag: truncating ssid range for ssid 12");
1475 ssid_range = sizeof(msg_bld_masks_12);
1476 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477 for (i = 0; i < ssid_range; i += 4)
1478 *(int *)(ptr + i) = msg_bld_masks_12[i/4];
1479 break;
1480 case MSG_SSID_13:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001481 if (ssid_range > sizeof(msg_bld_masks_13)) {
1482 pr_warning("diag: truncating ssid range for ssid 13");
1483 ssid_range = sizeof(msg_bld_masks_13);
1484 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 for (i = 0; i < ssid_range; i += 4)
1486 *(int *)(ptr + i) = msg_bld_masks_13[i/4];
1487 break;
1488 case MSG_SSID_14:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001489 if (ssid_range > sizeof(msg_bld_masks_14)) {
1490 pr_warning("diag: truncating ssid range for ssid 14");
1491 ssid_range = sizeof(msg_bld_masks_14);
1492 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001493 for (i = 0; i < ssid_range; i += 4)
1494 *(int *)(ptr + i) = msg_bld_masks_14[i/4];
1495 break;
1496 case MSG_SSID_15:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001497 if (ssid_range > sizeof(msg_bld_masks_15)) {
1498 pr_warning("diag: truncating ssid range for ssid 15");
1499 ssid_range = sizeof(msg_bld_masks_15);
1500 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001501 for (i = 0; i < ssid_range; i += 4)
1502 *(int *)(ptr + i) = msg_bld_masks_15[i/4];
1503 break;
1504 case MSG_SSID_16:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001505 if (ssid_range > sizeof(msg_bld_masks_16)) {
1506 pr_warning("diag: truncating ssid range for ssid 16");
1507 ssid_range = sizeof(msg_bld_masks_16);
1508 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001509 for (i = 0; i < ssid_range; i += 4)
1510 *(int *)(ptr + i) = msg_bld_masks_16[i/4];
1511 break;
1512 case MSG_SSID_17:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001513 if (ssid_range > sizeof(msg_bld_masks_17)) {
1514 pr_warning("diag: truncating ssid range for ssid 17");
1515 ssid_range = sizeof(msg_bld_masks_17);
1516 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001517 for (i = 0; i < ssid_range; i += 4)
1518 *(int *)(ptr + i) = msg_bld_masks_17[i/4];
1519 break;
1520 case MSG_SSID_18:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001521 if (ssid_range > sizeof(msg_bld_masks_18)) {
1522 pr_warning("diag: truncating ssid range for ssid 18");
1523 ssid_range = sizeof(msg_bld_masks_18);
1524 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001525 for (i = 0; i < ssid_range; i += 4)
1526 *(int *)(ptr + i) = msg_bld_masks_18[i/4];
1527 break;
Shalabh Jain321c8b52012-02-22 12:37:06 -08001528 case MSG_SSID_19:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001529 if (ssid_range > sizeof(msg_bld_masks_19)) {
1530 pr_warning("diag: truncating ssid range for ssid 19");
1531 ssid_range = sizeof(msg_bld_masks_19);
1532 }
Shalabh Jain321c8b52012-02-22 12:37:06 -08001533 for (i = 0; i < ssid_range; i += 4)
1534 *(int *)(ptr + i) = msg_bld_masks_19[i/4];
1535 break;
1536 case MSG_SSID_20:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001537 if (ssid_range > sizeof(msg_bld_masks_20)) {
1538 pr_warning("diag: truncating ssid range for ssid 20");
1539 ssid_range = sizeof(msg_bld_masks_20);
1540 }
Shalabh Jain321c8b52012-02-22 12:37:06 -08001541 for (i = 0; i < ssid_range; i += 4)
1542 *(int *)(ptr + i) = msg_bld_masks_20[i/4];
1543 break;
1544 case MSG_SSID_21:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001545 if (ssid_range > sizeof(msg_bld_masks_21)) {
1546 pr_warning("diag: truncating ssid range for ssid 21");
1547 ssid_range = sizeof(msg_bld_masks_21);
1548 }
Shalabh Jain321c8b52012-02-22 12:37:06 -08001549 for (i = 0; i < ssid_range; i += 4)
1550 *(int *)(ptr + i) = msg_bld_masks_21[i/4];
1551 break;
1552 case MSG_SSID_22:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001553 if (ssid_range > sizeof(msg_bld_masks_22)) {
1554 pr_warning("diag: truncating ssid range for ssid 22");
1555 ssid_range = sizeof(msg_bld_masks_22);
1556 }
Shalabh Jain321c8b52012-02-22 12:37:06 -08001557 for (i = 0; i < ssid_range; i += 4)
1558 *(int *)(ptr + i) = msg_bld_masks_22[i/4];
1559 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001560 }
Dixon Petersond6a20a92012-09-27 15:58:50 -07001561 encode_rsp_and_send(8 + ssid_range - 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001562 return 0;
1563 }
1564 /* Check for download command */
Shalabh Jain10f5f432012-01-11 11:45:44 +05301565 else if ((cpu_is_msm8x60() || chk_apps_master()) && (*buf == 0x3A)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001566 /* send response back */
1567 driver->apps_rsp_buf[0] = *buf;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001568 encode_rsp_and_send(0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 msleep(5000);
1570 /* call download API */
1571 msm_set_restart_mode(RESTART_DLOAD);
1572 printk(KERN_CRIT "diag: download mode set, Rebooting SoC..\n");
1573 kernel_restart(NULL);
1574 /* Not required, represents that command isnt sent to modem */
1575 return 0;
1576 }
Dixon Petersonb46bb992012-01-12 19:16:56 -08001577 /* Check for polling for Apps only DIAG */
1578 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1579 (*(buf+2) == 0x03)) {
Shalabh Jain3d29fc32012-02-09 17:15:59 -08001580 /* If no one has registered for polling */
Dixon Petersonb4618a42012-02-29 18:56:31 -08001581 if (chk_polling_response()) {
Dixon Petersonb46bb992012-01-12 19:16:56 -08001582 /* Respond to polling for Apps only DIAG */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001583 for (i = 0; i < 3; i++)
1584 driver->apps_rsp_buf[i] = *(buf+i);
1585 for (i = 0; i < 13; i++)
1586 driver->apps_rsp_buf[i+3] = 0;
1587
Dixon Petersond6a20a92012-09-27 15:58:50 -07001588 encode_rsp_and_send(15);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001589 return 0;
1590 }
Dixon Petersonb46bb992012-01-12 19:16:56 -08001591 }
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -08001592 /* Return the Delayed Response Wrap Status */
1593 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1594 (*(buf+2) == 0x04) && (*(buf+3) == 0x0)) {
1595 memcpy(driver->apps_rsp_buf, buf, 4);
1596 driver->apps_rsp_buf[4] = wrap_enabled;
1597 encode_rsp_and_send(4);
1598 return 0;
1599 }
1600 /* Wrap the Delayed Rsp ID */
1601 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1602 (*(buf+2) == 0x05) && (*(buf+3) == 0x0)) {
1603 wrap_enabled = true;
1604 memcpy(driver->apps_rsp_buf, buf, 4);
1605 driver->apps_rsp_buf[4] = wrap_count;
1606 encode_rsp_and_send(5);
1607 return 0;
1608 }
Dixon Petersonb46bb992012-01-12 19:16:56 -08001609 /* Check for ID for NO MODEM present */
Dixon Petersonb4618a42012-02-29 18:56:31 -08001610 else if (chk_polling_response()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001611 /* respond to 0x0 command */
Dixon Petersonb46bb992012-01-12 19:16:56 -08001612 if (*buf == 0x00) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001613 for (i = 0; i < 55; i++)
1614 driver->apps_rsp_buf[i] = 0;
1615
Dixon Petersond6a20a92012-09-27 15:58:50 -07001616 encode_rsp_and_send(54);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001617 return 0;
1618 }
1619 /* respond to 0x7c command */
1620 else if (*buf == 0x7c) {
1621 driver->apps_rsp_buf[0] = 0x7c;
1622 for (i = 1; i < 8; i++)
1623 driver->apps_rsp_buf[i] = 0;
1624 /* Tools ID for APQ 8060 */
1625 *(int *)(driver->apps_rsp_buf + 8) =
1626 chk_config_get_id();
1627 *(unsigned char *)(driver->apps_rsp_buf + 12) = '\0';
1628 *(unsigned char *)(driver->apps_rsp_buf + 13) = '\0';
Dixon Petersond6a20a92012-09-27 15:58:50 -07001629 encode_rsp_and_send(13);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001630 return 0;
1631 }
1632 }
1633#endif
Dixon Petersond6a20a92012-09-27 15:58:50 -07001634 return packet_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001635}
1636
1637#ifdef CONFIG_DIAG_OVER_USB
1638void diag_send_error_rsp(int index)
1639{
1640 int i;
Shalabh Jain1fedab92011-12-22 13:15:22 +05301641
Ravi Aravamudhancc9946862013-07-15 13:31:11 -07001642 /* -1 to accomodate the first byte 0x13 */
1643 if (index > APPS_BUF_SIZE-1) {
1644 pr_err("diag: cannot send err rsp, huge length: %d\n", index);
Shalabh Jain1fedab92011-12-22 13:15:22 +05301645 return;
1646 }
Ravi Aravamudhancc9946862013-07-15 13:31:11 -07001647
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001648 driver->apps_rsp_buf[0] = 0x13; /* error code 13 */
1649 for (i = 0; i < index; i++)
1650 driver->apps_rsp_buf[i+1] = *(driver->hdlc_buf+i);
Dixon Petersond6a20a92012-09-27 15:58:50 -07001651 encode_rsp_and_send(index - 3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001652}
1653#else
1654static inline void diag_send_error_rsp(int index) {}
1655#endif
1656
1657void diag_process_hdlc(void *data, unsigned len)
1658{
1659 struct diag_hdlc_decode_type hdlc;
Ravi Aravamudhan5dccccb2013-08-09 16:57:34 -07001660 int ret, type = 0, crc_chk = 0;
Dixon Peterson25f042b2013-02-27 13:00:08 -08001661
1662 mutex_lock(&driver->diag_hdlc_mutex);
1663
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001664 pr_debug("diag: HDLC decode fn, len of data %d\n", len);
1665 hdlc.dest_ptr = driver->hdlc_buf;
1666 hdlc.dest_size = USB_MAX_OUT_BUF;
1667 hdlc.src_ptr = data;
1668 hdlc.src_size = len;
1669 hdlc.src_idx = 0;
1670 hdlc.dest_idx = 0;
1671 hdlc.escaping = 0;
1672
1673 ret = diag_hdlc_decode(&hdlc);
Ravi Aravamudhan5dccccb2013-08-09 16:57:34 -07001674 if (ret) {
1675 crc_chk = crc_check(hdlc.dest_ptr, hdlc.dest_idx);
1676 if (crc_chk) {
1677 /* CRC check failed. */
1678 pr_err_ratelimited("diag: In %s, bad CRC. Dropping packet\n",
1679 __func__);
1680 mutex_unlock(&driver->diag_hdlc_mutex);
1681 return;
1682 }
1683 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001684
Dixon Petersonb4f84242013-02-27 18:46:56 -08001685 /*
1686 * If the message is 3 bytes or less in length then the message is
1687 * too short. A message will need 4 bytes minimum, since there are
1688 * 2 bytes for the CRC and 1 byte for the ending 0x7e for the hdlc
1689 * encoding
1690 */
1691 if (hdlc.dest_idx < 4) {
1692 pr_err_ratelimited("diag: In %s, message is too short, len: %d, dest len: %d\n",
1693 __func__, len, hdlc.dest_idx);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001694 mutex_unlock(&driver->diag_hdlc_mutex);
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001695 return;
1696 }
Dixon Petersonb4f84242013-02-27 18:46:56 -08001697
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001698 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699 type = diag_process_apps_pkt(driver->hdlc_buf,
1700 hdlc.dest_idx - 3);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001701 if (type < 0) {
1702 mutex_unlock(&driver->diag_hdlc_mutex);
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001703 return;
Dixon Peterson25f042b2013-02-27 13:00:08 -08001704 }
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001705 } else if (driver->debug_flag) {
Ravi Aravamudhan5dccccb2013-08-09 16:57:34 -07001706 pr_err("diag: In %s, partial packet received, dropping packet, len: %d\n",
1707 __func__, len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001708 print_hex_dump(KERN_DEBUG, "Dropped Packet Data: ", 16, 1,
1709 DUMP_PREFIX_ADDRESS, data, len, 1);
1710 driver->debug_flag = 0;
1711 }
1712 /* send error responses from APPS for Central Routing */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001713 if (type == 1 && chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001714 diag_send_error_rsp(hdlc.dest_idx);
1715 type = 0;
1716 }
1717 /* implies this packet is NOT meant for apps */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001718 if (!(driver->smd_data[MODEM_DATA].ch) && type == 1) {
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001719 if (chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720 diag_send_error_rsp(hdlc.dest_idx);
1721 } else { /* APQ 8060, Let Q6 respond */
Dixon Peterson25f042b2013-02-27 13:00:08 -08001722 if (driver->smd_data[LPASS_DATA].ch) {
1723 mutex_lock(&driver->smd_data[LPASS_DATA].
1724 smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001725 smd_write(driver->smd_data[LPASS_DATA].ch,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001726 driver->hdlc_buf,
1727 hdlc.dest_idx - 3);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001728 mutex_unlock(&driver->smd_data[LPASS_DATA].
1729 smd_ch_mutex);
1730 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001731 }
1732 type = 0;
1733 }
1734
1735#ifdef DIAG_DEBUG
1736 pr_debug("diag: hdlc.dest_idx = %d", hdlc.dest_idx);
1737 for (i = 0; i < hdlc.dest_idx; i++)
1738 printk(KERN_DEBUG "\t%x", *(((unsigned char *)
1739 driver->hdlc_buf)+i));
1740#endif /* DIAG DEBUG */
1741 /* ignore 2 bytes for CRC, one for 7E and send */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001742 if ((driver->smd_data[MODEM_DATA].ch) && (ret) && (type) &&
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001743 (hdlc.dest_idx > 3)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001744 APPEND_DEBUG('g');
Dixon Peterson25f042b2013-02-27 13:00:08 -08001745 mutex_lock(&driver->smd_data[MODEM_DATA].smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001746 smd_write(driver->smd_data[MODEM_DATA].ch,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001747 driver->hdlc_buf, hdlc.dest_idx - 3);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001748 mutex_unlock(&driver->smd_data[MODEM_DATA].smd_ch_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001749 APPEND_DEBUG('h');
1750#ifdef DIAG_DEBUG
1751 printk(KERN_INFO "writing data to SMD, pkt length %d\n", len);
1752 print_hex_dump(KERN_DEBUG, "Written Packet Data to SMD: ", 16,
1753 1, DUMP_PREFIX_ADDRESS, data, len, 1);
1754#endif /* DIAG DEBUG */
1755 }
Dixon Peterson25f042b2013-02-27 13:00:08 -08001756 mutex_unlock(&driver->diag_hdlc_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001757}
1758
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001759void diag_reset_smd_data(int queue)
1760{
1761 int i;
1762
1763 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1764 driver->smd_data[i].in_busy_1 = 0;
1765 driver->smd_data[i].in_busy_2 = 0;
1766 if (queue)
1767 /* Poll SMD data channels to check for data */
Dixon Petersonbba99ca2013-07-10 17:25:20 -07001768 queue_work(driver->smd_data[i].wq,
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001769 &(driver->smd_data[i].diag_read_smd_work));
1770 }
1771
1772 if (driver->supports_separate_cmdrsp) {
1773 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
1774 driver->smd_cmd[i].in_busy_1 = 0;
1775 driver->smd_cmd[i].in_busy_2 = 0;
1776 if (queue)
1777 /* Poll SMD data channels to check for data */
1778 queue_work(driver->diag_wq,
1779 &(driver->smd_cmd[i].
1780 diag_read_smd_work));
1781 }
1782 }
1783}
1784
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001785#ifdef CONFIG_DIAG_OVER_USB
Shalabh Jain8e9750a2011-09-09 13:06:29 -07001786/* 2+1 for modem ; 2 for LPASS ; 1 for WCNSS */
1787#define N_LEGACY_WRITE (driver->poolsize + 6)
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001788/* Additionally support number of command data and dci channels */
1789#define N_LEGACY_WRITE_CMD ((N_LEGACY_WRITE) + 4)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001790#define N_LEGACY_READ 1
1791
Mohit Aggarwalb4465772013-04-18 13:08:07 +05301792static void diag_usb_connect_work_fn(struct work_struct *w)
1793{
1794 diagfwd_connect();
1795}
1796
1797static void diag_usb_disconnect_work_fn(struct work_struct *w)
1798{
1799 diagfwd_disconnect();
1800}
1801
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802int diagfwd_connect(void)
1803{
1804 int err;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001805 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001806
1807 printk(KERN_DEBUG "diag: USB connected\n");
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001808 err = usb_diag_alloc_req(driver->legacy_ch,
1809 (driver->supports_separate_cmdrsp ?
1810 N_LEGACY_WRITE_CMD : N_LEGACY_WRITE),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001811 N_LEGACY_READ);
1812 if (err)
1813 printk(KERN_ERR "diag: unable to alloc USB req on legacy ch");
1814
1815 driver->usb_connected = 1;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001816 diag_reset_smd_data(RESET_AND_QUEUE);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001817 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001818 /* Poll SMD CNTL channels to check for data */
1819 diag_smd_notify(&(driver->smd_cntl[i]), SMD_EVENT_DATA);
1820 }
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001821 queue_work(driver->diag_real_time_wq,
1822 &driver->diag_real_time_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001823
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001824 /* Poll USB channel to check for data*/
1825 queue_work(driver->diag_wq, &(driver->diag_read_work));
1826#ifdef CONFIG_DIAG_SDIO_PIPE
1827 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
1828 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1829 diagfwd_connect_sdio();
1830 else
1831 printk(KERN_INFO "diag: No USB MDM ch");
1832 }
1833#endif
1834 return 0;
1835}
1836
1837int diagfwd_disconnect(void)
1838{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001839 int i;
1840
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001841 printk(KERN_DEBUG "diag: USB disconnected\n");
1842 driver->usb_connected = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001843 driver->debug_flag = 1;
1844 usb_diag_free_req(driver->legacy_ch);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001845 if (driver->logging_mode == USB_MODE) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001846 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1847 driver->smd_data[i].in_busy_1 = 1;
1848 driver->smd_data[i].in_busy_2 = 1;
1849 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001850
1851 if (driver->supports_separate_cmdrsp) {
1852 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
1853 driver->smd_cmd[i].in_busy_1 = 1;
1854 driver->smd_cmd[i].in_busy_2 = 1;
1855 }
1856 }
Shalabh Jain69890aa2011-10-10 12:59:16 -07001857 }
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001858 queue_work(driver->diag_real_time_wq,
1859 &driver->diag_real_time_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001860#ifdef CONFIG_DIAG_SDIO_PIPE
1861 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
1862 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1863 diagfwd_disconnect_sdio();
1864#endif
1865 /* TBD - notify and flow control SMD */
1866 return 0;
1867}
1868
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001869static int diagfwd_check_buf_match(int num_channels,
1870 struct diag_smd_info *data, unsigned char *buf)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001871{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001872 int i;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001873 int found_it = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001874
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001875 for (i = 0; i < num_channels; i++) {
1876 if (buf == (void *)data[i].buf_in_1) {
1877 data[i].in_busy_1 = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001878 found_it = 1;
1879 break;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001880 } else if (buf == (void *)data[i].buf_in_2) {
1881 data[i].in_busy_2 = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001882 found_it = 1;
1883 break;
1884 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001885 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001886
Dixon Petersonbba99ca2013-07-10 17:25:20 -07001887 if (found_it) {
1888 if (data[i].type == SMD_DATA_TYPE)
1889 queue_work(data[i].wq,
1890 &(data[i].diag_read_smd_work));
1891 else
1892 queue_work(driver->diag_wq,
1893 &(data[i].diag_read_smd_work));
1894 }
1895
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001896 return found_it;
1897}
1898
1899int diagfwd_write_complete(struct diag_request *diag_write_ptr)
1900{
1901 unsigned char *buf = diag_write_ptr->buf;
1902 int found_it = 0;
1903
1904 /* Determine if the write complete is for data from modem/apps/q6 */
1905 found_it = diagfwd_check_buf_match(NUM_SMD_DATA_CHANNELS,
1906 driver->smd_data, buf);
1907
1908 if (!found_it && driver->supports_separate_cmdrsp)
1909 found_it = diagfwd_check_buf_match(NUM_SMD_CMD_CHANNELS,
1910 driver->smd_cmd, buf);
1911
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001912#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001913 if (!found_it) {
1914 if (buf == (void *)driver->buf_in_sdio) {
1915 if (machine_is_msm8x60_fusion() ||
1916 machine_is_msm8x60_fusn_ffa())
1917 diagfwd_write_complete_sdio();
1918 else
1919 pr_err("diag: Incorrect buffer pointer while WRITE");
1920 found_it = 1;
1921 }
1922 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001923#endif
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001924 if (!found_it) {
Ravi Aravamudhand995a7f2013-07-03 13:06:15 -07001925 if (driver->logging_mode != USB_MODE)
1926 pr_debug("diag: freeing buffer when not in usb mode\n");
1927
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001928 diagmem_free(driver, (unsigned char *)buf,
1929 POOL_TYPE_HDLC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001930 diagmem_free(driver, (unsigned char *)diag_write_ptr,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001931 POOL_TYPE_WRITE_STRUCT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001932 }
1933 return 0;
1934}
1935
1936int diagfwd_read_complete(struct diag_request *diag_read_ptr)
1937{
1938 int status = diag_read_ptr->status;
1939 unsigned char *buf = diag_read_ptr->buf;
1940
1941 /* Determine if the read complete is for data on legacy/mdm ch */
1942 if (buf == (void *)driver->usb_buf_out) {
1943 driver->read_len_legacy = diag_read_ptr->actual;
1944 APPEND_DEBUG('s');
1945#ifdef DIAG_DEBUG
1946 printk(KERN_INFO "read data from USB, pkt length %d",
1947 diag_read_ptr->actual);
1948 print_hex_dump(KERN_DEBUG, "Read Packet Data from USB: ", 16, 1,
1949 DUMP_PREFIX_ADDRESS, diag_read_ptr->buf,
1950 diag_read_ptr->actual, 1);
1951#endif /* DIAG DEBUG */
1952 if (driver->logging_mode == USB_MODE) {
1953 if (status != -ECONNRESET && status != -ESHUTDOWN)
1954 queue_work(driver->diag_wq,
1955 &(driver->diag_proc_hdlc_work));
1956 else
1957 queue_work(driver->diag_wq,
1958 &(driver->diag_read_work));
1959 }
1960 }
1961#ifdef CONFIG_DIAG_SDIO_PIPE
1962 else if (buf == (void *)driver->usb_buf_mdm_out) {
1963 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -08001964 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001965 driver->read_len_mdm = diag_read_ptr->actual;
1966 diagfwd_read_complete_sdio();
1967 } else
1968 pr_err("diag: Incorrect buffer pointer while READ");
1969 }
1970#endif
1971 else
1972 printk(KERN_ERR "diag: Unknown buffer ptr from USB");
1973
1974 return 0;
1975}
1976
1977void diag_read_work_fn(struct work_struct *work)
1978{
1979 APPEND_DEBUG('d');
1980 driver->usb_read_ptr->buf = driver->usb_buf_out;
1981 driver->usb_read_ptr->length = USB_MAX_OUT_BUF;
1982 usb_diag_read(driver->legacy_ch, driver->usb_read_ptr);
1983 APPEND_DEBUG('e');
1984}
1985
1986void diag_process_hdlc_fn(struct work_struct *work)
1987{
1988 APPEND_DEBUG('D');
1989 diag_process_hdlc(driver->usb_buf_out, driver->read_len_legacy);
1990 diag_read_work_fn(work);
1991 APPEND_DEBUG('E');
1992}
1993
1994void diag_usb_legacy_notifier(void *priv, unsigned event,
1995 struct diag_request *d_req)
1996{
1997 switch (event) {
1998 case USB_DIAG_CONNECT:
Mohit Aggarwalb4465772013-04-18 13:08:07 +05301999 queue_work(driver->diag_wq,
2000 &driver->diag_usb_connect_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002001 break;
2002 case USB_DIAG_DISCONNECT:
Mohit Aggarwalb4465772013-04-18 13:08:07 +05302003 queue_work(driver->diag_wq,
2004 &driver->diag_usb_disconnect_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002005 break;
2006 case USB_DIAG_READ_DONE:
2007 diagfwd_read_complete(d_req);
2008 break;
2009 case USB_DIAG_WRITE_DONE:
2010 diagfwd_write_complete(d_req);
2011 break;
2012 default:
2013 printk(KERN_ERR "Unknown event from USB diag\n");
2014 break;
2015 }
2016}
2017
2018#endif /* DIAG OVER USB */
2019
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002020void diag_smd_notify(void *ctxt, unsigned event)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002021{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002022 struct diag_smd_info *smd_info = (struct diag_smd_info *)ctxt;
2023 if (!smd_info)
Shalabh Jaineefee052011-11-08 23:46:03 -08002024 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002026 if (event == SMD_EVENT_CLOSE) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002027 smd_info->ch = 0;
Shalabh Jainc70b3b62012-08-31 19:11:20 -07002028 wake_up(&driver->smd_wait_q);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002029 if (smd_info->type == SMD_DATA_TYPE) {
2030 smd_info->notify_context = event;
2031 queue_work(driver->diag_cntl_wq,
2032 &(smd_info->diag_notify_update_smd_work));
2033 } else if (smd_info->type == SMD_DCI_TYPE) {
2034 /* Notify the clients of the close */
2035 diag_dci_notify_client(smd_info->peripheral_mask,
2036 DIAG_STATUS_CLOSED);
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002037 } else if (smd_info->type == SMD_CNTL_TYPE) {
2038 diag_cntl_stm_notify(smd_info,
2039 CLEAR_PERIPHERAL_STM_STATE);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002040 }
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002041 return;
2042 } else if (event == SMD_EVENT_OPEN) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002043 if (smd_info->ch_save)
2044 smd_info->ch = smd_info->ch_save;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002045
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002046 if (smd_info->type == SMD_CNTL_TYPE) {
2047 smd_info->notify_context = event;
2048 queue_work(driver->diag_cntl_wq,
2049 &(smd_info->diag_notify_update_smd_work));
2050 } else if (smd_info->type == SMD_DCI_TYPE) {
2051 smd_info->notify_context = event;
2052 queue_work(driver->diag_dci_wq,
2053 &(smd_info->diag_notify_update_smd_work));
2054 /* Notify the clients of the open */
2055 diag_dci_notify_client(smd_info->peripheral_mask,
2056 DIAG_STATUS_OPEN);
2057 }
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002058 } else if (event == SMD_EVENT_DATA && !driver->real_time_mode &&
2059 smd_info->type == SMD_DATA_TYPE) {
2060 process_lock_on_notify(&smd_info->nrt_lock);
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002061 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002062
Shalabh Jainc70b3b62012-08-31 19:11:20 -07002063 wake_up(&driver->smd_wait_q);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002064
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002065 if (smd_info->type == SMD_DCI_TYPE ||
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07002066 smd_info->type == SMD_DCI_CMD_TYPE) {
2067 if (event == SMD_EVENT_DATA)
2068 diag_dci_try_activate_wakeup_source(smd_info->ch);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002069 queue_work(driver->diag_dci_wq,
2070 &(smd_info->diag_read_smd_work));
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002071 } else if (smd_info->type == SMD_DATA_TYPE) {
2072 queue_work(smd_info->wq,
2073 &(smd_info->diag_read_smd_work));
2074 } else {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002075 queue_work(driver->diag_wq, &(smd_info->diag_read_smd_work));
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002076 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002077}
2078
2079static int diag_smd_probe(struct platform_device *pdev)
2080{
2081 int r = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002082 int index = -1;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002083 const char *channel_name = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002084
Shalabh Jaineefee052011-11-08 23:46:03 -08002085 if (pdev->id == SMD_APPS_MODEM) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002086 index = MODEM_DATA;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002087 channel_name = "DIAG";
Shalabh Jaineefee052011-11-08 23:46:03 -08002088 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002089#if defined(CONFIG_MSM_N_WAY_SMD)
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002090 else if (pdev->id == SMD_APPS_QDSP) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002091 index = LPASS_DATA;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002092 channel_name = "DIAG";
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002093 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002094#endif
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002095 else if (pdev->id == SMD_APPS_WCNSS) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002096 index = WCNSS_DATA;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002097 channel_name = "APPS_RIVA_DATA";
2098 }
2099
2100 if (index != -1) {
2101 r = smd_named_open_on_edge(channel_name,
2102 pdev->id,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002103 &driver->smd_data[index].ch,
2104 &driver->smd_data[index],
2105 diag_smd_notify);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002106 driver->smd_data[index].ch_save = driver->smd_data[index].ch;
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002107 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002109 pm_runtime_set_active(&pdev->dev);
2110 pm_runtime_enable(&pdev->dev);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002111 pr_debug("diag: In %s, open SMD port, Id = %d, r = %d\n",
2112 __func__, pdev->id, r);
2113
2114 return 0;
2115}
2116
2117static int diag_smd_cmd_probe(struct platform_device *pdev)
2118{
2119 int r = 0;
2120 int index = -1;
2121 const char *channel_name = NULL;
2122
2123 if (!driver->supports_separate_cmdrsp)
2124 return 0;
2125
2126 if (pdev->id == SMD_APPS_MODEM) {
2127 index = MODEM_DATA;
2128 channel_name = "DIAG_CMD";
2129 }
2130
2131 if (index != -1) {
2132 r = smd_named_open_on_edge(channel_name,
2133 pdev->id,
2134 &driver->smd_cmd[index].ch,
2135 &driver->smd_cmd[index],
2136 diag_smd_notify);
2137 driver->smd_cmd[index].ch_save =
2138 driver->smd_cmd[index].ch;
2139 }
2140
2141 pr_debug("diag: In %s, open SMD CMD port, Id = %d, r = %d\n",
2142 __func__, pdev->id, r);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002143
2144 return 0;
2145}
2146
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002147static int diag_smd_runtime_suspend(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002148{
2149 dev_dbg(dev, "pm_runtime: suspending...\n");
2150 return 0;
2151}
2152
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002153static int diag_smd_runtime_resume(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154{
2155 dev_dbg(dev, "pm_runtime: resuming...\n");
2156 return 0;
2157}
2158
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002159static const struct dev_pm_ops diag_smd_dev_pm_ops = {
2160 .runtime_suspend = diag_smd_runtime_suspend,
2161 .runtime_resume = diag_smd_runtime_resume,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002162};
2163
2164static struct platform_driver msm_smd_ch1_driver = {
2165
2166 .probe = diag_smd_probe,
2167 .driver = {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002168 .name = "DIAG",
2169 .owner = THIS_MODULE,
2170 .pm = &diag_smd_dev_pm_ops,
2171 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002172};
2173
2174static struct platform_driver diag_smd_lite_driver = {
2175
2176 .probe = diag_smd_probe,
2177 .driver = {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002178 .name = "APPS_RIVA_DATA",
2179 .owner = THIS_MODULE,
2180 .pm = &diag_smd_dev_pm_ops,
2181 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002182};
2183
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002184static struct platform_driver
2185 smd_lite_data_cmd_drivers[NUM_SMD_CMD_CHANNELS] = {
2186 {
2187 /* Modem data */
2188 .probe = diag_smd_cmd_probe,
2189 .driver = {
2190 .name = "DIAG_CMD",
2191 .owner = THIS_MODULE,
2192 .pm = &diag_smd_dev_pm_ops,
2193 },
2194 }
2195};
2196
2197int device_supports_separate_cmdrsp(void)
2198{
2199 return driver->use_device_tree;
2200}
2201
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002202void diag_smd_destructor(struct diag_smd_info *smd_info)
2203{
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002204 if (smd_info->type == SMD_DATA_TYPE) {
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002205 wake_lock_destroy(&smd_info->nrt_lock.read_lock);
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002206 destroy_workqueue(smd_info->wq);
2207 }
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002208
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002209 if (smd_info->ch)
2210 smd_close(smd_info->ch);
2211
2212 smd_info->ch = 0;
2213 smd_info->ch_save = 0;
2214 kfree(smd_info->buf_in_1);
2215 kfree(smd_info->buf_in_2);
2216 kfree(smd_info->write_ptr_1);
2217 kfree(smd_info->write_ptr_2);
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002218 kfree(smd_info->buf_in_1_raw);
2219 kfree(smd_info->buf_in_2_raw);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002220}
2221
2222int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral,
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002223 int type)
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002224{
2225 smd_info->peripheral = peripheral;
2226 smd_info->type = type;
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002227 smd_info->encode_hdlc = 0;
Dixon Peterson25f042b2013-02-27 13:00:08 -08002228 mutex_init(&smd_info->smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002229
2230 switch (peripheral) {
2231 case MODEM_DATA:
2232 smd_info->peripheral_mask = DIAG_CON_MPSS;
2233 break;
2234 case LPASS_DATA:
2235 smd_info->peripheral_mask = DIAG_CON_LPASS;
2236 break;
2237 case WCNSS_DATA:
2238 smd_info->peripheral_mask = DIAG_CON_WCNSS;
2239 break;
2240 default:
2241 pr_err("diag: In %s, unknown peripheral, peripheral: %d\n",
2242 __func__, peripheral);
2243 goto err;
2244 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002245
2246 smd_info->ch = 0;
2247 smd_info->ch_save = 0;
2248
2249 if (smd_info->buf_in_1 == NULL) {
2250 smd_info->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
2251 if (smd_info->buf_in_1 == NULL)
2252 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002253 smd_info->buf_in_1_size = IN_BUF_SIZE;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002254 kmemleak_not_leak(smd_info->buf_in_1);
2255 }
2256
2257 if (smd_info->write_ptr_1 == NULL) {
2258 smd_info->write_ptr_1 = kzalloc(sizeof(struct diag_request),
2259 GFP_KERNEL);
2260 if (smd_info->write_ptr_1 == NULL)
2261 goto err;
2262 kmemleak_not_leak(smd_info->write_ptr_1);
2263 }
2264
2265 /* The smd data type needs two buffers */
2266 if (smd_info->type == SMD_DATA_TYPE) {
2267 if (smd_info->buf_in_2 == NULL) {
2268 smd_info->buf_in_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
2269 if (smd_info->buf_in_2 == NULL)
2270 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002271 smd_info->buf_in_2_size = IN_BUF_SIZE;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002272 kmemleak_not_leak(smd_info->buf_in_2);
2273 }
2274 if (smd_info->write_ptr_2 == NULL) {
2275 smd_info->write_ptr_2 =
2276 kzalloc(sizeof(struct diag_request),
2277 GFP_KERNEL);
2278 if (smd_info->write_ptr_2 == NULL)
2279 goto err;
2280 kmemleak_not_leak(smd_info->write_ptr_2);
2281 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002282 if (driver->supports_apps_hdlc_encoding) {
2283 /* In support of hdlc encoding */
2284 if (smd_info->buf_in_1_raw == NULL) {
2285 smd_info->buf_in_1_raw = kzalloc(IN_BUF_SIZE,
2286 GFP_KERNEL);
2287 if (smd_info->buf_in_1_raw == NULL)
2288 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002289 smd_info->buf_in_1_raw_size = IN_BUF_SIZE;
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002290 kmemleak_not_leak(smd_info->buf_in_1_raw);
2291 }
2292 if (smd_info->buf_in_2_raw == NULL) {
2293 smd_info->buf_in_2_raw = kzalloc(IN_BUF_SIZE,
2294 GFP_KERNEL);
2295 if (smd_info->buf_in_2_raw == NULL)
2296 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002297 smd_info->buf_in_2_raw_size = IN_BUF_SIZE;
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002298 kmemleak_not_leak(smd_info->buf_in_2_raw);
2299 }
2300 }
2301 }
2302
2303 if (smd_info->type == SMD_CMD_TYPE &&
2304 driver->supports_apps_hdlc_encoding) {
2305 /* In support of hdlc encoding */
2306 if (smd_info->buf_in_1_raw == NULL) {
2307 smd_info->buf_in_1_raw = kzalloc(IN_BUF_SIZE,
2308 GFP_KERNEL);
2309 if (smd_info->buf_in_1_raw == NULL)
2310 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002311 smd_info->buf_in_1_raw_size = IN_BUF_SIZE;
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002312 kmemleak_not_leak(smd_info->buf_in_1_raw);
2313 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002314 }
2315
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002316 /* The smd data type needs separate work queues for reads */
2317 if (type == SMD_DATA_TYPE) {
2318 switch (peripheral) {
2319 case MODEM_DATA:
2320 smd_info->wq = create_singlethread_workqueue(
2321 "diag_modem_data_read_wq");
2322 break;
2323 case LPASS_DATA:
2324 smd_info->wq = create_singlethread_workqueue(
2325 "diag_lpass_data_read_wq");
2326 break;
2327 case WCNSS_DATA:
2328 smd_info->wq = create_singlethread_workqueue(
2329 "diag_wcnss_data_read_wq");
2330 break;
2331 default:
2332 smd_info->wq = NULL;
2333 break;
2334 }
2335 } else {
2336 smd_info->wq = NULL;
2337 }
2338
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002339 INIT_WORK(&(smd_info->diag_read_smd_work), diag_read_smd_work_fn);
2340
2341 /*
2342 * The update function assigned to the diag_notify_update_smd_work
2343 * work_struct is meant to be used for updating that is not to
2344 * be done in the context of the smd notify function. The
2345 * notify_context variable can be used for passing additional
2346 * information to the update function.
2347 */
2348 smd_info->notify_context = 0;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002349 smd_info->general_context = 0;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002350 switch (type) {
2351 case SMD_DATA_TYPE:
2352 case SMD_CMD_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002353 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002354 diag_clean_reg_fn);
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002355 INIT_WORK(&(smd_info->diag_general_smd_work),
2356 diag_cntl_smd_work_fn);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002357 break;
2358 case SMD_CNTL_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002359 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002360 diag_mask_update_fn);
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002361 INIT_WORK(&(smd_info->diag_general_smd_work),
2362 diag_cntl_smd_work_fn);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002363 break;
2364 case SMD_DCI_TYPE:
2365 case SMD_DCI_CMD_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002366 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002367 diag_update_smd_dci_work_fn);
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002368 INIT_WORK(&(smd_info->diag_general_smd_work),
2369 diag_cntl_smd_work_fn);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002370 break;
2371 default:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002372 pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
2373 goto err;
2374 }
2375
2376 /*
2377 * Set function ptr for function to call to process the data that
2378 * was just read from the smd channel
2379 */
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002380 switch (type) {
2381 case SMD_DATA_TYPE:
2382 case SMD_CMD_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002383 smd_info->process_smd_read_data = diag_process_smd_read_data;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002384 break;
2385 case SMD_CNTL_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002386 smd_info->process_smd_read_data =
2387 diag_process_smd_cntl_read_data;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002388 break;
2389 case SMD_DCI_TYPE:
2390 case SMD_DCI_CMD_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002391 smd_info->process_smd_read_data =
2392 diag_process_smd_dci_read_data;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002393 break;
2394 default:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002395 pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
2396 goto err;
2397 }
2398
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002399 smd_info->nrt_lock.enabled = 0;
2400 smd_info->nrt_lock.ref_count = 0;
2401 smd_info->nrt_lock.copy_count = 0;
2402 if (type == SMD_DATA_TYPE) {
2403 spin_lock_init(&smd_info->nrt_lock.read_spinlock);
2404
2405 switch (peripheral) {
2406 case MODEM_DATA:
2407 wake_lock_init(&smd_info->nrt_lock.read_lock,
2408 WAKE_LOCK_SUSPEND, "diag_nrt_modem_read");
2409 break;
2410 case LPASS_DATA:
2411 wake_lock_init(&smd_info->nrt_lock.read_lock,
2412 WAKE_LOCK_SUSPEND, "diag_nrt_lpass_read");
2413 break;
2414 case WCNSS_DATA:
2415 wake_lock_init(&smd_info->nrt_lock.read_lock,
2416 WAKE_LOCK_SUSPEND, "diag_nrt_wcnss_read");
2417 break;
2418 default:
2419 break;
2420 }
2421 }
2422
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002423 return 1;
2424err:
2425 kfree(smd_info->buf_in_1);
2426 kfree(smd_info->buf_in_2);
2427 kfree(smd_info->write_ptr_1);
2428 kfree(smd_info->write_ptr_2);
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002429 kfree(smd_info->buf_in_1_raw);
2430 kfree(smd_info->buf_in_2_raw);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002431
2432 return 0;
2433}
2434
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002435void diagfwd_init(void)
2436{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002437 int success;
2438 int i;
2439
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -08002440 wrap_enabled = 0;
2441 wrap_count = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002442 diag_debug_buf_idx = 0;
2443 driver->read_len_legacy = 0;
Dixon Petersonb4618a42012-02-29 18:56:31 -08002444 driver->use_device_tree = has_device_tree();
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002445 driver->real_time_mode = 1;
Dixon Petersona6d98092013-05-16 12:26:26 -07002446 /*
2447 * The number of entries in table of buffers
2448 * should not be any smaller than hdlc poolsize.
2449 */
2450 driver->buf_tbl_size = (buf_tbl_size < driver->poolsize_hdlc) ?
2451 driver->poolsize_hdlc : buf_tbl_size;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002452 driver->supports_separate_cmdrsp = device_supports_separate_cmdrsp();
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002453 driver->supports_apps_hdlc_encoding = 0;
Dixon Peterson25f042b2013-02-27 13:00:08 -08002454 mutex_init(&driver->diag_hdlc_mutex);
Shalabh Jaina06c6d72012-04-30 13:40:35 -07002455 mutex_init(&driver->diag_cntl_mutex);
Shalabh Jain321c8b52012-02-22 12:37:06 -08002456
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002457 for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002458 driver->separate_cmdrsp[i] = 0;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002459 driver->peripheral_supports_stm[i] = DISABLE_STM;
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07002460 driver->rcvd_feature_mask[i] = 0;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002461 }
2462
2463 for (i = 0; i < NUM_STM_PROCESSORS; i++) {
2464 driver->stm_state_requested[i] = DISABLE_STM;
2465 driver->stm_state[i] = DISABLE_STM;
2466 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002467
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002468 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
2469 success = diag_smd_constructor(&driver->smd_data[i], i,
2470 SMD_DATA_TYPE);
2471 if (!success)
2472 goto err;
2473 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002474
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002475 if (driver->supports_separate_cmdrsp) {
2476 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
2477 success = diag_smd_constructor(&driver->smd_cmd[i], i,
2478 SMD_CMD_TYPE);
2479 if (!success)
2480 goto err;
2481 }
2482 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002484 if (driver->usb_buf_out == NULL &&
2485 (driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
2486 GFP_KERNEL)) == NULL)
2487 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002488 kmemleak_not_leak(driver->usb_buf_out);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002489 if (driver->hdlc_buf == NULL
2490 && (driver->hdlc_buf = kzalloc(HDLC_MAX, GFP_KERNEL)) == NULL)
2491 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002492 kmemleak_not_leak(driver->hdlc_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002493 if (driver->client_map == NULL &&
2494 (driver->client_map = kzalloc
2495 ((driver->num_clients) * sizeof(struct diag_client_map),
2496 GFP_KERNEL)) == NULL)
2497 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002498 kmemleak_not_leak(driver->client_map);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002499 if (driver->buf_tbl == NULL)
Dixon Petersona6d98092013-05-16 12:26:26 -07002500 driver->buf_tbl = kzalloc(driver->buf_tbl_size *
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002501 sizeof(struct diag_write_device), GFP_KERNEL);
2502 if (driver->buf_tbl == NULL)
2503 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002504 kmemleak_not_leak(driver->buf_tbl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002505 if (driver->data_ready == NULL &&
2506 (driver->data_ready = kzalloc(driver->num_clients * sizeof(int)
2507 , GFP_KERNEL)) == NULL)
2508 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002509 kmemleak_not_leak(driver->data_ready);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002510 if (driver->table == NULL &&
Shalabh Jainfe02b0c2012-02-21 14:48:03 -08002511 (driver->table = kzalloc(diag_max_reg*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002512 sizeof(struct diag_master_table),
2513 GFP_KERNEL)) == NULL)
2514 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002515 kmemleak_not_leak(driver->table);
Ashay Jaiswal29620122012-03-21 12:02:36 +05302516
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002517 if (driver->usb_read_ptr == NULL) {
2518 driver->usb_read_ptr = kzalloc(
2519 sizeof(struct diag_request), GFP_KERNEL);
2520 if (driver->usb_read_ptr == NULL)
2521 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002522 kmemleak_not_leak(driver->usb_read_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002523 }
2524 if (driver->pkt_buf == NULL &&
2525 (driver->pkt_buf = kzalloc(PKT_SIZE,
2526 GFP_KERNEL)) == NULL)
2527 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002528 kmemleak_not_leak(driver->pkt_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002529 if (driver->apps_rsp_buf == NULL) {
Shalabh Jain321c8b52012-02-22 12:37:06 -08002530 driver->apps_rsp_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002531 if (driver->apps_rsp_buf == NULL)
2532 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002533 kmemleak_not_leak(driver->apps_rsp_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002534 }
2535 driver->diag_wq = create_singlethread_workqueue("diag_wq");
2536#ifdef CONFIG_DIAG_OVER_USB
Mohit Aggarwalb4465772013-04-18 13:08:07 +05302537 INIT_WORK(&(driver->diag_usb_connect_work),
2538 diag_usb_connect_work_fn);
2539 INIT_WORK(&(driver->diag_usb_disconnect_work),
2540 diag_usb_disconnect_work_fn);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002541 INIT_WORK(&(driver->diag_proc_hdlc_work), diag_process_hdlc_fn);
2542 INIT_WORK(&(driver->diag_read_work), diag_read_work_fn);
2543 driver->legacy_ch = usb_diag_open(DIAG_LEGACY, driver,
2544 diag_usb_legacy_notifier);
2545 if (IS_ERR(driver->legacy_ch)) {
2546 printk(KERN_ERR "Unable to open USB diag legacy channel\n");
2547 goto err;
2548 }
2549#endif
2550 platform_driver_register(&msm_smd_ch1_driver);
2551 platform_driver_register(&diag_smd_lite_driver);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002552
2553 if (driver->supports_separate_cmdrsp) {
2554 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++)
2555 platform_driver_register(&smd_lite_data_cmd_drivers[i]);
2556 }
2557
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002558 return;
2559err:
Dixon Petersond6a20a92012-09-27 15:58:50 -07002560 pr_err("diag: Could not initialize diag buffers");
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002561
2562 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
2563 diag_smd_destructor(&driver->smd_data[i]);
2564
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002565 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++)
2566 diag_smd_destructor(&driver->smd_cmd[i]);
2567
Dixon Petersond6a20a92012-09-27 15:58:50 -07002568 kfree(driver->buf_msg_mask_update);
2569 kfree(driver->buf_log_mask_update);
2570 kfree(driver->buf_event_mask_update);
2571 kfree(driver->usb_buf_out);
2572 kfree(driver->hdlc_buf);
2573 kfree(driver->client_map);
2574 kfree(driver->buf_tbl);
2575 kfree(driver->data_ready);
2576 kfree(driver->table);
2577 kfree(driver->pkt_buf);
Dixon Petersond6a20a92012-09-27 15:58:50 -07002578 kfree(driver->usb_read_ptr);
2579 kfree(driver->apps_rsp_buf);
Dixon Petersond6a20a92012-09-27 15:58:50 -07002580 if (driver->diag_wq)
2581 destroy_workqueue(driver->diag_wq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002582}
2583
2584void diagfwd_exit(void)
2585{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002586 int i;
2587
2588 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
2589 diag_smd_destructor(&driver->smd_data[i]);
2590
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002591#ifdef CONFIG_DIAG_OVER_USB
2592 if (driver->usb_connected)
2593 usb_diag_free_req(driver->legacy_ch);
2594 usb_diag_close(driver->legacy_ch);
2595#endif
2596 platform_driver_unregister(&msm_smd_ch1_driver);
2597 platform_driver_unregister(&diag_smd_lite_driver);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002598
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002599 if (driver->supports_separate_cmdrsp) {
2600 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
2601 diag_smd_destructor(&driver->smd_cmd[i]);
2602 platform_driver_unregister(
2603 &smd_lite_data_cmd_drivers[i]);
2604 }
2605 }
2606
Shalabh Jain321c8b52012-02-22 12:37:06 -08002607 kfree(driver->buf_msg_mask_update);
2608 kfree(driver->buf_log_mask_update);
2609 kfree(driver->buf_event_mask_update);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002610 kfree(driver->usb_buf_out);
2611 kfree(driver->hdlc_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002612 kfree(driver->client_map);
2613 kfree(driver->buf_tbl);
2614 kfree(driver->data_ready);
2615 kfree(driver->table);
2616 kfree(driver->pkt_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002617 kfree(driver->usb_read_ptr);
2618 kfree(driver->apps_rsp_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002619 destroy_workqueue(driver->diag_wq);
2620}