blob: c74ab99310e821b12b9ca7a6def6207d688d319f [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;
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800206 else if (!(driver->smd_data[MODEM_DATA].ch) &&
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800207 !(chk_apps_master()))
Dixon Petersonb4618a42012-02-29 18:56:31 -0800208 /*
209 * If the apps processor is not the master and the modem
210 * is not up
211 */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530212 return 1;
213 else
214 return 0;
215}
216
Dixon Peterson743a11e2012-07-30 17:42:20 -0700217/*
218 * This function should be called if you feel that the logging process may
219 * need to be woken up. For instance, if the logging mode is MEMORY_DEVICE MODE
220 * and while trying to read data from a SMD data channel there are no buffers
221 * available to read the data into, then this function should be called to
222 * determine if the logging process needs to be woken up.
223 */
224void chk_logging_wakeup(void)
225{
226 int i;
227
228 /* Find the index of the logging process */
229 for (i = 0; i < driver->num_clients; i++)
230 if (driver->client_map[i].pid ==
231 driver->logging_process_id)
232 break;
233
234 if (i < driver->num_clients) {
235 /* At very high logging rates a race condition can
236 * occur where the buffers containing the data from
237 * an smd channel are all in use, but the data_ready
238 * flag is cleared. In this case, the buffers never
239 * have their data read/logged. Detect and remedy this
240 * situation.
241 */
Shalabh Jain84e30342012-10-16 16:16:08 -0700242 if ((driver->data_ready[i] & USER_SPACE_DATA_TYPE) == 0) {
243 driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
Dixon Peterson743a11e2012-07-30 17:42:20 -0700244 pr_debug("diag: Force wakeup of logging process\n");
245 wake_up_interruptible(&driver->wait_q);
246 }
247 }
248}
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800249int diag_add_hdlc_encoding(struct diag_smd_info *smd_info, void *buf,
250 int total_recd, uint8_t *encode_buf,
251 int *encoded_length)
252{
253 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
254 struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
255 struct data_header {
256 uint8_t control_char;
257 uint8_t version;
258 uint16_t length;
259 };
260 struct data_header *header;
261 int header_size = sizeof(struct data_header);
262 uint8_t *end_control_char;
263 uint8_t *payload;
264 uint8_t *temp_buf;
265 uint8_t *temp_encode_buf;
266 int src_pkt_len;
267 int encoded_pkt_length;
268 int max_size;
269 int total_processed = 0;
270 int bytes_remaining;
271 int success = 1;
272
273 temp_buf = buf;
274 temp_encode_buf = encode_buf;
275 bytes_remaining = *encoded_length;
276 while (total_processed < total_recd) {
277 header = (struct data_header *)temp_buf;
278 /* Perform initial error checking */
279 if (header->control_char != CONTROL_CHAR ||
280 header->version != 1) {
281 success = 0;
282 break;
283 }
284 payload = temp_buf + header_size;
285 end_control_char = payload + header->length;
286 if (*end_control_char != CONTROL_CHAR) {
287 success = 0;
288 break;
289 }
290
291 max_size = 2 * header->length + 3;
292 if (bytes_remaining < max_size) {
293 pr_err("diag: In %s, Not enough room to encode remaining data for peripheral: %d, bytes available: %d, max_size: %d\n",
294 __func__, smd_info->peripheral,
295 bytes_remaining, max_size);
296 success = 0;
297 break;
298 }
299
300 /* Prepare for encoding the data */
301 send.state = DIAG_STATE_START;
302 send.pkt = payload;
303 send.last = (void *)(payload + header->length - 1);
304 send.terminate = 1;
305
306 enc.dest = temp_encode_buf;
307 enc.dest_last = (void *)(temp_encode_buf + max_size);
308 enc.crc = 0;
309 diag_hdlc_encode(&send, &enc);
310
311 /* Prepare for next packet */
312 src_pkt_len = (header_size + header->length + 1);
313 total_processed += src_pkt_len;
314 temp_buf += src_pkt_len;
315
316 encoded_pkt_length = (uint8_t *)enc.dest - temp_encode_buf;
317 bytes_remaining -= encoded_pkt_length;
318 temp_encode_buf = enc.dest;
319 }
320
321 *encoded_length = (int)(temp_encode_buf - encode_buf);
322
323 return success;
324}
325
326static int check_bufsize_for_encoding(struct diag_smd_info *smd_info, void *buf,
327 int total_recd)
328{
329 int buf_size = IN_BUF_SIZE;
330 int max_size = 2 * total_recd + 3;
331 unsigned char *temp_buf;
332
333 if (max_size > IN_BUF_SIZE) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700334 if (max_size > MAX_IN_BUF_SIZE) {
335 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 -0800336 __func__, total_recd, max_size,
337 smd_info->peripheral);
Dixon Petersond2309b42013-08-28 21:00:05 -0700338 max_size = MAX_IN_BUF_SIZE;
339 }
340 if (buf == smd_info->buf_in_1_raw) {
341 /* Only realloc if we need to increase the size */
342 if (smd_info->buf_in_1_size < max_size) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800343 temp_buf = krealloc(smd_info->buf_in_1,
Dixon Petersond2309b42013-08-28 21:00:05 -0700344 max_size, GFP_KERNEL);
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800345 if (temp_buf) {
346 smd_info->buf_in_1 = temp_buf;
Dixon Petersond2309b42013-08-28 21:00:05 -0700347 smd_info->buf_in_1_size = max_size;
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800348 }
349 }
Dixon Petersond2309b42013-08-28 21:00:05 -0700350 buf_size = smd_info->buf_in_1_size;
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800351 } else {
Dixon Petersond2309b42013-08-28 21:00:05 -0700352 /* Only realloc if we need to increase the size */
353 if (smd_info->buf_in_2_size < max_size) {
354 temp_buf = krealloc(smd_info->buf_in_2,
355 max_size, GFP_KERNEL);
356 if (temp_buf) {
357 smd_info->buf_in_2 = temp_buf;
358 smd_info->buf_in_2_size = max_size;
359 }
360 }
361 buf_size = smd_info->buf_in_2_size;
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800362 }
363 }
364
365 return buf_size;
366}
Dixon Peterson743a11e2012-07-30 17:42:20 -0700367
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800368void process_lock_enabling(struct diag_nrt_wake_lock *lock, int real_time)
369{
370 unsigned long read_lock_flags;
371
372 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
373 if (real_time)
374 lock->enabled = 0;
375 else
376 lock->enabled = 1;
377 lock->ref_count = 0;
378 lock->copy_count = 0;
379 wake_unlock(&lock->read_lock);
380 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
381}
382
383void process_lock_on_notify(struct diag_nrt_wake_lock *lock)
384{
385 unsigned long read_lock_flags;
386
387 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
388 /*
389 * Do not work with ref_count here in case
390 * of spurious interrupt
391 */
392 if (lock->enabled)
393 wake_lock(&lock->read_lock);
394 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
395}
396
397void process_lock_on_read(struct diag_nrt_wake_lock *lock, int pkt_len)
398{
399 unsigned long read_lock_flags;
400
401 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
402 if (lock->enabled) {
403 if (pkt_len > 0) {
404 /*
405 * We have an data that is read that
406 * needs to be processed, make sure the
407 * processor does not go to sleep
408 */
409 lock->ref_count++;
410 if (!wake_lock_active(&lock->read_lock))
411 wake_lock(&lock->read_lock);
412 } else {
413 /*
414 * There was no data associated with the
415 * read from the smd, unlock the wake lock
416 * if it is not needed.
417 */
418 if (lock->ref_count < 1) {
419 if (wake_lock_active(&lock->read_lock))
420 wake_unlock(&lock->read_lock);
421 lock->ref_count = 0;
422 lock->copy_count = 0;
423 }
424 }
425 }
426 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
427}
428
429void process_lock_on_copy(struct diag_nrt_wake_lock *lock)
430{
431 unsigned long read_lock_flags;
432
433 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
434 if (lock->enabled)
435 lock->copy_count++;
436 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
437}
438
439void process_lock_on_copy_complete(struct diag_nrt_wake_lock *lock)
440{
441 unsigned long read_lock_flags;
442
443 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
444 if (lock->enabled) {
445 lock->ref_count -= lock->copy_count;
446 if (lock->ref_count < 1) {
447 wake_unlock(&lock->read_lock);
448 lock->ref_count = 0;
449 }
450 lock->copy_count = 0;
451 }
452 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
453}
454
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800455/* Process the data read from the smd data channel */
456int diag_process_smd_read_data(struct diag_smd_info *smd_info, void *buf,
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800457 int total_recd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700459 struct diag_request *write_ptr_modem = NULL;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800460 int *in_busy_ptr = 0;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800461 int err = 0;
462
463 /*
464 * Do not process data on command channel if the
465 * channel is not designated to do so
466 */
467 if ((smd_info->type == SMD_CMD_TYPE) &&
468 !driver->separate_cmdrsp[smd_info->peripheral]) {
469 /* This print is for debugging */
470 pr_err("diag, In %s, received data on non-designated command channel: %d\n",
471 __func__, smd_info->peripheral);
472 return 0;
473 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700474
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800475 /* If the data is already hdlc encoded */
476 if (!smd_info->encode_hdlc) {
477 if (smd_info->buf_in_1 == buf) {
478 write_ptr_modem = smd_info->write_ptr_1;
479 in_busy_ptr = &smd_info->in_busy_1;
480 } else if (smd_info->buf_in_2 == buf) {
481 write_ptr_modem = smd_info->write_ptr_2;
482 in_busy_ptr = &smd_info->in_busy_2;
483 } else {
484 pr_err("diag: In %s, no match for in_busy_1, peripheral: %d\n",
485 __func__, smd_info->peripheral);
486 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700487
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800488 if (write_ptr_modem) {
489 write_ptr_modem->length = total_recd;
490 *in_busy_ptr = 1;
491 err = diag_device_write(buf, smd_info->peripheral,
492 write_ptr_modem);
493 if (err) {
494 /* Free up the buffer for future use */
495 *in_busy_ptr = 0;
496 pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
497 __func__, err);
498 }
499 }
500 } else {
501 /* The data is raw and needs to be hdlc encoded */
502 if (smd_info->buf_in_1_raw == buf) {
503 write_ptr_modem = smd_info->write_ptr_1;
504 in_busy_ptr = &smd_info->in_busy_1;
505 } else if (smd_info->buf_in_2_raw == buf) {
506 write_ptr_modem = smd_info->write_ptr_2;
507 in_busy_ptr = &smd_info->in_busy_2;
508 } else {
509 pr_err("diag: In %s, no match for in_busy_1, peripheral: %d\n",
510 __func__, smd_info->peripheral);
511 }
512
513 if (write_ptr_modem) {
514 int success = 0;
515 int write_length = 0;
516 unsigned char *write_buf = NULL;
517
518 write_length = check_bufsize_for_encoding(smd_info, buf,
519 total_recd);
520 if (write_length) {
521 write_buf = (buf == smd_info->buf_in_1_raw) ?
522 smd_info->buf_in_1 : smd_info->buf_in_2;
523 success = diag_add_hdlc_encoding(smd_info, buf,
524 total_recd, write_buf,
525 &write_length);
526 if (success) {
527 write_ptr_modem->length = write_length;
528 *in_busy_ptr = 1;
529 err = diag_device_write(write_buf,
530 smd_info->peripheral,
531 write_ptr_modem);
532 if (err) {
533 /*
534 * Free up the buffer for
535 * future use
536 */
537 *in_busy_ptr = 0;
538 pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
539 __func__, err);
540 }
541 }
542 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800543 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800544 }
545
546 return 0;
547}
548
Dixon Petersond2309b42013-08-28 21:00:05 -0700549static int diag_smd_resize_buf(struct diag_smd_info *smd_info, void **buf,
550 unsigned int *buf_size,
551 unsigned int requested_size)
552{
553 int success = 0;
554 void *temp_buf = NULL;
555 unsigned int new_buf_size = requested_size;
556
557 if (!smd_info)
558 return success;
559
560 if (requested_size <= MAX_IN_BUF_SIZE) {
561 pr_debug("diag: In %s, SMD peripheral: %d sending in packets up to %d bytes\n",
562 __func__, smd_info->peripheral, requested_size);
563 } else {
564 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",
565 __func__, smd_info->peripheral, requested_size,
566 MAX_IN_BUF_SIZE);
567 new_buf_size = MAX_IN_BUF_SIZE;
568 }
569
570 /* Only resize if the buffer can be increased in size */
571 if (new_buf_size <= *buf_size) {
572 success = 1;
573 return success;
574 }
575
576 temp_buf = krealloc(*buf, new_buf_size, GFP_KERNEL);
577
578 if (temp_buf) {
579 /* Match the buffer and reset the pointer and size */
580 if (smd_info->encode_hdlc) {
581 /*
582 * This smd channel is supporting HDLC encoding
583 * on the apps
584 */
585 void *temp_hdlc = NULL;
586 if (*buf == smd_info->buf_in_1_raw) {
587 smd_info->buf_in_1_raw = temp_buf;
588 smd_info->buf_in_1_raw_size = new_buf_size;
589 temp_hdlc = krealloc(smd_info->buf_in_1,
590 MAX_IN_BUF_SIZE,
591 GFP_KERNEL);
592 if (temp_hdlc) {
593 smd_info->buf_in_1 = temp_hdlc;
594 smd_info->buf_in_1_size =
595 MAX_IN_BUF_SIZE;
596 }
597 } else if (*buf == smd_info->buf_in_2_raw) {
598 smd_info->buf_in_2_raw = temp_buf;
599 smd_info->buf_in_2_raw_size = new_buf_size;
600 temp_hdlc = krealloc(smd_info->buf_in_2,
601 MAX_IN_BUF_SIZE,
602 GFP_KERNEL);
603 if (temp_hdlc) {
604 smd_info->buf_in_2 = temp_hdlc;
605 smd_info->buf_in_2_size =
606 MAX_IN_BUF_SIZE;
607 }
608 }
609 } else {
610 if (*buf == smd_info->buf_in_1) {
611 smd_info->buf_in_1 = temp_buf;
612 smd_info->buf_in_1_size = new_buf_size;
613 } else if (*buf == smd_info->buf_in_2) {
614 smd_info->buf_in_2 = temp_buf;
615 smd_info->buf_in_2_size = new_buf_size;
616 }
617 }
618 *buf = temp_buf;
619 *buf_size = new_buf_size;
620 success = 1;
621 } else {
622 pr_err_ratelimited("diag: In %s, SMD peripheral: %d. packet size sent: %d, resize to support failed. Data beyond %d will be lost\n",
623 __func__, smd_info->peripheral, requested_size,
624 *buf_size);
625 }
626
627 return success;
628}
629
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800630void diag_smd_send_req(struct diag_smd_info *smd_info)
631{
632 void *buf = NULL, *temp_buf = NULL;
633 int total_recd = 0, r = 0, pkt_len;
634 int loop_count = 0;
635 int notify = 0;
Dixon Petersond2309b42013-08-28 21:00:05 -0700636 int buf_size = 0;
637 int resize_success = 0;
638 int buf_full = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800639
640 if (!smd_info) {
641 pr_err("diag: In %s, no smd info. Not able to read.\n",
642 __func__);
643 return;
644 }
645
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800646 /* Determine the buffer to read the data into. */
647 if (smd_info->type == SMD_DATA_TYPE) {
648 /* If the data is raw and not hdlc encoded */
649 if (smd_info->encode_hdlc) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700650 if (!smd_info->in_busy_1) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800651 buf = smd_info->buf_in_1_raw;
Dixon Petersond2309b42013-08-28 21:00:05 -0700652 buf_size = smd_info->buf_in_1_raw_size;
653 } else if (!smd_info->in_busy_2) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800654 buf = smd_info->buf_in_2_raw;
Dixon Petersond2309b42013-08-28 21:00:05 -0700655 buf_size = smd_info->buf_in_2_raw_size;
656 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800657 } else {
Dixon Petersond2309b42013-08-28 21:00:05 -0700658 if (!smd_info->in_busy_1) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800659 buf = smd_info->buf_in_1;
Dixon Petersond2309b42013-08-28 21:00:05 -0700660 buf_size = smd_info->buf_in_1_size;
661 } else if (!smd_info->in_busy_2) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800662 buf = smd_info->buf_in_2;
Dixon Petersond2309b42013-08-28 21:00:05 -0700663 buf_size = smd_info->buf_in_2_size;
664 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800665 }
666 } else if (smd_info->type == SMD_CMD_TYPE) {
667 /* If the data is raw and not hdlc encoded */
668 if (smd_info->encode_hdlc) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700669 if (!smd_info->in_busy_1) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800670 buf = smd_info->buf_in_1_raw;
Dixon Petersond2309b42013-08-28 21:00:05 -0700671 buf_size = smd_info->buf_in_1_raw_size;
672 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800673 } else {
Dixon Petersond2309b42013-08-28 21:00:05 -0700674 if (!smd_info->in_busy_1) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800675 buf = smd_info->buf_in_1;
Dixon Petersond2309b42013-08-28 21:00:05 -0700676 buf_size = smd_info->buf_in_1_size;
677 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800678 }
679 } else if (!smd_info->in_busy_1) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800680 buf = smd_info->buf_in_1;
Dixon Petersond2309b42013-08-28 21:00:05 -0700681 buf_size = smd_info->buf_in_1_size;
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800682 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800683
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700684 if (!buf && (smd_info->type == SMD_DCI_TYPE ||
685 smd_info->type == SMD_DCI_CMD_TYPE))
686 diag_dci_try_deactivate_wakeup_source(smd_info->ch);
687
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800688 if (smd_info->ch && buf) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800689 pkt_len = smd_cur_packet_size(smd_info->ch);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700691 if (pkt_len == 0 && (smd_info->type == SMD_DCI_TYPE ||
692 smd_info->type == SMD_DCI_CMD_TYPE))
693 diag_dci_try_deactivate_wakeup_source(smd_info->ch);
694
Dixon Petersond2309b42013-08-28 21:00:05 -0700695 if (pkt_len > buf_size)
696 resize_success = diag_smd_resize_buf(smd_info, &buf,
697 &buf_size, pkt_len);
698 temp_buf = buf;
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700699 while (pkt_len && (pkt_len != total_recd)) {
700 loop_count++;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800701 r = smd_read_avail(smd_info->ch);
Dixon Petersond2309b42013-08-28 21:00:05 -0700702 pr_debug("diag: In %s, SMD peripheral: %d, received pkt %d %d\n",
703 __func__, smd_info->peripheral, r, total_recd);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700704 if (!r) {
705 /* Nothing to read from SMD */
706 wait_event(driver->smd_wait_q,
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800707 ((smd_info->ch == 0) ||
708 smd_read_avail(smd_info->ch)));
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700709 /* If the smd channel is open */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800710 if (smd_info->ch) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700711 pr_debug("diag: In %s, SMD peripheral: %d, return from wait_event\n",
712 __func__, smd_info->peripheral);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700713 continue;
714 } else {
Dixon Petersond2309b42013-08-28 21:00:05 -0700715 pr_debug("diag: In %s, SMD peripheral: %d, return from wait_event ch closed\n",
716 __func__, smd_info->peripheral);
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700717 goto fail_return;
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700718 }
719 }
Dixon Petersond2309b42013-08-28 21:00:05 -0700720
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700721 if (pkt_len < r) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700722 pr_err("diag: In %s, SMD peripheral: %d, sending incorrect pkt\n",
723 __func__, smd_info->peripheral);
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700724 goto fail_return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700725 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800726 if (pkt_len > r) {
Dixon Peterson6dba7572013-04-12 18:45:16 -0700727 pr_debug("diag: In %s, SMD sending partial pkt %d %d %d %d %d %d\n",
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800728 __func__, pkt_len, r, total_recd, loop_count,
729 smd_info->peripheral, smd_info->type);
730 }
731
Dixon Petersond2309b42013-08-28 21:00:05 -0700732 /* Protect from going beyond the end of the buffer */
733 if (total_recd < buf_size) {
734 if (total_recd + r > buf_size) {
735 r = buf_size - total_recd;
736 buf_full = 1;
737 }
738
739 total_recd += r;
740
741 /* Keep reading for complete packet */
742 smd_read(smd_info->ch, temp_buf, r);
743 temp_buf += r;
744 } else {
745 /*
746 * This block handles the very rare case of a
747 * packet that is greater in length than what
748 * we can support. In this case, we
749 * incrementally drain the remaining portion
750 * of the packet that will not fit in the
751 * buffer, so that the entire packet is read
752 * from the smd.
753 */
754 int drain_bytes = (r > SMD_DRAIN_BUF_SIZE) ?
755 SMD_DRAIN_BUF_SIZE : r;
756 unsigned char *drain_buf = kzalloc(drain_bytes,
757 GFP_KERNEL);
758 if (drain_buf) {
759 total_recd += drain_bytes;
760 smd_read(smd_info->ch, drain_buf,
761 drain_bytes);
762 kfree(drain_buf);
763 } else {
764 pr_err("diag: In %s, SMD peripheral: %d, unable to allocate drain buffer\n",
765 __func__, smd_info->peripheral);
766 break;
767 }
768 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700769 }
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800770 if (!driver->real_time_mode && smd_info->type == SMD_DATA_TYPE)
771 process_lock_on_read(&smd_info->nrt_lock, pkt_len);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700772
773 if (total_recd > 0) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800774 if (!buf) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700775 pr_err("diag: In %s, SMD peripheral: %d, Out of diagmem for Modem\n",
776 __func__, smd_info->peripheral);
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800777 } else if (smd_info->process_smd_read_data) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700778 /*
779 * If the buffer was totally filled, reset
780 * total_recd appropriately
781 */
782 if (buf_full)
783 total_recd = buf_size;
784
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800785 notify = smd_info->process_smd_read_data(
786 smd_info, buf, total_recd);
787 /* Poll SMD channels to check for data */
788 if (notify)
789 diag_smd_notify(smd_info,
790 SMD_EVENT_DATA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700791 }
792 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800793 } else if (smd_info->ch && !buf &&
Dixon Peterson743a11e2012-07-30 17:42:20 -0700794 (driver->logging_mode == MEMORY_DEVICE_MODE)) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800795 chk_logging_wakeup();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700796 }
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700797 return;
798
799fail_return:
800 if (smd_info->type == SMD_DCI_TYPE ||
801 smd_info->type == SMD_DCI_CMD_TYPE)
802 diag_dci_try_deactivate_wakeup_source(smd_info->ch);
803 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804}
805
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800806void diag_read_smd_work_fn(struct work_struct *work)
807{
808 struct diag_smd_info *smd_info = container_of(work,
809 struct diag_smd_info,
810 diag_read_smd_work);
811 diag_smd_send_req(smd_info);
812}
813
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800814int diag_device_write(void *buf, int data_type, struct diag_request *write_ptr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700815{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800816 int i, err = 0, index;
817 index = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700818
819 if (driver->logging_mode == MEMORY_DEVICE_MODE) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800820 if (data_type == APPS_DATA) {
Dixon Petersona6d98092013-05-16 12:26:26 -0700821 for (i = 0; i < driver->buf_tbl_size; i++)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700822 if (driver->buf_tbl[i].length == 0) {
823 driver->buf_tbl[i].buf = buf;
824 driver->buf_tbl[i].length =
825 driver->used;
826#ifdef DIAG_DEBUG
827 pr_debug("diag: ENQUEUE buf ptr"
828 " and length is %x , %d\n",
829 (unsigned int)(driver->buf_
830 tbl[i].buf), driver->buf_tbl[i].length);
831#endif
832 break;
833 }
834 }
Dixon Peterson938f8602012-08-17 20:02:57 -0700835
Shalabh Jain737fca72012-11-14 21:53:43 -0800836#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Shalabh Jainb0037c02013-01-18 12:47:40 -0800837 else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700838 unsigned long flags;
839 int foundIndex = -1;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800840 index = data_type - HSIC_DATA;
841 spin_lock_irqsave(&diag_hsic[index].hsic_spinlock,
842 flags);
843 for (i = 0; i < diag_hsic[index].poolsize_hsic_write;
844 i++) {
845 if (diag_hsic[index].hsic_buf_tbl[i].length
846 == 0) {
847 diag_hsic[index].hsic_buf_tbl[i].buf
848 = buf;
849 diag_hsic[index].hsic_buf_tbl[i].length
850 = diag_bridge[index].write_len;
851 diag_hsic[index].
852 num_hsic_buf_tbl_entries++;
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700853 foundIndex = i;
Dixon Peterson938f8602012-08-17 20:02:57 -0700854 break;
855 }
856 }
Shalabh Jainb0037c02013-01-18 12:47:40 -0800857 spin_unlock_irqrestore(&diag_hsic[index].hsic_spinlock,
858 flags);
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700859 if (foundIndex == -1)
860 err = -1;
861 else
Shalabh Jainb0037c02013-01-18 12:47:40 -0800862 pr_debug("diag: ENQUEUE HSIC buf ptr and length is %x , %d, ch %d\n",
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700863 (unsigned int)buf,
Shalabh Jainb0037c02013-01-18 12:47:40 -0800864 diag_bridge[index].write_len, index);
Dixon Peterson938f8602012-08-17 20:02:57 -0700865 }
866#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700867 for (i = 0; i < driver->num_clients; i++)
868 if (driver->client_map[i].pid ==
869 driver->logging_process_id)
870 break;
871 if (i < driver->num_clients) {
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700872 pr_debug("diag: wake up logging process\n");
Dixon Petersonbba99ca2013-07-10 17:25:20 -0700873 driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700874 wake_up_interruptible(&driver->wait_q);
875 } else
876 return -EINVAL;
877 } else if (driver->logging_mode == NO_LOGGING_MODE) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800878 if ((data_type >= MODEM_DATA) && (data_type <= WCNSS_DATA)) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800879 driver->smd_data[data_type].in_busy_1 = 0;
880 driver->smd_data[data_type].in_busy_2 = 0;
Dixon Petersonbba99ca2013-07-10 17:25:20 -0700881 queue_work(driver->smd_data[data_type].wq,
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800882 &(driver->smd_data[data_type].
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800883 diag_read_smd_work));
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800884 if (data_type == MODEM_DATA &&
885 driver->separate_cmdrsp[data_type]) {
886 driver->smd_cmd[data_type].in_busy_1 = 0;
887 driver->smd_cmd[data_type].in_busy_2 = 0;
888 queue_work(driver->diag_wq,
889 &(driver->smd_cmd[data_type].
890 diag_read_smd_work));
891 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892 }
Shalabh Jain482bf122011-12-06 03:54:47 -0800893#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800894 else if (data_type == SDIO_DATA) {
Shalabh Jain482bf122011-12-06 03:54:47 -0800895 driver->in_busy_sdio = 0;
896 queue_work(driver->diag_sdio_wq,
897 &(driver->diag_read_sdio_work));
898 }
899#endif
Shalabh Jain737fca72012-11-14 21:53:43 -0800900#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Shalabh Jainb0037c02013-01-18 12:47:40 -0800901 else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
902 index = data_type - HSIC_DATA;
903 if (diag_hsic[index].hsic_ch)
904 queue_work(diag_bridge[index].wq,
905 &(diag_hsic[index].
906 diag_read_hsic_work));
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700907 }
908#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700909 err = -1;
910 }
911#ifdef CONFIG_DIAG_OVER_USB
912 else if (driver->logging_mode == USB_MODE) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800913 if (data_type == APPS_DATA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700914 driver->write_ptr_svc = (struct diag_request *)
915 (diagmem_alloc(driver, sizeof(struct diag_request),
916 POOL_TYPE_WRITE_STRUCT));
917 if (driver->write_ptr_svc) {
918 driver->write_ptr_svc->length = driver->used;
919 driver->write_ptr_svc->buf = buf;
920 err = usb_diag_write(driver->legacy_ch,
921 driver->write_ptr_svc);
Ravi Aravamudhand995a7f2013-07-03 13:06:15 -0700922 /* Free the buffer if write failed */
923 if (err) {
924 diagmem_free(driver,
925 (unsigned char *)driver->
926 write_ptr_svc,
927 POOL_TYPE_WRITE_STRUCT);
928 }
929 } else {
930 err = -ENOMEM;
931 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800932 } else if ((data_type >= MODEM_DATA) &&
933 (data_type <= WCNSS_DATA)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700934 write_ptr->buf = buf;
935#ifdef DIAG_DEBUG
936 printk(KERN_INFO "writing data to USB,"
937 "pkt length %d\n", write_ptr->length);
938 print_hex_dump(KERN_DEBUG, "Written Packet Data to"
939 " USB: ", 16, 1, DUMP_PREFIX_ADDRESS,
940 buf, write_ptr->length, 1);
941#endif /* DIAG DEBUG */
942 err = usb_diag_write(driver->legacy_ch, write_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943 }
944#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800945 else if (data_type == SDIO_DATA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700946 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -0800947 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700948 write_ptr->buf = buf;
949 err = usb_diag_write(driver->mdm_ch, write_ptr);
950 } else
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800951 pr_err("diag: Incorrect sdio data "
952 "while USB write\n");
953 }
954#endif
Shalabh Jain737fca72012-11-14 21:53:43 -0800955#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Shalabh Jainb0037c02013-01-18 12:47:40 -0800956 else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
957 index = data_type - HSIC_DATA;
958 if (diag_hsic[index].hsic_device_enabled) {
Dixon Peterson938f8602012-08-17 20:02:57 -0700959 struct diag_request *write_ptr_mdm;
960 write_ptr_mdm = (struct diag_request *)
961 diagmem_alloc(driver,
962 sizeof(struct diag_request),
Shalabh Jainb0037c02013-01-18 12:47:40 -0800963 index +
Dixon Peterson938f8602012-08-17 20:02:57 -0700964 POOL_TYPE_HSIC_WRITE);
965 if (write_ptr_mdm) {
966 write_ptr_mdm->buf = buf;
967 write_ptr_mdm->length =
Shalabh Jainb0037c02013-01-18 12:47:40 -0800968 diag_bridge[index].write_len;
969 write_ptr_mdm->context = (void *)index;
Shalabh Jain737fca72012-11-14 21:53:43 -0800970 err = usb_diag_write(
Shalabh Jainb0037c02013-01-18 12:47:40 -0800971 diag_bridge[index].ch, write_ptr_mdm);
Dixon Peterson938f8602012-08-17 20:02:57 -0700972 /* Return to the pool immediately */
973 if (err) {
974 diagmem_free(driver,
975 write_ptr_mdm,
Shalabh Jainb0037c02013-01-18 12:47:40 -0800976 index +
Dixon Peterson938f8602012-08-17 20:02:57 -0700977 POOL_TYPE_HSIC_WRITE);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800978 pr_err_ratelimited("diag: HSIC write failure, err: %d, ch %d\n",
979 err, index);
Dixon Peterson938f8602012-08-17 20:02:57 -0700980 }
981 } else {
982 pr_err("diag: allocate write fail\n");
983 err = -1;
984 }
985 } else {
Shalabh Jain737fca72012-11-14 21:53:43 -0800986 pr_err("diag: Incorrect HSIC data "
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800987 "while USB write\n");
Dixon Peterson938f8602012-08-17 20:02:57 -0700988 err = -1;
989 }
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800990 } else if (data_type == SMUX_DATA) {
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700991 write_ptr->buf = buf;
Shalabh Jain737fca72012-11-14 21:53:43 -0800992 write_ptr->context = (void *)SMUX;
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700993 pr_debug("diag: writing SMUX data\n");
Shalabh Jain737fca72012-11-14 21:53:43 -0800994 err = usb_diag_write(diag_bridge[SMUX].ch,
995 write_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700996 }
997#endif
998 APPEND_DEBUG('d');
999 }
1000#endif /* DIAG OVER USB */
1001 return err;
1002}
1003
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001004static void diag_update_pkt_buffer(unsigned char *buf)
1005{
1006 unsigned char *ptr = driver->pkt_buf;
1007 unsigned char *temp = buf;
1008
1009 mutex_lock(&driver->diagchar_mutex);
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001010 if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, driver->pkt_length)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001011 memcpy(ptr, temp , driver->pkt_length);
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001012 driver->in_busy_pktdata = 1;
1013 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001014 printk(KERN_CRIT " Not enough buffer space for PKT_RESP\n");
1015 mutex_unlock(&driver->diagchar_mutex);
1016}
1017
1018void diag_update_userspace_clients(unsigned int type)
1019{
1020 int i;
1021
1022 mutex_lock(&driver->diagchar_mutex);
1023 for (i = 0; i < driver->num_clients; i++)
1024 if (driver->client_map[i].pid != 0)
1025 driver->data_ready[i] |= type;
1026 wake_up_interruptible(&driver->wait_q);
1027 mutex_unlock(&driver->diagchar_mutex);
1028}
1029
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001030void diag_update_sleeping_process(int process_id, int data_type)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001031{
1032 int i;
1033
1034 mutex_lock(&driver->diagchar_mutex);
1035 for (i = 0; i < driver->num_clients; i++)
1036 if (driver->client_map[i].pid == process_id) {
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001037 driver->data_ready[i] |= data_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001038 break;
1039 }
1040 wake_up_interruptible(&driver->wait_q);
1041 mutex_unlock(&driver->diagchar_mutex);
1042}
1043
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001044static int diag_check_mode_reset(unsigned char *buf)
1045{
1046 int is_mode_reset = 0;
1047 if (chk_apps_master() && (int)(*(char *)buf) == MODE_CMD)
1048 if ((int)(*(char *)(buf+1)) == RESET_ID)
1049 is_mode_reset = 1;
1050 return is_mode_reset;
1051}
1052
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001053void diag_send_data(struct diag_master_table entry, unsigned char *buf,
1054 int len, int type)
1055{
1056 driver->pkt_length = len;
Dixon Petersoncf8b6292013-05-07 19:01:29 -07001057
1058 /* If the process_id corresponds to an apps process */
1059 if (entry.process_id != NON_APPS_PROC) {
1060 /* If the message is to be sent to the apps process */
1061 if (type != MODEM_DATA) {
1062 diag_update_pkt_buffer(buf);
1063 diag_update_sleeping_process(entry.process_id,
1064 PKT_TYPE);
1065 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066 } else {
1067 if (len > 0) {
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001068 if (entry.client_id < NUM_SMD_DATA_CHANNELS) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001069 struct diag_smd_info *smd_info;
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001070 int index = entry.client_id;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001071 /*
1072 * Mode reset should work even if
1073 * modem is down
1074 */
1075 if ((index == MODEM_DATA) &&
1076 diag_check_mode_reset(buf)) {
1077 return;
1078 }
1079 smd_info = (driver->separate_cmdrsp[index] &&
1080 index < NUM_SMD_CMD_CHANNELS) ?
1081 &driver->smd_cmd[index] :
1082 &driver->smd_data[index];
1083
1084 if (smd_info->ch) {
1085 mutex_lock(&smd_info->smd_ch_mutex);
1086 smd_write(smd_info->ch, buf, len);
1087 mutex_unlock(&smd_info->smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001088 } else {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001089 pr_err("diag: In %s, smd channel %d not open, peripheral: %d, type: %d\n",
1090 __func__, index,
1091 smd_info->peripheral,
1092 smd_info->type);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001093 }
Shalabh Jainc9f35092011-07-28 18:36:17 -07001094 } else {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001095 pr_alert("diag: In %s, incorrect channel: %d",
1096 __func__, entry.client_id);
Shalabh Jainc9f35092011-07-28 18:36:17 -07001097 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098 }
1099 }
1100}
1101
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07001102void diag_process_stm_mask(uint8_t cmd, uint8_t data_mask, int data_type,
1103 uint8_t *rsp_supported, uint8_t *rsp_smd_comply)
1104{
1105 int status = 0;
1106 if (data_type >= MODEM_DATA && data_type <= WCNSS_DATA) {
1107 if (driver->peripheral_supports_stm[data_type]) {
1108 status = diag_send_stm_state(
1109 &driver->smd_cntl[data_type], cmd);
1110 if (status == 1)
1111 *rsp_smd_comply |= data_mask;
1112 *rsp_supported |= data_mask;
1113 } else if (driver->smd_cntl[data_type].ch) {
1114 *rsp_smd_comply |= data_mask;
1115 }
1116 if ((*rsp_smd_comply & data_mask) &&
1117 (*rsp_supported & data_mask))
1118 driver->stm_state[data_type] = cmd;
1119
1120 driver->stm_state_requested[data_type] = cmd;
1121 } else if (data_type == APPS_DATA) {
1122 *rsp_supported |= data_mask;
1123 *rsp_smd_comply |= data_mask;
1124 driver->stm_state[data_type] = cmd;
1125 driver->stm_state_requested[data_type] = cmd;
1126 }
1127}
1128
1129int diag_process_stm_cmd(unsigned char *buf)
1130{
1131 uint8_t version = *(buf+STM_CMD_VERSION_OFFSET);
1132 uint8_t mask = *(buf+STM_CMD_MASK_OFFSET);
1133 uint8_t cmd = *(buf+STM_CMD_DATA_OFFSET);
1134 uint8_t rsp_supported = 0;
1135 uint8_t rsp_smd_comply = 0;
1136 int valid_command = 1;
1137 int i;
1138
1139 /* Check if command is valid */
1140 if ((version != 1) || (mask == 0) || (0 != (mask >> 4)) ||
1141 (cmd != ENABLE_STM && cmd != DISABLE_STM)) {
1142 valid_command = 0;
1143 } else {
1144 if (mask & DIAG_STM_MODEM)
1145 diag_process_stm_mask(cmd, DIAG_STM_MODEM, MODEM_DATA,
1146 &rsp_supported, &rsp_smd_comply);
1147
1148 if (mask & DIAG_STM_LPASS)
1149 diag_process_stm_mask(cmd, DIAG_STM_LPASS, LPASS_DATA,
1150 &rsp_supported, &rsp_smd_comply);
1151
1152 if (mask & DIAG_STM_WCNSS)
1153 diag_process_stm_mask(cmd, DIAG_STM_WCNSS, WCNSS_DATA,
1154 &rsp_supported, &rsp_smd_comply);
1155
1156 if (mask & DIAG_STM_APPS)
1157 diag_process_stm_mask(cmd, DIAG_STM_APPS, APPS_DATA,
1158 &rsp_supported, &rsp_smd_comply);
1159 }
1160
1161 for (i = 0; i < STM_CMD_NUM_BYTES; i++)
1162 driver->apps_rsp_buf[i] = *(buf+i);
1163
1164 driver->apps_rsp_buf[STM_RSP_VALID_INDEX] = valid_command;
1165 driver->apps_rsp_buf[STM_RSP_SUPPORTED_INDEX] = rsp_supported;
1166 driver->apps_rsp_buf[STM_RSP_SMD_COMPLY_INDEX] = rsp_smd_comply;
1167
1168 encode_rsp_and_send(STM_RSP_NUM_BYTES-1);
1169
1170 return 0;
1171}
1172
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001173int diag_process_apps_pkt(unsigned char *buf, int len)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174{
1175 uint16_t subsys_cmd_code;
1176 int subsys_id, ssid_first, ssid_last, ssid_range;
Shalabh Jain3fd986f2012-05-30 18:42:26 -07001177 int packet_type = 1, i, cmd_code;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001178 unsigned char *temp = buf;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001179 int data_type;
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001180 int mask_ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181#if defined(CONFIG_DIAG_OVER_USB)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001182 unsigned char *ptr;
1183#endif
1184
Dixon Petersond6a20a92012-09-27 15:58:50 -07001185 /* Check if the command is a supported mask command */
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001186 mask_ret = diag_process_apps_masks(buf, len);
1187 if (mask_ret <= 0)
1188 return mask_ret;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001190 /* Check for registered clients and forward packet to apropriate proc */
1191 cmd_code = (int)(*(char *)buf);
1192 temp++;
1193 subsys_id = (int)(*(char *)temp);
1194 temp++;
1195 subsys_cmd_code = *(uint16_t *)temp;
1196 temp += 2;
1197 data_type = APPS_DATA;
1198 /* Dont send any command other than mode reset */
Shalabh Jain10f5f432012-01-11 11:45:44 +05301199 if (chk_apps_master() && cmd_code == MODE_CMD) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200 if (subsys_id != RESET_ID)
1201 data_type = MODEM_DATA;
1202 }
1203
1204 pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
Shalabh Jainfe02b0c2012-02-21 14:48:03 -08001205 for (i = 0; i < diag_max_reg; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001206 entry = driver->table[i];
1207 if (entry.process_id != NO_PROCESS) {
1208 if (entry.cmd_code == cmd_code && entry.subsys_id ==
1209 subsys_id && entry.cmd_code_lo <=
1210 subsys_cmd_code &&
1211 entry.cmd_code_hi >= subsys_cmd_code) {
1212 diag_send_data(entry, buf, len, data_type);
1213 packet_type = 0;
1214 } else if (entry.cmd_code == 255
1215 && cmd_code == 75) {
1216 if (entry.subsys_id ==
1217 subsys_id &&
1218 entry.cmd_code_lo <=
1219 subsys_cmd_code &&
1220 entry.cmd_code_hi >=
1221 subsys_cmd_code) {
1222 diag_send_data(entry, buf, len,
1223 data_type);
1224 packet_type = 0;
1225 }
1226 } else if (entry.cmd_code == 255 &&
1227 entry.subsys_id == 255) {
1228 if (entry.cmd_code_lo <=
1229 cmd_code &&
1230 entry.
1231 cmd_code_hi >= cmd_code) {
1232 diag_send_data(entry, buf, len,
1233 data_type);
1234 packet_type = 0;
1235 }
1236 }
1237 }
1238 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239#if defined(CONFIG_DIAG_OVER_USB)
Dixon Petersona2dd7352012-05-21 17:37:10 -07001240 /* Check for the command/respond msg for the maximum packet length */
1241 if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
1242 (*(uint16_t *)(buf+2) == 0x0055)) {
1243 for (i = 0; i < 4; i++)
1244 *(driver->apps_rsp_buf+i) = *(buf+i);
1245 *(uint32_t *)(driver->apps_rsp_buf+4) = PKT_SIZE;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001246 encode_rsp_and_send(7);
Dixon Petersona2dd7352012-05-21 17:37:10 -07001247 return 0;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07001248 } else if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
1249 (*(uint16_t *)(buf+2) == 0x020E)) {
1250 return diag_process_stm_cmd(buf);
Dixon Petersona2dd7352012-05-21 17:37:10 -07001251 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001252 /* Check for Apps Only & get event mask request */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001253 else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only() &&
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001254 *buf == 0x81) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001255 driver->apps_rsp_buf[0] = 0x81;
1256 driver->apps_rsp_buf[1] = 0x0;
1257 *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
1258 *(uint16_t *)(driver->apps_rsp_buf + 4) = EVENT_LAST_ID + 1;
1259 for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
1260 *(unsigned char *)(driver->apps_rsp_buf + 6 + i) = 0x0;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001261 encode_rsp_and_send(6 + EVENT_LAST_ID/8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262 return 0;
1263 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001264 /* Get log ID range & Check for Apps Only */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001265 else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001266 && (*buf == 0x73) && *(int *)(buf+4) == 1) {
1267 driver->apps_rsp_buf[0] = 0x73;
1268 *(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
1269 *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success code */
1270 *(int *)(driver->apps_rsp_buf + 12) = LOG_GET_ITEM_NUM(LOG_0);
1271 *(int *)(driver->apps_rsp_buf + 16) = LOG_GET_ITEM_NUM(LOG_1);
1272 *(int *)(driver->apps_rsp_buf + 20) = LOG_GET_ITEM_NUM(LOG_2);
1273 *(int *)(driver->apps_rsp_buf + 24) = LOG_GET_ITEM_NUM(LOG_3);
1274 *(int *)(driver->apps_rsp_buf + 28) = LOG_GET_ITEM_NUM(LOG_4);
1275 *(int *)(driver->apps_rsp_buf + 32) = LOG_GET_ITEM_NUM(LOG_5);
1276 *(int *)(driver->apps_rsp_buf + 36) = LOG_GET_ITEM_NUM(LOG_6);
1277 *(int *)(driver->apps_rsp_buf + 40) = LOG_GET_ITEM_NUM(LOG_7);
1278 *(int *)(driver->apps_rsp_buf + 44) = LOG_GET_ITEM_NUM(LOG_8);
1279 *(int *)(driver->apps_rsp_buf + 48) = LOG_GET_ITEM_NUM(LOG_9);
1280 *(int *)(driver->apps_rsp_buf + 52) = LOG_GET_ITEM_NUM(LOG_10);
1281 *(int *)(driver->apps_rsp_buf + 56) = LOG_GET_ITEM_NUM(LOG_11);
1282 *(int *)(driver->apps_rsp_buf + 60) = LOG_GET_ITEM_NUM(LOG_12);
1283 *(int *)(driver->apps_rsp_buf + 64) = LOG_GET_ITEM_NUM(LOG_13);
1284 *(int *)(driver->apps_rsp_buf + 68) = LOG_GET_ITEM_NUM(LOG_14);
1285 *(int *)(driver->apps_rsp_buf + 72) = LOG_GET_ITEM_NUM(LOG_15);
Dixon Petersond6a20a92012-09-27 15:58:50 -07001286 encode_rsp_and_send(75);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001287 return 0;
1288 }
1289 /* Respond to Get SSID Range request message */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001290 else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291 && (*buf == 0x7d) && (*(buf+1) == 0x1)) {
1292 driver->apps_rsp_buf[0] = 0x7d;
1293 driver->apps_rsp_buf[1] = 0x1;
1294 driver->apps_rsp_buf[2] = 0x1;
1295 driver->apps_rsp_buf[3] = 0x0;
Shalabh Jain44b79b72012-06-15 13:39:27 -07001296 /* -1 to un-account for OEM SSID range */
1297 *(int *)(driver->apps_rsp_buf + 4) = MSG_MASK_TBL_CNT - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001298 *(uint16_t *)(driver->apps_rsp_buf + 8) = MSG_SSID_0;
1299 *(uint16_t *)(driver->apps_rsp_buf + 10) = MSG_SSID_0_LAST;
1300 *(uint16_t *)(driver->apps_rsp_buf + 12) = MSG_SSID_1;
1301 *(uint16_t *)(driver->apps_rsp_buf + 14) = MSG_SSID_1_LAST;
1302 *(uint16_t *)(driver->apps_rsp_buf + 16) = MSG_SSID_2;
1303 *(uint16_t *)(driver->apps_rsp_buf + 18) = MSG_SSID_2_LAST;
1304 *(uint16_t *)(driver->apps_rsp_buf + 20) = MSG_SSID_3;
1305 *(uint16_t *)(driver->apps_rsp_buf + 22) = MSG_SSID_3_LAST;
1306 *(uint16_t *)(driver->apps_rsp_buf + 24) = MSG_SSID_4;
1307 *(uint16_t *)(driver->apps_rsp_buf + 26) = MSG_SSID_4_LAST;
1308 *(uint16_t *)(driver->apps_rsp_buf + 28) = MSG_SSID_5;
1309 *(uint16_t *)(driver->apps_rsp_buf + 30) = MSG_SSID_5_LAST;
1310 *(uint16_t *)(driver->apps_rsp_buf + 32) = MSG_SSID_6;
1311 *(uint16_t *)(driver->apps_rsp_buf + 34) = MSG_SSID_6_LAST;
1312 *(uint16_t *)(driver->apps_rsp_buf + 36) = MSG_SSID_7;
1313 *(uint16_t *)(driver->apps_rsp_buf + 38) = MSG_SSID_7_LAST;
1314 *(uint16_t *)(driver->apps_rsp_buf + 40) = MSG_SSID_8;
1315 *(uint16_t *)(driver->apps_rsp_buf + 42) = MSG_SSID_8_LAST;
1316 *(uint16_t *)(driver->apps_rsp_buf + 44) = MSG_SSID_9;
1317 *(uint16_t *)(driver->apps_rsp_buf + 46) = MSG_SSID_9_LAST;
1318 *(uint16_t *)(driver->apps_rsp_buf + 48) = MSG_SSID_10;
1319 *(uint16_t *)(driver->apps_rsp_buf + 50) = MSG_SSID_10_LAST;
1320 *(uint16_t *)(driver->apps_rsp_buf + 52) = MSG_SSID_11;
1321 *(uint16_t *)(driver->apps_rsp_buf + 54) = MSG_SSID_11_LAST;
1322 *(uint16_t *)(driver->apps_rsp_buf + 56) = MSG_SSID_12;
1323 *(uint16_t *)(driver->apps_rsp_buf + 58) = MSG_SSID_12_LAST;
1324 *(uint16_t *)(driver->apps_rsp_buf + 60) = MSG_SSID_13;
1325 *(uint16_t *)(driver->apps_rsp_buf + 62) = MSG_SSID_13_LAST;
1326 *(uint16_t *)(driver->apps_rsp_buf + 64) = MSG_SSID_14;
1327 *(uint16_t *)(driver->apps_rsp_buf + 66) = MSG_SSID_14_LAST;
1328 *(uint16_t *)(driver->apps_rsp_buf + 68) = MSG_SSID_15;
1329 *(uint16_t *)(driver->apps_rsp_buf + 70) = MSG_SSID_15_LAST;
1330 *(uint16_t *)(driver->apps_rsp_buf + 72) = MSG_SSID_16;
1331 *(uint16_t *)(driver->apps_rsp_buf + 74) = MSG_SSID_16_LAST;
1332 *(uint16_t *)(driver->apps_rsp_buf + 76) = MSG_SSID_17;
1333 *(uint16_t *)(driver->apps_rsp_buf + 78) = MSG_SSID_17_LAST;
1334 *(uint16_t *)(driver->apps_rsp_buf + 80) = MSG_SSID_18;
1335 *(uint16_t *)(driver->apps_rsp_buf + 82) = MSG_SSID_18_LAST;
Shalabh Jain321c8b52012-02-22 12:37:06 -08001336 *(uint16_t *)(driver->apps_rsp_buf + 84) = MSG_SSID_19;
1337 *(uint16_t *)(driver->apps_rsp_buf + 86) = MSG_SSID_19_LAST;
1338 *(uint16_t *)(driver->apps_rsp_buf + 88) = MSG_SSID_20;
1339 *(uint16_t *)(driver->apps_rsp_buf + 90) = MSG_SSID_20_LAST;
1340 *(uint16_t *)(driver->apps_rsp_buf + 92) = MSG_SSID_21;
1341 *(uint16_t *)(driver->apps_rsp_buf + 94) = MSG_SSID_21_LAST;
1342 *(uint16_t *)(driver->apps_rsp_buf + 96) = MSG_SSID_22;
1343 *(uint16_t *)(driver->apps_rsp_buf + 98) = MSG_SSID_22_LAST;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001344 encode_rsp_and_send(99);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001345 return 0;
1346 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001347 /* Check for Apps Only Respond to Get Subsys Build mask */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001348 else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001349 && (*buf == 0x7d) && (*(buf+1) == 0x2)) {
1350 ssid_first = *(uint16_t *)(buf + 2);
1351 ssid_last = *(uint16_t *)(buf + 4);
1352 ssid_range = 4 * (ssid_last - ssid_first + 1);
1353 /* frame response */
1354 driver->apps_rsp_buf[0] = 0x7d;
1355 driver->apps_rsp_buf[1] = 0x2;
1356 *(uint16_t *)(driver->apps_rsp_buf + 2) = ssid_first;
1357 *(uint16_t *)(driver->apps_rsp_buf + 4) = ssid_last;
1358 driver->apps_rsp_buf[6] = 0x1;
1359 driver->apps_rsp_buf[7] = 0x0;
1360 ptr = driver->apps_rsp_buf + 8;
1361 /* bld time masks */
1362 switch (ssid_first) {
1363 case MSG_SSID_0:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001364 if (ssid_range > sizeof(msg_bld_masks_0)) {
1365 pr_warning("diag: truncating ssid range for ssid 0");
1366 ssid_range = sizeof(msg_bld_masks_0);
1367 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001368 for (i = 0; i < ssid_range; i += 4)
1369 *(int *)(ptr + i) = msg_bld_masks_0[i/4];
1370 break;
1371 case MSG_SSID_1:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001372 if (ssid_range > sizeof(msg_bld_masks_1)) {
1373 pr_warning("diag: truncating ssid range for ssid 1");
1374 ssid_range = sizeof(msg_bld_masks_1);
1375 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001376 for (i = 0; i < ssid_range; i += 4)
1377 *(int *)(ptr + i) = msg_bld_masks_1[i/4];
1378 break;
1379 case MSG_SSID_2:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001380 if (ssid_range > sizeof(msg_bld_masks_2)) {
1381 pr_warning("diag: truncating ssid range for ssid 2");
1382 ssid_range = sizeof(msg_bld_masks_2);
1383 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 for (i = 0; i < ssid_range; i += 4)
1385 *(int *)(ptr + i) = msg_bld_masks_2[i/4];
1386 break;
1387 case MSG_SSID_3:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001388 if (ssid_range > sizeof(msg_bld_masks_3)) {
1389 pr_warning("diag: truncating ssid range for ssid 3");
1390 ssid_range = sizeof(msg_bld_masks_3);
1391 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001392 for (i = 0; i < ssid_range; i += 4)
1393 *(int *)(ptr + i) = msg_bld_masks_3[i/4];
1394 break;
1395 case MSG_SSID_4:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001396 if (ssid_range > sizeof(msg_bld_masks_4)) {
1397 pr_warning("diag: truncating ssid range for ssid 4");
1398 ssid_range = sizeof(msg_bld_masks_4);
1399 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001400 for (i = 0; i < ssid_range; i += 4)
1401 *(int *)(ptr + i) = msg_bld_masks_4[i/4];
1402 break;
1403 case MSG_SSID_5:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001404 if (ssid_range > sizeof(msg_bld_masks_5)) {
1405 pr_warning("diag: truncating ssid range for ssid 5");
1406 ssid_range = sizeof(msg_bld_masks_5);
1407 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408 for (i = 0; i < ssid_range; i += 4)
1409 *(int *)(ptr + i) = msg_bld_masks_5[i/4];
1410 break;
1411 case MSG_SSID_6:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001412 if (ssid_range > sizeof(msg_bld_masks_6)) {
1413 pr_warning("diag: truncating ssid range for ssid 6");
1414 ssid_range = sizeof(msg_bld_masks_6);
1415 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001416 for (i = 0; i < ssid_range; i += 4)
1417 *(int *)(ptr + i) = msg_bld_masks_6[i/4];
1418 break;
1419 case MSG_SSID_7:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001420 if (ssid_range > sizeof(msg_bld_masks_7)) {
1421 pr_warning("diag: truncating ssid range for ssid 7");
1422 ssid_range = sizeof(msg_bld_masks_7);
1423 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001424 for (i = 0; i < ssid_range; i += 4)
1425 *(int *)(ptr + i) = msg_bld_masks_7[i/4];
1426 break;
1427 case MSG_SSID_8:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001428 if (ssid_range > sizeof(msg_bld_masks_8)) {
1429 pr_warning("diag: truncating ssid range for ssid 8");
1430 ssid_range = sizeof(msg_bld_masks_8);
1431 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001432 for (i = 0; i < ssid_range; i += 4)
1433 *(int *)(ptr + i) = msg_bld_masks_8[i/4];
1434 break;
1435 case MSG_SSID_9:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001436 if (ssid_range > sizeof(msg_bld_masks_9)) {
1437 pr_warning("diag: truncating ssid range for ssid 9");
1438 ssid_range = sizeof(msg_bld_masks_9);
1439 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001440 for (i = 0; i < ssid_range; i += 4)
1441 *(int *)(ptr + i) = msg_bld_masks_9[i/4];
1442 break;
1443 case MSG_SSID_10:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001444 if (ssid_range > sizeof(msg_bld_masks_10)) {
1445 pr_warning("diag: truncating ssid range for ssid 10");
1446 ssid_range = sizeof(msg_bld_masks_10);
1447 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001448 for (i = 0; i < ssid_range; i += 4)
1449 *(int *)(ptr + i) = msg_bld_masks_10[i/4];
1450 break;
1451 case MSG_SSID_11:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001452 if (ssid_range > sizeof(msg_bld_masks_11)) {
1453 pr_warning("diag: truncating ssid range for ssid 11");
1454 ssid_range = sizeof(msg_bld_masks_11);
1455 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456 for (i = 0; i < ssid_range; i += 4)
1457 *(int *)(ptr + i) = msg_bld_masks_11[i/4];
1458 break;
1459 case MSG_SSID_12:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001460 if (ssid_range > sizeof(msg_bld_masks_12)) {
1461 pr_warning("diag: truncating ssid range for ssid 12");
1462 ssid_range = sizeof(msg_bld_masks_12);
1463 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001464 for (i = 0; i < ssid_range; i += 4)
1465 *(int *)(ptr + i) = msg_bld_masks_12[i/4];
1466 break;
1467 case MSG_SSID_13:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001468 if (ssid_range > sizeof(msg_bld_masks_13)) {
1469 pr_warning("diag: truncating ssid range for ssid 13");
1470 ssid_range = sizeof(msg_bld_masks_13);
1471 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001472 for (i = 0; i < ssid_range; i += 4)
1473 *(int *)(ptr + i) = msg_bld_masks_13[i/4];
1474 break;
1475 case MSG_SSID_14:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001476 if (ssid_range > sizeof(msg_bld_masks_14)) {
1477 pr_warning("diag: truncating ssid range for ssid 14");
1478 ssid_range = sizeof(msg_bld_masks_14);
1479 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001480 for (i = 0; i < ssid_range; i += 4)
1481 *(int *)(ptr + i) = msg_bld_masks_14[i/4];
1482 break;
1483 case MSG_SSID_15:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001484 if (ssid_range > sizeof(msg_bld_masks_15)) {
1485 pr_warning("diag: truncating ssid range for ssid 15");
1486 ssid_range = sizeof(msg_bld_masks_15);
1487 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488 for (i = 0; i < ssid_range; i += 4)
1489 *(int *)(ptr + i) = msg_bld_masks_15[i/4];
1490 break;
1491 case MSG_SSID_16:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001492 if (ssid_range > sizeof(msg_bld_masks_16)) {
1493 pr_warning("diag: truncating ssid range for ssid 16");
1494 ssid_range = sizeof(msg_bld_masks_16);
1495 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001496 for (i = 0; i < ssid_range; i += 4)
1497 *(int *)(ptr + i) = msg_bld_masks_16[i/4];
1498 break;
1499 case MSG_SSID_17:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001500 if (ssid_range > sizeof(msg_bld_masks_17)) {
1501 pr_warning("diag: truncating ssid range for ssid 17");
1502 ssid_range = sizeof(msg_bld_masks_17);
1503 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001504 for (i = 0; i < ssid_range; i += 4)
1505 *(int *)(ptr + i) = msg_bld_masks_17[i/4];
1506 break;
1507 case MSG_SSID_18:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001508 if (ssid_range > sizeof(msg_bld_masks_18)) {
1509 pr_warning("diag: truncating ssid range for ssid 18");
1510 ssid_range = sizeof(msg_bld_masks_18);
1511 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512 for (i = 0; i < ssid_range; i += 4)
1513 *(int *)(ptr + i) = msg_bld_masks_18[i/4];
1514 break;
Shalabh Jain321c8b52012-02-22 12:37:06 -08001515 case MSG_SSID_19:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001516 if (ssid_range > sizeof(msg_bld_masks_19)) {
1517 pr_warning("diag: truncating ssid range for ssid 19");
1518 ssid_range = sizeof(msg_bld_masks_19);
1519 }
Shalabh Jain321c8b52012-02-22 12:37:06 -08001520 for (i = 0; i < ssid_range; i += 4)
1521 *(int *)(ptr + i) = msg_bld_masks_19[i/4];
1522 break;
1523 case MSG_SSID_20:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001524 if (ssid_range > sizeof(msg_bld_masks_20)) {
1525 pr_warning("diag: truncating ssid range for ssid 20");
1526 ssid_range = sizeof(msg_bld_masks_20);
1527 }
Shalabh Jain321c8b52012-02-22 12:37:06 -08001528 for (i = 0; i < ssid_range; i += 4)
1529 *(int *)(ptr + i) = msg_bld_masks_20[i/4];
1530 break;
1531 case MSG_SSID_21:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001532 if (ssid_range > sizeof(msg_bld_masks_21)) {
1533 pr_warning("diag: truncating ssid range for ssid 21");
1534 ssid_range = sizeof(msg_bld_masks_21);
1535 }
Shalabh Jain321c8b52012-02-22 12:37:06 -08001536 for (i = 0; i < ssid_range; i += 4)
1537 *(int *)(ptr + i) = msg_bld_masks_21[i/4];
1538 break;
1539 case MSG_SSID_22:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001540 if (ssid_range > sizeof(msg_bld_masks_22)) {
1541 pr_warning("diag: truncating ssid range for ssid 22");
1542 ssid_range = sizeof(msg_bld_masks_22);
1543 }
Shalabh Jain321c8b52012-02-22 12:37:06 -08001544 for (i = 0; i < ssid_range; i += 4)
1545 *(int *)(ptr + i) = msg_bld_masks_22[i/4];
1546 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001547 }
Dixon Petersond6a20a92012-09-27 15:58:50 -07001548 encode_rsp_and_send(8 + ssid_range - 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001549 return 0;
1550 }
1551 /* Check for download command */
Shalabh Jain10f5f432012-01-11 11:45:44 +05301552 else if ((cpu_is_msm8x60() || chk_apps_master()) && (*buf == 0x3A)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001553 /* send response back */
1554 driver->apps_rsp_buf[0] = *buf;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001555 encode_rsp_and_send(0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001556 msleep(5000);
1557 /* call download API */
1558 msm_set_restart_mode(RESTART_DLOAD);
1559 printk(KERN_CRIT "diag: download mode set, Rebooting SoC..\n");
1560 kernel_restart(NULL);
1561 /* Not required, represents that command isnt sent to modem */
1562 return 0;
1563 }
Dixon Petersonb46bb992012-01-12 19:16:56 -08001564 /* Check for polling for Apps only DIAG */
1565 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1566 (*(buf+2) == 0x03)) {
Shalabh Jain3d29fc32012-02-09 17:15:59 -08001567 /* If no one has registered for polling */
Dixon Petersonb4618a42012-02-29 18:56:31 -08001568 if (chk_polling_response()) {
Dixon Petersonb46bb992012-01-12 19:16:56 -08001569 /* Respond to polling for Apps only DIAG */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001570 for (i = 0; i < 3; i++)
1571 driver->apps_rsp_buf[i] = *(buf+i);
1572 for (i = 0; i < 13; i++)
1573 driver->apps_rsp_buf[i+3] = 0;
1574
Dixon Petersond6a20a92012-09-27 15:58:50 -07001575 encode_rsp_and_send(15);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001576 return 0;
1577 }
Dixon Petersonb46bb992012-01-12 19:16:56 -08001578 }
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -08001579 /* Return the Delayed Response Wrap Status */
1580 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1581 (*(buf+2) == 0x04) && (*(buf+3) == 0x0)) {
1582 memcpy(driver->apps_rsp_buf, buf, 4);
1583 driver->apps_rsp_buf[4] = wrap_enabled;
1584 encode_rsp_and_send(4);
1585 return 0;
1586 }
1587 /* Wrap the Delayed Rsp ID */
1588 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1589 (*(buf+2) == 0x05) && (*(buf+3) == 0x0)) {
1590 wrap_enabled = true;
1591 memcpy(driver->apps_rsp_buf, buf, 4);
1592 driver->apps_rsp_buf[4] = wrap_count;
1593 encode_rsp_and_send(5);
1594 return 0;
1595 }
Dixon Petersonb46bb992012-01-12 19:16:56 -08001596 /* Check for ID for NO MODEM present */
Dixon Petersonb4618a42012-02-29 18:56:31 -08001597 else if (chk_polling_response()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001598 /* respond to 0x0 command */
Dixon Petersonb46bb992012-01-12 19:16:56 -08001599 if (*buf == 0x00) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001600 for (i = 0; i < 55; i++)
1601 driver->apps_rsp_buf[i] = 0;
1602
Dixon Petersond6a20a92012-09-27 15:58:50 -07001603 encode_rsp_and_send(54);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001604 return 0;
1605 }
1606 /* respond to 0x7c command */
1607 else if (*buf == 0x7c) {
1608 driver->apps_rsp_buf[0] = 0x7c;
1609 for (i = 1; i < 8; i++)
1610 driver->apps_rsp_buf[i] = 0;
1611 /* Tools ID for APQ 8060 */
1612 *(int *)(driver->apps_rsp_buf + 8) =
1613 chk_config_get_id();
1614 *(unsigned char *)(driver->apps_rsp_buf + 12) = '\0';
1615 *(unsigned char *)(driver->apps_rsp_buf + 13) = '\0';
Dixon Petersond6a20a92012-09-27 15:58:50 -07001616 encode_rsp_and_send(13);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001617 return 0;
1618 }
1619 }
1620#endif
Dixon Petersond6a20a92012-09-27 15:58:50 -07001621 return packet_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001622}
1623
1624#ifdef CONFIG_DIAG_OVER_USB
1625void diag_send_error_rsp(int index)
1626{
1627 int i;
Shalabh Jain1fedab92011-12-22 13:15:22 +05301628
Ravi Aravamudhancc9946862013-07-15 13:31:11 -07001629 /* -1 to accomodate the first byte 0x13 */
1630 if (index > APPS_BUF_SIZE-1) {
1631 pr_err("diag: cannot send err rsp, huge length: %d\n", index);
Shalabh Jain1fedab92011-12-22 13:15:22 +05301632 return;
1633 }
Ravi Aravamudhancc9946862013-07-15 13:31:11 -07001634
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001635 driver->apps_rsp_buf[0] = 0x13; /* error code 13 */
1636 for (i = 0; i < index; i++)
1637 driver->apps_rsp_buf[i+1] = *(driver->hdlc_buf+i);
Dixon Petersond6a20a92012-09-27 15:58:50 -07001638 encode_rsp_and_send(index - 3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001639}
1640#else
1641static inline void diag_send_error_rsp(int index) {}
1642#endif
1643
1644void diag_process_hdlc(void *data, unsigned len)
1645{
1646 struct diag_hdlc_decode_type hdlc;
Ravi Aravamudhan5dccccb2013-08-09 16:57:34 -07001647 int ret, type = 0, crc_chk = 0;
Dixon Peterson25f042b2013-02-27 13:00:08 -08001648
1649 mutex_lock(&driver->diag_hdlc_mutex);
1650
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001651 pr_debug("diag: HDLC decode fn, len of data %d\n", len);
1652 hdlc.dest_ptr = driver->hdlc_buf;
1653 hdlc.dest_size = USB_MAX_OUT_BUF;
1654 hdlc.src_ptr = data;
1655 hdlc.src_size = len;
1656 hdlc.src_idx = 0;
1657 hdlc.dest_idx = 0;
1658 hdlc.escaping = 0;
1659
1660 ret = diag_hdlc_decode(&hdlc);
Ravi Aravamudhan5dccccb2013-08-09 16:57:34 -07001661 if (ret) {
1662 crc_chk = crc_check(hdlc.dest_ptr, hdlc.dest_idx);
1663 if (crc_chk) {
1664 /* CRC check failed. */
1665 pr_err_ratelimited("diag: In %s, bad CRC. Dropping packet\n",
1666 __func__);
1667 mutex_unlock(&driver->diag_hdlc_mutex);
1668 return;
1669 }
1670 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001671
Dixon Petersonb4f84242013-02-27 18:46:56 -08001672 /*
1673 * If the message is 3 bytes or less in length then the message is
1674 * too short. A message will need 4 bytes minimum, since there are
1675 * 2 bytes for the CRC and 1 byte for the ending 0x7e for the hdlc
1676 * encoding
1677 */
1678 if (hdlc.dest_idx < 4) {
1679 pr_err_ratelimited("diag: In %s, message is too short, len: %d, dest len: %d\n",
1680 __func__, len, hdlc.dest_idx);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001681 mutex_unlock(&driver->diag_hdlc_mutex);
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001682 return;
1683 }
Dixon Petersonb4f84242013-02-27 18:46:56 -08001684
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001685 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001686 type = diag_process_apps_pkt(driver->hdlc_buf,
1687 hdlc.dest_idx - 3);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001688 if (type < 0) {
1689 mutex_unlock(&driver->diag_hdlc_mutex);
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001690 return;
Dixon Peterson25f042b2013-02-27 13:00:08 -08001691 }
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001692 } else if (driver->debug_flag) {
Ravi Aravamudhan5dccccb2013-08-09 16:57:34 -07001693 pr_err("diag: In %s, partial packet received, dropping packet, len: %d\n",
1694 __func__, len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001695 print_hex_dump(KERN_DEBUG, "Dropped Packet Data: ", 16, 1,
1696 DUMP_PREFIX_ADDRESS, data, len, 1);
1697 driver->debug_flag = 0;
1698 }
1699 /* send error responses from APPS for Central Routing */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001700 if (type == 1 && chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001701 diag_send_error_rsp(hdlc.dest_idx);
1702 type = 0;
1703 }
1704 /* implies this packet is NOT meant for apps */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001705 if (!(driver->smd_data[MODEM_DATA].ch) && type == 1) {
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001706 if (chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001707 diag_send_error_rsp(hdlc.dest_idx);
1708 } else { /* APQ 8060, Let Q6 respond */
Dixon Peterson25f042b2013-02-27 13:00:08 -08001709 if (driver->smd_data[LPASS_DATA].ch) {
1710 mutex_lock(&driver->smd_data[LPASS_DATA].
1711 smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001712 smd_write(driver->smd_data[LPASS_DATA].ch,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001713 driver->hdlc_buf,
1714 hdlc.dest_idx - 3);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001715 mutex_unlock(&driver->smd_data[LPASS_DATA].
1716 smd_ch_mutex);
1717 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718 }
1719 type = 0;
1720 }
1721
1722#ifdef DIAG_DEBUG
1723 pr_debug("diag: hdlc.dest_idx = %d", hdlc.dest_idx);
1724 for (i = 0; i < hdlc.dest_idx; i++)
1725 printk(KERN_DEBUG "\t%x", *(((unsigned char *)
1726 driver->hdlc_buf)+i));
1727#endif /* DIAG DEBUG */
1728 /* ignore 2 bytes for CRC, one for 7E and send */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001729 if ((driver->smd_data[MODEM_DATA].ch) && (ret) && (type) &&
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001730 (hdlc.dest_idx > 3)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001731 APPEND_DEBUG('g');
Dixon Peterson25f042b2013-02-27 13:00:08 -08001732 mutex_lock(&driver->smd_data[MODEM_DATA].smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001733 smd_write(driver->smd_data[MODEM_DATA].ch,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001734 driver->hdlc_buf, hdlc.dest_idx - 3);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001735 mutex_unlock(&driver->smd_data[MODEM_DATA].smd_ch_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736 APPEND_DEBUG('h');
1737#ifdef DIAG_DEBUG
1738 printk(KERN_INFO "writing data to SMD, pkt length %d\n", len);
1739 print_hex_dump(KERN_DEBUG, "Written Packet Data to SMD: ", 16,
1740 1, DUMP_PREFIX_ADDRESS, data, len, 1);
1741#endif /* DIAG DEBUG */
1742 }
Dixon Peterson25f042b2013-02-27 13:00:08 -08001743 mutex_unlock(&driver->diag_hdlc_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001744}
1745
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001746void diag_reset_smd_data(int queue)
1747{
1748 int i;
1749
1750 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1751 driver->smd_data[i].in_busy_1 = 0;
1752 driver->smd_data[i].in_busy_2 = 0;
1753 if (queue)
1754 /* Poll SMD data channels to check for data */
Dixon Petersonbba99ca2013-07-10 17:25:20 -07001755 queue_work(driver->smd_data[i].wq,
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001756 &(driver->smd_data[i].diag_read_smd_work));
1757 }
1758
1759 if (driver->supports_separate_cmdrsp) {
1760 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
1761 driver->smd_cmd[i].in_busy_1 = 0;
1762 driver->smd_cmd[i].in_busy_2 = 0;
1763 if (queue)
1764 /* Poll SMD data channels to check for data */
1765 queue_work(driver->diag_wq,
1766 &(driver->smd_cmd[i].
1767 diag_read_smd_work));
1768 }
1769 }
1770}
1771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001772#ifdef CONFIG_DIAG_OVER_USB
Shalabh Jain8e9750a2011-09-09 13:06:29 -07001773/* 2+1 for modem ; 2 for LPASS ; 1 for WCNSS */
1774#define N_LEGACY_WRITE (driver->poolsize + 6)
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001775/* Additionally support number of command data and dci channels */
1776#define N_LEGACY_WRITE_CMD ((N_LEGACY_WRITE) + 4)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001777#define N_LEGACY_READ 1
1778
Mohit Aggarwalb4465772013-04-18 13:08:07 +05301779static void diag_usb_connect_work_fn(struct work_struct *w)
1780{
1781 diagfwd_connect();
1782}
1783
1784static void diag_usb_disconnect_work_fn(struct work_struct *w)
1785{
1786 diagfwd_disconnect();
1787}
1788
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001789int diagfwd_connect(void)
1790{
1791 int err;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001792 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793
1794 printk(KERN_DEBUG "diag: USB connected\n");
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001795 err = usb_diag_alloc_req(driver->legacy_ch,
1796 (driver->supports_separate_cmdrsp ?
1797 N_LEGACY_WRITE_CMD : N_LEGACY_WRITE),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001798 N_LEGACY_READ);
1799 if (err)
1800 printk(KERN_ERR "diag: unable to alloc USB req on legacy ch");
1801
1802 driver->usb_connected = 1;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001803 diag_reset_smd_data(RESET_AND_QUEUE);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001804 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001805 /* Poll SMD CNTL channels to check for data */
1806 diag_smd_notify(&(driver->smd_cntl[i]), SMD_EVENT_DATA);
1807 }
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001808 queue_work(driver->diag_real_time_wq,
1809 &driver->diag_real_time_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001810
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001811 /* Poll USB channel to check for data*/
1812 queue_work(driver->diag_wq, &(driver->diag_read_work));
1813#ifdef CONFIG_DIAG_SDIO_PIPE
1814 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
1815 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1816 diagfwd_connect_sdio();
1817 else
1818 printk(KERN_INFO "diag: No USB MDM ch");
1819 }
1820#endif
1821 return 0;
1822}
1823
1824int diagfwd_disconnect(void)
1825{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001826 int i;
1827
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001828 printk(KERN_DEBUG "diag: USB disconnected\n");
1829 driver->usb_connected = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001830 driver->debug_flag = 1;
1831 usb_diag_free_req(driver->legacy_ch);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001832 if (driver->logging_mode == USB_MODE) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001833 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1834 driver->smd_data[i].in_busy_1 = 1;
1835 driver->smd_data[i].in_busy_2 = 1;
1836 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001837
1838 if (driver->supports_separate_cmdrsp) {
1839 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
1840 driver->smd_cmd[i].in_busy_1 = 1;
1841 driver->smd_cmd[i].in_busy_2 = 1;
1842 }
1843 }
Shalabh Jain69890aa2011-10-10 12:59:16 -07001844 }
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001845 queue_work(driver->diag_real_time_wq,
1846 &driver->diag_real_time_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001847#ifdef CONFIG_DIAG_SDIO_PIPE
1848 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
1849 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1850 diagfwd_disconnect_sdio();
1851#endif
1852 /* TBD - notify and flow control SMD */
1853 return 0;
1854}
1855
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001856static int diagfwd_check_buf_match(int num_channels,
1857 struct diag_smd_info *data, unsigned char *buf)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001858{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001859 int i;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001860 int found_it = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001861
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001862 for (i = 0; i < num_channels; i++) {
1863 if (buf == (void *)data[i].buf_in_1) {
1864 data[i].in_busy_1 = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001865 found_it = 1;
1866 break;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001867 } else if (buf == (void *)data[i].buf_in_2) {
1868 data[i].in_busy_2 = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001869 found_it = 1;
1870 break;
1871 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001872 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001873
Dixon Petersonbba99ca2013-07-10 17:25:20 -07001874 if (found_it) {
1875 if (data[i].type == SMD_DATA_TYPE)
1876 queue_work(data[i].wq,
1877 &(data[i].diag_read_smd_work));
1878 else
1879 queue_work(driver->diag_wq,
1880 &(data[i].diag_read_smd_work));
1881 }
1882
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001883 return found_it;
1884}
1885
1886int diagfwd_write_complete(struct diag_request *diag_write_ptr)
1887{
1888 unsigned char *buf = diag_write_ptr->buf;
1889 int found_it = 0;
1890
1891 /* Determine if the write complete is for data from modem/apps/q6 */
1892 found_it = diagfwd_check_buf_match(NUM_SMD_DATA_CHANNELS,
1893 driver->smd_data, buf);
1894
1895 if (!found_it && driver->supports_separate_cmdrsp)
1896 found_it = diagfwd_check_buf_match(NUM_SMD_CMD_CHANNELS,
1897 driver->smd_cmd, buf);
1898
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001899#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001900 if (!found_it) {
1901 if (buf == (void *)driver->buf_in_sdio) {
1902 if (machine_is_msm8x60_fusion() ||
1903 machine_is_msm8x60_fusn_ffa())
1904 diagfwd_write_complete_sdio();
1905 else
1906 pr_err("diag: Incorrect buffer pointer while WRITE");
1907 found_it = 1;
1908 }
1909 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001910#endif
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001911 if (!found_it) {
Ravi Aravamudhand995a7f2013-07-03 13:06:15 -07001912 if (driver->logging_mode != USB_MODE)
1913 pr_debug("diag: freeing buffer when not in usb mode\n");
1914
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001915 diagmem_free(driver, (unsigned char *)buf,
1916 POOL_TYPE_HDLC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001917 diagmem_free(driver, (unsigned char *)diag_write_ptr,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001918 POOL_TYPE_WRITE_STRUCT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001919 }
1920 return 0;
1921}
1922
1923int diagfwd_read_complete(struct diag_request *diag_read_ptr)
1924{
1925 int status = diag_read_ptr->status;
1926 unsigned char *buf = diag_read_ptr->buf;
1927
1928 /* Determine if the read complete is for data on legacy/mdm ch */
1929 if (buf == (void *)driver->usb_buf_out) {
1930 driver->read_len_legacy = diag_read_ptr->actual;
1931 APPEND_DEBUG('s');
1932#ifdef DIAG_DEBUG
1933 printk(KERN_INFO "read data from USB, pkt length %d",
1934 diag_read_ptr->actual);
1935 print_hex_dump(KERN_DEBUG, "Read Packet Data from USB: ", 16, 1,
1936 DUMP_PREFIX_ADDRESS, diag_read_ptr->buf,
1937 diag_read_ptr->actual, 1);
1938#endif /* DIAG DEBUG */
1939 if (driver->logging_mode == USB_MODE) {
1940 if (status != -ECONNRESET && status != -ESHUTDOWN)
1941 queue_work(driver->diag_wq,
1942 &(driver->diag_proc_hdlc_work));
1943 else
1944 queue_work(driver->diag_wq,
1945 &(driver->diag_read_work));
1946 }
1947 }
1948#ifdef CONFIG_DIAG_SDIO_PIPE
1949 else if (buf == (void *)driver->usb_buf_mdm_out) {
1950 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -08001951 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001952 driver->read_len_mdm = diag_read_ptr->actual;
1953 diagfwd_read_complete_sdio();
1954 } else
1955 pr_err("diag: Incorrect buffer pointer while READ");
1956 }
1957#endif
1958 else
1959 printk(KERN_ERR "diag: Unknown buffer ptr from USB");
1960
1961 return 0;
1962}
1963
1964void diag_read_work_fn(struct work_struct *work)
1965{
1966 APPEND_DEBUG('d');
1967 driver->usb_read_ptr->buf = driver->usb_buf_out;
1968 driver->usb_read_ptr->length = USB_MAX_OUT_BUF;
1969 usb_diag_read(driver->legacy_ch, driver->usb_read_ptr);
1970 APPEND_DEBUG('e');
1971}
1972
1973void diag_process_hdlc_fn(struct work_struct *work)
1974{
1975 APPEND_DEBUG('D');
1976 diag_process_hdlc(driver->usb_buf_out, driver->read_len_legacy);
1977 diag_read_work_fn(work);
1978 APPEND_DEBUG('E');
1979}
1980
1981void diag_usb_legacy_notifier(void *priv, unsigned event,
1982 struct diag_request *d_req)
1983{
1984 switch (event) {
1985 case USB_DIAG_CONNECT:
Mohit Aggarwalb4465772013-04-18 13:08:07 +05301986 queue_work(driver->diag_wq,
1987 &driver->diag_usb_connect_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001988 break;
1989 case USB_DIAG_DISCONNECT:
Mohit Aggarwalb4465772013-04-18 13:08:07 +05301990 queue_work(driver->diag_wq,
1991 &driver->diag_usb_disconnect_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001992 break;
1993 case USB_DIAG_READ_DONE:
1994 diagfwd_read_complete(d_req);
1995 break;
1996 case USB_DIAG_WRITE_DONE:
1997 diagfwd_write_complete(d_req);
1998 break;
1999 default:
2000 printk(KERN_ERR "Unknown event from USB diag\n");
2001 break;
2002 }
2003}
2004
2005#endif /* DIAG OVER USB */
2006
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002007void diag_smd_notify(void *ctxt, unsigned event)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002008{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002009 struct diag_smd_info *smd_info = (struct diag_smd_info *)ctxt;
2010 if (!smd_info)
Shalabh Jaineefee052011-11-08 23:46:03 -08002011 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002012
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002013 if (event == SMD_EVENT_CLOSE) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002014 smd_info->ch = 0;
Shalabh Jainc70b3b62012-08-31 19:11:20 -07002015 wake_up(&driver->smd_wait_q);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002016 if (smd_info->type == SMD_DATA_TYPE) {
2017 smd_info->notify_context = event;
2018 queue_work(driver->diag_cntl_wq,
2019 &(smd_info->diag_notify_update_smd_work));
2020 } else if (smd_info->type == SMD_DCI_TYPE) {
2021 /* Notify the clients of the close */
2022 diag_dci_notify_client(smd_info->peripheral_mask,
2023 DIAG_STATUS_CLOSED);
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002024 } else if (smd_info->type == SMD_CNTL_TYPE) {
2025 diag_cntl_stm_notify(smd_info,
2026 CLEAR_PERIPHERAL_STM_STATE);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002027 }
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002028 return;
2029 } else if (event == SMD_EVENT_OPEN) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002030 if (smd_info->ch_save)
2031 smd_info->ch = smd_info->ch_save;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002032
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002033 if (smd_info->type == SMD_CNTL_TYPE) {
2034 smd_info->notify_context = event;
2035 queue_work(driver->diag_cntl_wq,
2036 &(smd_info->diag_notify_update_smd_work));
2037 } else if (smd_info->type == SMD_DCI_TYPE) {
2038 smd_info->notify_context = event;
2039 queue_work(driver->diag_dci_wq,
2040 &(smd_info->diag_notify_update_smd_work));
2041 /* Notify the clients of the open */
2042 diag_dci_notify_client(smd_info->peripheral_mask,
2043 DIAG_STATUS_OPEN);
2044 }
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002045 } else if (event == SMD_EVENT_DATA && !driver->real_time_mode &&
2046 smd_info->type == SMD_DATA_TYPE) {
2047 process_lock_on_notify(&smd_info->nrt_lock);
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002048 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002049
Shalabh Jainc70b3b62012-08-31 19:11:20 -07002050 wake_up(&driver->smd_wait_q);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002051
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002052 if (smd_info->type == SMD_DCI_TYPE ||
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07002053 smd_info->type == SMD_DCI_CMD_TYPE) {
2054 if (event == SMD_EVENT_DATA)
2055 diag_dci_try_activate_wakeup_source(smd_info->ch);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002056 queue_work(driver->diag_dci_wq,
2057 &(smd_info->diag_read_smd_work));
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002058 } else if (smd_info->type == SMD_DATA_TYPE) {
2059 queue_work(smd_info->wq,
2060 &(smd_info->diag_read_smd_work));
2061 } else {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002062 queue_work(driver->diag_wq, &(smd_info->diag_read_smd_work));
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002063 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002064}
2065
2066static int diag_smd_probe(struct platform_device *pdev)
2067{
2068 int r = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002069 int index = -1;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002070 const char *channel_name = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002071
Shalabh Jaineefee052011-11-08 23:46:03 -08002072 if (pdev->id == SMD_APPS_MODEM) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002073 index = MODEM_DATA;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002074 channel_name = "DIAG";
Shalabh Jaineefee052011-11-08 23:46:03 -08002075 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002076#if defined(CONFIG_MSM_N_WAY_SMD)
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002077 else if (pdev->id == SMD_APPS_QDSP) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002078 index = LPASS_DATA;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002079 channel_name = "DIAG";
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002080 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002081#endif
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002082 else if (pdev->id == SMD_APPS_WCNSS) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002083 index = WCNSS_DATA;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002084 channel_name = "APPS_RIVA_DATA";
2085 }
2086
2087 if (index != -1) {
2088 r = smd_named_open_on_edge(channel_name,
2089 pdev->id,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002090 &driver->smd_data[index].ch,
2091 &driver->smd_data[index],
2092 diag_smd_notify);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002093 driver->smd_data[index].ch_save = driver->smd_data[index].ch;
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002094 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002095
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002096 pm_runtime_set_active(&pdev->dev);
2097 pm_runtime_enable(&pdev->dev);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002098 pr_debug("diag: In %s, open SMD port, Id = %d, r = %d\n",
2099 __func__, pdev->id, r);
2100
2101 return 0;
2102}
2103
2104static int diag_smd_cmd_probe(struct platform_device *pdev)
2105{
2106 int r = 0;
2107 int index = -1;
2108 const char *channel_name = NULL;
2109
2110 if (!driver->supports_separate_cmdrsp)
2111 return 0;
2112
2113 if (pdev->id == SMD_APPS_MODEM) {
2114 index = MODEM_DATA;
2115 channel_name = "DIAG_CMD";
2116 }
2117
2118 if (index != -1) {
2119 r = smd_named_open_on_edge(channel_name,
2120 pdev->id,
2121 &driver->smd_cmd[index].ch,
2122 &driver->smd_cmd[index],
2123 diag_smd_notify);
2124 driver->smd_cmd[index].ch_save =
2125 driver->smd_cmd[index].ch;
2126 }
2127
2128 pr_debug("diag: In %s, open SMD CMD port, Id = %d, r = %d\n",
2129 __func__, pdev->id, r);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002130
2131 return 0;
2132}
2133
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002134static int diag_smd_runtime_suspend(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002135{
2136 dev_dbg(dev, "pm_runtime: suspending...\n");
2137 return 0;
2138}
2139
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002140static int diag_smd_runtime_resume(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002141{
2142 dev_dbg(dev, "pm_runtime: resuming...\n");
2143 return 0;
2144}
2145
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002146static const struct dev_pm_ops diag_smd_dev_pm_ops = {
2147 .runtime_suspend = diag_smd_runtime_suspend,
2148 .runtime_resume = diag_smd_runtime_resume,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002149};
2150
2151static struct platform_driver msm_smd_ch1_driver = {
2152
2153 .probe = diag_smd_probe,
2154 .driver = {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002155 .name = "DIAG",
2156 .owner = THIS_MODULE,
2157 .pm = &diag_smd_dev_pm_ops,
2158 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002159};
2160
2161static struct platform_driver diag_smd_lite_driver = {
2162
2163 .probe = diag_smd_probe,
2164 .driver = {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002165 .name = "APPS_RIVA_DATA",
2166 .owner = THIS_MODULE,
2167 .pm = &diag_smd_dev_pm_ops,
2168 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002169};
2170
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002171static struct platform_driver
2172 smd_lite_data_cmd_drivers[NUM_SMD_CMD_CHANNELS] = {
2173 {
2174 /* Modem data */
2175 .probe = diag_smd_cmd_probe,
2176 .driver = {
2177 .name = "DIAG_CMD",
2178 .owner = THIS_MODULE,
2179 .pm = &diag_smd_dev_pm_ops,
2180 },
2181 }
2182};
2183
2184int device_supports_separate_cmdrsp(void)
2185{
2186 return driver->use_device_tree;
2187}
2188
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002189void diag_smd_destructor(struct diag_smd_info *smd_info)
2190{
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002191 if (smd_info->type == SMD_DATA_TYPE) {
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002192 wake_lock_destroy(&smd_info->nrt_lock.read_lock);
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002193 destroy_workqueue(smd_info->wq);
2194 }
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002195
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002196 if (smd_info->ch)
2197 smd_close(smd_info->ch);
2198
2199 smd_info->ch = 0;
2200 smd_info->ch_save = 0;
2201 kfree(smd_info->buf_in_1);
2202 kfree(smd_info->buf_in_2);
2203 kfree(smd_info->write_ptr_1);
2204 kfree(smd_info->write_ptr_2);
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002205 kfree(smd_info->buf_in_1_raw);
2206 kfree(smd_info->buf_in_2_raw);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002207}
2208
2209int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral,
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002210 int type)
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002211{
2212 smd_info->peripheral = peripheral;
2213 smd_info->type = type;
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002214 smd_info->encode_hdlc = 0;
Dixon Peterson25f042b2013-02-27 13:00:08 -08002215 mutex_init(&smd_info->smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002216
2217 switch (peripheral) {
2218 case MODEM_DATA:
2219 smd_info->peripheral_mask = DIAG_CON_MPSS;
2220 break;
2221 case LPASS_DATA:
2222 smd_info->peripheral_mask = DIAG_CON_LPASS;
2223 break;
2224 case WCNSS_DATA:
2225 smd_info->peripheral_mask = DIAG_CON_WCNSS;
2226 break;
2227 default:
2228 pr_err("diag: In %s, unknown peripheral, peripheral: %d\n",
2229 __func__, peripheral);
2230 goto err;
2231 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002232
2233 smd_info->ch = 0;
2234 smd_info->ch_save = 0;
2235
2236 if (smd_info->buf_in_1 == NULL) {
2237 smd_info->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
2238 if (smd_info->buf_in_1 == NULL)
2239 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002240 smd_info->buf_in_1_size = IN_BUF_SIZE;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002241 kmemleak_not_leak(smd_info->buf_in_1);
2242 }
2243
2244 if (smd_info->write_ptr_1 == NULL) {
2245 smd_info->write_ptr_1 = kzalloc(sizeof(struct diag_request),
2246 GFP_KERNEL);
2247 if (smd_info->write_ptr_1 == NULL)
2248 goto err;
2249 kmemleak_not_leak(smd_info->write_ptr_1);
2250 }
2251
2252 /* The smd data type needs two buffers */
2253 if (smd_info->type == SMD_DATA_TYPE) {
2254 if (smd_info->buf_in_2 == NULL) {
2255 smd_info->buf_in_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
2256 if (smd_info->buf_in_2 == NULL)
2257 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002258 smd_info->buf_in_2_size = IN_BUF_SIZE;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002259 kmemleak_not_leak(smd_info->buf_in_2);
2260 }
2261 if (smd_info->write_ptr_2 == NULL) {
2262 smd_info->write_ptr_2 =
2263 kzalloc(sizeof(struct diag_request),
2264 GFP_KERNEL);
2265 if (smd_info->write_ptr_2 == NULL)
2266 goto err;
2267 kmemleak_not_leak(smd_info->write_ptr_2);
2268 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002269 if (driver->supports_apps_hdlc_encoding) {
2270 /* In support of hdlc encoding */
2271 if (smd_info->buf_in_1_raw == NULL) {
2272 smd_info->buf_in_1_raw = kzalloc(IN_BUF_SIZE,
2273 GFP_KERNEL);
2274 if (smd_info->buf_in_1_raw == NULL)
2275 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002276 smd_info->buf_in_1_raw_size = IN_BUF_SIZE;
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002277 kmemleak_not_leak(smd_info->buf_in_1_raw);
2278 }
2279 if (smd_info->buf_in_2_raw == NULL) {
2280 smd_info->buf_in_2_raw = kzalloc(IN_BUF_SIZE,
2281 GFP_KERNEL);
2282 if (smd_info->buf_in_2_raw == NULL)
2283 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002284 smd_info->buf_in_2_raw_size = IN_BUF_SIZE;
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002285 kmemleak_not_leak(smd_info->buf_in_2_raw);
2286 }
2287 }
2288 }
2289
2290 if (smd_info->type == SMD_CMD_TYPE &&
2291 driver->supports_apps_hdlc_encoding) {
2292 /* In support of hdlc encoding */
2293 if (smd_info->buf_in_1_raw == NULL) {
2294 smd_info->buf_in_1_raw = kzalloc(IN_BUF_SIZE,
2295 GFP_KERNEL);
2296 if (smd_info->buf_in_1_raw == NULL)
2297 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002298 smd_info->buf_in_1_raw_size = IN_BUF_SIZE;
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002299 kmemleak_not_leak(smd_info->buf_in_1_raw);
2300 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002301 }
2302
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002303 /* The smd data type needs separate work queues for reads */
2304 if (type == SMD_DATA_TYPE) {
2305 switch (peripheral) {
2306 case MODEM_DATA:
2307 smd_info->wq = create_singlethread_workqueue(
2308 "diag_modem_data_read_wq");
2309 break;
2310 case LPASS_DATA:
2311 smd_info->wq = create_singlethread_workqueue(
2312 "diag_lpass_data_read_wq");
2313 break;
2314 case WCNSS_DATA:
2315 smd_info->wq = create_singlethread_workqueue(
2316 "diag_wcnss_data_read_wq");
2317 break;
2318 default:
2319 smd_info->wq = NULL;
2320 break;
2321 }
2322 } else {
2323 smd_info->wq = NULL;
2324 }
2325
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002326 INIT_WORK(&(smd_info->diag_read_smd_work), diag_read_smd_work_fn);
2327
2328 /*
2329 * The update function assigned to the diag_notify_update_smd_work
2330 * work_struct is meant to be used for updating that is not to
2331 * be done in the context of the smd notify function. The
2332 * notify_context variable can be used for passing additional
2333 * information to the update function.
2334 */
2335 smd_info->notify_context = 0;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002336 smd_info->general_context = 0;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002337 switch (type) {
2338 case SMD_DATA_TYPE:
2339 case SMD_CMD_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002340 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002341 diag_clean_reg_fn);
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002342 INIT_WORK(&(smd_info->diag_general_smd_work),
2343 diag_cntl_smd_work_fn);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002344 break;
2345 case SMD_CNTL_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002346 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002347 diag_mask_update_fn);
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002348 INIT_WORK(&(smd_info->diag_general_smd_work),
2349 diag_cntl_smd_work_fn);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002350 break;
2351 case SMD_DCI_TYPE:
2352 case SMD_DCI_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_update_smd_dci_work_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 default:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002359 pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
2360 goto err;
2361 }
2362
2363 /*
2364 * Set function ptr for function to call to process the data that
2365 * was just read from the smd channel
2366 */
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002367 switch (type) {
2368 case SMD_DATA_TYPE:
2369 case SMD_CMD_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002370 smd_info->process_smd_read_data = diag_process_smd_read_data;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002371 break;
2372 case SMD_CNTL_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002373 smd_info->process_smd_read_data =
2374 diag_process_smd_cntl_read_data;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002375 break;
2376 case SMD_DCI_TYPE:
2377 case SMD_DCI_CMD_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002378 smd_info->process_smd_read_data =
2379 diag_process_smd_dci_read_data;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002380 break;
2381 default:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002382 pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
2383 goto err;
2384 }
2385
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002386 smd_info->nrt_lock.enabled = 0;
2387 smd_info->nrt_lock.ref_count = 0;
2388 smd_info->nrt_lock.copy_count = 0;
2389 if (type == SMD_DATA_TYPE) {
2390 spin_lock_init(&smd_info->nrt_lock.read_spinlock);
2391
2392 switch (peripheral) {
2393 case MODEM_DATA:
2394 wake_lock_init(&smd_info->nrt_lock.read_lock,
2395 WAKE_LOCK_SUSPEND, "diag_nrt_modem_read");
2396 break;
2397 case LPASS_DATA:
2398 wake_lock_init(&smd_info->nrt_lock.read_lock,
2399 WAKE_LOCK_SUSPEND, "diag_nrt_lpass_read");
2400 break;
2401 case WCNSS_DATA:
2402 wake_lock_init(&smd_info->nrt_lock.read_lock,
2403 WAKE_LOCK_SUSPEND, "diag_nrt_wcnss_read");
2404 break;
2405 default:
2406 break;
2407 }
2408 }
2409
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002410 return 1;
2411err:
2412 kfree(smd_info->buf_in_1);
2413 kfree(smd_info->buf_in_2);
2414 kfree(smd_info->write_ptr_1);
2415 kfree(smd_info->write_ptr_2);
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002416 kfree(smd_info->buf_in_1_raw);
2417 kfree(smd_info->buf_in_2_raw);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002418
2419 return 0;
2420}
2421
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002422void diagfwd_init(void)
2423{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002424 int success;
2425 int i;
2426
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -08002427 wrap_enabled = 0;
2428 wrap_count = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002429 diag_debug_buf_idx = 0;
2430 driver->read_len_legacy = 0;
Dixon Petersonb4618a42012-02-29 18:56:31 -08002431 driver->use_device_tree = has_device_tree();
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002432 driver->real_time_mode = 1;
Dixon Petersona6d98092013-05-16 12:26:26 -07002433 /*
2434 * The number of entries in table of buffers
2435 * should not be any smaller than hdlc poolsize.
2436 */
2437 driver->buf_tbl_size = (buf_tbl_size < driver->poolsize_hdlc) ?
2438 driver->poolsize_hdlc : buf_tbl_size;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002439 driver->supports_separate_cmdrsp = device_supports_separate_cmdrsp();
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002440 driver->supports_apps_hdlc_encoding = 0;
Dixon Peterson25f042b2013-02-27 13:00:08 -08002441 mutex_init(&driver->diag_hdlc_mutex);
Shalabh Jaina06c6d72012-04-30 13:40:35 -07002442 mutex_init(&driver->diag_cntl_mutex);
Shalabh Jain321c8b52012-02-22 12:37:06 -08002443
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002444 for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002445 driver->separate_cmdrsp[i] = 0;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002446 driver->peripheral_supports_stm[i] = DISABLE_STM;
2447 }
2448
2449 for (i = 0; i < NUM_STM_PROCESSORS; i++) {
2450 driver->stm_state_requested[i] = DISABLE_STM;
2451 driver->stm_state[i] = DISABLE_STM;
2452 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002453
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002454 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
2455 success = diag_smd_constructor(&driver->smd_data[i], i,
2456 SMD_DATA_TYPE);
2457 if (!success)
2458 goto err;
2459 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002460
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002461 if (driver->supports_separate_cmdrsp) {
2462 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
2463 success = diag_smd_constructor(&driver->smd_cmd[i], i,
2464 SMD_CMD_TYPE);
2465 if (!success)
2466 goto err;
2467 }
2468 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002469
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002470 if (driver->usb_buf_out == NULL &&
2471 (driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
2472 GFP_KERNEL)) == NULL)
2473 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002474 kmemleak_not_leak(driver->usb_buf_out);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002475 if (driver->hdlc_buf == NULL
2476 && (driver->hdlc_buf = kzalloc(HDLC_MAX, GFP_KERNEL)) == NULL)
2477 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002478 kmemleak_not_leak(driver->hdlc_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002479 if (driver->client_map == NULL &&
2480 (driver->client_map = kzalloc
2481 ((driver->num_clients) * sizeof(struct diag_client_map),
2482 GFP_KERNEL)) == NULL)
2483 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002484 kmemleak_not_leak(driver->client_map);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002485 if (driver->buf_tbl == NULL)
Dixon Petersona6d98092013-05-16 12:26:26 -07002486 driver->buf_tbl = kzalloc(driver->buf_tbl_size *
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002487 sizeof(struct diag_write_device), GFP_KERNEL);
2488 if (driver->buf_tbl == NULL)
2489 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002490 kmemleak_not_leak(driver->buf_tbl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002491 if (driver->data_ready == NULL &&
2492 (driver->data_ready = kzalloc(driver->num_clients * sizeof(int)
2493 , GFP_KERNEL)) == NULL)
2494 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002495 kmemleak_not_leak(driver->data_ready);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002496 if (driver->table == NULL &&
Shalabh Jainfe02b0c2012-02-21 14:48:03 -08002497 (driver->table = kzalloc(diag_max_reg*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002498 sizeof(struct diag_master_table),
2499 GFP_KERNEL)) == NULL)
2500 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002501 kmemleak_not_leak(driver->table);
Ashay Jaiswal29620122012-03-21 12:02:36 +05302502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002503 if (driver->usb_read_ptr == NULL) {
2504 driver->usb_read_ptr = kzalloc(
2505 sizeof(struct diag_request), GFP_KERNEL);
2506 if (driver->usb_read_ptr == NULL)
2507 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002508 kmemleak_not_leak(driver->usb_read_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002509 }
2510 if (driver->pkt_buf == NULL &&
2511 (driver->pkt_buf = kzalloc(PKT_SIZE,
2512 GFP_KERNEL)) == NULL)
2513 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002514 kmemleak_not_leak(driver->pkt_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002515 if (driver->apps_rsp_buf == NULL) {
Shalabh Jain321c8b52012-02-22 12:37:06 -08002516 driver->apps_rsp_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002517 if (driver->apps_rsp_buf == NULL)
2518 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002519 kmemleak_not_leak(driver->apps_rsp_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002520 }
2521 driver->diag_wq = create_singlethread_workqueue("diag_wq");
2522#ifdef CONFIG_DIAG_OVER_USB
Mohit Aggarwalb4465772013-04-18 13:08:07 +05302523 INIT_WORK(&(driver->diag_usb_connect_work),
2524 diag_usb_connect_work_fn);
2525 INIT_WORK(&(driver->diag_usb_disconnect_work),
2526 diag_usb_disconnect_work_fn);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002527 INIT_WORK(&(driver->diag_proc_hdlc_work), diag_process_hdlc_fn);
2528 INIT_WORK(&(driver->diag_read_work), diag_read_work_fn);
2529 driver->legacy_ch = usb_diag_open(DIAG_LEGACY, driver,
2530 diag_usb_legacy_notifier);
2531 if (IS_ERR(driver->legacy_ch)) {
2532 printk(KERN_ERR "Unable to open USB diag legacy channel\n");
2533 goto err;
2534 }
2535#endif
2536 platform_driver_register(&msm_smd_ch1_driver);
2537 platform_driver_register(&diag_smd_lite_driver);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002538
2539 if (driver->supports_separate_cmdrsp) {
2540 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++)
2541 platform_driver_register(&smd_lite_data_cmd_drivers[i]);
2542 }
2543
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002544 return;
2545err:
Dixon Petersond6a20a92012-09-27 15:58:50 -07002546 pr_err("diag: Could not initialize diag buffers");
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002547
2548 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
2549 diag_smd_destructor(&driver->smd_data[i]);
2550
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002551 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++)
2552 diag_smd_destructor(&driver->smd_cmd[i]);
2553
Dixon Petersond6a20a92012-09-27 15:58:50 -07002554 kfree(driver->buf_msg_mask_update);
2555 kfree(driver->buf_log_mask_update);
2556 kfree(driver->buf_event_mask_update);
2557 kfree(driver->usb_buf_out);
2558 kfree(driver->hdlc_buf);
2559 kfree(driver->client_map);
2560 kfree(driver->buf_tbl);
2561 kfree(driver->data_ready);
2562 kfree(driver->table);
2563 kfree(driver->pkt_buf);
Dixon Petersond6a20a92012-09-27 15:58:50 -07002564 kfree(driver->usb_read_ptr);
2565 kfree(driver->apps_rsp_buf);
Dixon Petersond6a20a92012-09-27 15:58:50 -07002566 if (driver->diag_wq)
2567 destroy_workqueue(driver->diag_wq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002568}
2569
2570void diagfwd_exit(void)
2571{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002572 int i;
2573
2574 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
2575 diag_smd_destructor(&driver->smd_data[i]);
2576
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002577#ifdef CONFIG_DIAG_OVER_USB
2578 if (driver->usb_connected)
2579 usb_diag_free_req(driver->legacy_ch);
2580 usb_diag_close(driver->legacy_ch);
2581#endif
2582 platform_driver_unregister(&msm_smd_ch1_driver);
2583 platform_driver_unregister(&diag_smd_lite_driver);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002584
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002585 if (driver->supports_separate_cmdrsp) {
2586 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
2587 diag_smd_destructor(&driver->smd_cmd[i]);
2588 platform_driver_unregister(
2589 &smd_lite_data_cmd_drivers[i]);
2590 }
2591 }
2592
Shalabh Jain321c8b52012-02-22 12:37:06 -08002593 kfree(driver->buf_msg_mask_update);
2594 kfree(driver->buf_log_mask_update);
2595 kfree(driver->buf_event_mask_update);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002596 kfree(driver->usb_buf_out);
2597 kfree(driver->hdlc_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002598 kfree(driver->client_map);
2599 kfree(driver->buf_tbl);
2600 kfree(driver->data_ready);
2601 kfree(driver->table);
2602 kfree(driver->pkt_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002603 kfree(driver->usb_read_ptr);
2604 kfree(driver->apps_rsp_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002605 destroy_workqueue(driver->diag_wq);
2606}