blob: 395bea028eb43e72dea9b0bc839e8c5c41b8fdf7 [file] [log] [blame]
Shalabh Jainb0037c02013-01-18 12:47:40 -08001/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070012#include <linux/slab.h>
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/err.h>
17#include <linux/platform_device.h>
18#include <linux/sched.h>
Dixon Peterson6beff2d2012-09-13 18:51:47 -070019#include <linux/ratelimit.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070020#include <linux/workqueue.h>
21#include <linux/pm_runtime.h>
22#include <linux/diagchar.h>
23#include <linux/delay.h>
24#include <linux/reboot.h>
Dixon Petersonb4618a42012-02-29 18:56:31 -080025#include <linux/of.h>
Dixon Petersoncc0bea772012-04-11 20:45:37 -070026#include <linux/kmemleak.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027#ifdef CONFIG_DIAG_OVER_USB
28#include <mach/usbdiag.h>
29#endif
30#include <mach/msm_smd.h>
31#include <mach/socinfo.h>
32#include <mach/restart.h>
33#include "diagmem.h"
34#include "diagchar.h"
35#include "diagfwd.h"
36#include "diagfwd_cntl.h"
Shalabh Jainb0037c02013-01-18 12:47:40 -080037#include "diagfwd_hsic.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038#include "diagchar_hdlc.h"
39#ifdef CONFIG_DIAG_SDIO_PIPE
40#include "diagfwd_sdio.h"
41#endif
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070042#include "diag_dci.h"
Dixon Petersond6a20a92012-09-27 15:58:50 -070043#include "diag_masks.h"
Shalabh Jain737fca72012-11-14 21:53:43 -080044#include "diagfwd_bridge.h"
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070045
Shalabh Jain6a2ca7c2012-04-10 14:35:15 -070046#define MODE_CMD 41
47#define RESET_ID 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070048
Dixon Peterson15a6ecb2013-06-25 12:36:33 -070049#define STM_CMD_VERSION_OFFSET 4
50#define STM_CMD_MASK_OFFSET 5
51#define STM_CMD_DATA_OFFSET 6
52#define STM_CMD_NUM_BYTES 7
53
54#define STM_RSP_VALID_INDEX 7
55#define STM_RSP_SUPPORTED_INDEX 8
56#define STM_RSP_SMD_COMPLY_INDEX 9
57#define STM_RSP_NUM_BYTES 10
58
Dixon Petersond2309b42013-08-28 21:00:05 -070059#define SMD_DRAIN_BUF_SIZE 4096
60
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061int diag_debug_buf_idx;
62unsigned char diag_debug_buf[1024];
Dixon Petersona6d98092013-05-16 12:26:26 -070063/* Number of entries in table of buffers */
64static unsigned int buf_tbl_size = 10;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065struct diag_master_table entry;
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -080066int wrap_enabled;
67uint16_t wrap_count;
Shalabh Jain6a2ca7c2012-04-10 14:35:15 -070068
Dixon Petersond6a20a92012-09-27 15:58:50 -070069void encode_rsp_and_send(int buf_length)
70{
Dixon Peterson9ce39c62013-02-21 13:00:52 -080071 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
72 struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
Dixon Petersoneecbadb2012-12-10 21:59:28 -080073 struct diag_smd_info *data = &(driver->smd_data[MODEM_DATA]);
Ravi Aravamudhancc9946862013-07-15 13:31:11 -070074
75 if (buf_length > APPS_BUF_SIZE) {
76 pr_err("diag: In %s, invalid len %d, permissible len %d\n",
77 __func__, buf_length, APPS_BUF_SIZE);
78 return;
79 }
80
Dixon Petersond6a20a92012-09-27 15:58:50 -070081 send.state = DIAG_STATE_START;
82 send.pkt = driver->apps_rsp_buf;
83 send.last = (void *)(driver->apps_rsp_buf + buf_length);
84 send.terminate = 1;
Dixon Peterson66fb11b2012-12-04 20:30:54 -080085 if (!data->in_busy_1) {
86 enc.dest = data->buf_in_1;
87 enc.dest_last = (void *)(data->buf_in_1 + APPS_BUF_SIZE - 1);
Dixon Petersond6a20a92012-09-27 15:58:50 -070088 diag_hdlc_encode(&send, &enc);
Dixon Peterson66fb11b2012-12-04 20:30:54 -080089 data->write_ptr_1->buf = data->buf_in_1;
90 data->write_ptr_1->length = (int)(enc.dest -
91 (void *)(data->buf_in_1));
92 data->in_busy_1 = 1;
Dixon Petersoneecbadb2012-12-10 21:59:28 -080093 diag_device_write(data->buf_in_1, data->peripheral,
Dixon Peterson66fb11b2012-12-04 20:30:54 -080094 data->write_ptr_1);
Dixon Petersond6a20a92012-09-27 15:58:50 -070095 memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);
96 }
97}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098
Dixon Petersonb4618a42012-02-29 18:56:31 -080099/* Determine if this device uses a device tree */
100#ifdef CONFIG_OF
101static int has_device_tree(void)
102{
103 struct device_node *node;
104
105 node = of_find_node_by_path("/");
106 if (node) {
107 of_node_put(node);
108 return 1;
109 }
110 return 0;
111}
112#else
113static int has_device_tree(void)
114{
115 return 0;
116}
117#endif
118
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700119int chk_config_get_id(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700120{
Shashank Mittal24771632013-02-06 19:34:57 -0800121 /* For all Fusion targets, Modem will always be present */
Shalabh Jain482bf122011-12-06 03:54:47 -0800122 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
123 return 0;
124
Dixon Petersonb4618a42012-02-29 18:56:31 -0800125 if (driver->use_device_tree) {
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700126 if (machine_is_msm8974())
Dixon Petersonb4618a42012-02-29 18:56:31 -0800127 return MSM8974_TOOLS_ID;
128 else
129 return 0;
130 } else {
131 switch (socinfo_get_msm_cpu()) {
132 case MSM_CPU_8X60:
133 return APQ8060_TOOLS_ID;
134 case MSM_CPU_8960:
Stepan Moskovchenko9c749262012-07-09 19:30:44 -0700135 case MSM_CPU_8960AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800136 return AO8960_TOOLS_ID;
137 case MSM_CPU_8064:
Jay Chokshi11abd8b2012-09-20 14:35:17 -0700138 case MSM_CPU_8064AB:
Shashank Mittal24771632013-02-06 19:34:57 -0800139 case MSM_CPU_8064AA:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800140 return APQ8064_TOOLS_ID;
141 case MSM_CPU_8930:
Stepan Moskovchenko0df9bb22012-07-06 18:19:15 -0700142 case MSM_CPU_8930AA:
Stepan Moskovchenkoecb0d9b2012-10-16 18:35:34 -0700143 case MSM_CPU_8930AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800144 return MSM8930_TOOLS_ID;
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700145 case MSM_CPU_8974:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800146 return MSM8974_TOOLS_ID;
147 case MSM_CPU_8625:
148 return MSM8625_TOOLS_ID;
149 default:
150 return 0;
151 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700152 }
153}
154
155/*
Shalabh Jain321c8b52012-02-22 12:37:06 -0800156 * This will return TRUE for targets which support apps only mode and hence SSR.
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700157 * This applies to 8960 and newer targets.
158 */
159int chk_apps_only(void)
160{
Dixon Petersonb4618a42012-02-29 18:56:31 -0800161 if (driver->use_device_tree)
162 return 1;
163
164 switch (socinfo_get_msm_cpu()) {
165 case MSM_CPU_8960:
Stepan Moskovchenko9c749262012-07-09 19:30:44 -0700166 case MSM_CPU_8960AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800167 case MSM_CPU_8064:
Jay Chokshi11abd8b2012-09-20 14:35:17 -0700168 case MSM_CPU_8064AB:
Shashank Mittal24771632013-02-06 19:34:57 -0800169 case MSM_CPU_8064AA:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800170 case MSM_CPU_8930:
Stepan Moskovchenko0df9bb22012-07-06 18:19:15 -0700171 case MSM_CPU_8930AA:
Stepan Moskovchenkoecb0d9b2012-10-16 18:35:34 -0700172 case MSM_CPU_8930AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800173 case MSM_CPU_8627:
174 case MSM_CPU_9615:
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700175 case MSM_CPU_8974:
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700176 return 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700177 default:
178 return 0;
179 }
180}
181
Shalabh Jain10f5f432012-01-11 11:45:44 +0530182/*
183 * This will return TRUE for targets which support apps as master.
184 * Thus, SW DLOAD and Mode Reset are supported on apps processor.
185 * This applies to 8960 and newer targets.
186 */
187int chk_apps_master(void)
188{
Dixon Petersonb4618a42012-02-29 18:56:31 -0800189 if (driver->use_device_tree)
190 return 1;
Stepan Moskovchenko5b9e7762012-09-21 20:32:17 -0700191 else if (soc_class_is_msm8960() || soc_class_is_msm8930() ||
192 soc_class_is_apq8064() || cpu_is_msm9615())
Dixon Petersonb4618a42012-02-29 18:56:31 -0800193 return 1;
194 else
195 return 0;
196}
197
Dixon Peterson29aebee2012-04-06 12:44:08 -0700198int chk_polling_response(void)
Dixon Petersonb4618a42012-02-29 18:56:31 -0800199{
200 if (!(driver->polling_reg_flag) && chk_apps_master())
201 /*
202 * If the apps processor is master and no other processor
203 * has registered to respond for polling
204 */
205 return 1;
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -0700206 else if (!((driver->smd_data[MODEM_DATA].ch) &&
207 (driver->rcvd_feature_mask[MODEM_DATA])) &&
208 (chk_apps_master()))
Dixon Petersonb4618a42012-02-29 18:56:31 -0800209 /*
210 * If the apps processor is not the master and the modem
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -0700211 * is not up or we did not receive the feature masks from Modem
Dixon Petersonb4618a42012-02-29 18:56:31 -0800212 */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530213 return 1;
214 else
215 return 0;
216}
217
Dixon Peterson743a11e2012-07-30 17:42:20 -0700218/*
219 * This function should be called if you feel that the logging process may
220 * need to be woken up. For instance, if the logging mode is MEMORY_DEVICE MODE
221 * and while trying to read data from a SMD data channel there are no buffers
222 * available to read the data into, then this function should be called to
223 * determine if the logging process needs to be woken up.
224 */
225void chk_logging_wakeup(void)
226{
227 int i;
228
229 /* Find the index of the logging process */
230 for (i = 0; i < driver->num_clients; i++)
231 if (driver->client_map[i].pid ==
232 driver->logging_process_id)
233 break;
234
235 if (i < driver->num_clients) {
236 /* At very high logging rates a race condition can
237 * occur where the buffers containing the data from
238 * an smd channel are all in use, but the data_ready
239 * flag is cleared. In this case, the buffers never
240 * have their data read/logged. Detect and remedy this
241 * situation.
242 */
Shalabh Jain84e30342012-10-16 16:16:08 -0700243 if ((driver->data_ready[i] & USER_SPACE_DATA_TYPE) == 0) {
244 driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
Dixon Peterson743a11e2012-07-30 17:42:20 -0700245 pr_debug("diag: Force wakeup of logging process\n");
246 wake_up_interruptible(&driver->wait_q);
247 }
248 }
249}
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800250int diag_add_hdlc_encoding(struct diag_smd_info *smd_info, void *buf,
251 int total_recd, uint8_t *encode_buf,
252 int *encoded_length)
253{
254 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
255 struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
256 struct data_header {
257 uint8_t control_char;
258 uint8_t version;
259 uint16_t length;
260 };
261 struct data_header *header;
262 int header_size = sizeof(struct data_header);
263 uint8_t *end_control_char;
264 uint8_t *payload;
265 uint8_t *temp_buf;
266 uint8_t *temp_encode_buf;
267 int src_pkt_len;
268 int encoded_pkt_length;
269 int max_size;
270 int total_processed = 0;
271 int bytes_remaining;
272 int success = 1;
273
274 temp_buf = buf;
275 temp_encode_buf = encode_buf;
276 bytes_remaining = *encoded_length;
277 while (total_processed < total_recd) {
278 header = (struct data_header *)temp_buf;
279 /* Perform initial error checking */
280 if (header->control_char != CONTROL_CHAR ||
281 header->version != 1) {
282 success = 0;
283 break;
284 }
285 payload = temp_buf + header_size;
286 end_control_char = payload + header->length;
287 if (*end_control_char != CONTROL_CHAR) {
288 success = 0;
289 break;
290 }
291
292 max_size = 2 * header->length + 3;
293 if (bytes_remaining < max_size) {
294 pr_err("diag: In %s, Not enough room to encode remaining data for peripheral: %d, bytes available: %d, max_size: %d\n",
295 __func__, smd_info->peripheral,
296 bytes_remaining, max_size);
297 success = 0;
298 break;
299 }
300
301 /* Prepare for encoding the data */
302 send.state = DIAG_STATE_START;
303 send.pkt = payload;
304 send.last = (void *)(payload + header->length - 1);
305 send.terminate = 1;
306
307 enc.dest = temp_encode_buf;
308 enc.dest_last = (void *)(temp_encode_buf + max_size);
309 enc.crc = 0;
310 diag_hdlc_encode(&send, &enc);
311
312 /* Prepare for next packet */
313 src_pkt_len = (header_size + header->length + 1);
314 total_processed += src_pkt_len;
315 temp_buf += src_pkt_len;
316
317 encoded_pkt_length = (uint8_t *)enc.dest - temp_encode_buf;
318 bytes_remaining -= encoded_pkt_length;
319 temp_encode_buf = enc.dest;
320 }
321
322 *encoded_length = (int)(temp_encode_buf - encode_buf);
323
324 return success;
325}
326
327static int check_bufsize_for_encoding(struct diag_smd_info *smd_info, void *buf,
328 int total_recd)
329{
330 int buf_size = IN_BUF_SIZE;
331 int max_size = 2 * total_recd + 3;
332 unsigned char *temp_buf;
333
334 if (max_size > IN_BUF_SIZE) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700335 if (max_size > MAX_IN_BUF_SIZE) {
336 pr_err_ratelimited("diag: In %s, SMD sending packet of %d bytes that may expand to %d bytes, peripheral: %d\n",
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800337 __func__, total_recd, max_size,
338 smd_info->peripheral);
Dixon Petersond2309b42013-08-28 21:00:05 -0700339 max_size = MAX_IN_BUF_SIZE;
340 }
341 if (buf == smd_info->buf_in_1_raw) {
342 /* Only realloc if we need to increase the size */
343 if (smd_info->buf_in_1_size < max_size) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800344 temp_buf = krealloc(smd_info->buf_in_1,
Dixon Petersond2309b42013-08-28 21:00:05 -0700345 max_size, GFP_KERNEL);
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800346 if (temp_buf) {
347 smd_info->buf_in_1 = temp_buf;
Dixon Petersond2309b42013-08-28 21:00:05 -0700348 smd_info->buf_in_1_size = max_size;
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800349 }
350 }
Dixon Petersond2309b42013-08-28 21:00:05 -0700351 buf_size = smd_info->buf_in_1_size;
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800352 } else {
Dixon Petersond2309b42013-08-28 21:00:05 -0700353 /* Only realloc if we need to increase the size */
354 if (smd_info->buf_in_2_size < max_size) {
355 temp_buf = krealloc(smd_info->buf_in_2,
356 max_size, GFP_KERNEL);
357 if (temp_buf) {
358 smd_info->buf_in_2 = temp_buf;
359 smd_info->buf_in_2_size = max_size;
360 }
361 }
362 buf_size = smd_info->buf_in_2_size;
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800363 }
364 }
365
366 return buf_size;
367}
Dixon Peterson743a11e2012-07-30 17:42:20 -0700368
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800369void process_lock_enabling(struct diag_nrt_wake_lock *lock, int real_time)
370{
371 unsigned long read_lock_flags;
372
373 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
374 if (real_time)
375 lock->enabled = 0;
376 else
377 lock->enabled = 1;
378 lock->ref_count = 0;
379 lock->copy_count = 0;
380 wake_unlock(&lock->read_lock);
381 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
382}
383
384void process_lock_on_notify(struct diag_nrt_wake_lock *lock)
385{
386 unsigned long read_lock_flags;
387
388 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
389 /*
390 * Do not work with ref_count here in case
391 * of spurious interrupt
392 */
Mohit Aggarwal912b3812013-08-28 17:52:36 +0530393 if (lock->enabled && !wake_lock_active(&lock->read_lock))
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800394 wake_lock(&lock->read_lock);
395 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
396}
397
398void process_lock_on_read(struct diag_nrt_wake_lock *lock, int pkt_len)
399{
400 unsigned long read_lock_flags;
401
402 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
403 if (lock->enabled) {
404 if (pkt_len > 0) {
405 /*
406 * We have an data that is read that
407 * needs to be processed, make sure the
408 * processor does not go to sleep
409 */
410 lock->ref_count++;
411 if (!wake_lock_active(&lock->read_lock))
412 wake_lock(&lock->read_lock);
413 } else {
414 /*
415 * There was no data associated with the
416 * read from the smd, unlock the wake lock
417 * if it is not needed.
418 */
419 if (lock->ref_count < 1) {
420 if (wake_lock_active(&lock->read_lock))
421 wake_unlock(&lock->read_lock);
422 lock->ref_count = 0;
423 lock->copy_count = 0;
424 }
425 }
426 }
427 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
428}
429
430void process_lock_on_copy(struct diag_nrt_wake_lock *lock)
431{
432 unsigned long read_lock_flags;
433
434 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
435 if (lock->enabled)
436 lock->copy_count++;
437 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
438}
439
440void process_lock_on_copy_complete(struct diag_nrt_wake_lock *lock)
441{
442 unsigned long read_lock_flags;
443
444 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
445 if (lock->enabled) {
446 lock->ref_count -= lock->copy_count;
447 if (lock->ref_count < 1) {
448 wake_unlock(&lock->read_lock);
449 lock->ref_count = 0;
450 }
451 lock->copy_count = 0;
452 }
453 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
454}
455
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800456/* Process the data read from the smd data channel */
457int diag_process_smd_read_data(struct diag_smd_info *smd_info, void *buf,
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800458 int total_recd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700459{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460 struct diag_request *write_ptr_modem = NULL;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800461 int *in_busy_ptr = 0;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800462 int err = 0;
463
464 /*
465 * Do not process data on command channel if the
466 * channel is not designated to do so
467 */
468 if ((smd_info->type == SMD_CMD_TYPE) &&
469 !driver->separate_cmdrsp[smd_info->peripheral]) {
470 /* This print is for debugging */
471 pr_err("diag, In %s, received data on non-designated command channel: %d\n",
472 __func__, smd_info->peripheral);
473 return 0;
474 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800476 /* If the data is already hdlc encoded */
477 if (!smd_info->encode_hdlc) {
478 if (smd_info->buf_in_1 == buf) {
479 write_ptr_modem = smd_info->write_ptr_1;
480 in_busy_ptr = &smd_info->in_busy_1;
481 } else if (smd_info->buf_in_2 == buf) {
482 write_ptr_modem = smd_info->write_ptr_2;
483 in_busy_ptr = &smd_info->in_busy_2;
484 } else {
485 pr_err("diag: In %s, no match for in_busy_1, peripheral: %d\n",
486 __func__, smd_info->peripheral);
487 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800489 if (write_ptr_modem) {
490 write_ptr_modem->length = total_recd;
491 *in_busy_ptr = 1;
492 err = diag_device_write(buf, smd_info->peripheral,
493 write_ptr_modem);
494 if (err) {
495 /* Free up the buffer for future use */
496 *in_busy_ptr = 0;
497 pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
498 __func__, err);
499 }
500 }
501 } else {
502 /* The data is raw and needs to be hdlc encoded */
503 if (smd_info->buf_in_1_raw == buf) {
504 write_ptr_modem = smd_info->write_ptr_1;
505 in_busy_ptr = &smd_info->in_busy_1;
506 } else if (smd_info->buf_in_2_raw == buf) {
507 write_ptr_modem = smd_info->write_ptr_2;
508 in_busy_ptr = &smd_info->in_busy_2;
509 } else {
510 pr_err("diag: In %s, no match for in_busy_1, peripheral: %d\n",
511 __func__, smd_info->peripheral);
512 }
513
514 if (write_ptr_modem) {
515 int success = 0;
516 int write_length = 0;
517 unsigned char *write_buf = NULL;
518
519 write_length = check_bufsize_for_encoding(smd_info, buf,
520 total_recd);
521 if (write_length) {
522 write_buf = (buf == smd_info->buf_in_1_raw) ?
523 smd_info->buf_in_1 : smd_info->buf_in_2;
524 success = diag_add_hdlc_encoding(smd_info, buf,
525 total_recd, write_buf,
526 &write_length);
527 if (success) {
528 write_ptr_modem->length = write_length;
529 *in_busy_ptr = 1;
530 err = diag_device_write(write_buf,
531 smd_info->peripheral,
532 write_ptr_modem);
533 if (err) {
534 /*
535 * Free up the buffer for
536 * future use
537 */
538 *in_busy_ptr = 0;
539 pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
540 __func__, err);
541 }
542 }
543 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800544 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800545 }
546
547 return 0;
548}
549
Dixon Petersond2309b42013-08-28 21:00:05 -0700550static int diag_smd_resize_buf(struct diag_smd_info *smd_info, void **buf,
551 unsigned int *buf_size,
552 unsigned int requested_size)
553{
554 int success = 0;
555 void *temp_buf = NULL;
556 unsigned int new_buf_size = requested_size;
557
558 if (!smd_info)
559 return success;
560
561 if (requested_size <= MAX_IN_BUF_SIZE) {
562 pr_debug("diag: In %s, SMD peripheral: %d sending in packets up to %d bytes\n",
563 __func__, smd_info->peripheral, requested_size);
564 } else {
565 pr_err_ratelimited("diag: In %s, SMD peripheral: %d, Packet size sent: %d, Max size supported (%d) exceeded. Data beyond max size will be lost\n",
566 __func__, smd_info->peripheral, requested_size,
567 MAX_IN_BUF_SIZE);
568 new_buf_size = MAX_IN_BUF_SIZE;
569 }
570
571 /* Only resize if the buffer can be increased in size */
572 if (new_buf_size <= *buf_size) {
573 success = 1;
574 return success;
575 }
576
577 temp_buf = krealloc(*buf, new_buf_size, GFP_KERNEL);
578
579 if (temp_buf) {
580 /* Match the buffer and reset the pointer and size */
581 if (smd_info->encode_hdlc) {
582 /*
583 * This smd channel is supporting HDLC encoding
584 * on the apps
585 */
586 void *temp_hdlc = NULL;
587 if (*buf == smd_info->buf_in_1_raw) {
588 smd_info->buf_in_1_raw = temp_buf;
589 smd_info->buf_in_1_raw_size = new_buf_size;
590 temp_hdlc = krealloc(smd_info->buf_in_1,
591 MAX_IN_BUF_SIZE,
592 GFP_KERNEL);
593 if (temp_hdlc) {
594 smd_info->buf_in_1 = temp_hdlc;
595 smd_info->buf_in_1_size =
596 MAX_IN_BUF_SIZE;
597 }
598 } else if (*buf == smd_info->buf_in_2_raw) {
599 smd_info->buf_in_2_raw = temp_buf;
600 smd_info->buf_in_2_raw_size = new_buf_size;
601 temp_hdlc = krealloc(smd_info->buf_in_2,
602 MAX_IN_BUF_SIZE,
603 GFP_KERNEL);
604 if (temp_hdlc) {
605 smd_info->buf_in_2 = temp_hdlc;
606 smd_info->buf_in_2_size =
607 MAX_IN_BUF_SIZE;
608 }
609 }
610 } else {
611 if (*buf == smd_info->buf_in_1) {
612 smd_info->buf_in_1 = temp_buf;
613 smd_info->buf_in_1_size = new_buf_size;
614 } else if (*buf == smd_info->buf_in_2) {
615 smd_info->buf_in_2 = temp_buf;
616 smd_info->buf_in_2_size = new_buf_size;
617 }
618 }
619 *buf = temp_buf;
620 *buf_size = new_buf_size;
621 success = 1;
622 } else {
623 pr_err_ratelimited("diag: In %s, SMD peripheral: %d. packet size sent: %d, resize to support failed. Data beyond %d will be lost\n",
624 __func__, smd_info->peripheral, requested_size,
625 *buf_size);
626 }
627
628 return success;
629}
630
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800631void diag_smd_send_req(struct diag_smd_info *smd_info)
632{
633 void *buf = NULL, *temp_buf = NULL;
634 int total_recd = 0, r = 0, pkt_len;
635 int loop_count = 0;
636 int notify = 0;
Dixon Petersond2309b42013-08-28 21:00:05 -0700637 int buf_size = 0;
638 int resize_success = 0;
639 int buf_full = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800640
641 if (!smd_info) {
642 pr_err("diag: In %s, no smd info. Not able to read.\n",
643 __func__);
644 return;
645 }
646
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800647 /* Determine the buffer to read the data into. */
648 if (smd_info->type == SMD_DATA_TYPE) {
649 /* If the data is raw and not hdlc encoded */
650 if (smd_info->encode_hdlc) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700651 if (!smd_info->in_busy_1) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800652 buf = smd_info->buf_in_1_raw;
Dixon Petersond2309b42013-08-28 21:00:05 -0700653 buf_size = smd_info->buf_in_1_raw_size;
654 } else if (!smd_info->in_busy_2) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800655 buf = smd_info->buf_in_2_raw;
Dixon Petersond2309b42013-08-28 21:00:05 -0700656 buf_size = smd_info->buf_in_2_raw_size;
657 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800658 } else {
Dixon Petersond2309b42013-08-28 21:00:05 -0700659 if (!smd_info->in_busy_1) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800660 buf = smd_info->buf_in_1;
Dixon Petersond2309b42013-08-28 21:00:05 -0700661 buf_size = smd_info->buf_in_1_size;
662 } else if (!smd_info->in_busy_2) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800663 buf = smd_info->buf_in_2;
Dixon Petersond2309b42013-08-28 21:00:05 -0700664 buf_size = smd_info->buf_in_2_size;
665 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800666 }
667 } else if (smd_info->type == SMD_CMD_TYPE) {
668 /* If the data is raw and not hdlc encoded */
669 if (smd_info->encode_hdlc) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700670 if (!smd_info->in_busy_1) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800671 buf = smd_info->buf_in_1_raw;
Dixon Petersond2309b42013-08-28 21:00:05 -0700672 buf_size = smd_info->buf_in_1_raw_size;
673 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800674 } else {
Dixon Petersond2309b42013-08-28 21:00:05 -0700675 if (!smd_info->in_busy_1) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800676 buf = smd_info->buf_in_1;
Dixon Petersond2309b42013-08-28 21:00:05 -0700677 buf_size = smd_info->buf_in_1_size;
678 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800679 }
680 } else if (!smd_info->in_busy_1) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800681 buf = smd_info->buf_in_1;
Dixon Petersond2309b42013-08-28 21:00:05 -0700682 buf_size = smd_info->buf_in_1_size;
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800683 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800684
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700685 if (!buf && (smd_info->type == SMD_DCI_TYPE ||
686 smd_info->type == SMD_DCI_CMD_TYPE))
687 diag_dci_try_deactivate_wakeup_source(smd_info->ch);
688
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800689 if (smd_info->ch && buf) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800690 pkt_len = smd_cur_packet_size(smd_info->ch);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700691
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700692 if (pkt_len == 0 && (smd_info->type == SMD_DCI_TYPE ||
693 smd_info->type == SMD_DCI_CMD_TYPE))
694 diag_dci_try_deactivate_wakeup_source(smd_info->ch);
695
Dixon Petersond2309b42013-08-28 21:00:05 -0700696 if (pkt_len > buf_size)
697 resize_success = diag_smd_resize_buf(smd_info, &buf,
698 &buf_size, pkt_len);
699 temp_buf = buf;
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700700 while (pkt_len && (pkt_len != total_recd)) {
701 loop_count++;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800702 r = smd_read_avail(smd_info->ch);
Dixon Petersond2309b42013-08-28 21:00:05 -0700703 pr_debug("diag: In %s, SMD peripheral: %d, received pkt %d %d\n",
704 __func__, smd_info->peripheral, r, total_recd);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700705 if (!r) {
706 /* Nothing to read from SMD */
707 wait_event(driver->smd_wait_q,
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800708 ((smd_info->ch == 0) ||
709 smd_read_avail(smd_info->ch)));
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700710 /* If the smd channel is open */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800711 if (smd_info->ch) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700712 pr_debug("diag: In %s, SMD peripheral: %d, return from wait_event\n",
713 __func__, smd_info->peripheral);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700714 continue;
715 } else {
Dixon Petersond2309b42013-08-28 21:00:05 -0700716 pr_debug("diag: In %s, SMD peripheral: %d, return from wait_event ch closed\n",
717 __func__, smd_info->peripheral);
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700718 goto fail_return;
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700719 }
720 }
Dixon Petersond2309b42013-08-28 21:00:05 -0700721
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700722 if (pkt_len < r) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700723 pr_err("diag: In %s, SMD peripheral: %d, sending incorrect pkt\n",
724 __func__, smd_info->peripheral);
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700725 goto fail_return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700726 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800727 if (pkt_len > r) {
Dixon Peterson6dba7572013-04-12 18:45:16 -0700728 pr_debug("diag: In %s, SMD sending partial pkt %d %d %d %d %d %d\n",
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800729 __func__, pkt_len, r, total_recd, loop_count,
730 smd_info->peripheral, smd_info->type);
731 }
732
Dixon Petersond2309b42013-08-28 21:00:05 -0700733 /* Protect from going beyond the end of the buffer */
734 if (total_recd < buf_size) {
735 if (total_recd + r > buf_size) {
736 r = buf_size - total_recd;
737 buf_full = 1;
738 }
739
740 total_recd += r;
741
742 /* Keep reading for complete packet */
743 smd_read(smd_info->ch, temp_buf, r);
744 temp_buf += r;
745 } else {
746 /*
747 * This block handles the very rare case of a
748 * packet that is greater in length than what
749 * we can support. In this case, we
750 * incrementally drain the remaining portion
751 * of the packet that will not fit in the
752 * buffer, so that the entire packet is read
753 * from the smd.
754 */
755 int drain_bytes = (r > SMD_DRAIN_BUF_SIZE) ?
756 SMD_DRAIN_BUF_SIZE : r;
757 unsigned char *drain_buf = kzalloc(drain_bytes,
758 GFP_KERNEL);
759 if (drain_buf) {
760 total_recd += drain_bytes;
761 smd_read(smd_info->ch, drain_buf,
762 drain_bytes);
763 kfree(drain_buf);
764 } else {
765 pr_err("diag: In %s, SMD peripheral: %d, unable to allocate drain buffer\n",
766 __func__, smd_info->peripheral);
767 break;
768 }
769 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700770 }
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800771 if (!driver->real_time_mode && smd_info->type == SMD_DATA_TYPE)
772 process_lock_on_read(&smd_info->nrt_lock, pkt_len);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700773
774 if (total_recd > 0) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800775 if (!buf) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700776 pr_err("diag: In %s, SMD peripheral: %d, Out of diagmem for Modem\n",
777 __func__, smd_info->peripheral);
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800778 } else if (smd_info->process_smd_read_data) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700779 /*
780 * If the buffer was totally filled, reset
781 * total_recd appropriately
782 */
783 if (buf_full)
784 total_recd = buf_size;
785
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800786 notify = smd_info->process_smd_read_data(
787 smd_info, buf, total_recd);
788 /* Poll SMD channels to check for data */
789 if (notify)
790 diag_smd_notify(smd_info,
791 SMD_EVENT_DATA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792 }
793 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800794 } else if (smd_info->ch && !buf &&
Dixon Peterson743a11e2012-07-30 17:42:20 -0700795 (driver->logging_mode == MEMORY_DEVICE_MODE)) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800796 chk_logging_wakeup();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700797 }
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700798 return;
799
800fail_return:
801 if (smd_info->type == SMD_DCI_TYPE ||
802 smd_info->type == SMD_DCI_CMD_TYPE)
803 diag_dci_try_deactivate_wakeup_source(smd_info->ch);
804 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805}
806
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800807void diag_read_smd_work_fn(struct work_struct *work)
808{
809 struct diag_smd_info *smd_info = container_of(work,
810 struct diag_smd_info,
811 diag_read_smd_work);
812 diag_smd_send_req(smd_info);
813}
814
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800815int diag_device_write(void *buf, int data_type, struct diag_request *write_ptr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700816{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800817 int i, err = 0, index;
818 index = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700819
820 if (driver->logging_mode == MEMORY_DEVICE_MODE) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800821 if (data_type == APPS_DATA) {
Dixon Petersona6d98092013-05-16 12:26:26 -0700822 for (i = 0; i < driver->buf_tbl_size; i++)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700823 if (driver->buf_tbl[i].length == 0) {
824 driver->buf_tbl[i].buf = buf;
825 driver->buf_tbl[i].length =
826 driver->used;
827#ifdef DIAG_DEBUG
828 pr_debug("diag: ENQUEUE buf ptr"
829 " and length is %x , %d\n",
830 (unsigned int)(driver->buf_
831 tbl[i].buf), driver->buf_tbl[i].length);
832#endif
833 break;
834 }
835 }
Dixon Peterson938f8602012-08-17 20:02:57 -0700836
Shalabh Jain737fca72012-11-14 21:53:43 -0800837#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Shalabh Jainb0037c02013-01-18 12:47:40 -0800838 else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700839 unsigned long flags;
840 int foundIndex = -1;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800841 index = data_type - HSIC_DATA;
842 spin_lock_irqsave(&diag_hsic[index].hsic_spinlock,
843 flags);
844 for (i = 0; i < diag_hsic[index].poolsize_hsic_write;
845 i++) {
846 if (diag_hsic[index].hsic_buf_tbl[i].length
847 == 0) {
848 diag_hsic[index].hsic_buf_tbl[i].buf
849 = buf;
850 diag_hsic[index].hsic_buf_tbl[i].length
851 = diag_bridge[index].write_len;
852 diag_hsic[index].
853 num_hsic_buf_tbl_entries++;
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700854 foundIndex = i;
Dixon Peterson938f8602012-08-17 20:02:57 -0700855 break;
856 }
857 }
Shalabh Jainb0037c02013-01-18 12:47:40 -0800858 spin_unlock_irqrestore(&diag_hsic[index].hsic_spinlock,
859 flags);
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700860 if (foundIndex == -1)
861 err = -1;
862 else
Shalabh Jainb0037c02013-01-18 12:47:40 -0800863 pr_debug("diag: ENQUEUE HSIC buf ptr and length is %x , %d, ch %d\n",
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700864 (unsigned int)buf,
Shalabh Jainb0037c02013-01-18 12:47:40 -0800865 diag_bridge[index].write_len, index);
Dixon Peterson938f8602012-08-17 20:02:57 -0700866 }
867#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700868 for (i = 0; i < driver->num_clients; i++)
869 if (driver->client_map[i].pid ==
870 driver->logging_process_id)
871 break;
872 if (i < driver->num_clients) {
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700873 pr_debug("diag: wake up logging process\n");
Dixon Petersonbba99ca2013-07-10 17:25:20 -0700874 driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700875 wake_up_interruptible(&driver->wait_q);
876 } else
877 return -EINVAL;
878 } else if (driver->logging_mode == NO_LOGGING_MODE) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800879 if ((data_type >= MODEM_DATA) && (data_type <= WCNSS_DATA)) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800880 driver->smd_data[data_type].in_busy_1 = 0;
881 driver->smd_data[data_type].in_busy_2 = 0;
Dixon Petersonbba99ca2013-07-10 17:25:20 -0700882 queue_work(driver->smd_data[data_type].wq,
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800883 &(driver->smd_data[data_type].
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800884 diag_read_smd_work));
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800885 if (data_type == MODEM_DATA &&
886 driver->separate_cmdrsp[data_type]) {
887 driver->smd_cmd[data_type].in_busy_1 = 0;
888 driver->smd_cmd[data_type].in_busy_2 = 0;
889 queue_work(driver->diag_wq,
890 &(driver->smd_cmd[data_type].
891 diag_read_smd_work));
892 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700893 }
Shalabh Jain482bf122011-12-06 03:54:47 -0800894#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800895 else if (data_type == SDIO_DATA) {
Shalabh Jain482bf122011-12-06 03:54:47 -0800896 driver->in_busy_sdio = 0;
897 queue_work(driver->diag_sdio_wq,
898 &(driver->diag_read_sdio_work));
899 }
900#endif
Shalabh Jain737fca72012-11-14 21:53:43 -0800901#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Shalabh Jainb0037c02013-01-18 12:47:40 -0800902 else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
903 index = data_type - HSIC_DATA;
904 if (diag_hsic[index].hsic_ch)
905 queue_work(diag_bridge[index].wq,
906 &(diag_hsic[index].
907 diag_read_hsic_work));
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700908 }
909#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910 err = -1;
911 }
912#ifdef CONFIG_DIAG_OVER_USB
913 else if (driver->logging_mode == USB_MODE) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800914 if (data_type == APPS_DATA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700915 driver->write_ptr_svc = (struct diag_request *)
916 (diagmem_alloc(driver, sizeof(struct diag_request),
917 POOL_TYPE_WRITE_STRUCT));
918 if (driver->write_ptr_svc) {
919 driver->write_ptr_svc->length = driver->used;
920 driver->write_ptr_svc->buf = buf;
921 err = usb_diag_write(driver->legacy_ch,
922 driver->write_ptr_svc);
Ravi Aravamudhand995a7f2013-07-03 13:06:15 -0700923 /* Free the buffer if write failed */
924 if (err) {
925 diagmem_free(driver,
926 (unsigned char *)driver->
927 write_ptr_svc,
928 POOL_TYPE_WRITE_STRUCT);
929 }
930 } else {
931 err = -ENOMEM;
932 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800933 } else if ((data_type >= MODEM_DATA) &&
934 (data_type <= WCNSS_DATA)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700935 write_ptr->buf = buf;
936#ifdef DIAG_DEBUG
937 printk(KERN_INFO "writing data to USB,"
938 "pkt length %d\n", write_ptr->length);
939 print_hex_dump(KERN_DEBUG, "Written Packet Data to"
940 " USB: ", 16, 1, DUMP_PREFIX_ADDRESS,
941 buf, write_ptr->length, 1);
942#endif /* DIAG DEBUG */
943 err = usb_diag_write(driver->legacy_ch, write_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700944 }
945#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800946 else if (data_type == SDIO_DATA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700947 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -0800948 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700949 write_ptr->buf = buf;
950 err = usb_diag_write(driver->mdm_ch, write_ptr);
951 } else
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800952 pr_err("diag: Incorrect sdio data "
953 "while USB write\n");
954 }
955#endif
Shalabh Jain737fca72012-11-14 21:53:43 -0800956#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Shalabh Jainb0037c02013-01-18 12:47:40 -0800957 else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
958 index = data_type - HSIC_DATA;
959 if (diag_hsic[index].hsic_device_enabled) {
Dixon Peterson938f8602012-08-17 20:02:57 -0700960 struct diag_request *write_ptr_mdm;
961 write_ptr_mdm = (struct diag_request *)
962 diagmem_alloc(driver,
963 sizeof(struct diag_request),
Shalabh Jainb0037c02013-01-18 12:47:40 -0800964 index +
Dixon Peterson938f8602012-08-17 20:02:57 -0700965 POOL_TYPE_HSIC_WRITE);
966 if (write_ptr_mdm) {
967 write_ptr_mdm->buf = buf;
968 write_ptr_mdm->length =
Shalabh Jainb0037c02013-01-18 12:47:40 -0800969 diag_bridge[index].write_len;
970 write_ptr_mdm->context = (void *)index;
Shalabh Jain737fca72012-11-14 21:53:43 -0800971 err = usb_diag_write(
Shalabh Jainb0037c02013-01-18 12:47:40 -0800972 diag_bridge[index].ch, write_ptr_mdm);
Dixon Peterson938f8602012-08-17 20:02:57 -0700973 /* Return to the pool immediately */
974 if (err) {
975 diagmem_free(driver,
976 write_ptr_mdm,
Shalabh Jainb0037c02013-01-18 12:47:40 -0800977 index +
Dixon Peterson938f8602012-08-17 20:02:57 -0700978 POOL_TYPE_HSIC_WRITE);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800979 pr_err_ratelimited("diag: HSIC write failure, err: %d, ch %d\n",
980 err, index);
Dixon Peterson938f8602012-08-17 20:02:57 -0700981 }
982 } else {
983 pr_err("diag: allocate write fail\n");
984 err = -1;
985 }
986 } else {
Shalabh Jain737fca72012-11-14 21:53:43 -0800987 pr_err("diag: Incorrect HSIC data "
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800988 "while USB write\n");
Dixon Peterson938f8602012-08-17 20:02:57 -0700989 err = -1;
990 }
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800991 } else if (data_type == SMUX_DATA) {
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700992 write_ptr->buf = buf;
Shalabh Jain737fca72012-11-14 21:53:43 -0800993 write_ptr->context = (void *)SMUX;
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700994 pr_debug("diag: writing SMUX data\n");
Shalabh Jain737fca72012-11-14 21:53:43 -0800995 err = usb_diag_write(diag_bridge[SMUX].ch,
996 write_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700997 }
998#endif
999 APPEND_DEBUG('d');
1000 }
1001#endif /* DIAG OVER USB */
1002 return err;
1003}
1004
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001005static void diag_update_pkt_buffer(unsigned char *buf)
1006{
1007 unsigned char *ptr = driver->pkt_buf;
1008 unsigned char *temp = buf;
1009
1010 mutex_lock(&driver->diagchar_mutex);
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001011 if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, driver->pkt_length)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012 memcpy(ptr, temp , driver->pkt_length);
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001013 driver->in_busy_pktdata = 1;
1014 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001015 printk(KERN_CRIT " Not enough buffer space for PKT_RESP\n");
1016 mutex_unlock(&driver->diagchar_mutex);
1017}
1018
1019void diag_update_userspace_clients(unsigned int type)
1020{
1021 int i;
1022
1023 mutex_lock(&driver->diagchar_mutex);
1024 for (i = 0; i < driver->num_clients; i++)
1025 if (driver->client_map[i].pid != 0)
1026 driver->data_ready[i] |= type;
1027 wake_up_interruptible(&driver->wait_q);
1028 mutex_unlock(&driver->diagchar_mutex);
1029}
1030
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001031void diag_update_sleeping_process(int process_id, int data_type)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032{
1033 int i;
1034
1035 mutex_lock(&driver->diagchar_mutex);
1036 for (i = 0; i < driver->num_clients; i++)
1037 if (driver->client_map[i].pid == process_id) {
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001038 driver->data_ready[i] |= data_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001039 break;
1040 }
1041 wake_up_interruptible(&driver->wait_q);
1042 mutex_unlock(&driver->diagchar_mutex);
1043}
1044
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001045static int diag_check_mode_reset(unsigned char *buf)
1046{
1047 int is_mode_reset = 0;
1048 if (chk_apps_master() && (int)(*(char *)buf) == MODE_CMD)
1049 if ((int)(*(char *)(buf+1)) == RESET_ID)
1050 is_mode_reset = 1;
1051 return is_mode_reset;
1052}
1053
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001054int diag_send_data(struct diag_master_table entry, unsigned char *buf,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001055 int len, int type)
1056{
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001057 int success = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001058 driver->pkt_length = len;
Dixon Petersoncf8b6292013-05-07 19:01:29 -07001059
1060 /* If the process_id corresponds to an apps process */
1061 if (entry.process_id != NON_APPS_PROC) {
1062 /* If the message is to be sent to the apps process */
1063 if (type != MODEM_DATA) {
1064 diag_update_pkt_buffer(buf);
1065 diag_update_sleeping_process(entry.process_id,
1066 PKT_TYPE);
1067 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001068 } else {
1069 if (len > 0) {
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001070 if (entry.client_id < NUM_SMD_DATA_CHANNELS) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001071 struct diag_smd_info *smd_info;
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001072 int index = entry.client_id;
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001073 if (!driver->rcvd_feature_mask[
1074 entry.client_id]) {
1075 pr_debug("diag: In %s, feature mask for peripheral: %d not received yet\n",
1076 __func__, entry.client_id);
1077 return 0;
1078 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001079 /*
1080 * Mode reset should work even if
1081 * modem is down
1082 */
1083 if ((index == MODEM_DATA) &&
1084 diag_check_mode_reset(buf)) {
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001085 return 1;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001086 }
1087 smd_info = (driver->separate_cmdrsp[index] &&
1088 index < NUM_SMD_CMD_CHANNELS) ?
1089 &driver->smd_cmd[index] :
1090 &driver->smd_data[index];
1091
1092 if (smd_info->ch) {
1093 mutex_lock(&smd_info->smd_ch_mutex);
1094 smd_write(smd_info->ch, buf, len);
1095 mutex_unlock(&smd_info->smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001096 } else {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001097 pr_err("diag: In %s, smd channel %d not open, peripheral: %d, type: %d\n",
1098 __func__, index,
1099 smd_info->peripheral,
1100 smd_info->type);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001101 }
Shalabh Jainc9f35092011-07-28 18:36:17 -07001102 } else {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001103 pr_alert("diag: In %s, incorrect channel: %d",
1104 __func__, entry.client_id);
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001105 success = 0;
Shalabh Jainc9f35092011-07-28 18:36:17 -07001106 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107 }
1108 }
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001109
1110 return success;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001111}
1112
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07001113void diag_process_stm_mask(uint8_t cmd, uint8_t data_mask, int data_type,
1114 uint8_t *rsp_supported, uint8_t *rsp_smd_comply)
1115{
1116 int status = 0;
1117 if (data_type >= MODEM_DATA && data_type <= WCNSS_DATA) {
1118 if (driver->peripheral_supports_stm[data_type]) {
1119 status = diag_send_stm_state(
1120 &driver->smd_cntl[data_type], cmd);
1121 if (status == 1)
1122 *rsp_smd_comply |= data_mask;
1123 *rsp_supported |= data_mask;
1124 } else if (driver->smd_cntl[data_type].ch) {
1125 *rsp_smd_comply |= data_mask;
1126 }
1127 if ((*rsp_smd_comply & data_mask) &&
1128 (*rsp_supported & data_mask))
1129 driver->stm_state[data_type] = cmd;
1130
1131 driver->stm_state_requested[data_type] = cmd;
1132 } else if (data_type == APPS_DATA) {
1133 *rsp_supported |= data_mask;
1134 *rsp_smd_comply |= data_mask;
1135 driver->stm_state[data_type] = cmd;
1136 driver->stm_state_requested[data_type] = cmd;
1137 }
1138}
1139
1140int diag_process_stm_cmd(unsigned char *buf)
1141{
1142 uint8_t version = *(buf+STM_CMD_VERSION_OFFSET);
1143 uint8_t mask = *(buf+STM_CMD_MASK_OFFSET);
1144 uint8_t cmd = *(buf+STM_CMD_DATA_OFFSET);
1145 uint8_t rsp_supported = 0;
1146 uint8_t rsp_smd_comply = 0;
1147 int valid_command = 1;
1148 int i;
1149
1150 /* Check if command is valid */
1151 if ((version != 1) || (mask == 0) || (0 != (mask >> 4)) ||
1152 (cmd != ENABLE_STM && cmd != DISABLE_STM)) {
1153 valid_command = 0;
1154 } else {
1155 if (mask & DIAG_STM_MODEM)
1156 diag_process_stm_mask(cmd, DIAG_STM_MODEM, MODEM_DATA,
1157 &rsp_supported, &rsp_smd_comply);
1158
1159 if (mask & DIAG_STM_LPASS)
1160 diag_process_stm_mask(cmd, DIAG_STM_LPASS, LPASS_DATA,
1161 &rsp_supported, &rsp_smd_comply);
1162
1163 if (mask & DIAG_STM_WCNSS)
1164 diag_process_stm_mask(cmd, DIAG_STM_WCNSS, WCNSS_DATA,
1165 &rsp_supported, &rsp_smd_comply);
1166
1167 if (mask & DIAG_STM_APPS)
1168 diag_process_stm_mask(cmd, DIAG_STM_APPS, APPS_DATA,
1169 &rsp_supported, &rsp_smd_comply);
1170 }
1171
1172 for (i = 0; i < STM_CMD_NUM_BYTES; i++)
1173 driver->apps_rsp_buf[i] = *(buf+i);
1174
1175 driver->apps_rsp_buf[STM_RSP_VALID_INDEX] = valid_command;
1176 driver->apps_rsp_buf[STM_RSP_SUPPORTED_INDEX] = rsp_supported;
1177 driver->apps_rsp_buf[STM_RSP_SMD_COMPLY_INDEX] = rsp_smd_comply;
1178
1179 encode_rsp_and_send(STM_RSP_NUM_BYTES-1);
1180
1181 return 0;
1182}
1183
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07001184int diag_apps_responds()
1185{
1186 if (chk_apps_only()) {
1187 if (driver->smd_data[MODEM_DATA].ch &&
1188 driver->rcvd_feature_mask[MODEM_DATA]) {
1189 return 0;
1190 }
1191 return 1;
1192 }
1193 return 0;
1194}
1195
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001196int diag_process_apps_pkt(unsigned char *buf, int len)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001197{
1198 uint16_t subsys_cmd_code;
1199 int subsys_id, ssid_first, ssid_last, ssid_range;
Shalabh Jain3fd986f2012-05-30 18:42:26 -07001200 int packet_type = 1, i, cmd_code;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001201 unsigned char *temp = buf;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001202 int data_type;
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001203 int mask_ret;
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001204 int status = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205#if defined(CONFIG_DIAG_OVER_USB)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001206 unsigned char *ptr;
1207#endif
1208
Dixon Petersond6a20a92012-09-27 15:58:50 -07001209 /* Check if the command is a supported mask command */
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001210 mask_ret = diag_process_apps_masks(buf, len);
1211 if (mask_ret <= 0)
1212 return mask_ret;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001213
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001214 /* Check for registered clients and forward packet to apropriate proc */
1215 cmd_code = (int)(*(char *)buf);
1216 temp++;
1217 subsys_id = (int)(*(char *)temp);
1218 temp++;
1219 subsys_cmd_code = *(uint16_t *)temp;
1220 temp += 2;
1221 data_type = APPS_DATA;
1222 /* Dont send any command other than mode reset */
Shalabh Jain10f5f432012-01-11 11:45:44 +05301223 if (chk_apps_master() && cmd_code == MODE_CMD) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001224 if (subsys_id != RESET_ID)
1225 data_type = MODEM_DATA;
1226 }
1227
1228 pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
Shalabh Jainfe02b0c2012-02-21 14:48:03 -08001229 for (i = 0; i < diag_max_reg; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230 entry = driver->table[i];
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001231 if (entry.process_id != NO_PROCESS) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001232 if (entry.cmd_code == cmd_code && entry.subsys_id ==
1233 subsys_id && entry.cmd_code_lo <=
1234 subsys_cmd_code &&
1235 entry.cmd_code_hi >= subsys_cmd_code) {
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001236 status = diag_send_data(entry, buf, len,
1237 data_type);
1238 if (status)
1239 packet_type = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001240 } else if (entry.cmd_code == 255
1241 && cmd_code == 75) {
1242 if (entry.subsys_id ==
1243 subsys_id &&
1244 entry.cmd_code_lo <=
1245 subsys_cmd_code &&
1246 entry.cmd_code_hi >=
1247 subsys_cmd_code) {
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001248 status = diag_send_data(entry, buf,
1249 len, data_type);
1250 if (status)
1251 packet_type = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001252 }
1253 } else if (entry.cmd_code == 255 &&
1254 entry.subsys_id == 255) {
1255 if (entry.cmd_code_lo <=
1256 cmd_code &&
1257 entry.
1258 cmd_code_hi >= cmd_code) {
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001259 status = diag_send_data(entry, buf, len,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001260 data_type);
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001261 if (status)
1262 packet_type = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001263 }
1264 }
1265 }
1266 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267#if defined(CONFIG_DIAG_OVER_USB)
Dixon Petersona2dd7352012-05-21 17:37:10 -07001268 /* Check for the command/respond msg for the maximum packet length */
1269 if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
1270 (*(uint16_t *)(buf+2) == 0x0055)) {
1271 for (i = 0; i < 4; i++)
1272 *(driver->apps_rsp_buf+i) = *(buf+i);
1273 *(uint32_t *)(driver->apps_rsp_buf+4) = PKT_SIZE;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001274 encode_rsp_and_send(7);
Dixon Petersona2dd7352012-05-21 17:37:10 -07001275 return 0;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07001276 } else if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
1277 (*(uint16_t *)(buf+2) == 0x020E)) {
1278 return diag_process_stm_cmd(buf);
Dixon Petersona2dd7352012-05-21 17:37:10 -07001279 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001280 /* Check for Apps Only & get event mask request */
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07001281 else if (diag_apps_responds() && *buf == 0x81) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001282 driver->apps_rsp_buf[0] = 0x81;
1283 driver->apps_rsp_buf[1] = 0x0;
1284 *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
1285 *(uint16_t *)(driver->apps_rsp_buf + 4) = EVENT_LAST_ID + 1;
1286 for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
1287 *(unsigned char *)(driver->apps_rsp_buf + 6 + i) = 0x0;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001288 encode_rsp_and_send(6 + EVENT_LAST_ID/8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001289 return 0;
1290 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001291 /* Get log ID range & Check for Apps Only */
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07001292 else if (diag_apps_responds() && (*buf == 0x73) &&
1293 *(int *)(buf+4) == 1) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001294 driver->apps_rsp_buf[0] = 0x73;
1295 *(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
1296 *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success code */
Ravi Aravamudhanbbcb99f2013-11-06 19:43:03 -08001297 *(int *)(driver->apps_rsp_buf + 12) =
1298 LOG_GET_ITEM_NUM(log_code_last_tbl[0]);
1299 *(int *)(driver->apps_rsp_buf + 16) =
1300 LOG_GET_ITEM_NUM(log_code_last_tbl[1]);
1301 *(int *)(driver->apps_rsp_buf + 20) =
1302 LOG_GET_ITEM_NUM(log_code_last_tbl[2]);
1303 *(int *)(driver->apps_rsp_buf + 24) =
1304 LOG_GET_ITEM_NUM(log_code_last_tbl[3]);
1305 *(int *)(driver->apps_rsp_buf + 28) =
1306 LOG_GET_ITEM_NUM(log_code_last_tbl[4]);
1307 *(int *)(driver->apps_rsp_buf + 32) =
1308 LOG_GET_ITEM_NUM(log_code_last_tbl[5]);
1309 *(int *)(driver->apps_rsp_buf + 36) =
1310 LOG_GET_ITEM_NUM(log_code_last_tbl[6]);
1311 *(int *)(driver->apps_rsp_buf + 40) =
1312 LOG_GET_ITEM_NUM(log_code_last_tbl[7]);
1313 *(int *)(driver->apps_rsp_buf + 44) =
1314 LOG_GET_ITEM_NUM(log_code_last_tbl[8]);
1315 *(int *)(driver->apps_rsp_buf + 48) =
1316 LOG_GET_ITEM_NUM(log_code_last_tbl[9]);
1317 *(int *)(driver->apps_rsp_buf + 52) =
1318 LOG_GET_ITEM_NUM(log_code_last_tbl[10]);
1319 *(int *)(driver->apps_rsp_buf + 56) =
1320 LOG_GET_ITEM_NUM(log_code_last_tbl[11]);
1321 *(int *)(driver->apps_rsp_buf + 60) =
1322 LOG_GET_ITEM_NUM(log_code_last_tbl[12]);
1323 *(int *)(driver->apps_rsp_buf + 64) =
1324 LOG_GET_ITEM_NUM(log_code_last_tbl[13]);
1325 *(int *)(driver->apps_rsp_buf + 68) =
1326 LOG_GET_ITEM_NUM(log_code_last_tbl[14]);
1327 *(int *)(driver->apps_rsp_buf + 72) =
1328 LOG_GET_ITEM_NUM(log_code_last_tbl[15]);
Dixon Petersond6a20a92012-09-27 15:58:50 -07001329 encode_rsp_and_send(75);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001330 return 0;
1331 }
1332 /* Respond to Get SSID Range request message */
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07001333 else if (diag_apps_responds() && (*buf == 0x7d) &&
1334 (*(buf+1) == 0x1)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001335 driver->apps_rsp_buf[0] = 0x7d;
1336 driver->apps_rsp_buf[1] = 0x1;
1337 driver->apps_rsp_buf[2] = 0x1;
1338 driver->apps_rsp_buf[3] = 0x0;
Shalabh Jain44b79b72012-06-15 13:39:27 -07001339 /* -1 to un-account for OEM SSID range */
1340 *(int *)(driver->apps_rsp_buf + 4) = MSG_MASK_TBL_CNT - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341 *(uint16_t *)(driver->apps_rsp_buf + 8) = MSG_SSID_0;
1342 *(uint16_t *)(driver->apps_rsp_buf + 10) = MSG_SSID_0_LAST;
1343 *(uint16_t *)(driver->apps_rsp_buf + 12) = MSG_SSID_1;
1344 *(uint16_t *)(driver->apps_rsp_buf + 14) = MSG_SSID_1_LAST;
1345 *(uint16_t *)(driver->apps_rsp_buf + 16) = MSG_SSID_2;
1346 *(uint16_t *)(driver->apps_rsp_buf + 18) = MSG_SSID_2_LAST;
1347 *(uint16_t *)(driver->apps_rsp_buf + 20) = MSG_SSID_3;
1348 *(uint16_t *)(driver->apps_rsp_buf + 22) = MSG_SSID_3_LAST;
1349 *(uint16_t *)(driver->apps_rsp_buf + 24) = MSG_SSID_4;
1350 *(uint16_t *)(driver->apps_rsp_buf + 26) = MSG_SSID_4_LAST;
1351 *(uint16_t *)(driver->apps_rsp_buf + 28) = MSG_SSID_5;
1352 *(uint16_t *)(driver->apps_rsp_buf + 30) = MSG_SSID_5_LAST;
1353 *(uint16_t *)(driver->apps_rsp_buf + 32) = MSG_SSID_6;
1354 *(uint16_t *)(driver->apps_rsp_buf + 34) = MSG_SSID_6_LAST;
1355 *(uint16_t *)(driver->apps_rsp_buf + 36) = MSG_SSID_7;
1356 *(uint16_t *)(driver->apps_rsp_buf + 38) = MSG_SSID_7_LAST;
1357 *(uint16_t *)(driver->apps_rsp_buf + 40) = MSG_SSID_8;
1358 *(uint16_t *)(driver->apps_rsp_buf + 42) = MSG_SSID_8_LAST;
1359 *(uint16_t *)(driver->apps_rsp_buf + 44) = MSG_SSID_9;
1360 *(uint16_t *)(driver->apps_rsp_buf + 46) = MSG_SSID_9_LAST;
1361 *(uint16_t *)(driver->apps_rsp_buf + 48) = MSG_SSID_10;
1362 *(uint16_t *)(driver->apps_rsp_buf + 50) = MSG_SSID_10_LAST;
1363 *(uint16_t *)(driver->apps_rsp_buf + 52) = MSG_SSID_11;
1364 *(uint16_t *)(driver->apps_rsp_buf + 54) = MSG_SSID_11_LAST;
1365 *(uint16_t *)(driver->apps_rsp_buf + 56) = MSG_SSID_12;
1366 *(uint16_t *)(driver->apps_rsp_buf + 58) = MSG_SSID_12_LAST;
1367 *(uint16_t *)(driver->apps_rsp_buf + 60) = MSG_SSID_13;
1368 *(uint16_t *)(driver->apps_rsp_buf + 62) = MSG_SSID_13_LAST;
1369 *(uint16_t *)(driver->apps_rsp_buf + 64) = MSG_SSID_14;
1370 *(uint16_t *)(driver->apps_rsp_buf + 66) = MSG_SSID_14_LAST;
1371 *(uint16_t *)(driver->apps_rsp_buf + 68) = MSG_SSID_15;
1372 *(uint16_t *)(driver->apps_rsp_buf + 70) = MSG_SSID_15_LAST;
1373 *(uint16_t *)(driver->apps_rsp_buf + 72) = MSG_SSID_16;
1374 *(uint16_t *)(driver->apps_rsp_buf + 74) = MSG_SSID_16_LAST;
1375 *(uint16_t *)(driver->apps_rsp_buf + 76) = MSG_SSID_17;
1376 *(uint16_t *)(driver->apps_rsp_buf + 78) = MSG_SSID_17_LAST;
1377 *(uint16_t *)(driver->apps_rsp_buf + 80) = MSG_SSID_18;
1378 *(uint16_t *)(driver->apps_rsp_buf + 82) = MSG_SSID_18_LAST;
Shalabh Jain321c8b52012-02-22 12:37:06 -08001379 *(uint16_t *)(driver->apps_rsp_buf + 84) = MSG_SSID_19;
1380 *(uint16_t *)(driver->apps_rsp_buf + 86) = MSG_SSID_19_LAST;
1381 *(uint16_t *)(driver->apps_rsp_buf + 88) = MSG_SSID_20;
1382 *(uint16_t *)(driver->apps_rsp_buf + 90) = MSG_SSID_20_LAST;
1383 *(uint16_t *)(driver->apps_rsp_buf + 92) = MSG_SSID_21;
1384 *(uint16_t *)(driver->apps_rsp_buf + 94) = MSG_SSID_21_LAST;
1385 *(uint16_t *)(driver->apps_rsp_buf + 96) = MSG_SSID_22;
1386 *(uint16_t *)(driver->apps_rsp_buf + 98) = MSG_SSID_22_LAST;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001387 encode_rsp_and_send(99);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001388 return 0;
1389 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001390 /* Check for Apps Only Respond to Get Subsys Build mask */
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07001391 else if (diag_apps_responds() && (*buf == 0x7d) &&
1392 (*(buf+1) == 0x2)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393 ssid_first = *(uint16_t *)(buf + 2);
1394 ssid_last = *(uint16_t *)(buf + 4);
1395 ssid_range = 4 * (ssid_last - ssid_first + 1);
1396 /* frame response */
1397 driver->apps_rsp_buf[0] = 0x7d;
1398 driver->apps_rsp_buf[1] = 0x2;
1399 *(uint16_t *)(driver->apps_rsp_buf + 2) = ssid_first;
1400 *(uint16_t *)(driver->apps_rsp_buf + 4) = ssid_last;
1401 driver->apps_rsp_buf[6] = 0x1;
1402 driver->apps_rsp_buf[7] = 0x0;
1403 ptr = driver->apps_rsp_buf + 8;
1404 /* bld time masks */
1405 switch (ssid_first) {
1406 case MSG_SSID_0:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001407 if (ssid_range > sizeof(msg_bld_masks_0)) {
1408 pr_warning("diag: truncating ssid range for ssid 0");
1409 ssid_range = sizeof(msg_bld_masks_0);
1410 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001411 for (i = 0; i < ssid_range; i += 4)
1412 *(int *)(ptr + i) = msg_bld_masks_0[i/4];
1413 break;
1414 case MSG_SSID_1:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001415 if (ssid_range > sizeof(msg_bld_masks_1)) {
1416 pr_warning("diag: truncating ssid range for ssid 1");
1417 ssid_range = sizeof(msg_bld_masks_1);
1418 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001419 for (i = 0; i < ssid_range; i += 4)
1420 *(int *)(ptr + i) = msg_bld_masks_1[i/4];
1421 break;
1422 case MSG_SSID_2:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001423 if (ssid_range > sizeof(msg_bld_masks_2)) {
1424 pr_warning("diag: truncating ssid range for ssid 2");
1425 ssid_range = sizeof(msg_bld_masks_2);
1426 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001427 for (i = 0; i < ssid_range; i += 4)
1428 *(int *)(ptr + i) = msg_bld_masks_2[i/4];
1429 break;
1430 case MSG_SSID_3:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001431 if (ssid_range > sizeof(msg_bld_masks_3)) {
1432 pr_warning("diag: truncating ssid range for ssid 3");
1433 ssid_range = sizeof(msg_bld_masks_3);
1434 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001435 for (i = 0; i < ssid_range; i += 4)
1436 *(int *)(ptr + i) = msg_bld_masks_3[i/4];
1437 break;
1438 case MSG_SSID_4:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001439 if (ssid_range > sizeof(msg_bld_masks_4)) {
1440 pr_warning("diag: truncating ssid range for ssid 4");
1441 ssid_range = sizeof(msg_bld_masks_4);
1442 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001443 for (i = 0; i < ssid_range; i += 4)
1444 *(int *)(ptr + i) = msg_bld_masks_4[i/4];
1445 break;
1446 case MSG_SSID_5:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001447 if (ssid_range > sizeof(msg_bld_masks_5)) {
1448 pr_warning("diag: truncating ssid range for ssid 5");
1449 ssid_range = sizeof(msg_bld_masks_5);
1450 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 for (i = 0; i < ssid_range; i += 4)
1452 *(int *)(ptr + i) = msg_bld_masks_5[i/4];
1453 break;
1454 case MSG_SSID_6:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001455 if (ssid_range > sizeof(msg_bld_masks_6)) {
1456 pr_warning("diag: truncating ssid range for ssid 6");
1457 ssid_range = sizeof(msg_bld_masks_6);
1458 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001459 for (i = 0; i < ssid_range; i += 4)
1460 *(int *)(ptr + i) = msg_bld_masks_6[i/4];
1461 break;
1462 case MSG_SSID_7:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001463 if (ssid_range > sizeof(msg_bld_masks_7)) {
1464 pr_warning("diag: truncating ssid range for ssid 7");
1465 ssid_range = sizeof(msg_bld_masks_7);
1466 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001467 for (i = 0; i < ssid_range; i += 4)
1468 *(int *)(ptr + i) = msg_bld_masks_7[i/4];
1469 break;
1470 case MSG_SSID_8:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001471 if (ssid_range > sizeof(msg_bld_masks_8)) {
1472 pr_warning("diag: truncating ssid range for ssid 8");
1473 ssid_range = sizeof(msg_bld_masks_8);
1474 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001475 for (i = 0; i < ssid_range; i += 4)
1476 *(int *)(ptr + i) = msg_bld_masks_8[i/4];
1477 break;
1478 case MSG_SSID_9:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001479 if (ssid_range > sizeof(msg_bld_masks_9)) {
1480 pr_warning("diag: truncating ssid range for ssid 9");
1481 ssid_range = sizeof(msg_bld_masks_9);
1482 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001483 for (i = 0; i < ssid_range; i += 4)
1484 *(int *)(ptr + i) = msg_bld_masks_9[i/4];
1485 break;
1486 case MSG_SSID_10:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001487 if (ssid_range > sizeof(msg_bld_masks_10)) {
1488 pr_warning("diag: truncating ssid range for ssid 10");
1489 ssid_range = sizeof(msg_bld_masks_10);
1490 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 for (i = 0; i < ssid_range; i += 4)
1492 *(int *)(ptr + i) = msg_bld_masks_10[i/4];
1493 break;
1494 case MSG_SSID_11:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001495 if (ssid_range > sizeof(msg_bld_masks_11)) {
1496 pr_warning("diag: truncating ssid range for ssid 11");
1497 ssid_range = sizeof(msg_bld_masks_11);
1498 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001499 for (i = 0; i < ssid_range; i += 4)
1500 *(int *)(ptr + i) = msg_bld_masks_11[i/4];
1501 break;
1502 case MSG_SSID_12:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001503 if (ssid_range > sizeof(msg_bld_masks_12)) {
1504 pr_warning("diag: truncating ssid range for ssid 12");
1505 ssid_range = sizeof(msg_bld_masks_12);
1506 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507 for (i = 0; i < ssid_range; i += 4)
1508 *(int *)(ptr + i) = msg_bld_masks_12[i/4];
1509 break;
1510 case MSG_SSID_13:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001511 if (ssid_range > sizeof(msg_bld_masks_13)) {
1512 pr_warning("diag: truncating ssid range for ssid 13");
1513 ssid_range = sizeof(msg_bld_masks_13);
1514 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001515 for (i = 0; i < ssid_range; i += 4)
1516 *(int *)(ptr + i) = msg_bld_masks_13[i/4];
1517 break;
1518 case MSG_SSID_14:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001519 if (ssid_range > sizeof(msg_bld_masks_14)) {
1520 pr_warning("diag: truncating ssid range for ssid 14");
1521 ssid_range = sizeof(msg_bld_masks_14);
1522 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001523 for (i = 0; i < ssid_range; i += 4)
1524 *(int *)(ptr + i) = msg_bld_masks_14[i/4];
1525 break;
1526 case MSG_SSID_15:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001527 if (ssid_range > sizeof(msg_bld_masks_15)) {
1528 pr_warning("diag: truncating ssid range for ssid 15");
1529 ssid_range = sizeof(msg_bld_masks_15);
1530 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001531 for (i = 0; i < ssid_range; i += 4)
1532 *(int *)(ptr + i) = msg_bld_masks_15[i/4];
1533 break;
1534 case MSG_SSID_16:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001535 if (ssid_range > sizeof(msg_bld_masks_16)) {
1536 pr_warning("diag: truncating ssid range for ssid 16");
1537 ssid_range = sizeof(msg_bld_masks_16);
1538 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001539 for (i = 0; i < ssid_range; i += 4)
1540 *(int *)(ptr + i) = msg_bld_masks_16[i/4];
1541 break;
1542 case MSG_SSID_17:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001543 if (ssid_range > sizeof(msg_bld_masks_17)) {
1544 pr_warning("diag: truncating ssid range for ssid 17");
1545 ssid_range = sizeof(msg_bld_masks_17);
1546 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001547 for (i = 0; i < ssid_range; i += 4)
1548 *(int *)(ptr + i) = msg_bld_masks_17[i/4];
1549 break;
1550 case MSG_SSID_18:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001551 if (ssid_range > sizeof(msg_bld_masks_18)) {
1552 pr_warning("diag: truncating ssid range for ssid 18");
1553 ssid_range = sizeof(msg_bld_masks_18);
1554 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001555 for (i = 0; i < ssid_range; i += 4)
1556 *(int *)(ptr + i) = msg_bld_masks_18[i/4];
1557 break;
Shalabh Jain321c8b52012-02-22 12:37:06 -08001558 case MSG_SSID_19:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001559 if (ssid_range > sizeof(msg_bld_masks_19)) {
1560 pr_warning("diag: truncating ssid range for ssid 19");
1561 ssid_range = sizeof(msg_bld_masks_19);
1562 }
Shalabh Jain321c8b52012-02-22 12:37:06 -08001563 for (i = 0; i < ssid_range; i += 4)
1564 *(int *)(ptr + i) = msg_bld_masks_19[i/4];
1565 break;
1566 case MSG_SSID_20:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001567 if (ssid_range > sizeof(msg_bld_masks_20)) {
1568 pr_warning("diag: truncating ssid range for ssid 20");
1569 ssid_range = sizeof(msg_bld_masks_20);
1570 }
Shalabh Jain321c8b52012-02-22 12:37:06 -08001571 for (i = 0; i < ssid_range; i += 4)
1572 *(int *)(ptr + i) = msg_bld_masks_20[i/4];
1573 break;
1574 case MSG_SSID_21:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001575 if (ssid_range > sizeof(msg_bld_masks_21)) {
1576 pr_warning("diag: truncating ssid range for ssid 21");
1577 ssid_range = sizeof(msg_bld_masks_21);
1578 }
Shalabh Jain321c8b52012-02-22 12:37:06 -08001579 for (i = 0; i < ssid_range; i += 4)
1580 *(int *)(ptr + i) = msg_bld_masks_21[i/4];
1581 break;
1582 case MSG_SSID_22:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001583 if (ssid_range > sizeof(msg_bld_masks_22)) {
1584 pr_warning("diag: truncating ssid range for ssid 22");
1585 ssid_range = sizeof(msg_bld_masks_22);
1586 }
Shalabh Jain321c8b52012-02-22 12:37:06 -08001587 for (i = 0; i < ssid_range; i += 4)
1588 *(int *)(ptr + i) = msg_bld_masks_22[i/4];
1589 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001590 }
Dixon Petersond6a20a92012-09-27 15:58:50 -07001591 encode_rsp_and_send(8 + ssid_range - 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001592 return 0;
1593 }
1594 /* Check for download command */
Shalabh Jain10f5f432012-01-11 11:45:44 +05301595 else if ((cpu_is_msm8x60() || chk_apps_master()) && (*buf == 0x3A)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001596 /* send response back */
1597 driver->apps_rsp_buf[0] = *buf;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001598 encode_rsp_and_send(0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001599 msleep(5000);
1600 /* call download API */
1601 msm_set_restart_mode(RESTART_DLOAD);
1602 printk(KERN_CRIT "diag: download mode set, Rebooting SoC..\n");
1603 kernel_restart(NULL);
1604 /* Not required, represents that command isnt sent to modem */
1605 return 0;
1606 }
Dixon Petersonb46bb992012-01-12 19:16:56 -08001607 /* Check for polling for Apps only DIAG */
1608 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1609 (*(buf+2) == 0x03)) {
Shalabh Jain3d29fc32012-02-09 17:15:59 -08001610 /* If no one has registered for polling */
Dixon Petersonb4618a42012-02-29 18:56:31 -08001611 if (chk_polling_response()) {
Dixon Petersonb46bb992012-01-12 19:16:56 -08001612 /* Respond to polling for Apps only DIAG */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001613 for (i = 0; i < 3; i++)
1614 driver->apps_rsp_buf[i] = *(buf+i);
1615 for (i = 0; i < 13; i++)
1616 driver->apps_rsp_buf[i+3] = 0;
1617
Dixon Petersond6a20a92012-09-27 15:58:50 -07001618 encode_rsp_and_send(15);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001619 return 0;
1620 }
Dixon Petersonb46bb992012-01-12 19:16:56 -08001621 }
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -08001622 /* Return the Delayed Response Wrap Status */
1623 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1624 (*(buf+2) == 0x04) && (*(buf+3) == 0x0)) {
1625 memcpy(driver->apps_rsp_buf, buf, 4);
1626 driver->apps_rsp_buf[4] = wrap_enabled;
1627 encode_rsp_and_send(4);
1628 return 0;
1629 }
1630 /* Wrap the Delayed Rsp ID */
1631 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1632 (*(buf+2) == 0x05) && (*(buf+3) == 0x0)) {
1633 wrap_enabled = true;
1634 memcpy(driver->apps_rsp_buf, buf, 4);
1635 driver->apps_rsp_buf[4] = wrap_count;
1636 encode_rsp_and_send(5);
1637 return 0;
1638 }
Dixon Petersonb46bb992012-01-12 19:16:56 -08001639 /* Check for ID for NO MODEM present */
Dixon Petersonb4618a42012-02-29 18:56:31 -08001640 else if (chk_polling_response()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001641 /* respond to 0x0 command */
Dixon Petersonb46bb992012-01-12 19:16:56 -08001642 if (*buf == 0x00) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643 for (i = 0; i < 55; i++)
1644 driver->apps_rsp_buf[i] = 0;
1645
Dixon Petersond6a20a92012-09-27 15:58:50 -07001646 encode_rsp_and_send(54);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001647 return 0;
1648 }
1649 /* respond to 0x7c command */
1650 else if (*buf == 0x7c) {
1651 driver->apps_rsp_buf[0] = 0x7c;
1652 for (i = 1; i < 8; i++)
1653 driver->apps_rsp_buf[i] = 0;
1654 /* Tools ID for APQ 8060 */
1655 *(int *)(driver->apps_rsp_buf + 8) =
1656 chk_config_get_id();
1657 *(unsigned char *)(driver->apps_rsp_buf + 12) = '\0';
1658 *(unsigned char *)(driver->apps_rsp_buf + 13) = '\0';
Dixon Petersond6a20a92012-09-27 15:58:50 -07001659 encode_rsp_and_send(13);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001660 return 0;
1661 }
1662 }
1663#endif
Dixon Petersond6a20a92012-09-27 15:58:50 -07001664 return packet_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001665}
1666
1667#ifdef CONFIG_DIAG_OVER_USB
1668void diag_send_error_rsp(int index)
1669{
1670 int i;
Shalabh Jain1fedab92011-12-22 13:15:22 +05301671
Ravi Aravamudhancc9946862013-07-15 13:31:11 -07001672 /* -1 to accomodate the first byte 0x13 */
1673 if (index > APPS_BUF_SIZE-1) {
1674 pr_err("diag: cannot send err rsp, huge length: %d\n", index);
Shalabh Jain1fedab92011-12-22 13:15:22 +05301675 return;
1676 }
Ravi Aravamudhancc9946862013-07-15 13:31:11 -07001677
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001678 driver->apps_rsp_buf[0] = 0x13; /* error code 13 */
1679 for (i = 0; i < index; i++)
1680 driver->apps_rsp_buf[i+1] = *(driver->hdlc_buf+i);
Dixon Petersond6a20a92012-09-27 15:58:50 -07001681 encode_rsp_and_send(index - 3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001682}
1683#else
1684static inline void diag_send_error_rsp(int index) {}
1685#endif
1686
1687void diag_process_hdlc(void *data, unsigned len)
1688{
1689 struct diag_hdlc_decode_type hdlc;
Ravi Aravamudhan5dccccb2013-08-09 16:57:34 -07001690 int ret, type = 0, crc_chk = 0;
Dixon Peterson25f042b2013-02-27 13:00:08 -08001691
1692 mutex_lock(&driver->diag_hdlc_mutex);
1693
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001694 pr_debug("diag: HDLC decode fn, len of data %d\n", len);
1695 hdlc.dest_ptr = driver->hdlc_buf;
1696 hdlc.dest_size = USB_MAX_OUT_BUF;
1697 hdlc.src_ptr = data;
1698 hdlc.src_size = len;
1699 hdlc.src_idx = 0;
1700 hdlc.dest_idx = 0;
1701 hdlc.escaping = 0;
1702
1703 ret = diag_hdlc_decode(&hdlc);
Ravi Aravamudhan5dccccb2013-08-09 16:57:34 -07001704 if (ret) {
1705 crc_chk = crc_check(hdlc.dest_ptr, hdlc.dest_idx);
1706 if (crc_chk) {
1707 /* CRC check failed. */
1708 pr_err_ratelimited("diag: In %s, bad CRC. Dropping packet\n",
1709 __func__);
1710 mutex_unlock(&driver->diag_hdlc_mutex);
1711 return;
1712 }
1713 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001714
Dixon Petersonb4f84242013-02-27 18:46:56 -08001715 /*
1716 * If the message is 3 bytes or less in length then the message is
1717 * too short. A message will need 4 bytes minimum, since there are
1718 * 2 bytes for the CRC and 1 byte for the ending 0x7e for the hdlc
1719 * encoding
1720 */
1721 if (hdlc.dest_idx < 4) {
1722 pr_err_ratelimited("diag: In %s, message is too short, len: %d, dest len: %d\n",
1723 __func__, len, hdlc.dest_idx);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001724 mutex_unlock(&driver->diag_hdlc_mutex);
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001725 return;
1726 }
Dixon Petersonb4f84242013-02-27 18:46:56 -08001727
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001728 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729 type = diag_process_apps_pkt(driver->hdlc_buf,
1730 hdlc.dest_idx - 3);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001731 if (type < 0) {
1732 mutex_unlock(&driver->diag_hdlc_mutex);
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001733 return;
Dixon Peterson25f042b2013-02-27 13:00:08 -08001734 }
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001735 } else if (driver->debug_flag) {
Ravi Aravamudhan5dccccb2013-08-09 16:57:34 -07001736 pr_err("diag: In %s, partial packet received, dropping packet, len: %d\n",
1737 __func__, len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001738 print_hex_dump(KERN_DEBUG, "Dropped Packet Data: ", 16, 1,
1739 DUMP_PREFIX_ADDRESS, data, len, 1);
1740 driver->debug_flag = 0;
1741 }
1742 /* send error responses from APPS for Central Routing */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001743 if (type == 1 && chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001744 diag_send_error_rsp(hdlc.dest_idx);
1745 type = 0;
1746 }
1747 /* implies this packet is NOT meant for apps */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001748 if (!(driver->smd_data[MODEM_DATA].ch) && type == 1) {
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001749 if (chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001750 diag_send_error_rsp(hdlc.dest_idx);
1751 } else { /* APQ 8060, Let Q6 respond */
Dixon Peterson25f042b2013-02-27 13:00:08 -08001752 if (driver->smd_data[LPASS_DATA].ch) {
1753 mutex_lock(&driver->smd_data[LPASS_DATA].
1754 smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001755 smd_write(driver->smd_data[LPASS_DATA].ch,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001756 driver->hdlc_buf,
1757 hdlc.dest_idx - 3);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001758 mutex_unlock(&driver->smd_data[LPASS_DATA].
1759 smd_ch_mutex);
1760 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001761 }
1762 type = 0;
1763 }
1764
1765#ifdef DIAG_DEBUG
1766 pr_debug("diag: hdlc.dest_idx = %d", hdlc.dest_idx);
1767 for (i = 0; i < hdlc.dest_idx; i++)
1768 printk(KERN_DEBUG "\t%x", *(((unsigned char *)
1769 driver->hdlc_buf)+i));
1770#endif /* DIAG DEBUG */
1771 /* ignore 2 bytes for CRC, one for 7E and send */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001772 if ((driver->smd_data[MODEM_DATA].ch) && (ret) && (type) &&
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001773 (hdlc.dest_idx > 3)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774 APPEND_DEBUG('g');
Dixon Peterson25f042b2013-02-27 13:00:08 -08001775 mutex_lock(&driver->smd_data[MODEM_DATA].smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001776 smd_write(driver->smd_data[MODEM_DATA].ch,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001777 driver->hdlc_buf, hdlc.dest_idx - 3);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001778 mutex_unlock(&driver->smd_data[MODEM_DATA].smd_ch_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001779 APPEND_DEBUG('h');
1780#ifdef DIAG_DEBUG
1781 printk(KERN_INFO "writing data to SMD, pkt length %d\n", len);
1782 print_hex_dump(KERN_DEBUG, "Written Packet Data to SMD: ", 16,
1783 1, DUMP_PREFIX_ADDRESS, data, len, 1);
1784#endif /* DIAG DEBUG */
1785 }
Dixon Peterson25f042b2013-02-27 13:00:08 -08001786 mutex_unlock(&driver->diag_hdlc_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001787}
1788
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001789void diag_reset_smd_data(int queue)
1790{
1791 int i;
1792
1793 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1794 driver->smd_data[i].in_busy_1 = 0;
1795 driver->smd_data[i].in_busy_2 = 0;
1796 if (queue)
1797 /* Poll SMD data channels to check for data */
Dixon Petersonbba99ca2013-07-10 17:25:20 -07001798 queue_work(driver->smd_data[i].wq,
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001799 &(driver->smd_data[i].diag_read_smd_work));
1800 }
1801
1802 if (driver->supports_separate_cmdrsp) {
1803 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
1804 driver->smd_cmd[i].in_busy_1 = 0;
1805 driver->smd_cmd[i].in_busy_2 = 0;
1806 if (queue)
1807 /* Poll SMD data channels to check for data */
1808 queue_work(driver->diag_wq,
1809 &(driver->smd_cmd[i].
1810 diag_read_smd_work));
1811 }
1812 }
1813}
1814
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001815#ifdef CONFIG_DIAG_OVER_USB
Shalabh Jain8e9750a2011-09-09 13:06:29 -07001816/* 2+1 for modem ; 2 for LPASS ; 1 for WCNSS */
1817#define N_LEGACY_WRITE (driver->poolsize + 6)
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001818/* Additionally support number of command data and dci channels */
1819#define N_LEGACY_WRITE_CMD ((N_LEGACY_WRITE) + 4)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001820#define N_LEGACY_READ 1
1821
Mohit Aggarwalb4465772013-04-18 13:08:07 +05301822static void diag_usb_connect_work_fn(struct work_struct *w)
1823{
1824 diagfwd_connect();
1825}
1826
1827static void diag_usb_disconnect_work_fn(struct work_struct *w)
1828{
1829 diagfwd_disconnect();
1830}
1831
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832int diagfwd_connect(void)
1833{
1834 int err;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001835 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001836
1837 printk(KERN_DEBUG "diag: USB connected\n");
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001838 err = usb_diag_alloc_req(driver->legacy_ch,
1839 (driver->supports_separate_cmdrsp ?
1840 N_LEGACY_WRITE_CMD : N_LEGACY_WRITE),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001841 N_LEGACY_READ);
1842 if (err)
1843 printk(KERN_ERR "diag: unable to alloc USB req on legacy ch");
1844
1845 driver->usb_connected = 1;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001846 diag_reset_smd_data(RESET_AND_QUEUE);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001847 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001848 /* Poll SMD CNTL channels to check for data */
1849 diag_smd_notify(&(driver->smd_cntl[i]), SMD_EVENT_DATA);
1850 }
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001851 queue_work(driver->diag_real_time_wq,
1852 &driver->diag_real_time_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001853
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001854 /* Poll USB channel to check for data*/
1855 queue_work(driver->diag_wq, &(driver->diag_read_work));
1856#ifdef CONFIG_DIAG_SDIO_PIPE
1857 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
1858 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1859 diagfwd_connect_sdio();
1860 else
1861 printk(KERN_INFO "diag: No USB MDM ch");
1862 }
1863#endif
1864 return 0;
1865}
1866
1867int diagfwd_disconnect(void)
1868{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001869 int i;
1870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001871 printk(KERN_DEBUG "diag: USB disconnected\n");
1872 driver->usb_connected = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001873 driver->debug_flag = 1;
1874 usb_diag_free_req(driver->legacy_ch);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001875 if (driver->logging_mode == USB_MODE) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001876 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1877 driver->smd_data[i].in_busy_1 = 1;
1878 driver->smd_data[i].in_busy_2 = 1;
1879 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001880
1881 if (driver->supports_separate_cmdrsp) {
1882 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
1883 driver->smd_cmd[i].in_busy_1 = 1;
1884 driver->smd_cmd[i].in_busy_2 = 1;
1885 }
1886 }
Shalabh Jain69890aa2011-10-10 12:59:16 -07001887 }
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001888 queue_work(driver->diag_real_time_wq,
1889 &driver->diag_real_time_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001890#ifdef CONFIG_DIAG_SDIO_PIPE
1891 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
1892 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1893 diagfwd_disconnect_sdio();
1894#endif
1895 /* TBD - notify and flow control SMD */
1896 return 0;
1897}
1898
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001899static int diagfwd_check_buf_match(int num_channels,
1900 struct diag_smd_info *data, unsigned char *buf)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001901{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001902 int i;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001903 int found_it = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001904
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001905 for (i = 0; i < num_channels; i++) {
1906 if (buf == (void *)data[i].buf_in_1) {
1907 data[i].in_busy_1 = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001908 found_it = 1;
1909 break;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001910 } else if (buf == (void *)data[i].buf_in_2) {
1911 data[i].in_busy_2 = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001912 found_it = 1;
1913 break;
1914 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001915 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001916
Dixon Petersonbba99ca2013-07-10 17:25:20 -07001917 if (found_it) {
1918 if (data[i].type == SMD_DATA_TYPE)
1919 queue_work(data[i].wq,
1920 &(data[i].diag_read_smd_work));
1921 else
1922 queue_work(driver->diag_wq,
1923 &(data[i].diag_read_smd_work));
1924 }
1925
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001926 return found_it;
1927}
1928
1929int diagfwd_write_complete(struct diag_request *diag_write_ptr)
1930{
1931 unsigned char *buf = diag_write_ptr->buf;
1932 int found_it = 0;
1933
1934 /* Determine if the write complete is for data from modem/apps/q6 */
1935 found_it = diagfwd_check_buf_match(NUM_SMD_DATA_CHANNELS,
1936 driver->smd_data, buf);
1937
1938 if (!found_it && driver->supports_separate_cmdrsp)
1939 found_it = diagfwd_check_buf_match(NUM_SMD_CMD_CHANNELS,
1940 driver->smd_cmd, buf);
1941
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001942#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001943 if (!found_it) {
1944 if (buf == (void *)driver->buf_in_sdio) {
1945 if (machine_is_msm8x60_fusion() ||
1946 machine_is_msm8x60_fusn_ffa())
1947 diagfwd_write_complete_sdio();
1948 else
1949 pr_err("diag: Incorrect buffer pointer while WRITE");
1950 found_it = 1;
1951 }
1952 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001953#endif
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001954 if (!found_it) {
Ravi Aravamudhand995a7f2013-07-03 13:06:15 -07001955 if (driver->logging_mode != USB_MODE)
1956 pr_debug("diag: freeing buffer when not in usb mode\n");
1957
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001958 diagmem_free(driver, (unsigned char *)buf,
1959 POOL_TYPE_HDLC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001960 diagmem_free(driver, (unsigned char *)diag_write_ptr,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001961 POOL_TYPE_WRITE_STRUCT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001962 }
1963 return 0;
1964}
1965
1966int diagfwd_read_complete(struct diag_request *diag_read_ptr)
1967{
1968 int status = diag_read_ptr->status;
1969 unsigned char *buf = diag_read_ptr->buf;
1970
1971 /* Determine if the read complete is for data on legacy/mdm ch */
1972 if (buf == (void *)driver->usb_buf_out) {
1973 driver->read_len_legacy = diag_read_ptr->actual;
1974 APPEND_DEBUG('s');
1975#ifdef DIAG_DEBUG
1976 printk(KERN_INFO "read data from USB, pkt length %d",
1977 diag_read_ptr->actual);
1978 print_hex_dump(KERN_DEBUG, "Read Packet Data from USB: ", 16, 1,
1979 DUMP_PREFIX_ADDRESS, diag_read_ptr->buf,
1980 diag_read_ptr->actual, 1);
1981#endif /* DIAG DEBUG */
1982 if (driver->logging_mode == USB_MODE) {
1983 if (status != -ECONNRESET && status != -ESHUTDOWN)
1984 queue_work(driver->diag_wq,
1985 &(driver->diag_proc_hdlc_work));
1986 else
1987 queue_work(driver->diag_wq,
1988 &(driver->diag_read_work));
1989 }
1990 }
1991#ifdef CONFIG_DIAG_SDIO_PIPE
1992 else if (buf == (void *)driver->usb_buf_mdm_out) {
1993 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -08001994 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001995 driver->read_len_mdm = diag_read_ptr->actual;
1996 diagfwd_read_complete_sdio();
1997 } else
1998 pr_err("diag: Incorrect buffer pointer while READ");
1999 }
2000#endif
2001 else
2002 printk(KERN_ERR "diag: Unknown buffer ptr from USB");
2003
2004 return 0;
2005}
2006
2007void diag_read_work_fn(struct work_struct *work)
2008{
2009 APPEND_DEBUG('d');
2010 driver->usb_read_ptr->buf = driver->usb_buf_out;
2011 driver->usb_read_ptr->length = USB_MAX_OUT_BUF;
2012 usb_diag_read(driver->legacy_ch, driver->usb_read_ptr);
2013 APPEND_DEBUG('e');
2014}
2015
2016void diag_process_hdlc_fn(struct work_struct *work)
2017{
2018 APPEND_DEBUG('D');
2019 diag_process_hdlc(driver->usb_buf_out, driver->read_len_legacy);
2020 diag_read_work_fn(work);
2021 APPEND_DEBUG('E');
2022}
2023
2024void diag_usb_legacy_notifier(void *priv, unsigned event,
2025 struct diag_request *d_req)
2026{
2027 switch (event) {
2028 case USB_DIAG_CONNECT:
Mohit Aggarwalb4465772013-04-18 13:08:07 +05302029 queue_work(driver->diag_wq,
2030 &driver->diag_usb_connect_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002031 break;
2032 case USB_DIAG_DISCONNECT:
Mohit Aggarwalb4465772013-04-18 13:08:07 +05302033 queue_work(driver->diag_wq,
2034 &driver->diag_usb_disconnect_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002035 break;
2036 case USB_DIAG_READ_DONE:
2037 diagfwd_read_complete(d_req);
2038 break;
2039 case USB_DIAG_WRITE_DONE:
2040 diagfwd_write_complete(d_req);
2041 break;
2042 default:
2043 printk(KERN_ERR "Unknown event from USB diag\n");
2044 break;
2045 }
2046}
2047
2048#endif /* DIAG OVER USB */
2049
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002050void diag_smd_notify(void *ctxt, unsigned event)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002051{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002052 struct diag_smd_info *smd_info = (struct diag_smd_info *)ctxt;
2053 if (!smd_info)
Shalabh Jaineefee052011-11-08 23:46:03 -08002054 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002055
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002056 if (event == SMD_EVENT_CLOSE) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002057 smd_info->ch = 0;
Shalabh Jainc70b3b62012-08-31 19:11:20 -07002058 wake_up(&driver->smd_wait_q);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002059 if (smd_info->type == SMD_DATA_TYPE) {
2060 smd_info->notify_context = event;
2061 queue_work(driver->diag_cntl_wq,
2062 &(smd_info->diag_notify_update_smd_work));
2063 } else if (smd_info->type == SMD_DCI_TYPE) {
2064 /* Notify the clients of the close */
2065 diag_dci_notify_client(smd_info->peripheral_mask,
2066 DIAG_STATUS_CLOSED);
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002067 } else if (smd_info->type == SMD_CNTL_TYPE) {
2068 diag_cntl_stm_notify(smd_info,
2069 CLEAR_PERIPHERAL_STM_STATE);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002070 }
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002071 return;
2072 } else if (event == SMD_EVENT_OPEN) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002073 if (smd_info->ch_save)
2074 smd_info->ch = smd_info->ch_save;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002075
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002076 if (smd_info->type == SMD_CNTL_TYPE) {
2077 smd_info->notify_context = event;
2078 queue_work(driver->diag_cntl_wq,
2079 &(smd_info->diag_notify_update_smd_work));
2080 } else if (smd_info->type == SMD_DCI_TYPE) {
2081 smd_info->notify_context = event;
2082 queue_work(driver->diag_dci_wq,
2083 &(smd_info->diag_notify_update_smd_work));
2084 /* Notify the clients of the open */
2085 diag_dci_notify_client(smd_info->peripheral_mask,
2086 DIAG_STATUS_OPEN);
2087 }
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002088 } else if (event == SMD_EVENT_DATA && !driver->real_time_mode &&
2089 smd_info->type == SMD_DATA_TYPE) {
2090 process_lock_on_notify(&smd_info->nrt_lock);
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002091 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002092
Shalabh Jainc70b3b62012-08-31 19:11:20 -07002093 wake_up(&driver->smd_wait_q);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002094
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002095 if (smd_info->type == SMD_DCI_TYPE ||
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07002096 smd_info->type == SMD_DCI_CMD_TYPE) {
2097 if (event == SMD_EVENT_DATA)
2098 diag_dci_try_activate_wakeup_source(smd_info->ch);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002099 queue_work(driver->diag_dci_wq,
2100 &(smd_info->diag_read_smd_work));
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002101 } else if (smd_info->type == SMD_DATA_TYPE) {
2102 queue_work(smd_info->wq,
2103 &(smd_info->diag_read_smd_work));
2104 } else {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002105 queue_work(driver->diag_wq, &(smd_info->diag_read_smd_work));
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002106 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002107}
2108
2109static int diag_smd_probe(struct platform_device *pdev)
2110{
2111 int r = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002112 int index = -1;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002113 const char *channel_name = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002114
Shalabh Jaineefee052011-11-08 23:46:03 -08002115 if (pdev->id == SMD_APPS_MODEM) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002116 index = MODEM_DATA;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002117 channel_name = "DIAG";
Shalabh Jaineefee052011-11-08 23:46:03 -08002118 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002119#if defined(CONFIG_MSM_N_WAY_SMD)
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002120 else if (pdev->id == SMD_APPS_QDSP) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002121 index = LPASS_DATA;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002122 channel_name = "DIAG";
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002123 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002124#endif
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002125 else if (pdev->id == SMD_APPS_WCNSS) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002126 index = WCNSS_DATA;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002127 channel_name = "APPS_RIVA_DATA";
2128 }
2129
2130 if (index != -1) {
2131 r = smd_named_open_on_edge(channel_name,
2132 pdev->id,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002133 &driver->smd_data[index].ch,
2134 &driver->smd_data[index],
2135 diag_smd_notify);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002136 driver->smd_data[index].ch_save = driver->smd_data[index].ch;
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002137 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002138
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002139 pm_runtime_set_active(&pdev->dev);
2140 pm_runtime_enable(&pdev->dev);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002141 pr_debug("diag: In %s, open SMD port, Id = %d, r = %d\n",
2142 __func__, pdev->id, r);
2143
2144 return 0;
2145}
2146
2147static int diag_smd_cmd_probe(struct platform_device *pdev)
2148{
2149 int r = 0;
2150 int index = -1;
2151 const char *channel_name = NULL;
2152
2153 if (!driver->supports_separate_cmdrsp)
2154 return 0;
2155
2156 if (pdev->id == SMD_APPS_MODEM) {
2157 index = MODEM_DATA;
2158 channel_name = "DIAG_CMD";
2159 }
2160
2161 if (index != -1) {
2162 r = smd_named_open_on_edge(channel_name,
2163 pdev->id,
2164 &driver->smd_cmd[index].ch,
2165 &driver->smd_cmd[index],
2166 diag_smd_notify);
2167 driver->smd_cmd[index].ch_save =
2168 driver->smd_cmd[index].ch;
2169 }
2170
2171 pr_debug("diag: In %s, open SMD CMD port, Id = %d, r = %d\n",
2172 __func__, pdev->id, r);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002173
2174 return 0;
2175}
2176
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002177static int diag_smd_runtime_suspend(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002178{
2179 dev_dbg(dev, "pm_runtime: suspending...\n");
2180 return 0;
2181}
2182
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002183static int diag_smd_runtime_resume(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002184{
2185 dev_dbg(dev, "pm_runtime: resuming...\n");
2186 return 0;
2187}
2188
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002189static const struct dev_pm_ops diag_smd_dev_pm_ops = {
2190 .runtime_suspend = diag_smd_runtime_suspend,
2191 .runtime_resume = diag_smd_runtime_resume,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002192};
2193
2194static struct platform_driver msm_smd_ch1_driver = {
2195
2196 .probe = diag_smd_probe,
2197 .driver = {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002198 .name = "DIAG",
2199 .owner = THIS_MODULE,
2200 .pm = &diag_smd_dev_pm_ops,
2201 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002202};
2203
2204static struct platform_driver diag_smd_lite_driver = {
2205
2206 .probe = diag_smd_probe,
2207 .driver = {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002208 .name = "APPS_RIVA_DATA",
2209 .owner = THIS_MODULE,
2210 .pm = &diag_smd_dev_pm_ops,
2211 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002212};
2213
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002214static struct platform_driver
2215 smd_lite_data_cmd_drivers[NUM_SMD_CMD_CHANNELS] = {
2216 {
2217 /* Modem data */
2218 .probe = diag_smd_cmd_probe,
2219 .driver = {
2220 .name = "DIAG_CMD",
2221 .owner = THIS_MODULE,
2222 .pm = &diag_smd_dev_pm_ops,
2223 },
2224 }
2225};
2226
2227int device_supports_separate_cmdrsp(void)
2228{
2229 return driver->use_device_tree;
2230}
2231
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002232void diag_smd_destructor(struct diag_smd_info *smd_info)
2233{
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002234 if (smd_info->type == SMD_DATA_TYPE) {
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002235 wake_lock_destroy(&smd_info->nrt_lock.read_lock);
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002236 destroy_workqueue(smd_info->wq);
2237 }
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002238
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002239 if (smd_info->ch)
2240 smd_close(smd_info->ch);
2241
2242 smd_info->ch = 0;
2243 smd_info->ch_save = 0;
2244 kfree(smd_info->buf_in_1);
2245 kfree(smd_info->buf_in_2);
2246 kfree(smd_info->write_ptr_1);
2247 kfree(smd_info->write_ptr_2);
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002248 kfree(smd_info->buf_in_1_raw);
2249 kfree(smd_info->buf_in_2_raw);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002250}
2251
2252int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral,
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002253 int type)
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002254{
2255 smd_info->peripheral = peripheral;
2256 smd_info->type = type;
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002257 smd_info->encode_hdlc = 0;
Dixon Peterson25f042b2013-02-27 13:00:08 -08002258 mutex_init(&smd_info->smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002259
2260 switch (peripheral) {
2261 case MODEM_DATA:
2262 smd_info->peripheral_mask = DIAG_CON_MPSS;
2263 break;
2264 case LPASS_DATA:
2265 smd_info->peripheral_mask = DIAG_CON_LPASS;
2266 break;
2267 case WCNSS_DATA:
2268 smd_info->peripheral_mask = DIAG_CON_WCNSS;
2269 break;
2270 default:
2271 pr_err("diag: In %s, unknown peripheral, peripheral: %d\n",
2272 __func__, peripheral);
2273 goto err;
2274 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002275
2276 smd_info->ch = 0;
2277 smd_info->ch_save = 0;
2278
2279 if (smd_info->buf_in_1 == NULL) {
2280 smd_info->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
2281 if (smd_info->buf_in_1 == NULL)
2282 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002283 smd_info->buf_in_1_size = IN_BUF_SIZE;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002284 kmemleak_not_leak(smd_info->buf_in_1);
2285 }
2286
2287 if (smd_info->write_ptr_1 == NULL) {
2288 smd_info->write_ptr_1 = kzalloc(sizeof(struct diag_request),
2289 GFP_KERNEL);
2290 if (smd_info->write_ptr_1 == NULL)
2291 goto err;
2292 kmemleak_not_leak(smd_info->write_ptr_1);
2293 }
2294
2295 /* The smd data type needs two buffers */
2296 if (smd_info->type == SMD_DATA_TYPE) {
2297 if (smd_info->buf_in_2 == NULL) {
2298 smd_info->buf_in_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
2299 if (smd_info->buf_in_2 == NULL)
2300 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002301 smd_info->buf_in_2_size = IN_BUF_SIZE;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002302 kmemleak_not_leak(smd_info->buf_in_2);
2303 }
2304 if (smd_info->write_ptr_2 == NULL) {
2305 smd_info->write_ptr_2 =
2306 kzalloc(sizeof(struct diag_request),
2307 GFP_KERNEL);
2308 if (smd_info->write_ptr_2 == NULL)
2309 goto err;
2310 kmemleak_not_leak(smd_info->write_ptr_2);
2311 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002312 if (driver->supports_apps_hdlc_encoding) {
2313 /* In support of hdlc encoding */
2314 if (smd_info->buf_in_1_raw == NULL) {
2315 smd_info->buf_in_1_raw = kzalloc(IN_BUF_SIZE,
2316 GFP_KERNEL);
2317 if (smd_info->buf_in_1_raw == NULL)
2318 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002319 smd_info->buf_in_1_raw_size = IN_BUF_SIZE;
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002320 kmemleak_not_leak(smd_info->buf_in_1_raw);
2321 }
2322 if (smd_info->buf_in_2_raw == NULL) {
2323 smd_info->buf_in_2_raw = kzalloc(IN_BUF_SIZE,
2324 GFP_KERNEL);
2325 if (smd_info->buf_in_2_raw == NULL)
2326 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002327 smd_info->buf_in_2_raw_size = IN_BUF_SIZE;
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002328 kmemleak_not_leak(smd_info->buf_in_2_raw);
2329 }
2330 }
2331 }
2332
2333 if (smd_info->type == SMD_CMD_TYPE &&
2334 driver->supports_apps_hdlc_encoding) {
2335 /* In support of hdlc encoding */
2336 if (smd_info->buf_in_1_raw == NULL) {
2337 smd_info->buf_in_1_raw = kzalloc(IN_BUF_SIZE,
2338 GFP_KERNEL);
2339 if (smd_info->buf_in_1_raw == NULL)
2340 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002341 smd_info->buf_in_1_raw_size = IN_BUF_SIZE;
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002342 kmemleak_not_leak(smd_info->buf_in_1_raw);
2343 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002344 }
2345
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002346 /* The smd data type needs separate work queues for reads */
2347 if (type == SMD_DATA_TYPE) {
2348 switch (peripheral) {
2349 case MODEM_DATA:
2350 smd_info->wq = create_singlethread_workqueue(
2351 "diag_modem_data_read_wq");
2352 break;
2353 case LPASS_DATA:
2354 smd_info->wq = create_singlethread_workqueue(
2355 "diag_lpass_data_read_wq");
2356 break;
2357 case WCNSS_DATA:
2358 smd_info->wq = create_singlethread_workqueue(
2359 "diag_wcnss_data_read_wq");
2360 break;
2361 default:
2362 smd_info->wq = NULL;
2363 break;
2364 }
2365 } else {
2366 smd_info->wq = NULL;
2367 }
2368
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002369 INIT_WORK(&(smd_info->diag_read_smd_work), diag_read_smd_work_fn);
2370
2371 /*
2372 * The update function assigned to the diag_notify_update_smd_work
2373 * work_struct is meant to be used for updating that is not to
2374 * be done in the context of the smd notify function. The
2375 * notify_context variable can be used for passing additional
2376 * information to the update function.
2377 */
2378 smd_info->notify_context = 0;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002379 smd_info->general_context = 0;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002380 switch (type) {
2381 case SMD_DATA_TYPE:
2382 case SMD_CMD_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002383 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002384 diag_clean_reg_fn);
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002385 INIT_WORK(&(smd_info->diag_general_smd_work),
2386 diag_cntl_smd_work_fn);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002387 break;
2388 case SMD_CNTL_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002389 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002390 diag_mask_update_fn);
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002391 INIT_WORK(&(smd_info->diag_general_smd_work),
2392 diag_cntl_smd_work_fn);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002393 break;
2394 case SMD_DCI_TYPE:
2395 case SMD_DCI_CMD_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002396 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002397 diag_update_smd_dci_work_fn);
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002398 INIT_WORK(&(smd_info->diag_general_smd_work),
2399 diag_cntl_smd_work_fn);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002400 break;
2401 default:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002402 pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
2403 goto err;
2404 }
2405
2406 /*
2407 * Set function ptr for function to call to process the data that
2408 * was just read from the smd channel
2409 */
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002410 switch (type) {
2411 case SMD_DATA_TYPE:
2412 case SMD_CMD_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002413 smd_info->process_smd_read_data = diag_process_smd_read_data;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002414 break;
2415 case SMD_CNTL_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002416 smd_info->process_smd_read_data =
2417 diag_process_smd_cntl_read_data;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002418 break;
2419 case SMD_DCI_TYPE:
2420 case SMD_DCI_CMD_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002421 smd_info->process_smd_read_data =
2422 diag_process_smd_dci_read_data;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002423 break;
2424 default:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002425 pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
2426 goto err;
2427 }
2428
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002429 smd_info->nrt_lock.enabled = 0;
2430 smd_info->nrt_lock.ref_count = 0;
2431 smd_info->nrt_lock.copy_count = 0;
2432 if (type == SMD_DATA_TYPE) {
2433 spin_lock_init(&smd_info->nrt_lock.read_spinlock);
2434
2435 switch (peripheral) {
2436 case MODEM_DATA:
2437 wake_lock_init(&smd_info->nrt_lock.read_lock,
2438 WAKE_LOCK_SUSPEND, "diag_nrt_modem_read");
2439 break;
2440 case LPASS_DATA:
2441 wake_lock_init(&smd_info->nrt_lock.read_lock,
2442 WAKE_LOCK_SUSPEND, "diag_nrt_lpass_read");
2443 break;
2444 case WCNSS_DATA:
2445 wake_lock_init(&smd_info->nrt_lock.read_lock,
2446 WAKE_LOCK_SUSPEND, "diag_nrt_wcnss_read");
2447 break;
2448 default:
2449 break;
2450 }
2451 }
2452
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002453 return 1;
2454err:
2455 kfree(smd_info->buf_in_1);
2456 kfree(smd_info->buf_in_2);
2457 kfree(smd_info->write_ptr_1);
2458 kfree(smd_info->write_ptr_2);
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002459 kfree(smd_info->buf_in_1_raw);
2460 kfree(smd_info->buf_in_2_raw);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002461
2462 return 0;
2463}
2464
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002465void diagfwd_init(void)
2466{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002467 int success;
2468 int i;
2469
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -08002470 wrap_enabled = 0;
2471 wrap_count = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472 diag_debug_buf_idx = 0;
2473 driver->read_len_legacy = 0;
Dixon Petersonb4618a42012-02-29 18:56:31 -08002474 driver->use_device_tree = has_device_tree();
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002475 driver->real_time_mode = 1;
Dixon Petersona6d98092013-05-16 12:26:26 -07002476 /*
2477 * The number of entries in table of buffers
2478 * should not be any smaller than hdlc poolsize.
2479 */
2480 driver->buf_tbl_size = (buf_tbl_size < driver->poolsize_hdlc) ?
2481 driver->poolsize_hdlc : buf_tbl_size;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002482 driver->supports_separate_cmdrsp = device_supports_separate_cmdrsp();
Dixon Petersonebcfc2b2013-09-19 17:13:09 -07002483 driver->supports_apps_hdlc_encoding = 1;
Dixon Peterson25f042b2013-02-27 13:00:08 -08002484 mutex_init(&driver->diag_hdlc_mutex);
Shalabh Jaina06c6d72012-04-30 13:40:35 -07002485 mutex_init(&driver->diag_cntl_mutex);
Shalabh Jain321c8b52012-02-22 12:37:06 -08002486
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002487 for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002488 driver->separate_cmdrsp[i] = 0;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002489 driver->peripheral_supports_stm[i] = DISABLE_STM;
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07002490 driver->rcvd_feature_mask[i] = 0;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002491 }
2492
2493 for (i = 0; i < NUM_STM_PROCESSORS; i++) {
2494 driver->stm_state_requested[i] = DISABLE_STM;
2495 driver->stm_state[i] = DISABLE_STM;
2496 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002497
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002498 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
2499 success = diag_smd_constructor(&driver->smd_data[i], i,
2500 SMD_DATA_TYPE);
2501 if (!success)
2502 goto err;
2503 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002504
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002505 if (driver->supports_separate_cmdrsp) {
2506 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
2507 success = diag_smd_constructor(&driver->smd_cmd[i], i,
2508 SMD_CMD_TYPE);
2509 if (!success)
2510 goto err;
2511 }
2512 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002513
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002514 if (driver->usb_buf_out == NULL &&
2515 (driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
2516 GFP_KERNEL)) == NULL)
2517 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002518 kmemleak_not_leak(driver->usb_buf_out);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002519 if (driver->hdlc_buf == NULL
2520 && (driver->hdlc_buf = kzalloc(HDLC_MAX, GFP_KERNEL)) == NULL)
2521 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002522 kmemleak_not_leak(driver->hdlc_buf);
Mohit Aggarwala0118b12013-12-05 17:14:35 +05302523 if (driver->user_space_data_buf == NULL)
2524 driver->user_space_data_buf = kzalloc(USER_SPACE_DATA,
2525 GFP_KERNEL);
2526 if (driver->user_space_data_buf == NULL)
2527 goto err;
2528 kmemleak_not_leak(driver->user_space_data_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002529 if (driver->client_map == NULL &&
2530 (driver->client_map = kzalloc
2531 ((driver->num_clients) * sizeof(struct diag_client_map),
2532 GFP_KERNEL)) == NULL)
2533 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002534 kmemleak_not_leak(driver->client_map);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002535 if (driver->buf_tbl == NULL)
Dixon Petersona6d98092013-05-16 12:26:26 -07002536 driver->buf_tbl = kzalloc(driver->buf_tbl_size *
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002537 sizeof(struct diag_write_device), GFP_KERNEL);
2538 if (driver->buf_tbl == NULL)
2539 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002540 kmemleak_not_leak(driver->buf_tbl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002541 if (driver->data_ready == NULL &&
2542 (driver->data_ready = kzalloc(driver->num_clients * sizeof(int)
2543 , GFP_KERNEL)) == NULL)
2544 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002545 kmemleak_not_leak(driver->data_ready);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002546 if (driver->table == NULL &&
Shalabh Jainfe02b0c2012-02-21 14:48:03 -08002547 (driver->table = kzalloc(diag_max_reg*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002548 sizeof(struct diag_master_table),
2549 GFP_KERNEL)) == NULL)
2550 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002551 kmemleak_not_leak(driver->table);
Ashay Jaiswal29620122012-03-21 12:02:36 +05302552
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002553 if (driver->usb_read_ptr == NULL) {
2554 driver->usb_read_ptr = kzalloc(
2555 sizeof(struct diag_request), GFP_KERNEL);
2556 if (driver->usb_read_ptr == NULL)
2557 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002558 kmemleak_not_leak(driver->usb_read_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002559 }
2560 if (driver->pkt_buf == NULL &&
2561 (driver->pkt_buf = kzalloc(PKT_SIZE,
2562 GFP_KERNEL)) == NULL)
2563 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002564 kmemleak_not_leak(driver->pkt_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002565 if (driver->apps_rsp_buf == NULL) {
Shalabh Jain321c8b52012-02-22 12:37:06 -08002566 driver->apps_rsp_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002567 if (driver->apps_rsp_buf == NULL)
2568 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002569 kmemleak_not_leak(driver->apps_rsp_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002570 }
2571 driver->diag_wq = create_singlethread_workqueue("diag_wq");
2572#ifdef CONFIG_DIAG_OVER_USB
Mohit Aggarwalb4465772013-04-18 13:08:07 +05302573 INIT_WORK(&(driver->diag_usb_connect_work),
2574 diag_usb_connect_work_fn);
2575 INIT_WORK(&(driver->diag_usb_disconnect_work),
2576 diag_usb_disconnect_work_fn);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002577 INIT_WORK(&(driver->diag_proc_hdlc_work), diag_process_hdlc_fn);
2578 INIT_WORK(&(driver->diag_read_work), diag_read_work_fn);
2579 driver->legacy_ch = usb_diag_open(DIAG_LEGACY, driver,
2580 diag_usb_legacy_notifier);
2581 if (IS_ERR(driver->legacy_ch)) {
2582 printk(KERN_ERR "Unable to open USB diag legacy channel\n");
2583 goto err;
2584 }
2585#endif
2586 platform_driver_register(&msm_smd_ch1_driver);
2587 platform_driver_register(&diag_smd_lite_driver);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002588
2589 if (driver->supports_separate_cmdrsp) {
2590 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++)
2591 platform_driver_register(&smd_lite_data_cmd_drivers[i]);
2592 }
2593
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002594 return;
2595err:
Dixon Petersond6a20a92012-09-27 15:58:50 -07002596 pr_err("diag: Could not initialize diag buffers");
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002597
2598 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
2599 diag_smd_destructor(&driver->smd_data[i]);
2600
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002601 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++)
2602 diag_smd_destructor(&driver->smd_cmd[i]);
2603
Dixon Petersond6a20a92012-09-27 15:58:50 -07002604 kfree(driver->buf_msg_mask_update);
2605 kfree(driver->buf_log_mask_update);
2606 kfree(driver->buf_event_mask_update);
2607 kfree(driver->usb_buf_out);
2608 kfree(driver->hdlc_buf);
2609 kfree(driver->client_map);
2610 kfree(driver->buf_tbl);
2611 kfree(driver->data_ready);
2612 kfree(driver->table);
2613 kfree(driver->pkt_buf);
Dixon Petersond6a20a92012-09-27 15:58:50 -07002614 kfree(driver->usb_read_ptr);
2615 kfree(driver->apps_rsp_buf);
Mohit Aggarwala0118b12013-12-05 17:14:35 +05302616 kfree(driver->user_space_data_buf);
Dixon Petersond6a20a92012-09-27 15:58:50 -07002617 if (driver->diag_wq)
2618 destroy_workqueue(driver->diag_wq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002619}
2620
2621void diagfwd_exit(void)
2622{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002623 int i;
2624
2625 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
2626 diag_smd_destructor(&driver->smd_data[i]);
2627
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002628#ifdef CONFIG_DIAG_OVER_USB
2629 if (driver->usb_connected)
2630 usb_diag_free_req(driver->legacy_ch);
2631 usb_diag_close(driver->legacy_ch);
2632#endif
2633 platform_driver_unregister(&msm_smd_ch1_driver);
2634 platform_driver_unregister(&diag_smd_lite_driver);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002635
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002636 if (driver->supports_separate_cmdrsp) {
2637 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
2638 diag_smd_destructor(&driver->smd_cmd[i]);
2639 platform_driver_unregister(
2640 &smd_lite_data_cmd_drivers[i]);
2641 }
2642 }
2643
Shalabh Jain321c8b52012-02-22 12:37:06 -08002644 kfree(driver->buf_msg_mask_update);
2645 kfree(driver->buf_log_mask_update);
2646 kfree(driver->buf_event_mask_update);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002647 kfree(driver->usb_buf_out);
2648 kfree(driver->hdlc_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002649 kfree(driver->client_map);
2650 kfree(driver->buf_tbl);
2651 kfree(driver->data_ready);
2652 kfree(driver->table);
2653 kfree(driver->pkt_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002654 kfree(driver->usb_read_ptr);
2655 kfree(driver->apps_rsp_buf);
Mohit Aggarwala0118b12013-12-05 17:14:35 +05302656 kfree(driver->user_space_data_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002657 destroy_workqueue(driver->diag_wq);
2658}