blob: eb8a75b755f714160d577dacfd833f7de38294e5 [file] [log] [blame]
Katish Paran244514d2013-08-01 18:39:31 -07001/* Copyright (c) 2008-2014, 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
Dixon Peterson15a6ecb2013-06-25 12:36:33 -070046#define STM_CMD_VERSION_OFFSET 4
47#define STM_CMD_MASK_OFFSET 5
48#define STM_CMD_DATA_OFFSET 6
49#define STM_CMD_NUM_BYTES 7
50
51#define STM_RSP_VALID_INDEX 7
52#define STM_RSP_SUPPORTED_INDEX 8
53#define STM_RSP_SMD_COMPLY_INDEX 9
54#define STM_RSP_NUM_BYTES 10
55
Dixon Petersondd73a912014-02-13 18:45:11 -080056#define STM_COMMAND_VALID 1
57
Dixon Petersond2309b42013-08-28 21:00:05 -070058#define SMD_DRAIN_BUF_SIZE 4096
59
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060int diag_debug_buf_idx;
61unsigned char diag_debug_buf[1024];
Dixon Petersona6d98092013-05-16 12:26:26 -070062/* Number of entries in table of buffers */
63static unsigned int buf_tbl_size = 10;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064struct diag_master_table entry;
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -080065int wrap_enabled;
66uint16_t wrap_count;
Shalabh Jain6a2ca7c2012-04-10 14:35:15 -070067
Dixon Petersond6a20a92012-09-27 15:58:50 -070068void encode_rsp_and_send(int buf_length)
69{
Dixon Peterson9ce39c62013-02-21 13:00:52 -080070 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
71 struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
Dixon Petersoneecbadb2012-12-10 21:59:28 -080072 struct diag_smd_info *data = &(driver->smd_data[MODEM_DATA]);
Ravi Aravamudhan3db73922013-11-15 12:26:22 -080073 int err;
74 unsigned long flags;
Ravi Aravamudhancc9946862013-07-15 13:31:11 -070075
76 if (buf_length > APPS_BUF_SIZE) {
77 pr_err("diag: In %s, invalid len %d, permissible len %d\n",
78 __func__, buf_length, APPS_BUF_SIZE);
79 return;
80 }
81
Dixon Petersond6a20a92012-09-27 15:58:50 -070082 send.state = DIAG_STATE_START;
83 send.pkt = driver->apps_rsp_buf;
84 send.last = (void *)(driver->apps_rsp_buf + buf_length);
85 send.terminate = 1;
Dixon Peterson66fb11b2012-12-04 20:30:54 -080086 if (!data->in_busy_1) {
Ravi Aravamudhan3db73922013-11-15 12:26:22 -080087 spin_lock_irqsave(&data->in_busy_lock, flags);
Dixon Peterson66fb11b2012-12-04 20:30:54 -080088 enc.dest = data->buf_in_1;
89 enc.dest_last = (void *)(data->buf_in_1 + APPS_BUF_SIZE - 1);
Dixon Petersond6a20a92012-09-27 15:58:50 -070090 diag_hdlc_encode(&send, &enc);
Dixon Peterson66fb11b2012-12-04 20:30:54 -080091 data->write_ptr_1->buf = data->buf_in_1;
92 data->write_ptr_1->length = (int)(enc.dest -
93 (void *)(data->buf_in_1));
94 data->in_busy_1 = 1;
Ravi Aravamudhan3db73922013-11-15 12:26:22 -080095 err = diag_device_write(data->buf_in_1, data->peripheral,
Dixon Peterson66fb11b2012-12-04 20:30:54 -080096 data->write_ptr_1);
Ravi Aravamudhan3db73922013-11-15 12:26:22 -080097 if (err) {
98 pr_err("diag: In %s, Unable to write to device, err: %d\n",
99 __func__, err);
100 data->in_busy_1 = 0;
101 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700102 memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);
Ravi Aravamudhan3db73922013-11-15 12:26:22 -0800103 spin_unlock_irqrestore(&data->in_busy_lock, flags);
Dixon Petersond6a20a92012-09-27 15:58:50 -0700104 }
105}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106
Dixon Petersonb4618a42012-02-29 18:56:31 -0800107/* Determine if this device uses a device tree */
108#ifdef CONFIG_OF
109static int has_device_tree(void)
110{
111 struct device_node *node;
112
113 node = of_find_node_by_path("/");
114 if (node) {
115 of_node_put(node);
116 return 1;
117 }
118 return 0;
119}
120#else
121static int has_device_tree(void)
122{
123 return 0;
124}
125#endif
126
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700127int chk_config_get_id(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128{
Shashank Mittal24771632013-02-06 19:34:57 -0800129 /* For all Fusion targets, Modem will always be present */
Shalabh Jain482bf122011-12-06 03:54:47 -0800130 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
131 return 0;
132
Dixon Petersonb4618a42012-02-29 18:56:31 -0800133 if (driver->use_device_tree) {
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700134 if (machine_is_msm8974())
Dixon Petersonb4618a42012-02-29 18:56:31 -0800135 return MSM8974_TOOLS_ID;
136 else
137 return 0;
138 } else {
139 switch (socinfo_get_msm_cpu()) {
140 case MSM_CPU_8X60:
141 return APQ8060_TOOLS_ID;
142 case MSM_CPU_8960:
Stepan Moskovchenko9c749262012-07-09 19:30:44 -0700143 case MSM_CPU_8960AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800144 return AO8960_TOOLS_ID;
145 case MSM_CPU_8064:
Jay Chokshi11abd8b2012-09-20 14:35:17 -0700146 case MSM_CPU_8064AB:
Shashank Mittal24771632013-02-06 19:34:57 -0800147 case MSM_CPU_8064AA:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800148 return APQ8064_TOOLS_ID;
149 case MSM_CPU_8930:
Stepan Moskovchenko0df9bb22012-07-06 18:19:15 -0700150 case MSM_CPU_8930AA:
Stepan Moskovchenkoecb0d9b2012-10-16 18:35:34 -0700151 case MSM_CPU_8930AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800152 return MSM8930_TOOLS_ID;
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700153 case MSM_CPU_8974:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800154 return MSM8974_TOOLS_ID;
155 case MSM_CPU_8625:
156 return MSM8625_TOOLS_ID;
157 default:
158 return 0;
159 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700160 }
161}
162
163/*
Shalabh Jain321c8b52012-02-22 12:37:06 -0800164 * This will return TRUE for targets which support apps only mode and hence SSR.
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700165 * This applies to 8960 and newer targets.
166 */
167int chk_apps_only(void)
168{
Dixon Petersonb4618a42012-02-29 18:56:31 -0800169 if (driver->use_device_tree)
170 return 1;
171
172 switch (socinfo_get_msm_cpu()) {
173 case MSM_CPU_8960:
Stepan Moskovchenko9c749262012-07-09 19:30:44 -0700174 case MSM_CPU_8960AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800175 case MSM_CPU_8064:
Jay Chokshi11abd8b2012-09-20 14:35:17 -0700176 case MSM_CPU_8064AB:
Shashank Mittal24771632013-02-06 19:34:57 -0800177 case MSM_CPU_8064AA:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800178 case MSM_CPU_8930:
Stepan Moskovchenko0df9bb22012-07-06 18:19:15 -0700179 case MSM_CPU_8930AA:
Stepan Moskovchenkoecb0d9b2012-10-16 18:35:34 -0700180 case MSM_CPU_8930AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800181 case MSM_CPU_8627:
182 case MSM_CPU_9615:
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700183 case MSM_CPU_8974:
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700184 return 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700185 default:
186 return 0;
187 }
188}
189
Shalabh Jain10f5f432012-01-11 11:45:44 +0530190/*
191 * This will return TRUE for targets which support apps as master.
192 * Thus, SW DLOAD and Mode Reset are supported on apps processor.
193 * This applies to 8960 and newer targets.
194 */
195int chk_apps_master(void)
196{
Dixon Petersonb4618a42012-02-29 18:56:31 -0800197 if (driver->use_device_tree)
198 return 1;
Stepan Moskovchenko5b9e7762012-09-21 20:32:17 -0700199 else if (soc_class_is_msm8960() || soc_class_is_msm8930() ||
200 soc_class_is_apq8064() || cpu_is_msm9615())
Dixon Petersonb4618a42012-02-29 18:56:31 -0800201 return 1;
202 else
203 return 0;
204}
205
Dixon Peterson29aebee2012-04-06 12:44:08 -0700206int chk_polling_response(void)
Dixon Petersonb4618a42012-02-29 18:56:31 -0800207{
208 if (!(driver->polling_reg_flag) && chk_apps_master())
209 /*
210 * If the apps processor is master and no other processor
211 * has registered to respond for polling
212 */
213 return 1;
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -0700214 else if (!((driver->smd_data[MODEM_DATA].ch) &&
215 (driver->rcvd_feature_mask[MODEM_DATA])) &&
216 (chk_apps_master()))
Dixon Petersonb4618a42012-02-29 18:56:31 -0800217 /*
218 * If the apps processor is not the master and the modem
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -0700219 * is not up or we did not receive the feature masks from Modem
Dixon Petersonb4618a42012-02-29 18:56:31 -0800220 */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530221 return 1;
222 else
223 return 0;
224}
225
Dixon Peterson743a11e2012-07-30 17:42:20 -0700226/*
227 * This function should be called if you feel that the logging process may
228 * need to be woken up. For instance, if the logging mode is MEMORY_DEVICE MODE
229 * and while trying to read data from a SMD data channel there are no buffers
230 * available to read the data into, then this function should be called to
231 * determine if the logging process needs to be woken up.
232 */
233void chk_logging_wakeup(void)
234{
235 int i;
236
237 /* Find the index of the logging process */
238 for (i = 0; i < driver->num_clients; i++)
239 if (driver->client_map[i].pid ==
240 driver->logging_process_id)
241 break;
242
243 if (i < driver->num_clients) {
244 /* At very high logging rates a race condition can
245 * occur where the buffers containing the data from
246 * an smd channel are all in use, but the data_ready
247 * flag is cleared. In this case, the buffers never
248 * have their data read/logged. Detect and remedy this
249 * situation.
250 */
Shalabh Jain84e30342012-10-16 16:16:08 -0700251 if ((driver->data_ready[i] & USER_SPACE_DATA_TYPE) == 0) {
252 driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
Dixon Peterson743a11e2012-07-30 17:42:20 -0700253 pr_debug("diag: Force wakeup of logging process\n");
254 wake_up_interruptible(&driver->wait_q);
255 }
256 }
257}
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800258int diag_add_hdlc_encoding(struct diag_smd_info *smd_info, void *buf,
259 int total_recd, uint8_t *encode_buf,
260 int *encoded_length)
261{
262 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
263 struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
264 struct data_header {
265 uint8_t control_char;
266 uint8_t version;
267 uint16_t length;
268 };
269 struct data_header *header;
270 int header_size = sizeof(struct data_header);
271 uint8_t *end_control_char;
272 uint8_t *payload;
273 uint8_t *temp_buf;
274 uint8_t *temp_encode_buf;
275 int src_pkt_len;
276 int encoded_pkt_length;
277 int max_size;
278 int total_processed = 0;
279 int bytes_remaining;
280 int success = 1;
281
282 temp_buf = buf;
283 temp_encode_buf = encode_buf;
284 bytes_remaining = *encoded_length;
285 while (total_processed < total_recd) {
286 header = (struct data_header *)temp_buf;
287 /* Perform initial error checking */
288 if (header->control_char != CONTROL_CHAR ||
289 header->version != 1) {
290 success = 0;
291 break;
292 }
293 payload = temp_buf + header_size;
294 end_control_char = payload + header->length;
295 if (*end_control_char != CONTROL_CHAR) {
296 success = 0;
297 break;
298 }
299
300 max_size = 2 * header->length + 3;
301 if (bytes_remaining < max_size) {
302 pr_err("diag: In %s, Not enough room to encode remaining data for peripheral: %d, bytes available: %d, max_size: %d\n",
303 __func__, smd_info->peripheral,
304 bytes_remaining, max_size);
305 success = 0;
306 break;
307 }
308
309 /* Prepare for encoding the data */
310 send.state = DIAG_STATE_START;
311 send.pkt = payload;
312 send.last = (void *)(payload + header->length - 1);
313 send.terminate = 1;
314
315 enc.dest = temp_encode_buf;
316 enc.dest_last = (void *)(temp_encode_buf + max_size);
317 enc.crc = 0;
318 diag_hdlc_encode(&send, &enc);
319
320 /* Prepare for next packet */
321 src_pkt_len = (header_size + header->length + 1);
322 total_processed += src_pkt_len;
323 temp_buf += src_pkt_len;
324
325 encoded_pkt_length = (uint8_t *)enc.dest - temp_encode_buf;
326 bytes_remaining -= encoded_pkt_length;
327 temp_encode_buf = enc.dest;
328 }
329
330 *encoded_length = (int)(temp_encode_buf - encode_buf);
331
332 return success;
333}
334
335static int check_bufsize_for_encoding(struct diag_smd_info *smd_info, void *buf,
336 int total_recd)
337{
338 int buf_size = IN_BUF_SIZE;
339 int max_size = 2 * total_recd + 3;
340 unsigned char *temp_buf;
341
342 if (max_size > IN_BUF_SIZE) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700343 if (max_size > MAX_IN_BUF_SIZE) {
344 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 -0800345 __func__, total_recd, max_size,
346 smd_info->peripheral);
Dixon Petersond2309b42013-08-28 21:00:05 -0700347 max_size = MAX_IN_BUF_SIZE;
348 }
349 if (buf == smd_info->buf_in_1_raw) {
350 /* Only realloc if we need to increase the size */
351 if (smd_info->buf_in_1_size < max_size) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800352 temp_buf = krealloc(smd_info->buf_in_1,
Dixon Petersond2309b42013-08-28 21:00:05 -0700353 max_size, GFP_KERNEL);
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800354 if (temp_buf) {
355 smd_info->buf_in_1 = temp_buf;
Dixon Petersond2309b42013-08-28 21:00:05 -0700356 smd_info->buf_in_1_size = max_size;
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800357 }
358 }
Dixon Petersond2309b42013-08-28 21:00:05 -0700359 buf_size = smd_info->buf_in_1_size;
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800360 } else {
Dixon Petersond2309b42013-08-28 21:00:05 -0700361 /* Only realloc if we need to increase the size */
362 if (smd_info->buf_in_2_size < max_size) {
363 temp_buf = krealloc(smd_info->buf_in_2,
364 max_size, GFP_KERNEL);
365 if (temp_buf) {
366 smd_info->buf_in_2 = temp_buf;
367 smd_info->buf_in_2_size = max_size;
368 }
369 }
370 buf_size = smd_info->buf_in_2_size;
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800371 }
372 }
373
374 return buf_size;
375}
Dixon Peterson743a11e2012-07-30 17:42:20 -0700376
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800377void process_lock_enabling(struct diag_nrt_wake_lock *lock, int real_time)
378{
379 unsigned long read_lock_flags;
380
381 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
382 if (real_time)
383 lock->enabled = 0;
384 else
385 lock->enabled = 1;
386 lock->ref_count = 0;
387 lock->copy_count = 0;
388 wake_unlock(&lock->read_lock);
389 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
390}
391
392void process_lock_on_notify(struct diag_nrt_wake_lock *lock)
393{
394 unsigned long read_lock_flags;
395
396 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
397 /*
398 * Do not work with ref_count here in case
399 * of spurious interrupt
400 */
Mohit Aggarwal912b3812013-08-28 17:52:36 +0530401 if (lock->enabled && !wake_lock_active(&lock->read_lock))
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800402 wake_lock(&lock->read_lock);
403 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
404}
405
406void process_lock_on_read(struct diag_nrt_wake_lock *lock, int pkt_len)
407{
408 unsigned long read_lock_flags;
409
410 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
411 if (lock->enabled) {
412 if (pkt_len > 0) {
413 /*
414 * We have an data that is read that
415 * needs to be processed, make sure the
416 * processor does not go to sleep
417 */
418 lock->ref_count++;
419 if (!wake_lock_active(&lock->read_lock))
420 wake_lock(&lock->read_lock);
421 } else {
422 /*
423 * There was no data associated with the
424 * read from the smd, unlock the wake lock
425 * if it is not needed.
426 */
427 if (lock->ref_count < 1) {
428 if (wake_lock_active(&lock->read_lock))
429 wake_unlock(&lock->read_lock);
430 lock->ref_count = 0;
431 lock->copy_count = 0;
432 }
433 }
434 }
435 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
436}
437
438void process_lock_on_copy(struct diag_nrt_wake_lock *lock)
439{
440 unsigned long read_lock_flags;
441
442 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
443 if (lock->enabled)
444 lock->copy_count++;
445 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
446}
447
448void process_lock_on_copy_complete(struct diag_nrt_wake_lock *lock)
449{
450 unsigned long read_lock_flags;
451
452 spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
453 if (lock->enabled) {
454 lock->ref_count -= lock->copy_count;
455 if (lock->ref_count < 1) {
456 wake_unlock(&lock->read_lock);
457 lock->ref_count = 0;
458 }
459 lock->copy_count = 0;
460 }
461 spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
462}
463
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800464/* Process the data read from the smd data channel */
465int diag_process_smd_read_data(struct diag_smd_info *smd_info, void *buf,
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800466 int total_recd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700467{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700468 struct diag_request *write_ptr_modem = NULL;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800469 int *in_busy_ptr = 0;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800470 int err = 0;
Ravi Aravamudhan3db73922013-11-15 12:26:22 -0800471 unsigned long flags;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800472
473 /*
474 * Do not process data on command channel if the
475 * channel is not designated to do so
476 */
477 if ((smd_info->type == SMD_CMD_TYPE) &&
478 !driver->separate_cmdrsp[smd_info->peripheral]) {
479 /* This print is for debugging */
480 pr_err("diag, In %s, received data on non-designated command channel: %d\n",
481 __func__, smd_info->peripheral);
482 return 0;
483 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700484
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800485 /* If the data is already hdlc encoded */
486 if (!smd_info->encode_hdlc) {
487 if (smd_info->buf_in_1 == buf) {
488 write_ptr_modem = smd_info->write_ptr_1;
489 in_busy_ptr = &smd_info->in_busy_1;
490 } else if (smd_info->buf_in_2 == buf) {
491 write_ptr_modem = smd_info->write_ptr_2;
492 in_busy_ptr = &smd_info->in_busy_2;
493 } else {
494 pr_err("diag: In %s, no match for in_busy_1, peripheral: %d\n",
495 __func__, smd_info->peripheral);
496 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800498 if (write_ptr_modem) {
Ravi Aravamudhan3db73922013-11-15 12:26:22 -0800499 spin_lock_irqsave(&smd_info->in_busy_lock, flags);
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800500 write_ptr_modem->length = total_recd;
501 *in_busy_ptr = 1;
502 err = diag_device_write(buf, smd_info->peripheral,
503 write_ptr_modem);
504 if (err) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800505 pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
506 __func__, err);
507 }
Ravi Aravamudhan3db73922013-11-15 12:26:22 -0800508 spin_unlock_irqrestore(&smd_info->in_busy_lock, flags);
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800509 }
510 } else {
511 /* The data is raw and needs to be hdlc encoded */
512 if (smd_info->buf_in_1_raw == buf) {
513 write_ptr_modem = smd_info->write_ptr_1;
514 in_busy_ptr = &smd_info->in_busy_1;
515 } else if (smd_info->buf_in_2_raw == buf) {
516 write_ptr_modem = smd_info->write_ptr_2;
517 in_busy_ptr = &smd_info->in_busy_2;
518 } else {
519 pr_err("diag: In %s, no match for in_busy_1, peripheral: %d\n",
520 __func__, smd_info->peripheral);
521 }
522
523 if (write_ptr_modem) {
524 int success = 0;
525 int write_length = 0;
526 unsigned char *write_buf = NULL;
527
528 write_length = check_bufsize_for_encoding(smd_info, buf,
529 total_recd);
530 if (write_length) {
531 write_buf = (buf == smd_info->buf_in_1_raw) ?
532 smd_info->buf_in_1 : smd_info->buf_in_2;
533 success = diag_add_hdlc_encoding(smd_info, buf,
534 total_recd, write_buf,
535 &write_length);
Ravi Aravamudhan3db73922013-11-15 12:26:22 -0800536 spin_lock_irqsave(&smd_info->in_busy_lock,
537 flags);
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800538 if (success) {
539 write_ptr_modem->length = write_length;
540 *in_busy_ptr = 1;
541 err = diag_device_write(write_buf,
542 smd_info->peripheral,
543 write_ptr_modem);
544 if (err) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800545 pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
546 __func__, err);
547 }
548 }
Ravi Aravamudhan3db73922013-11-15 12:26:22 -0800549 spin_unlock_irqrestore(&smd_info->in_busy_lock,
550 flags);
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800551 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800552 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800553 }
554
555 return 0;
556}
557
Dixon Petersond2309b42013-08-28 21:00:05 -0700558static int diag_smd_resize_buf(struct diag_smd_info *smd_info, void **buf,
559 unsigned int *buf_size,
560 unsigned int requested_size)
561{
562 int success = 0;
563 void *temp_buf = NULL;
564 unsigned int new_buf_size = requested_size;
565
566 if (!smd_info)
567 return success;
568
569 if (requested_size <= MAX_IN_BUF_SIZE) {
570 pr_debug("diag: In %s, SMD peripheral: %d sending in packets up to %d bytes\n",
571 __func__, smd_info->peripheral, requested_size);
572 } else {
573 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",
574 __func__, smd_info->peripheral, requested_size,
575 MAX_IN_BUF_SIZE);
576 new_buf_size = MAX_IN_BUF_SIZE;
577 }
578
579 /* Only resize if the buffer can be increased in size */
580 if (new_buf_size <= *buf_size) {
581 success = 1;
582 return success;
583 }
584
585 temp_buf = krealloc(*buf, new_buf_size, GFP_KERNEL);
586
587 if (temp_buf) {
588 /* Match the buffer and reset the pointer and size */
589 if (smd_info->encode_hdlc) {
590 /*
591 * This smd channel is supporting HDLC encoding
592 * on the apps
593 */
594 void *temp_hdlc = NULL;
595 if (*buf == smd_info->buf_in_1_raw) {
596 smd_info->buf_in_1_raw = temp_buf;
597 smd_info->buf_in_1_raw_size = new_buf_size;
598 temp_hdlc = krealloc(smd_info->buf_in_1,
599 MAX_IN_BUF_SIZE,
600 GFP_KERNEL);
601 if (temp_hdlc) {
602 smd_info->buf_in_1 = temp_hdlc;
603 smd_info->buf_in_1_size =
604 MAX_IN_BUF_SIZE;
605 }
606 } else if (*buf == smd_info->buf_in_2_raw) {
607 smd_info->buf_in_2_raw = temp_buf;
608 smd_info->buf_in_2_raw_size = new_buf_size;
609 temp_hdlc = krealloc(smd_info->buf_in_2,
610 MAX_IN_BUF_SIZE,
611 GFP_KERNEL);
612 if (temp_hdlc) {
613 smd_info->buf_in_2 = temp_hdlc;
614 smd_info->buf_in_2_size =
615 MAX_IN_BUF_SIZE;
616 }
617 }
618 } else {
619 if (*buf == smd_info->buf_in_1) {
620 smd_info->buf_in_1 = temp_buf;
621 smd_info->buf_in_1_size = new_buf_size;
622 } else if (*buf == smd_info->buf_in_2) {
623 smd_info->buf_in_2 = temp_buf;
624 smd_info->buf_in_2_size = new_buf_size;
625 }
626 }
627 *buf = temp_buf;
628 *buf_size = new_buf_size;
629 success = 1;
630 } else {
631 pr_err_ratelimited("diag: In %s, SMD peripheral: %d. packet size sent: %d, resize to support failed. Data beyond %d will be lost\n",
632 __func__, smd_info->peripheral, requested_size,
633 *buf_size);
634 }
635
636 return success;
637}
638
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800639void diag_smd_send_req(struct diag_smd_info *smd_info)
640{
641 void *buf = NULL, *temp_buf = NULL;
642 int total_recd = 0, r = 0, pkt_len;
643 int loop_count = 0;
644 int notify = 0;
Dixon Petersond2309b42013-08-28 21:00:05 -0700645 int buf_size = 0;
646 int resize_success = 0;
647 int buf_full = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800648
649 if (!smd_info) {
650 pr_err("diag: In %s, no smd info. Not able to read.\n",
651 __func__);
652 return;
653 }
654
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800655 /* Determine the buffer to read the data into. */
656 if (smd_info->type == SMD_DATA_TYPE) {
657 /* If the data is raw and not hdlc encoded */
658 if (smd_info->encode_hdlc) {
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_raw;
Dixon Petersond2309b42013-08-28 21:00:05 -0700661 buf_size = smd_info->buf_in_1_raw_size;
662 } else if (!smd_info->in_busy_2) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800663 buf = smd_info->buf_in_2_raw;
Dixon Petersond2309b42013-08-28 21:00:05 -0700664 buf_size = smd_info->buf_in_2_raw_size;
665 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800666 } else {
Dixon Petersond2309b42013-08-28 21:00:05 -0700667 if (!smd_info->in_busy_1) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800668 buf = smd_info->buf_in_1;
Dixon Petersond2309b42013-08-28 21:00:05 -0700669 buf_size = smd_info->buf_in_1_size;
670 } else if (!smd_info->in_busy_2) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800671 buf = smd_info->buf_in_2;
Dixon Petersond2309b42013-08-28 21:00:05 -0700672 buf_size = smd_info->buf_in_2_size;
673 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800674 }
675 } else if (smd_info->type == SMD_CMD_TYPE) {
676 /* If the data is raw and not hdlc encoded */
677 if (smd_info->encode_hdlc) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700678 if (!smd_info->in_busy_1) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800679 buf = smd_info->buf_in_1_raw;
Dixon Petersond2309b42013-08-28 21:00:05 -0700680 buf_size = smd_info->buf_in_1_raw_size;
681 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800682 } else {
Dixon Petersond2309b42013-08-28 21:00:05 -0700683 if (!smd_info->in_busy_1) {
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800684 buf = smd_info->buf_in_1;
Dixon Petersond2309b42013-08-28 21:00:05 -0700685 buf_size = smd_info->buf_in_1_size;
686 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800687 }
688 } else if (!smd_info->in_busy_1) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800689 buf = smd_info->buf_in_1;
Dixon Petersond2309b42013-08-28 21:00:05 -0700690 buf_size = smd_info->buf_in_1_size;
Dixon Peterson9ce39c62013-02-21 13:00:52 -0800691 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800692
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700693 if (!buf && (smd_info->type == SMD_DCI_TYPE ||
694 smd_info->type == SMD_DCI_CMD_TYPE))
Katish Paran244514d2013-08-01 18:39:31 -0700695 diag_dci_try_deactivate_wakeup_source();
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700696
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800697 if (smd_info->ch && buf) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700698
Katish Paran244514d2013-08-01 18:39:31 -0700699 pkt_len = smd_cur_packet_size(smd_info->ch);
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700700 if (pkt_len == 0 && (smd_info->type == SMD_DCI_TYPE ||
701 smd_info->type == SMD_DCI_CMD_TYPE))
Katish Paran244514d2013-08-01 18:39:31 -0700702 diag_dci_try_deactivate_wakeup_source();
Dixon Petersond2309b42013-08-28 21:00:05 -0700703 if (pkt_len > buf_size)
704 resize_success = diag_smd_resize_buf(smd_info, &buf,
705 &buf_size, pkt_len);
706 temp_buf = buf;
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700707 while (pkt_len && (pkt_len != total_recd)) {
708 loop_count++;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800709 r = smd_read_avail(smd_info->ch);
Dixon Petersond2309b42013-08-28 21:00:05 -0700710 pr_debug("diag: In %s, SMD peripheral: %d, received pkt %d %d\n",
711 __func__, smd_info->peripheral, r, total_recd);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700712 if (!r) {
713 /* Nothing to read from SMD */
714 wait_event(driver->smd_wait_q,
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800715 ((smd_info->ch == 0) ||
716 smd_read_avail(smd_info->ch)));
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700717 /* If the smd channel is open */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800718 if (smd_info->ch) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700719 pr_debug("diag: In %s, SMD peripheral: %d, return from wait_event\n",
720 __func__, smd_info->peripheral);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700721 continue;
722 } else {
Dixon Petersond2309b42013-08-28 21:00:05 -0700723 pr_debug("diag: In %s, SMD peripheral: %d, return from wait_event ch closed\n",
724 __func__, smd_info->peripheral);
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700725 goto fail_return;
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700726 }
727 }
Dixon Petersond2309b42013-08-28 21:00:05 -0700728
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700729 if (pkt_len < r) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700730 pr_err("diag: In %s, SMD peripheral: %d, sending incorrect pkt\n",
731 __func__, smd_info->peripheral);
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700732 goto fail_return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700733 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800734 if (pkt_len > r) {
Dixon Peterson6dba7572013-04-12 18:45:16 -0700735 pr_debug("diag: In %s, SMD sending partial pkt %d %d %d %d %d %d\n",
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800736 __func__, pkt_len, r, total_recd, loop_count,
737 smd_info->peripheral, smd_info->type);
738 }
739
Dixon Petersond2309b42013-08-28 21:00:05 -0700740 /* Protect from going beyond the end of the buffer */
741 if (total_recd < buf_size) {
742 if (total_recd + r > buf_size) {
743 r = buf_size - total_recd;
744 buf_full = 1;
745 }
746
747 total_recd += r;
748
749 /* Keep reading for complete packet */
750 smd_read(smd_info->ch, temp_buf, r);
751 temp_buf += r;
752 } else {
753 /*
754 * This block handles the very rare case of a
755 * packet that is greater in length than what
756 * we can support. In this case, we
757 * incrementally drain the remaining portion
758 * of the packet that will not fit in the
759 * buffer, so that the entire packet is read
760 * from the smd.
761 */
762 int drain_bytes = (r > SMD_DRAIN_BUF_SIZE) ?
763 SMD_DRAIN_BUF_SIZE : r;
764 unsigned char *drain_buf = kzalloc(drain_bytes,
765 GFP_KERNEL);
766 if (drain_buf) {
767 total_recd += drain_bytes;
768 smd_read(smd_info->ch, drain_buf,
769 drain_bytes);
770 kfree(drain_buf);
771 } else {
772 pr_err("diag: In %s, SMD peripheral: %d, unable to allocate drain buffer\n",
773 __func__, smd_info->peripheral);
774 break;
775 }
776 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700777 }
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800778 if (!driver->real_time_mode && smd_info->type == SMD_DATA_TYPE)
779 process_lock_on_read(&smd_info->nrt_lock, pkt_len);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700780
781 if (total_recd > 0) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800782 if (!buf) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700783 pr_err("diag: In %s, SMD peripheral: %d, Out of diagmem for Modem\n",
784 __func__, smd_info->peripheral);
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800785 } else if (smd_info->process_smd_read_data) {
Dixon Petersond2309b42013-08-28 21:00:05 -0700786 /*
787 * If the buffer was totally filled, reset
788 * total_recd appropriately
789 */
790 if (buf_full)
791 total_recd = buf_size;
792
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800793 notify = smd_info->process_smd_read_data(
794 smd_info, buf, total_recd);
795 /* Poll SMD channels to check for data */
796 if (notify)
797 diag_smd_notify(smd_info,
798 SMD_EVENT_DATA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700799 }
800 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800801 } else if (smd_info->ch && !buf &&
Dixon Peterson743a11e2012-07-30 17:42:20 -0700802 (driver->logging_mode == MEMORY_DEVICE_MODE)) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800803 chk_logging_wakeup();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804 }
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700805 return;
806
807fail_return:
808 if (smd_info->type == SMD_DCI_TYPE ||
809 smd_info->type == SMD_DCI_CMD_TYPE)
Katish Paran244514d2013-08-01 18:39:31 -0700810 diag_dci_try_deactivate_wakeup_source();
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -0700811 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700812}
813
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800814void diag_read_smd_work_fn(struct work_struct *work)
815{
816 struct diag_smd_info *smd_info = container_of(work,
817 struct diag_smd_info,
818 diag_read_smd_work);
819 diag_smd_send_req(smd_info);
820}
821
Ravi Aravamudhan3db73922013-11-15 12:26:22 -0800822#ifdef CONFIG_DIAG_OVER_USB
823static int diag_write_to_usb(struct usb_diag_ch *ch,
824 struct diag_request *write_ptr)
825{
826 int err = 0;
827 uint8_t retry_count, max_retries;
828
829 if (!ch || !write_ptr)
830 return -EIO;
831
832 retry_count = 0;
833 max_retries = 3;
834
835 while (retry_count < max_retries) {
836 retry_count++;
837 /* If USB is not connected, don't try to write */
838 if (!driver->usb_connected) {
839 err = -ENODEV;
840 break;
841 }
842 err = usb_diag_write(ch, write_ptr);
843 if (err == -EAGAIN) {
844 /*
845 * USB is not configured. Wait for sometime and
846 * try again. The value 10000 was chosen empirically
847 * as an optimum value for USB to be configured.
848 */
849 usleep_range(10000, 10100);
850 continue;
851 } else {
852 break;
853 }
854 }
855 return err;
856}
857#endif
858
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800859int diag_device_write(void *buf, int data_type, struct diag_request *write_ptr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800861 int i, err = 0, index;
862 index = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700863
864 if (driver->logging_mode == MEMORY_DEVICE_MODE) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800865 if (data_type == APPS_DATA) {
Dixon Petersona6d98092013-05-16 12:26:26 -0700866 for (i = 0; i < driver->buf_tbl_size; i++)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700867 if (driver->buf_tbl[i].length == 0) {
868 driver->buf_tbl[i].buf = buf;
869 driver->buf_tbl[i].length =
870 driver->used;
871#ifdef DIAG_DEBUG
Ravi Aravamudhan910f5662014-01-21 10:07:06 -0800872 pr_debug("diag: ENQUEUE buf ptr and length is %p , %d\n",
873 driver->buf_tbl[i].buf,
874 driver->buf_tbl[i].length);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700875#endif
876 break;
877 }
878 }
Dixon Peterson938f8602012-08-17 20:02:57 -0700879
Shalabh Jain737fca72012-11-14 21:53:43 -0800880#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Shalabh Jainb0037c02013-01-18 12:47:40 -0800881 else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700882 unsigned long flags;
883 int foundIndex = -1;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800884 index = data_type - HSIC_DATA;
885 spin_lock_irqsave(&diag_hsic[index].hsic_spinlock,
886 flags);
887 for (i = 0; i < diag_hsic[index].poolsize_hsic_write;
888 i++) {
889 if (diag_hsic[index].hsic_buf_tbl[i].length
890 == 0) {
891 diag_hsic[index].hsic_buf_tbl[i].buf
892 = buf;
893 diag_hsic[index].hsic_buf_tbl[i].length
894 = diag_bridge[index].write_len;
895 diag_hsic[index].
896 num_hsic_buf_tbl_entries++;
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700897 foundIndex = i;
Dixon Peterson938f8602012-08-17 20:02:57 -0700898 break;
899 }
900 }
Shalabh Jainb0037c02013-01-18 12:47:40 -0800901 spin_unlock_irqrestore(&diag_hsic[index].hsic_spinlock,
902 flags);
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700903 if (foundIndex == -1)
904 err = -1;
905 else
Ravi Aravamudhan910f5662014-01-21 10:07:06 -0800906 pr_debug("diag: ENQUEUE HSIC buf ptr and length is %p , %d, ch %d\n",
907 buf, diag_bridge[index].write_len,
908 index);
Dixon Peterson938f8602012-08-17 20:02:57 -0700909 }
910#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700911 for (i = 0; i < driver->num_clients; i++)
912 if (driver->client_map[i].pid ==
913 driver->logging_process_id)
914 break;
915 if (i < driver->num_clients) {
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700916 pr_debug("diag: wake up logging process\n");
Dixon Petersonbba99ca2013-07-10 17:25:20 -0700917 driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700918 wake_up_interruptible(&driver->wait_q);
919 } else
920 return -EINVAL;
921 } else if (driver->logging_mode == NO_LOGGING_MODE) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800922 if ((data_type >= MODEM_DATA) && (data_type <= WCNSS_DATA)) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800923 driver->smd_data[data_type].in_busy_1 = 0;
924 driver->smd_data[data_type].in_busy_2 = 0;
Dixon Petersonbba99ca2013-07-10 17:25:20 -0700925 queue_work(driver->smd_data[data_type].wq,
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800926 &(driver->smd_data[data_type].
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800927 diag_read_smd_work));
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800928 if (data_type == MODEM_DATA &&
929 driver->separate_cmdrsp[data_type]) {
930 driver->smd_cmd[data_type].in_busy_1 = 0;
931 driver->smd_cmd[data_type].in_busy_2 = 0;
932 queue_work(driver->diag_wq,
933 &(driver->smd_cmd[data_type].
934 diag_read_smd_work));
935 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700936 }
Shalabh Jain482bf122011-12-06 03:54:47 -0800937#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800938 else if (data_type == SDIO_DATA) {
Shalabh Jain482bf122011-12-06 03:54:47 -0800939 driver->in_busy_sdio = 0;
940 queue_work(driver->diag_sdio_wq,
941 &(driver->diag_read_sdio_work));
942 }
943#endif
Shalabh Jain737fca72012-11-14 21:53:43 -0800944#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Shalabh Jainb0037c02013-01-18 12:47:40 -0800945 else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
946 index = data_type - HSIC_DATA;
947 if (diag_hsic[index].hsic_ch)
948 queue_work(diag_bridge[index].wq,
949 &(diag_hsic[index].
950 diag_read_hsic_work));
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700951 }
952#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700953 err = -1;
954 }
955#ifdef CONFIG_DIAG_OVER_USB
956 else if (driver->logging_mode == USB_MODE) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800957 if (data_type == APPS_DATA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700958 driver->write_ptr_svc = (struct diag_request *)
959 (diagmem_alloc(driver, sizeof(struct diag_request),
960 POOL_TYPE_WRITE_STRUCT));
961 if (driver->write_ptr_svc) {
962 driver->write_ptr_svc->length = driver->used;
963 driver->write_ptr_svc->buf = buf;
Ravi Aravamudhan3db73922013-11-15 12:26:22 -0800964 err = diag_write_to_usb(driver->legacy_ch,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965 driver->write_ptr_svc);
Ravi Aravamudhand995a7f2013-07-03 13:06:15 -0700966 /* Free the buffer if write failed */
967 if (err) {
968 diagmem_free(driver,
969 (unsigned char *)driver->
970 write_ptr_svc,
971 POOL_TYPE_WRITE_STRUCT);
972 }
973 } else {
974 err = -ENOMEM;
975 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800976 } else if ((data_type >= MODEM_DATA) &&
977 (data_type <= WCNSS_DATA)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700978 write_ptr->buf = buf;
979#ifdef DIAG_DEBUG
980 printk(KERN_INFO "writing data to USB,"
981 "pkt length %d\n", write_ptr->length);
982 print_hex_dump(KERN_DEBUG, "Written Packet Data to"
983 " USB: ", 16, 1, DUMP_PREFIX_ADDRESS,
984 buf, write_ptr->length, 1);
985#endif /* DIAG DEBUG */
Ravi Aravamudhan3db73922013-11-15 12:26:22 -0800986 err = diag_write_to_usb(driver->legacy_ch, write_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700987 }
988#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800989 else if (data_type == SDIO_DATA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700990 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -0800991 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700992 write_ptr->buf = buf;
993 err = usb_diag_write(driver->mdm_ch, write_ptr);
994 } else
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800995 pr_err("diag: Incorrect sdio data "
996 "while USB write\n");
997 }
998#endif
Shalabh Jain737fca72012-11-14 21:53:43 -0800999#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Shalabh Jainb0037c02013-01-18 12:47:40 -08001000 else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
1001 index = data_type - HSIC_DATA;
1002 if (diag_hsic[index].hsic_device_enabled) {
Dixon Peterson938f8602012-08-17 20:02:57 -07001003 struct diag_request *write_ptr_mdm;
1004 write_ptr_mdm = (struct diag_request *)
1005 diagmem_alloc(driver,
1006 sizeof(struct diag_request),
Shalabh Jainb0037c02013-01-18 12:47:40 -08001007 index +
Dixon Peterson938f8602012-08-17 20:02:57 -07001008 POOL_TYPE_HSIC_WRITE);
1009 if (write_ptr_mdm) {
1010 write_ptr_mdm->buf = buf;
1011 write_ptr_mdm->length =
Shalabh Jainb0037c02013-01-18 12:47:40 -08001012 diag_bridge[index].write_len;
1013 write_ptr_mdm->context = (void *)index;
Shalabh Jain737fca72012-11-14 21:53:43 -08001014 err = usb_diag_write(
Shalabh Jainb0037c02013-01-18 12:47:40 -08001015 diag_bridge[index].ch, write_ptr_mdm);
Dixon Peterson938f8602012-08-17 20:02:57 -07001016 /* Return to the pool immediately */
1017 if (err) {
1018 diagmem_free(driver,
1019 write_ptr_mdm,
Shalabh Jainb0037c02013-01-18 12:47:40 -08001020 index +
Dixon Peterson938f8602012-08-17 20:02:57 -07001021 POOL_TYPE_HSIC_WRITE);
Shalabh Jainb0037c02013-01-18 12:47:40 -08001022 pr_err_ratelimited("diag: HSIC write failure, err: %d, ch %d\n",
1023 err, index);
Dixon Peterson938f8602012-08-17 20:02:57 -07001024 }
1025 } else {
1026 pr_err("diag: allocate write fail\n");
1027 err = -1;
1028 }
1029 } else {
Shalabh Jain737fca72012-11-14 21:53:43 -08001030 pr_err("diag: Incorrect HSIC data "
Dixon Peterson32e70bb2011-12-16 13:26:45 -08001031 "while USB write\n");
Dixon Peterson938f8602012-08-17 20:02:57 -07001032 err = -1;
1033 }
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001034 } else if (data_type == SMUX_DATA) {
Shalabh Jainf7228dc2012-05-23 17:32:05 -07001035 write_ptr->buf = buf;
Shalabh Jain737fca72012-11-14 21:53:43 -08001036 write_ptr->context = (void *)SMUX;
Shalabh Jainf7228dc2012-05-23 17:32:05 -07001037 pr_debug("diag: writing SMUX data\n");
Shalabh Jain737fca72012-11-14 21:53:43 -08001038 err = usb_diag_write(diag_bridge[SMUX].ch,
1039 write_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001040 }
1041#endif
1042 APPEND_DEBUG('d');
1043 }
1044#endif /* DIAG OVER USB */
1045 return err;
1046}
1047
Katish Paran244514d2013-08-01 18:39:31 -07001048void diag_update_pkt_buffer(unsigned char *buf, int type)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001049{
Katish Paran244514d2013-08-01 18:39:31 -07001050 unsigned char *ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051 unsigned char *temp = buf;
Katish Paran244514d2013-08-01 18:39:31 -07001052 unsigned int length;
1053 int *in_busy = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001054
Katish Paran244514d2013-08-01 18:39:31 -07001055 if (!buf) {
1056 pr_err("diag: Invalid buffer in %s\n", __func__);
1057 return;
1058 }
1059
1060 switch (type) {
1061 case PKT_TYPE:
1062 ptr = driver->pkt_buf;
1063 length = driver->pkt_length;
1064 in_busy = &driver->in_busy_pktdata;
1065 break;
1066 case DCI_PKT_TYPE:
1067 ptr = driver->dci_pkt_buf;
1068 length = driver->dci_pkt_length;
1069 in_busy = &driver->in_busy_dcipktdata;
1070 break;
1071 default:
1072 pr_err("diag: Invalid type %d in %s\n", type, __func__);
1073 return;
1074 }
1075
1076 if (!ptr || length == 0) {
1077 pr_err("diag: Invalid ptr %p and length %d in %s",
1078 ptr, length, __func__);
1079 return;
1080 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081 mutex_lock(&driver->diagchar_mutex);
Katish Paran244514d2013-08-01 18:39:31 -07001082 if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, length)) {
1083 memcpy(ptr, temp , length);
1084 *in_busy = 1;
1085 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001086 printk(KERN_CRIT " Not enough buffer space for PKT_RESP\n");
Katish Paran244514d2013-08-01 18:39:31 -07001087 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001088 mutex_unlock(&driver->diagchar_mutex);
1089}
1090
1091void diag_update_userspace_clients(unsigned int type)
1092{
1093 int i;
1094
1095 mutex_lock(&driver->diagchar_mutex);
1096 for (i = 0; i < driver->num_clients; i++)
1097 if (driver->client_map[i].pid != 0)
1098 driver->data_ready[i] |= type;
1099 wake_up_interruptible(&driver->wait_q);
1100 mutex_unlock(&driver->diagchar_mutex);
1101}
1102
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001103void diag_update_sleeping_process(int process_id, int data_type)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001104{
1105 int i;
1106
1107 mutex_lock(&driver->diagchar_mutex);
1108 for (i = 0; i < driver->num_clients; i++)
1109 if (driver->client_map[i].pid == process_id) {
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001110 driver->data_ready[i] |= data_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001111 break;
1112 }
1113 wake_up_interruptible(&driver->wait_q);
1114 mutex_unlock(&driver->diagchar_mutex);
1115}
1116
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001117static int diag_check_mode_reset(unsigned char *buf)
1118{
1119 int is_mode_reset = 0;
1120 if (chk_apps_master() && (int)(*(char *)buf) == MODE_CMD)
1121 if ((int)(*(char *)(buf+1)) == RESET_ID)
1122 is_mode_reset = 1;
1123 return is_mode_reset;
1124}
1125
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001126int diag_send_data(struct diag_master_table entry, unsigned char *buf,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127 int len, int type)
1128{
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001129 int success = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001130 driver->pkt_length = len;
Dixon Petersoncf8b6292013-05-07 19:01:29 -07001131
1132 /* If the process_id corresponds to an apps process */
1133 if (entry.process_id != NON_APPS_PROC) {
1134 /* If the message is to be sent to the apps process */
1135 if (type != MODEM_DATA) {
Katish Paran244514d2013-08-01 18:39:31 -07001136 diag_update_pkt_buffer(buf, PKT_TYPE);
Dixon Petersoncf8b6292013-05-07 19:01:29 -07001137 diag_update_sleeping_process(entry.process_id,
1138 PKT_TYPE);
1139 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 } else {
1141 if (len > 0) {
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001142 if (entry.client_id < NUM_SMD_DATA_CHANNELS) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001143 struct diag_smd_info *smd_info;
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001144 int index = entry.client_id;
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001145 if (!driver->rcvd_feature_mask[
1146 entry.client_id]) {
1147 pr_debug("diag: In %s, feature mask for peripheral: %d not received yet\n",
1148 __func__, entry.client_id);
1149 return 0;
1150 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001151 /*
1152 * Mode reset should work even if
1153 * modem is down
1154 */
1155 if ((index == MODEM_DATA) &&
1156 diag_check_mode_reset(buf)) {
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001157 return 1;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001158 }
1159 smd_info = (driver->separate_cmdrsp[index] &&
1160 index < NUM_SMD_CMD_CHANNELS) ?
1161 &driver->smd_cmd[index] :
1162 &driver->smd_data[index];
1163
1164 if (smd_info->ch) {
1165 mutex_lock(&smd_info->smd_ch_mutex);
1166 smd_write(smd_info->ch, buf, len);
1167 mutex_unlock(&smd_info->smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001168 } else {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001169 pr_err("diag: In %s, smd channel %d not open, peripheral: %d, type: %d\n",
1170 __func__, index,
1171 smd_info->peripheral,
1172 smd_info->type);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001173 }
Shalabh Jainc9f35092011-07-28 18:36:17 -07001174 } else {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001175 pr_alert("diag: In %s, incorrect channel: %d",
1176 __func__, entry.client_id);
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001177 success = 0;
Shalabh Jainc9f35092011-07-28 18:36:17 -07001178 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001179 }
1180 }
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001181
1182 return success;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001183}
1184
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07001185void diag_process_stm_mask(uint8_t cmd, uint8_t data_mask, int data_type,
1186 uint8_t *rsp_supported, uint8_t *rsp_smd_comply)
1187{
1188 int status = 0;
1189 if (data_type >= MODEM_DATA && data_type <= WCNSS_DATA) {
1190 if (driver->peripheral_supports_stm[data_type]) {
1191 status = diag_send_stm_state(
1192 &driver->smd_cntl[data_type], cmd);
1193 if (status == 1)
1194 *rsp_smd_comply |= data_mask;
1195 *rsp_supported |= data_mask;
1196 } else if (driver->smd_cntl[data_type].ch) {
1197 *rsp_smd_comply |= data_mask;
1198 }
1199 if ((*rsp_smd_comply & data_mask) &&
1200 (*rsp_supported & data_mask))
1201 driver->stm_state[data_type] = cmd;
1202
1203 driver->stm_state_requested[data_type] = cmd;
1204 } else if (data_type == APPS_DATA) {
1205 *rsp_supported |= data_mask;
1206 *rsp_smd_comply |= data_mask;
1207 driver->stm_state[data_type] = cmd;
1208 driver->stm_state_requested[data_type] = cmd;
1209 }
1210}
1211
Dixon Petersondd73a912014-02-13 18:45:11 -08001212int diag_process_stm_cmd(unsigned char *buf, unsigned char *dest_buf)
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07001213{
Dixon Petersondd73a912014-02-13 18:45:11 -08001214 uint8_t version, mask, cmd;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07001215 uint8_t rsp_supported = 0;
1216 uint8_t rsp_smd_comply = 0;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07001217 int i;
1218
Dixon Petersondd73a912014-02-13 18:45:11 -08001219 if (!buf || !dest_buf) {
1220 pr_err("diag: Invalid pointers buf: %p, dest_buf %p in %s\n",
1221 buf, dest_buf, __func__);
1222 return -EIO;
1223 }
1224
1225 version = *(buf + STM_CMD_VERSION_OFFSET);
1226 mask = *(buf + STM_CMD_MASK_OFFSET);
1227 cmd = *(buf + STM_CMD_DATA_OFFSET);
1228
1229 /*
1230 * Check if command is valid. If the command is asking for
1231 * status, then the processor mask field is to be ignored.
1232 */
1233 if ((version != 1) || (cmd > STATUS_STM) ||
1234 ((cmd != STATUS_STM) && ((mask == 0) || (0 != (mask >> 4))))) {
1235 /* Command is invalid. Send bad param message response */
1236 dest_buf[0] = BAD_PARAM_RESPONSE_MESSAGE;
1237 for (i = 0; i < STM_CMD_NUM_BYTES; i++)
1238 dest_buf[i+1] = *(buf + i);
1239 return STM_CMD_NUM_BYTES+1;
1240 } else if (cmd == STATUS_STM) {
1241 /*
1242 * Only the status is being queried, so fill in whether diag
1243 * over stm is supported or not
1244 */
1245 for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
1246 if (driver->peripheral_supports_stm[i])
1247 rsp_supported |= 1 << i;
1248
1249 rsp_supported |= DIAG_STM_APPS;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07001250 } else {
1251 if (mask & DIAG_STM_MODEM)
1252 diag_process_stm_mask(cmd, DIAG_STM_MODEM, MODEM_DATA,
1253 &rsp_supported, &rsp_smd_comply);
1254
1255 if (mask & DIAG_STM_LPASS)
1256 diag_process_stm_mask(cmd, DIAG_STM_LPASS, LPASS_DATA,
1257 &rsp_supported, &rsp_smd_comply);
1258
1259 if (mask & DIAG_STM_WCNSS)
1260 diag_process_stm_mask(cmd, DIAG_STM_WCNSS, WCNSS_DATA,
1261 &rsp_supported, &rsp_smd_comply);
1262
1263 if (mask & DIAG_STM_APPS)
1264 diag_process_stm_mask(cmd, DIAG_STM_APPS, APPS_DATA,
1265 &rsp_supported, &rsp_smd_comply);
1266 }
1267
1268 for (i = 0; i < STM_CMD_NUM_BYTES; i++)
Dixon Petersondd73a912014-02-13 18:45:11 -08001269 dest_buf[i] = *(buf + i);
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07001270
Dixon Petersondd73a912014-02-13 18:45:11 -08001271 dest_buf[STM_RSP_VALID_INDEX] = STM_COMMAND_VALID;
1272 dest_buf[STM_RSP_SUPPORTED_INDEX] = rsp_supported;
1273 dest_buf[STM_RSP_SMD_COMPLY_INDEX] = rsp_smd_comply;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07001274
Dixon Petersondd73a912014-02-13 18:45:11 -08001275 return STM_RSP_NUM_BYTES;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07001276}
1277
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07001278int diag_apps_responds()
1279{
1280 if (chk_apps_only()) {
1281 if (driver->smd_data[MODEM_DATA].ch &&
1282 driver->rcvd_feature_mask[MODEM_DATA]) {
1283 return 0;
1284 }
1285 return 1;
1286 }
1287 return 0;
1288}
1289
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001290int diag_process_apps_pkt(unsigned char *buf, int len)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291{
1292 uint16_t subsys_cmd_code;
1293 int subsys_id, ssid_first, ssid_last, ssid_range;
Shalabh Jain3fd986f2012-05-30 18:42:26 -07001294 int packet_type = 1, i, cmd_code;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001295 unsigned char *temp = buf;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001296 int data_type;
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001297 int mask_ret;
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001298 int status = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001299#if defined(CONFIG_DIAG_OVER_USB)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300 unsigned char *ptr;
1301#endif
1302
Dixon Petersond6a20a92012-09-27 15:58:50 -07001303 /* Check if the command is a supported mask command */
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001304 mask_ret = diag_process_apps_masks(buf, len);
1305 if (mask_ret <= 0)
1306 return mask_ret;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001307
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001308 /* Check for registered clients and forward packet to apropriate proc */
1309 cmd_code = (int)(*(char *)buf);
1310 temp++;
1311 subsys_id = (int)(*(char *)temp);
1312 temp++;
1313 subsys_cmd_code = *(uint16_t *)temp;
1314 temp += 2;
1315 data_type = APPS_DATA;
1316 /* Dont send any command other than mode reset */
Shalabh Jain10f5f432012-01-11 11:45:44 +05301317 if (chk_apps_master() && cmd_code == MODE_CMD) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001318 if (subsys_id != RESET_ID)
1319 data_type = MODEM_DATA;
1320 }
1321
1322 pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
Shalabh Jainfe02b0c2012-02-21 14:48:03 -08001323 for (i = 0; i < diag_max_reg; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324 entry = driver->table[i];
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001325 if (entry.process_id != NO_PROCESS) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001326 if (entry.cmd_code == cmd_code && entry.subsys_id ==
1327 subsys_id && entry.cmd_code_lo <=
1328 subsys_cmd_code &&
1329 entry.cmd_code_hi >= subsys_cmd_code) {
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001330 status = diag_send_data(entry, buf, len,
1331 data_type);
1332 if (status)
1333 packet_type = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001334 } else if (entry.cmd_code == 255
1335 && cmd_code == 75) {
1336 if (entry.subsys_id ==
1337 subsys_id &&
1338 entry.cmd_code_lo <=
1339 subsys_cmd_code &&
1340 entry.cmd_code_hi >=
1341 subsys_cmd_code) {
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001342 status = diag_send_data(entry, buf,
1343 len, data_type);
1344 if (status)
1345 packet_type = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001346 }
1347 } else if (entry.cmd_code == 255 &&
1348 entry.subsys_id == 255) {
1349 if (entry.cmd_code_lo <=
1350 cmd_code &&
1351 entry.
1352 cmd_code_hi >= cmd_code) {
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001353 status = diag_send_data(entry, buf, len,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001354 data_type);
Dixon Petersonc4f1ca62013-10-24 21:01:46 -07001355 if (status)
1356 packet_type = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001357 }
1358 }
1359 }
1360 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001361#if defined(CONFIG_DIAG_OVER_USB)
Dixon Petersona2dd7352012-05-21 17:37:10 -07001362 /* Check for the command/respond msg for the maximum packet length */
1363 if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
1364 (*(uint16_t *)(buf+2) == 0x0055)) {
1365 for (i = 0; i < 4; i++)
1366 *(driver->apps_rsp_buf+i) = *(buf+i);
1367 *(uint32_t *)(driver->apps_rsp_buf+4) = PKT_SIZE;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001368 encode_rsp_and_send(7);
Dixon Petersona2dd7352012-05-21 17:37:10 -07001369 return 0;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07001370 } else if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
Dixon Petersondd73a912014-02-13 18:45:11 -08001371 (*(uint16_t *)(buf+2) == DIAG_DIAG_STM)) {
1372 len = diag_process_stm_cmd(buf, driver->apps_rsp_buf);
1373 if (len > 0) {
1374 encode_rsp_and_send(len - 1);
1375 return 0;
1376 }
1377 return len;
Dixon Petersona2dd7352012-05-21 17:37:10 -07001378 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001379 /* Check for Apps Only & get event mask request */
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07001380 else if (diag_apps_responds() && *buf == 0x81) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001381 driver->apps_rsp_buf[0] = 0x81;
1382 driver->apps_rsp_buf[1] = 0x0;
1383 *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
1384 *(uint16_t *)(driver->apps_rsp_buf + 4) = EVENT_LAST_ID + 1;
1385 for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
1386 *(unsigned char *)(driver->apps_rsp_buf + 6 + i) = 0x0;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001387 encode_rsp_and_send(6 + EVENT_LAST_ID/8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001388 return 0;
1389 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001390 /* Get log ID range & Check for Apps Only */
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07001391 else if (diag_apps_responds() && (*buf == 0x73) &&
1392 *(int *)(buf+4) == 1) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393 driver->apps_rsp_buf[0] = 0x73;
1394 *(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
1395 *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success code */
Ravi Aravamudhanbbcb99f2013-11-06 19:43:03 -08001396 *(int *)(driver->apps_rsp_buf + 12) =
1397 LOG_GET_ITEM_NUM(log_code_last_tbl[0]);
1398 *(int *)(driver->apps_rsp_buf + 16) =
1399 LOG_GET_ITEM_NUM(log_code_last_tbl[1]);
1400 *(int *)(driver->apps_rsp_buf + 20) =
1401 LOG_GET_ITEM_NUM(log_code_last_tbl[2]);
1402 *(int *)(driver->apps_rsp_buf + 24) =
1403 LOG_GET_ITEM_NUM(log_code_last_tbl[3]);
1404 *(int *)(driver->apps_rsp_buf + 28) =
1405 LOG_GET_ITEM_NUM(log_code_last_tbl[4]);
1406 *(int *)(driver->apps_rsp_buf + 32) =
1407 LOG_GET_ITEM_NUM(log_code_last_tbl[5]);
1408 *(int *)(driver->apps_rsp_buf + 36) =
1409 LOG_GET_ITEM_NUM(log_code_last_tbl[6]);
1410 *(int *)(driver->apps_rsp_buf + 40) =
1411 LOG_GET_ITEM_NUM(log_code_last_tbl[7]);
1412 *(int *)(driver->apps_rsp_buf + 44) =
1413 LOG_GET_ITEM_NUM(log_code_last_tbl[8]);
1414 *(int *)(driver->apps_rsp_buf + 48) =
1415 LOG_GET_ITEM_NUM(log_code_last_tbl[9]);
1416 *(int *)(driver->apps_rsp_buf + 52) =
1417 LOG_GET_ITEM_NUM(log_code_last_tbl[10]);
1418 *(int *)(driver->apps_rsp_buf + 56) =
1419 LOG_GET_ITEM_NUM(log_code_last_tbl[11]);
1420 *(int *)(driver->apps_rsp_buf + 60) =
1421 LOG_GET_ITEM_NUM(log_code_last_tbl[12]);
1422 *(int *)(driver->apps_rsp_buf + 64) =
1423 LOG_GET_ITEM_NUM(log_code_last_tbl[13]);
1424 *(int *)(driver->apps_rsp_buf + 68) =
1425 LOG_GET_ITEM_NUM(log_code_last_tbl[14]);
1426 *(int *)(driver->apps_rsp_buf + 72) =
1427 LOG_GET_ITEM_NUM(log_code_last_tbl[15]);
Dixon Petersond6a20a92012-09-27 15:58:50 -07001428 encode_rsp_and_send(75);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001429 return 0;
1430 }
1431 /* Respond to Get SSID Range request message */
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07001432 else if (diag_apps_responds() && (*buf == 0x7d) &&
1433 (*(buf+1) == 0x1)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434 driver->apps_rsp_buf[0] = 0x7d;
1435 driver->apps_rsp_buf[1] = 0x1;
1436 driver->apps_rsp_buf[2] = 0x1;
1437 driver->apps_rsp_buf[3] = 0x0;
Shalabh Jain44b79b72012-06-15 13:39:27 -07001438 /* -1 to un-account for OEM SSID range */
1439 *(int *)(driver->apps_rsp_buf + 4) = MSG_MASK_TBL_CNT - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001440 *(uint16_t *)(driver->apps_rsp_buf + 8) = MSG_SSID_0;
1441 *(uint16_t *)(driver->apps_rsp_buf + 10) = MSG_SSID_0_LAST;
1442 *(uint16_t *)(driver->apps_rsp_buf + 12) = MSG_SSID_1;
1443 *(uint16_t *)(driver->apps_rsp_buf + 14) = MSG_SSID_1_LAST;
1444 *(uint16_t *)(driver->apps_rsp_buf + 16) = MSG_SSID_2;
1445 *(uint16_t *)(driver->apps_rsp_buf + 18) = MSG_SSID_2_LAST;
1446 *(uint16_t *)(driver->apps_rsp_buf + 20) = MSG_SSID_3;
1447 *(uint16_t *)(driver->apps_rsp_buf + 22) = MSG_SSID_3_LAST;
1448 *(uint16_t *)(driver->apps_rsp_buf + 24) = MSG_SSID_4;
1449 *(uint16_t *)(driver->apps_rsp_buf + 26) = MSG_SSID_4_LAST;
1450 *(uint16_t *)(driver->apps_rsp_buf + 28) = MSG_SSID_5;
1451 *(uint16_t *)(driver->apps_rsp_buf + 30) = MSG_SSID_5_LAST;
1452 *(uint16_t *)(driver->apps_rsp_buf + 32) = MSG_SSID_6;
1453 *(uint16_t *)(driver->apps_rsp_buf + 34) = MSG_SSID_6_LAST;
1454 *(uint16_t *)(driver->apps_rsp_buf + 36) = MSG_SSID_7;
1455 *(uint16_t *)(driver->apps_rsp_buf + 38) = MSG_SSID_7_LAST;
1456 *(uint16_t *)(driver->apps_rsp_buf + 40) = MSG_SSID_8;
1457 *(uint16_t *)(driver->apps_rsp_buf + 42) = MSG_SSID_8_LAST;
1458 *(uint16_t *)(driver->apps_rsp_buf + 44) = MSG_SSID_9;
1459 *(uint16_t *)(driver->apps_rsp_buf + 46) = MSG_SSID_9_LAST;
1460 *(uint16_t *)(driver->apps_rsp_buf + 48) = MSG_SSID_10;
1461 *(uint16_t *)(driver->apps_rsp_buf + 50) = MSG_SSID_10_LAST;
1462 *(uint16_t *)(driver->apps_rsp_buf + 52) = MSG_SSID_11;
1463 *(uint16_t *)(driver->apps_rsp_buf + 54) = MSG_SSID_11_LAST;
1464 *(uint16_t *)(driver->apps_rsp_buf + 56) = MSG_SSID_12;
1465 *(uint16_t *)(driver->apps_rsp_buf + 58) = MSG_SSID_12_LAST;
1466 *(uint16_t *)(driver->apps_rsp_buf + 60) = MSG_SSID_13;
1467 *(uint16_t *)(driver->apps_rsp_buf + 62) = MSG_SSID_13_LAST;
1468 *(uint16_t *)(driver->apps_rsp_buf + 64) = MSG_SSID_14;
1469 *(uint16_t *)(driver->apps_rsp_buf + 66) = MSG_SSID_14_LAST;
1470 *(uint16_t *)(driver->apps_rsp_buf + 68) = MSG_SSID_15;
1471 *(uint16_t *)(driver->apps_rsp_buf + 70) = MSG_SSID_15_LAST;
1472 *(uint16_t *)(driver->apps_rsp_buf + 72) = MSG_SSID_16;
1473 *(uint16_t *)(driver->apps_rsp_buf + 74) = MSG_SSID_16_LAST;
1474 *(uint16_t *)(driver->apps_rsp_buf + 76) = MSG_SSID_17;
1475 *(uint16_t *)(driver->apps_rsp_buf + 78) = MSG_SSID_17_LAST;
1476 *(uint16_t *)(driver->apps_rsp_buf + 80) = MSG_SSID_18;
1477 *(uint16_t *)(driver->apps_rsp_buf + 82) = MSG_SSID_18_LAST;
Shalabh Jain321c8b52012-02-22 12:37:06 -08001478 *(uint16_t *)(driver->apps_rsp_buf + 84) = MSG_SSID_19;
1479 *(uint16_t *)(driver->apps_rsp_buf + 86) = MSG_SSID_19_LAST;
1480 *(uint16_t *)(driver->apps_rsp_buf + 88) = MSG_SSID_20;
1481 *(uint16_t *)(driver->apps_rsp_buf + 90) = MSG_SSID_20_LAST;
1482 *(uint16_t *)(driver->apps_rsp_buf + 92) = MSG_SSID_21;
1483 *(uint16_t *)(driver->apps_rsp_buf + 94) = MSG_SSID_21_LAST;
1484 *(uint16_t *)(driver->apps_rsp_buf + 96) = MSG_SSID_22;
1485 *(uint16_t *)(driver->apps_rsp_buf + 98) = MSG_SSID_22_LAST;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001486 encode_rsp_and_send(99);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001487 return 0;
1488 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001489 /* Check for Apps Only Respond to Get Subsys Build mask */
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07001490 else if (diag_apps_responds() && (*buf == 0x7d) &&
1491 (*(buf+1) == 0x2)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492 ssid_first = *(uint16_t *)(buf + 2);
1493 ssid_last = *(uint16_t *)(buf + 4);
1494 ssid_range = 4 * (ssid_last - ssid_first + 1);
1495 /* frame response */
1496 driver->apps_rsp_buf[0] = 0x7d;
1497 driver->apps_rsp_buf[1] = 0x2;
1498 *(uint16_t *)(driver->apps_rsp_buf + 2) = ssid_first;
1499 *(uint16_t *)(driver->apps_rsp_buf + 4) = ssid_last;
1500 driver->apps_rsp_buf[6] = 0x1;
1501 driver->apps_rsp_buf[7] = 0x0;
1502 ptr = driver->apps_rsp_buf + 8;
1503 /* bld time masks */
1504 switch (ssid_first) {
1505 case MSG_SSID_0:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001506 if (ssid_range > sizeof(msg_bld_masks_0)) {
1507 pr_warning("diag: truncating ssid range for ssid 0");
1508 ssid_range = sizeof(msg_bld_masks_0);
1509 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001510 for (i = 0; i < ssid_range; i += 4)
1511 *(int *)(ptr + i) = msg_bld_masks_0[i/4];
1512 break;
1513 case MSG_SSID_1:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001514 if (ssid_range > sizeof(msg_bld_masks_1)) {
1515 pr_warning("diag: truncating ssid range for ssid 1");
1516 ssid_range = sizeof(msg_bld_masks_1);
1517 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518 for (i = 0; i < ssid_range; i += 4)
1519 *(int *)(ptr + i) = msg_bld_masks_1[i/4];
1520 break;
1521 case MSG_SSID_2:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001522 if (ssid_range > sizeof(msg_bld_masks_2)) {
1523 pr_warning("diag: truncating ssid range for ssid 2");
1524 ssid_range = sizeof(msg_bld_masks_2);
1525 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001526 for (i = 0; i < ssid_range; i += 4)
1527 *(int *)(ptr + i) = msg_bld_masks_2[i/4];
1528 break;
1529 case MSG_SSID_3:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001530 if (ssid_range > sizeof(msg_bld_masks_3)) {
1531 pr_warning("diag: truncating ssid range for ssid 3");
1532 ssid_range = sizeof(msg_bld_masks_3);
1533 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001534 for (i = 0; i < ssid_range; i += 4)
1535 *(int *)(ptr + i) = msg_bld_masks_3[i/4];
1536 break;
1537 case MSG_SSID_4:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001538 if (ssid_range > sizeof(msg_bld_masks_4)) {
1539 pr_warning("diag: truncating ssid range for ssid 4");
1540 ssid_range = sizeof(msg_bld_masks_4);
1541 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001542 for (i = 0; i < ssid_range; i += 4)
1543 *(int *)(ptr + i) = msg_bld_masks_4[i/4];
1544 break;
1545 case MSG_SSID_5:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001546 if (ssid_range > sizeof(msg_bld_masks_5)) {
1547 pr_warning("diag: truncating ssid range for ssid 5");
1548 ssid_range = sizeof(msg_bld_masks_5);
1549 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001550 for (i = 0; i < ssid_range; i += 4)
1551 *(int *)(ptr + i) = msg_bld_masks_5[i/4];
1552 break;
1553 case MSG_SSID_6:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001554 if (ssid_range > sizeof(msg_bld_masks_6)) {
1555 pr_warning("diag: truncating ssid range for ssid 6");
1556 ssid_range = sizeof(msg_bld_masks_6);
1557 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001558 for (i = 0; i < ssid_range; i += 4)
1559 *(int *)(ptr + i) = msg_bld_masks_6[i/4];
1560 break;
1561 case MSG_SSID_7:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001562 if (ssid_range > sizeof(msg_bld_masks_7)) {
1563 pr_warning("diag: truncating ssid range for ssid 7");
1564 ssid_range = sizeof(msg_bld_masks_7);
1565 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001566 for (i = 0; i < ssid_range; i += 4)
1567 *(int *)(ptr + i) = msg_bld_masks_7[i/4];
1568 break;
1569 case MSG_SSID_8:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001570 if (ssid_range > sizeof(msg_bld_masks_8)) {
1571 pr_warning("diag: truncating ssid range for ssid 8");
1572 ssid_range = sizeof(msg_bld_masks_8);
1573 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001574 for (i = 0; i < ssid_range; i += 4)
1575 *(int *)(ptr + i) = msg_bld_masks_8[i/4];
1576 break;
1577 case MSG_SSID_9:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001578 if (ssid_range > sizeof(msg_bld_masks_9)) {
1579 pr_warning("diag: truncating ssid range for ssid 9");
1580 ssid_range = sizeof(msg_bld_masks_9);
1581 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001582 for (i = 0; i < ssid_range; i += 4)
1583 *(int *)(ptr + i) = msg_bld_masks_9[i/4];
1584 break;
1585 case MSG_SSID_10:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001586 if (ssid_range > sizeof(msg_bld_masks_10)) {
1587 pr_warning("diag: truncating ssid range for ssid 10");
1588 ssid_range = sizeof(msg_bld_masks_10);
1589 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001590 for (i = 0; i < ssid_range; i += 4)
1591 *(int *)(ptr + i) = msg_bld_masks_10[i/4];
1592 break;
1593 case MSG_SSID_11:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001594 if (ssid_range > sizeof(msg_bld_masks_11)) {
1595 pr_warning("diag: truncating ssid range for ssid 11");
1596 ssid_range = sizeof(msg_bld_masks_11);
1597 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001598 for (i = 0; i < ssid_range; i += 4)
1599 *(int *)(ptr + i) = msg_bld_masks_11[i/4];
1600 break;
1601 case MSG_SSID_12:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001602 if (ssid_range > sizeof(msg_bld_masks_12)) {
1603 pr_warning("diag: truncating ssid range for ssid 12");
1604 ssid_range = sizeof(msg_bld_masks_12);
1605 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001606 for (i = 0; i < ssid_range; i += 4)
1607 *(int *)(ptr + i) = msg_bld_masks_12[i/4];
1608 break;
1609 case MSG_SSID_13:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001610 if (ssid_range > sizeof(msg_bld_masks_13)) {
1611 pr_warning("diag: truncating ssid range for ssid 13");
1612 ssid_range = sizeof(msg_bld_masks_13);
1613 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614 for (i = 0; i < ssid_range; i += 4)
1615 *(int *)(ptr + i) = msg_bld_masks_13[i/4];
1616 break;
1617 case MSG_SSID_14:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001618 if (ssid_range > sizeof(msg_bld_masks_14)) {
1619 pr_warning("diag: truncating ssid range for ssid 14");
1620 ssid_range = sizeof(msg_bld_masks_14);
1621 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001622 for (i = 0; i < ssid_range; i += 4)
1623 *(int *)(ptr + i) = msg_bld_masks_14[i/4];
1624 break;
1625 case MSG_SSID_15:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001626 if (ssid_range > sizeof(msg_bld_masks_15)) {
1627 pr_warning("diag: truncating ssid range for ssid 15");
1628 ssid_range = sizeof(msg_bld_masks_15);
1629 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001630 for (i = 0; i < ssid_range; i += 4)
1631 *(int *)(ptr + i) = msg_bld_masks_15[i/4];
1632 break;
1633 case MSG_SSID_16:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001634 if (ssid_range > sizeof(msg_bld_masks_16)) {
1635 pr_warning("diag: truncating ssid range for ssid 16");
1636 ssid_range = sizeof(msg_bld_masks_16);
1637 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001638 for (i = 0; i < ssid_range; i += 4)
1639 *(int *)(ptr + i) = msg_bld_masks_16[i/4];
1640 break;
1641 case MSG_SSID_17:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001642 if (ssid_range > sizeof(msg_bld_masks_17)) {
1643 pr_warning("diag: truncating ssid range for ssid 17");
1644 ssid_range = sizeof(msg_bld_masks_17);
1645 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001646 for (i = 0; i < ssid_range; i += 4)
1647 *(int *)(ptr + i) = msg_bld_masks_17[i/4];
1648 break;
1649 case MSG_SSID_18:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001650 if (ssid_range > sizeof(msg_bld_masks_18)) {
1651 pr_warning("diag: truncating ssid range for ssid 18");
1652 ssid_range = sizeof(msg_bld_masks_18);
1653 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001654 for (i = 0; i < ssid_range; i += 4)
1655 *(int *)(ptr + i) = msg_bld_masks_18[i/4];
1656 break;
Shalabh Jain321c8b52012-02-22 12:37:06 -08001657 case MSG_SSID_19:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001658 if (ssid_range > sizeof(msg_bld_masks_19)) {
1659 pr_warning("diag: truncating ssid range for ssid 19");
1660 ssid_range = sizeof(msg_bld_masks_19);
1661 }
Shalabh Jain321c8b52012-02-22 12:37:06 -08001662 for (i = 0; i < ssid_range; i += 4)
1663 *(int *)(ptr + i) = msg_bld_masks_19[i/4];
1664 break;
1665 case MSG_SSID_20:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001666 if (ssid_range > sizeof(msg_bld_masks_20)) {
1667 pr_warning("diag: truncating ssid range for ssid 20");
1668 ssid_range = sizeof(msg_bld_masks_20);
1669 }
Shalabh Jain321c8b52012-02-22 12:37:06 -08001670 for (i = 0; i < ssid_range; i += 4)
1671 *(int *)(ptr + i) = msg_bld_masks_20[i/4];
1672 break;
1673 case MSG_SSID_21:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001674 if (ssid_range > sizeof(msg_bld_masks_21)) {
1675 pr_warning("diag: truncating ssid range for ssid 21");
1676 ssid_range = sizeof(msg_bld_masks_21);
1677 }
Shalabh Jain321c8b52012-02-22 12:37:06 -08001678 for (i = 0; i < ssid_range; i += 4)
1679 *(int *)(ptr + i) = msg_bld_masks_21[i/4];
1680 break;
1681 case MSG_SSID_22:
Ravi Aravamudhanc839bd72013-04-16 14:32:10 -07001682 if (ssid_range > sizeof(msg_bld_masks_22)) {
1683 pr_warning("diag: truncating ssid range for ssid 22");
1684 ssid_range = sizeof(msg_bld_masks_22);
1685 }
Shalabh Jain321c8b52012-02-22 12:37:06 -08001686 for (i = 0; i < ssid_range; i += 4)
1687 *(int *)(ptr + i) = msg_bld_masks_22[i/4];
1688 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001689 }
Dixon Petersond6a20a92012-09-27 15:58:50 -07001690 encode_rsp_and_send(8 + ssid_range - 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001691 return 0;
1692 }
1693 /* Check for download command */
Shalabh Jain10f5f432012-01-11 11:45:44 +05301694 else if ((cpu_is_msm8x60() || chk_apps_master()) && (*buf == 0x3A)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001695 /* send response back */
1696 driver->apps_rsp_buf[0] = *buf;
Dixon Petersond6a20a92012-09-27 15:58:50 -07001697 encode_rsp_and_send(0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001698 msleep(5000);
1699 /* call download API */
1700 msm_set_restart_mode(RESTART_DLOAD);
1701 printk(KERN_CRIT "diag: download mode set, Rebooting SoC..\n");
1702 kernel_restart(NULL);
1703 /* Not required, represents that command isnt sent to modem */
1704 return 0;
1705 }
Dixon Petersonb46bb992012-01-12 19:16:56 -08001706 /* Check for polling for Apps only DIAG */
1707 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1708 (*(buf+2) == 0x03)) {
Shalabh Jain3d29fc32012-02-09 17:15:59 -08001709 /* If no one has registered for polling */
Dixon Petersonb4618a42012-02-29 18:56:31 -08001710 if (chk_polling_response()) {
Dixon Petersonb46bb992012-01-12 19:16:56 -08001711 /* Respond to polling for Apps only DIAG */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001712 for (i = 0; i < 3; i++)
1713 driver->apps_rsp_buf[i] = *(buf+i);
1714 for (i = 0; i < 13; i++)
1715 driver->apps_rsp_buf[i+3] = 0;
1716
Dixon Petersond6a20a92012-09-27 15:58:50 -07001717 encode_rsp_and_send(15);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718 return 0;
1719 }
Dixon Petersonb46bb992012-01-12 19:16:56 -08001720 }
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -08001721 /* Return the Delayed Response Wrap Status */
1722 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1723 (*(buf+2) == 0x04) && (*(buf+3) == 0x0)) {
1724 memcpy(driver->apps_rsp_buf, buf, 4);
1725 driver->apps_rsp_buf[4] = wrap_enabled;
1726 encode_rsp_and_send(4);
1727 return 0;
1728 }
1729 /* Wrap the Delayed Rsp ID */
1730 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1731 (*(buf+2) == 0x05) && (*(buf+3) == 0x0)) {
1732 wrap_enabled = true;
1733 memcpy(driver->apps_rsp_buf, buf, 4);
1734 driver->apps_rsp_buf[4] = wrap_count;
1735 encode_rsp_and_send(5);
1736 return 0;
1737 }
Dixon Petersonb46bb992012-01-12 19:16:56 -08001738 /* Check for ID for NO MODEM present */
Dixon Petersonb4618a42012-02-29 18:56:31 -08001739 else if (chk_polling_response()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001740 /* respond to 0x0 command */
Dixon Petersonb46bb992012-01-12 19:16:56 -08001741 if (*buf == 0x00) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001742 for (i = 0; i < 55; i++)
1743 driver->apps_rsp_buf[i] = 0;
1744
Dixon Petersond6a20a92012-09-27 15:58:50 -07001745 encode_rsp_and_send(54);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 return 0;
1747 }
1748 /* respond to 0x7c command */
1749 else if (*buf == 0x7c) {
1750 driver->apps_rsp_buf[0] = 0x7c;
1751 for (i = 1; i < 8; i++)
1752 driver->apps_rsp_buf[i] = 0;
1753 /* Tools ID for APQ 8060 */
1754 *(int *)(driver->apps_rsp_buf + 8) =
1755 chk_config_get_id();
1756 *(unsigned char *)(driver->apps_rsp_buf + 12) = '\0';
1757 *(unsigned char *)(driver->apps_rsp_buf + 13) = '\0';
Dixon Petersond6a20a92012-09-27 15:58:50 -07001758 encode_rsp_and_send(13);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001759 return 0;
1760 }
1761 }
1762#endif
Dixon Petersond6a20a92012-09-27 15:58:50 -07001763 return packet_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001764}
1765
1766#ifdef CONFIG_DIAG_OVER_USB
1767void diag_send_error_rsp(int index)
1768{
1769 int i;
Shalabh Jain1fedab92011-12-22 13:15:22 +05301770
Ravi Aravamudhancc9946862013-07-15 13:31:11 -07001771 /* -1 to accomodate the first byte 0x13 */
1772 if (index > APPS_BUF_SIZE-1) {
1773 pr_err("diag: cannot send err rsp, huge length: %d\n", index);
Shalabh Jain1fedab92011-12-22 13:15:22 +05301774 return;
1775 }
Ravi Aravamudhancc9946862013-07-15 13:31:11 -07001776
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001777 driver->apps_rsp_buf[0] = 0x13; /* error code 13 */
1778 for (i = 0; i < index; i++)
1779 driver->apps_rsp_buf[i+1] = *(driver->hdlc_buf+i);
Dixon Petersond6a20a92012-09-27 15:58:50 -07001780 encode_rsp_and_send(index - 3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001781}
1782#else
1783static inline void diag_send_error_rsp(int index) {}
1784#endif
1785
1786void diag_process_hdlc(void *data, unsigned len)
1787{
1788 struct diag_hdlc_decode_type hdlc;
Ravi Aravamudhan5dccccb2013-08-09 16:57:34 -07001789 int ret, type = 0, crc_chk = 0;
Dixon Peterson25f042b2013-02-27 13:00:08 -08001790
1791 mutex_lock(&driver->diag_hdlc_mutex);
1792
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793 pr_debug("diag: HDLC decode fn, len of data %d\n", len);
1794 hdlc.dest_ptr = driver->hdlc_buf;
1795 hdlc.dest_size = USB_MAX_OUT_BUF;
1796 hdlc.src_ptr = data;
1797 hdlc.src_size = len;
1798 hdlc.src_idx = 0;
1799 hdlc.dest_idx = 0;
1800 hdlc.escaping = 0;
1801
1802 ret = diag_hdlc_decode(&hdlc);
Ravi Aravamudhan5dccccb2013-08-09 16:57:34 -07001803 if (ret) {
1804 crc_chk = crc_check(hdlc.dest_ptr, hdlc.dest_idx);
1805 if (crc_chk) {
1806 /* CRC check failed. */
1807 pr_err_ratelimited("diag: In %s, bad CRC. Dropping packet\n",
1808 __func__);
1809 mutex_unlock(&driver->diag_hdlc_mutex);
1810 return;
1811 }
1812 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001813
Dixon Petersonb4f84242013-02-27 18:46:56 -08001814 /*
1815 * If the message is 3 bytes or less in length then the message is
1816 * too short. A message will need 4 bytes minimum, since there are
1817 * 2 bytes for the CRC and 1 byte for the ending 0x7e for the hdlc
1818 * encoding
1819 */
1820 if (hdlc.dest_idx < 4) {
1821 pr_err_ratelimited("diag: In %s, message is too short, len: %d, dest len: %d\n",
1822 __func__, len, hdlc.dest_idx);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001823 mutex_unlock(&driver->diag_hdlc_mutex);
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001824 return;
1825 }
Dixon Petersonb4f84242013-02-27 18:46:56 -08001826
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001827 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001828 type = diag_process_apps_pkt(driver->hdlc_buf,
1829 hdlc.dest_idx - 3);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001830 if (type < 0) {
1831 mutex_unlock(&driver->diag_hdlc_mutex);
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001832 return;
Dixon Peterson25f042b2013-02-27 13:00:08 -08001833 }
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001834 } else if (driver->debug_flag) {
Ravi Aravamudhan5dccccb2013-08-09 16:57:34 -07001835 pr_err("diag: In %s, partial packet received, dropping packet, len: %d\n",
1836 __func__, len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001837 print_hex_dump(KERN_DEBUG, "Dropped Packet Data: ", 16, 1,
1838 DUMP_PREFIX_ADDRESS, data, len, 1);
1839 driver->debug_flag = 0;
1840 }
1841 /* send error responses from APPS for Central Routing */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001842 if (type == 1 && chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001843 diag_send_error_rsp(hdlc.dest_idx);
1844 type = 0;
1845 }
1846 /* implies this packet is NOT meant for apps */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001847 if (!(driver->smd_data[MODEM_DATA].ch) && type == 1) {
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001848 if (chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001849 diag_send_error_rsp(hdlc.dest_idx);
1850 } else { /* APQ 8060, Let Q6 respond */
Dixon Peterson25f042b2013-02-27 13:00:08 -08001851 if (driver->smd_data[LPASS_DATA].ch) {
1852 mutex_lock(&driver->smd_data[LPASS_DATA].
1853 smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001854 smd_write(driver->smd_data[LPASS_DATA].ch,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001855 driver->hdlc_buf,
1856 hdlc.dest_idx - 3);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001857 mutex_unlock(&driver->smd_data[LPASS_DATA].
1858 smd_ch_mutex);
1859 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001860 }
1861 type = 0;
1862 }
1863
1864#ifdef DIAG_DEBUG
1865 pr_debug("diag: hdlc.dest_idx = %d", hdlc.dest_idx);
1866 for (i = 0; i < hdlc.dest_idx; i++)
1867 printk(KERN_DEBUG "\t%x", *(((unsigned char *)
1868 driver->hdlc_buf)+i));
1869#endif /* DIAG DEBUG */
1870 /* ignore 2 bytes for CRC, one for 7E and send */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001871 if ((driver->smd_data[MODEM_DATA].ch) && (ret) && (type) &&
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001872 (hdlc.dest_idx > 3)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001873 APPEND_DEBUG('g');
Dixon Peterson25f042b2013-02-27 13:00:08 -08001874 mutex_lock(&driver->smd_data[MODEM_DATA].smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001875 smd_write(driver->smd_data[MODEM_DATA].ch,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001876 driver->hdlc_buf, hdlc.dest_idx - 3);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001877 mutex_unlock(&driver->smd_data[MODEM_DATA].smd_ch_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001878 APPEND_DEBUG('h');
1879#ifdef DIAG_DEBUG
1880 printk(KERN_INFO "writing data to SMD, pkt length %d\n", len);
1881 print_hex_dump(KERN_DEBUG, "Written Packet Data to SMD: ", 16,
1882 1, DUMP_PREFIX_ADDRESS, data, len, 1);
1883#endif /* DIAG DEBUG */
1884 }
Dixon Peterson25f042b2013-02-27 13:00:08 -08001885 mutex_unlock(&driver->diag_hdlc_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001886}
1887
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001888void diag_reset_smd_data(int queue)
1889{
1890 int i;
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001891 unsigned long flags;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001892
1893 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001894 spin_lock_irqsave(&driver->smd_data[i].in_busy_lock, flags);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001895 driver->smd_data[i].in_busy_1 = 0;
1896 driver->smd_data[i].in_busy_2 = 0;
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001897 spin_unlock_irqrestore(&driver->smd_data[i].in_busy_lock,
1898 flags);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001899 if (queue)
1900 /* Poll SMD data channels to check for data */
Dixon Petersonbba99ca2013-07-10 17:25:20 -07001901 queue_work(driver->smd_data[i].wq,
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001902 &(driver->smd_data[i].diag_read_smd_work));
1903 }
1904
1905 if (driver->supports_separate_cmdrsp) {
1906 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001907 spin_lock_irqsave(&driver->smd_cmd[i].in_busy_lock,
1908 flags);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001909 driver->smd_cmd[i].in_busy_1 = 0;
1910 driver->smd_cmd[i].in_busy_2 = 0;
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001911 spin_unlock_irqrestore(&driver->smd_cmd[i].in_busy_lock,
1912 flags);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001913 if (queue)
1914 /* Poll SMD data channels to check for data */
1915 queue_work(driver->diag_wq,
1916 &(driver->smd_cmd[i].
1917 diag_read_smd_work));
1918 }
1919 }
1920}
1921
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001922#ifdef CONFIG_DIAG_OVER_USB
Shalabh Jain8e9750a2011-09-09 13:06:29 -07001923/* 2+1 for modem ; 2 for LPASS ; 1 for WCNSS */
1924#define N_LEGACY_WRITE (driver->poolsize + 6)
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001925/* Additionally support number of command data and dci channels */
1926#define N_LEGACY_WRITE_CMD ((N_LEGACY_WRITE) + 4)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001927#define N_LEGACY_READ 1
1928
Mohit Aggarwalb4465772013-04-18 13:08:07 +05301929static void diag_usb_connect_work_fn(struct work_struct *w)
1930{
1931 diagfwd_connect();
1932}
1933
1934static void diag_usb_disconnect_work_fn(struct work_struct *w)
1935{
1936 diagfwd_disconnect();
1937}
1938
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001939int diagfwd_connect(void)
1940{
1941 int err;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001942 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001943
1944 printk(KERN_DEBUG "diag: USB connected\n");
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001945 err = usb_diag_alloc_req(driver->legacy_ch,
1946 (driver->supports_separate_cmdrsp ?
1947 N_LEGACY_WRITE_CMD : N_LEGACY_WRITE),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001948 N_LEGACY_READ);
1949 if (err)
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001950 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001951 driver->usb_connected = 1;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001952 diag_reset_smd_data(RESET_AND_QUEUE);
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001953 for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001954 /* Poll SMD CNTL channels to check for data */
1955 diag_smd_notify(&(driver->smd_cntl[i]), SMD_EVENT_DATA);
1956 }
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001957 queue_work(driver->diag_real_time_wq,
1958 &driver->diag_real_time_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001959
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001960 /* Poll USB channel to check for data*/
1961 queue_work(driver->diag_wq, &(driver->diag_read_work));
1962#ifdef CONFIG_DIAG_SDIO_PIPE
1963 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
1964 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1965 diagfwd_connect_sdio();
1966 else
1967 printk(KERN_INFO "diag: No USB MDM ch");
1968 }
1969#endif
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001970
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001971 return 0;
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001972exit:
1973 pr_err("diag: unable to alloc USB req on legacy ch, err: %d", err);
1974 return err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001975}
1976
1977int diagfwd_disconnect(void)
1978{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001979 int i;
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001980 unsigned long flags;
1981 struct diag_smd_info *smd_info = NULL;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001983 printk(KERN_DEBUG "diag: USB disconnected\n");
1984 driver->usb_connected = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001985 driver->debug_flag = 1;
Shalabh Jain69890aa2011-10-10 12:59:16 -07001986 if (driver->logging_mode == USB_MODE) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001987 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001988 smd_info = &driver->smd_data[i];
1989 spin_lock_irqsave(&smd_info->in_busy_lock, flags);
1990 smd_info->in_busy_1 = 1;
1991 smd_info->in_busy_2 = 1;
1992 spin_unlock_irqrestore(&smd_info->in_busy_lock, flags);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001993 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001994
1995 if (driver->supports_separate_cmdrsp) {
1996 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001997 smd_info = &driver->smd_cmd[i];
1998 spin_lock_irqsave(&smd_info->in_busy_lock,
1999 flags);
2000 smd_info->in_busy_1 = 1;
2001 smd_info->in_busy_2 = 1;
2002 spin_unlock_irqrestore(&smd_info->in_busy_lock,
2003 flags);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002004 }
2005 }
Shalabh Jain69890aa2011-10-10 12:59:16 -07002006 }
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07002007 queue_work(driver->diag_real_time_wq,
2008 &driver->diag_real_time_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002009#ifdef CONFIG_DIAG_SDIO_PIPE
2010 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
2011 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
2012 diagfwd_disconnect_sdio();
2013#endif
2014 /* TBD - notify and flow control SMD */
2015 return 0;
2016}
2017
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002018static int diagfwd_check_buf_match(int num_channels,
2019 struct diag_smd_info *data, unsigned char *buf)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002020{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002021 int i;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002022 int found_it = 0;
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08002023 unsigned long flags;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002024
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08002025 spin_lock_irqsave(&data->in_busy_lock, flags);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002026 for (i = 0; i < num_channels; i++) {
2027 if (buf == (void *)data[i].buf_in_1) {
2028 data[i].in_busy_1 = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002029 found_it = 1;
2030 break;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002031 } else if (buf == (void *)data[i].buf_in_2) {
2032 data[i].in_busy_2 = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002033 found_it = 1;
2034 break;
2035 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002036 }
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08002037 spin_unlock_irqrestore(&data->in_busy_lock, flags);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002038
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002039 if (found_it) {
2040 if (data[i].type == SMD_DATA_TYPE)
2041 queue_work(data[i].wq,
2042 &(data[i].diag_read_smd_work));
2043 else
2044 queue_work(driver->diag_wq,
2045 &(data[i].diag_read_smd_work));
2046 }
2047
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002048 return found_it;
2049}
2050
2051int diagfwd_write_complete(struct diag_request *diag_write_ptr)
2052{
2053 unsigned char *buf = diag_write_ptr->buf;
2054 int found_it = 0;
2055
2056 /* Determine if the write complete is for data from modem/apps/q6 */
2057 found_it = diagfwd_check_buf_match(NUM_SMD_DATA_CHANNELS,
2058 driver->smd_data, buf);
2059
2060 if (!found_it && driver->supports_separate_cmdrsp)
2061 found_it = diagfwd_check_buf_match(NUM_SMD_CMD_CHANNELS,
2062 driver->smd_cmd, buf);
2063
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002064#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002065 if (!found_it) {
2066 if (buf == (void *)driver->buf_in_sdio) {
2067 if (machine_is_msm8x60_fusion() ||
2068 machine_is_msm8x60_fusn_ffa())
2069 diagfwd_write_complete_sdio();
2070 else
2071 pr_err("diag: Incorrect buffer pointer while WRITE");
2072 found_it = 1;
2073 }
2074 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002075#endif
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002076 if (!found_it) {
Ravi Aravamudhand995a7f2013-07-03 13:06:15 -07002077 if (driver->logging_mode != USB_MODE)
2078 pr_debug("diag: freeing buffer when not in usb mode\n");
2079
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002080 diagmem_free(driver, (unsigned char *)buf,
2081 POOL_TYPE_HDLC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002082 diagmem_free(driver, (unsigned char *)diag_write_ptr,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002083 POOL_TYPE_WRITE_STRUCT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002084 }
2085 return 0;
2086}
2087
2088int diagfwd_read_complete(struct diag_request *diag_read_ptr)
2089{
2090 int status = diag_read_ptr->status;
2091 unsigned char *buf = diag_read_ptr->buf;
2092
2093 /* Determine if the read complete is for data on legacy/mdm ch */
2094 if (buf == (void *)driver->usb_buf_out) {
2095 driver->read_len_legacy = diag_read_ptr->actual;
2096 APPEND_DEBUG('s');
2097#ifdef DIAG_DEBUG
2098 printk(KERN_INFO "read data from USB, pkt length %d",
2099 diag_read_ptr->actual);
2100 print_hex_dump(KERN_DEBUG, "Read Packet Data from USB: ", 16, 1,
2101 DUMP_PREFIX_ADDRESS, diag_read_ptr->buf,
2102 diag_read_ptr->actual, 1);
2103#endif /* DIAG DEBUG */
2104 if (driver->logging_mode == USB_MODE) {
2105 if (status != -ECONNRESET && status != -ESHUTDOWN)
2106 queue_work(driver->diag_wq,
2107 &(driver->diag_proc_hdlc_work));
2108 else
2109 queue_work(driver->diag_wq,
2110 &(driver->diag_read_work));
2111 }
2112 }
2113#ifdef CONFIG_DIAG_SDIO_PIPE
2114 else if (buf == (void *)driver->usb_buf_mdm_out) {
2115 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -08002116 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002117 driver->read_len_mdm = diag_read_ptr->actual;
2118 diagfwd_read_complete_sdio();
2119 } else
2120 pr_err("diag: Incorrect buffer pointer while READ");
2121 }
2122#endif
2123 else
2124 printk(KERN_ERR "diag: Unknown buffer ptr from USB");
2125
2126 return 0;
2127}
2128
2129void diag_read_work_fn(struct work_struct *work)
2130{
2131 APPEND_DEBUG('d');
2132 driver->usb_read_ptr->buf = driver->usb_buf_out;
2133 driver->usb_read_ptr->length = USB_MAX_OUT_BUF;
2134 usb_diag_read(driver->legacy_ch, driver->usb_read_ptr);
2135 APPEND_DEBUG('e');
2136}
2137
2138void diag_process_hdlc_fn(struct work_struct *work)
2139{
2140 APPEND_DEBUG('D');
2141 diag_process_hdlc(driver->usb_buf_out, driver->read_len_legacy);
2142 diag_read_work_fn(work);
2143 APPEND_DEBUG('E');
2144}
2145
2146void diag_usb_legacy_notifier(void *priv, unsigned event,
2147 struct diag_request *d_req)
2148{
2149 switch (event) {
2150 case USB_DIAG_CONNECT:
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08002151 queue_work(driver->diag_usb_wq,
Mohit Aggarwalb4465772013-04-18 13:08:07 +05302152 &driver->diag_usb_connect_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002153 break;
2154 case USB_DIAG_DISCONNECT:
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08002155 queue_work(driver->diag_usb_wq,
Mohit Aggarwalb4465772013-04-18 13:08:07 +05302156 &driver->diag_usb_disconnect_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002157 break;
2158 case USB_DIAG_READ_DONE:
2159 diagfwd_read_complete(d_req);
2160 break;
2161 case USB_DIAG_WRITE_DONE:
2162 diagfwd_write_complete(d_req);
2163 break;
2164 default:
2165 printk(KERN_ERR "Unknown event from USB diag\n");
2166 break;
2167 }
2168}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002169#endif /* DIAG OVER USB */
2170
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002171void diag_smd_notify(void *ctxt, unsigned event)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002172{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002173 struct diag_smd_info *smd_info = (struct diag_smd_info *)ctxt;
2174 if (!smd_info)
Shalabh Jaineefee052011-11-08 23:46:03 -08002175 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002176
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002177 if (event == SMD_EVENT_CLOSE) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002178 smd_info->ch = 0;
Shalabh Jainc70b3b62012-08-31 19:11:20 -07002179 wake_up(&driver->smd_wait_q);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002180 if (smd_info->type == SMD_DATA_TYPE) {
2181 smd_info->notify_context = event;
2182 queue_work(driver->diag_cntl_wq,
2183 &(smd_info->diag_notify_update_smd_work));
2184 } else if (smd_info->type == SMD_DCI_TYPE) {
2185 /* Notify the clients of the close */
2186 diag_dci_notify_client(smd_info->peripheral_mask,
2187 DIAG_STATUS_CLOSED);
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002188 } else if (smd_info->type == SMD_CNTL_TYPE) {
2189 diag_cntl_stm_notify(smd_info,
2190 CLEAR_PERIPHERAL_STM_STATE);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002191 }
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002192 return;
2193 } else if (event == SMD_EVENT_OPEN) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002194 if (smd_info->ch_save)
2195 smd_info->ch = smd_info->ch_save;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002196
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002197 if (smd_info->type == SMD_CNTL_TYPE) {
2198 smd_info->notify_context = event;
2199 queue_work(driver->diag_cntl_wq,
2200 &(smd_info->diag_notify_update_smd_work));
2201 } else if (smd_info->type == SMD_DCI_TYPE) {
2202 smd_info->notify_context = event;
2203 queue_work(driver->diag_dci_wq,
2204 &(smd_info->diag_notify_update_smd_work));
2205 /* Notify the clients of the open */
2206 diag_dci_notify_client(smd_info->peripheral_mask,
2207 DIAG_STATUS_OPEN);
2208 }
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002209 } else if (event == SMD_EVENT_DATA && !driver->real_time_mode &&
2210 smd_info->type == SMD_DATA_TYPE) {
2211 process_lock_on_notify(&smd_info->nrt_lock);
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002212 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002213
Shalabh Jainc70b3b62012-08-31 19:11:20 -07002214 wake_up(&driver->smd_wait_q);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002215
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002216 if (smd_info->type == SMD_DCI_TYPE ||
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07002217 smd_info->type == SMD_DCI_CMD_TYPE) {
2218 if (event == SMD_EVENT_DATA)
Katish Paran244514d2013-08-01 18:39:31 -07002219 diag_dci_try_activate_wakeup_source();
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002220 queue_work(driver->diag_dci_wq,
2221 &(smd_info->diag_read_smd_work));
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002222 } else if (smd_info->type == SMD_DATA_TYPE) {
2223 queue_work(smd_info->wq,
2224 &(smd_info->diag_read_smd_work));
2225 } else {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002226 queue_work(driver->diag_wq, &(smd_info->diag_read_smd_work));
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002227 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002228}
2229
2230static int diag_smd_probe(struct platform_device *pdev)
2231{
2232 int r = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002233 int index = -1;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002234 const char *channel_name = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002235
Shalabh Jaineefee052011-11-08 23:46:03 -08002236 if (pdev->id == SMD_APPS_MODEM) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002237 index = MODEM_DATA;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002238 channel_name = "DIAG";
Shalabh Jaineefee052011-11-08 23:46:03 -08002239 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002240#if defined(CONFIG_MSM_N_WAY_SMD)
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002241 else if (pdev->id == SMD_APPS_QDSP) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002242 index = LPASS_DATA;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002243 channel_name = "DIAG";
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002244 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002245#endif
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002246 else if (pdev->id == SMD_APPS_WCNSS) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002247 index = WCNSS_DATA;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002248 channel_name = "APPS_RIVA_DATA";
2249 }
2250
2251 if (index != -1) {
2252 r = smd_named_open_on_edge(channel_name,
2253 pdev->id,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002254 &driver->smd_data[index].ch,
2255 &driver->smd_data[index],
2256 diag_smd_notify);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002257 driver->smd_data[index].ch_save = driver->smd_data[index].ch;
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08002258 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002259
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002260 pm_runtime_set_active(&pdev->dev);
2261 pm_runtime_enable(&pdev->dev);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002262 pr_debug("diag: In %s, open SMD port, Id = %d, r = %d\n",
2263 __func__, pdev->id, r);
2264
2265 return 0;
2266}
2267
2268static int diag_smd_cmd_probe(struct platform_device *pdev)
2269{
2270 int r = 0;
2271 int index = -1;
2272 const char *channel_name = NULL;
2273
2274 if (!driver->supports_separate_cmdrsp)
2275 return 0;
2276
2277 if (pdev->id == SMD_APPS_MODEM) {
2278 index = MODEM_DATA;
2279 channel_name = "DIAG_CMD";
2280 }
2281
2282 if (index != -1) {
2283 r = smd_named_open_on_edge(channel_name,
2284 pdev->id,
2285 &driver->smd_cmd[index].ch,
2286 &driver->smd_cmd[index],
2287 diag_smd_notify);
2288 driver->smd_cmd[index].ch_save =
2289 driver->smd_cmd[index].ch;
2290 }
2291
2292 pr_debug("diag: In %s, open SMD CMD port, Id = %d, r = %d\n",
2293 __func__, pdev->id, r);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002294
2295 return 0;
2296}
2297
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002298static int diag_smd_runtime_suspend(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002299{
2300 dev_dbg(dev, "pm_runtime: suspending...\n");
2301 return 0;
2302}
2303
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002304static int diag_smd_runtime_resume(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002305{
2306 dev_dbg(dev, "pm_runtime: resuming...\n");
2307 return 0;
2308}
2309
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002310static const struct dev_pm_ops diag_smd_dev_pm_ops = {
2311 .runtime_suspend = diag_smd_runtime_suspend,
2312 .runtime_resume = diag_smd_runtime_resume,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002313};
2314
2315static struct platform_driver msm_smd_ch1_driver = {
2316
2317 .probe = diag_smd_probe,
2318 .driver = {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002319 .name = "DIAG",
2320 .owner = THIS_MODULE,
2321 .pm = &diag_smd_dev_pm_ops,
2322 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002323};
2324
2325static struct platform_driver diag_smd_lite_driver = {
2326
2327 .probe = diag_smd_probe,
2328 .driver = {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002329 .name = "APPS_RIVA_DATA",
2330 .owner = THIS_MODULE,
2331 .pm = &diag_smd_dev_pm_ops,
2332 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002333};
2334
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002335static struct platform_driver
2336 smd_lite_data_cmd_drivers[NUM_SMD_CMD_CHANNELS] = {
2337 {
2338 /* Modem data */
2339 .probe = diag_smd_cmd_probe,
2340 .driver = {
2341 .name = "DIAG_CMD",
2342 .owner = THIS_MODULE,
2343 .pm = &diag_smd_dev_pm_ops,
2344 },
2345 }
2346};
2347
2348int device_supports_separate_cmdrsp(void)
2349{
2350 return driver->use_device_tree;
2351}
2352
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002353void diag_smd_destructor(struct diag_smd_info *smd_info)
2354{
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002355 if (smd_info->type == SMD_DATA_TYPE) {
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002356 wake_lock_destroy(&smd_info->nrt_lock.read_lock);
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002357 destroy_workqueue(smd_info->wq);
2358 }
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002359
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002360 if (smd_info->ch)
2361 smd_close(smd_info->ch);
2362
2363 smd_info->ch = 0;
2364 smd_info->ch_save = 0;
2365 kfree(smd_info->buf_in_1);
2366 kfree(smd_info->buf_in_2);
2367 kfree(smd_info->write_ptr_1);
2368 kfree(smd_info->write_ptr_2);
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002369 kfree(smd_info->buf_in_1_raw);
2370 kfree(smd_info->buf_in_2_raw);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002371}
2372
2373int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral,
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002374 int type)
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002375{
2376 smd_info->peripheral = peripheral;
2377 smd_info->type = type;
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002378 smd_info->encode_hdlc = 0;
Dixon Peterson25f042b2013-02-27 13:00:08 -08002379 mutex_init(&smd_info->smd_ch_mutex);
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08002380 spin_lock_init(&smd_info->in_busy_lock);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08002381
2382 switch (peripheral) {
2383 case MODEM_DATA:
2384 smd_info->peripheral_mask = DIAG_CON_MPSS;
2385 break;
2386 case LPASS_DATA:
2387 smd_info->peripheral_mask = DIAG_CON_LPASS;
2388 break;
2389 case WCNSS_DATA:
2390 smd_info->peripheral_mask = DIAG_CON_WCNSS;
2391 break;
2392 default:
2393 pr_err("diag: In %s, unknown peripheral, peripheral: %d\n",
2394 __func__, peripheral);
2395 goto err;
2396 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002397
2398 smd_info->ch = 0;
2399 smd_info->ch_save = 0;
2400
2401 if (smd_info->buf_in_1 == NULL) {
2402 smd_info->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
2403 if (smd_info->buf_in_1 == NULL)
2404 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002405 smd_info->buf_in_1_size = IN_BUF_SIZE;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002406 kmemleak_not_leak(smd_info->buf_in_1);
2407 }
2408
2409 if (smd_info->write_ptr_1 == NULL) {
2410 smd_info->write_ptr_1 = kzalloc(sizeof(struct diag_request),
2411 GFP_KERNEL);
2412 if (smd_info->write_ptr_1 == NULL)
2413 goto err;
2414 kmemleak_not_leak(smd_info->write_ptr_1);
2415 }
2416
2417 /* The smd data type needs two buffers */
2418 if (smd_info->type == SMD_DATA_TYPE) {
2419 if (smd_info->buf_in_2 == NULL) {
2420 smd_info->buf_in_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
2421 if (smd_info->buf_in_2 == NULL)
2422 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002423 smd_info->buf_in_2_size = IN_BUF_SIZE;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002424 kmemleak_not_leak(smd_info->buf_in_2);
2425 }
2426 if (smd_info->write_ptr_2 == NULL) {
2427 smd_info->write_ptr_2 =
2428 kzalloc(sizeof(struct diag_request),
2429 GFP_KERNEL);
2430 if (smd_info->write_ptr_2 == NULL)
2431 goto err;
2432 kmemleak_not_leak(smd_info->write_ptr_2);
2433 }
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002434 if (driver->supports_apps_hdlc_encoding) {
2435 /* In support of hdlc encoding */
2436 if (smd_info->buf_in_1_raw == NULL) {
2437 smd_info->buf_in_1_raw = kzalloc(IN_BUF_SIZE,
2438 GFP_KERNEL);
2439 if (smd_info->buf_in_1_raw == NULL)
2440 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002441 smd_info->buf_in_1_raw_size = IN_BUF_SIZE;
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002442 kmemleak_not_leak(smd_info->buf_in_1_raw);
2443 }
2444 if (smd_info->buf_in_2_raw == NULL) {
2445 smd_info->buf_in_2_raw = kzalloc(IN_BUF_SIZE,
2446 GFP_KERNEL);
2447 if (smd_info->buf_in_2_raw == NULL)
2448 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002449 smd_info->buf_in_2_raw_size = IN_BUF_SIZE;
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002450 kmemleak_not_leak(smd_info->buf_in_2_raw);
2451 }
2452 }
2453 }
2454
2455 if (smd_info->type == SMD_CMD_TYPE &&
2456 driver->supports_apps_hdlc_encoding) {
2457 /* In support of hdlc encoding */
2458 if (smd_info->buf_in_1_raw == NULL) {
2459 smd_info->buf_in_1_raw = kzalloc(IN_BUF_SIZE,
2460 GFP_KERNEL);
2461 if (smd_info->buf_in_1_raw == NULL)
2462 goto err;
Dixon Petersond2309b42013-08-28 21:00:05 -07002463 smd_info->buf_in_1_raw_size = IN_BUF_SIZE;
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002464 kmemleak_not_leak(smd_info->buf_in_1_raw);
2465 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002466 }
2467
Dixon Petersonbba99ca2013-07-10 17:25:20 -07002468 /* The smd data type needs separate work queues for reads */
2469 if (type == SMD_DATA_TYPE) {
2470 switch (peripheral) {
2471 case MODEM_DATA:
2472 smd_info->wq = create_singlethread_workqueue(
2473 "diag_modem_data_read_wq");
2474 break;
2475 case LPASS_DATA:
2476 smd_info->wq = create_singlethread_workqueue(
2477 "diag_lpass_data_read_wq");
2478 break;
2479 case WCNSS_DATA:
2480 smd_info->wq = create_singlethread_workqueue(
2481 "diag_wcnss_data_read_wq");
2482 break;
2483 default:
2484 smd_info->wq = NULL;
2485 break;
2486 }
2487 } else {
2488 smd_info->wq = NULL;
2489 }
2490
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002491 INIT_WORK(&(smd_info->diag_read_smd_work), diag_read_smd_work_fn);
2492
2493 /*
2494 * The update function assigned to the diag_notify_update_smd_work
2495 * work_struct is meant to be used for updating that is not to
2496 * be done in the context of the smd notify function. The
2497 * notify_context variable can be used for passing additional
2498 * information to the update function.
2499 */
2500 smd_info->notify_context = 0;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002501 smd_info->general_context = 0;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002502 switch (type) {
2503 case SMD_DATA_TYPE:
2504 case SMD_CMD_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002505 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002506 diag_clean_reg_fn);
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002507 INIT_WORK(&(smd_info->diag_general_smd_work),
2508 diag_cntl_smd_work_fn);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002509 break;
2510 case SMD_CNTL_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002511 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002512 diag_mask_update_fn);
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002513 INIT_WORK(&(smd_info->diag_general_smd_work),
2514 diag_cntl_smd_work_fn);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002515 break;
2516 case SMD_DCI_TYPE:
2517 case SMD_DCI_CMD_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002518 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002519 diag_update_smd_dci_work_fn);
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002520 INIT_WORK(&(smd_info->diag_general_smd_work),
2521 diag_cntl_smd_work_fn);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002522 break;
2523 default:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002524 pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
2525 goto err;
2526 }
2527
2528 /*
2529 * Set function ptr for function to call to process the data that
2530 * was just read from the smd channel
2531 */
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002532 switch (type) {
2533 case SMD_DATA_TYPE:
2534 case SMD_CMD_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002535 smd_info->process_smd_read_data = diag_process_smd_read_data;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002536 break;
2537 case SMD_CNTL_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002538 smd_info->process_smd_read_data =
2539 diag_process_smd_cntl_read_data;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002540 break;
2541 case SMD_DCI_TYPE:
2542 case SMD_DCI_CMD_TYPE:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002543 smd_info->process_smd_read_data =
2544 diag_process_smd_dci_read_data;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002545 break;
2546 default:
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002547 pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
2548 goto err;
2549 }
2550
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002551 smd_info->nrt_lock.enabled = 0;
2552 smd_info->nrt_lock.ref_count = 0;
2553 smd_info->nrt_lock.copy_count = 0;
2554 if (type == SMD_DATA_TYPE) {
2555 spin_lock_init(&smd_info->nrt_lock.read_spinlock);
2556
2557 switch (peripheral) {
2558 case MODEM_DATA:
2559 wake_lock_init(&smd_info->nrt_lock.read_lock,
2560 WAKE_LOCK_SUSPEND, "diag_nrt_modem_read");
2561 break;
2562 case LPASS_DATA:
2563 wake_lock_init(&smd_info->nrt_lock.read_lock,
2564 WAKE_LOCK_SUSPEND, "diag_nrt_lpass_read");
2565 break;
2566 case WCNSS_DATA:
2567 wake_lock_init(&smd_info->nrt_lock.read_lock,
2568 WAKE_LOCK_SUSPEND, "diag_nrt_wcnss_read");
2569 break;
2570 default:
2571 break;
2572 }
2573 }
2574
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002575 return 1;
2576err:
2577 kfree(smd_info->buf_in_1);
2578 kfree(smd_info->buf_in_2);
2579 kfree(smd_info->write_ptr_1);
2580 kfree(smd_info->write_ptr_2);
Dixon Peterson9ce39c62013-02-21 13:00:52 -08002581 kfree(smd_info->buf_in_1_raw);
2582 kfree(smd_info->buf_in_2_raw);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002583
2584 return 0;
2585}
2586
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002587void diagfwd_init(void)
2588{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002589 int success;
2590 int i;
2591
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -08002592 wrap_enabled = 0;
2593 wrap_count = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002594 diag_debug_buf_idx = 0;
2595 driver->read_len_legacy = 0;
Dixon Petersonb4618a42012-02-29 18:56:31 -08002596 driver->use_device_tree = has_device_tree();
Dixon Petersonf2d449c2013-02-01 18:02:20 -08002597 driver->real_time_mode = 1;
Dixon Petersona6d98092013-05-16 12:26:26 -07002598 /*
2599 * The number of entries in table of buffers
2600 * should not be any smaller than hdlc poolsize.
2601 */
2602 driver->buf_tbl_size = (buf_tbl_size < driver->poolsize_hdlc) ?
2603 driver->poolsize_hdlc : buf_tbl_size;
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002604 driver->supports_separate_cmdrsp = device_supports_separate_cmdrsp();
Dixon Petersonebcfc2b2013-09-19 17:13:09 -07002605 driver->supports_apps_hdlc_encoding = 1;
Dixon Peterson25f042b2013-02-27 13:00:08 -08002606 mutex_init(&driver->diag_hdlc_mutex);
Shalabh Jaina06c6d72012-04-30 13:40:35 -07002607 mutex_init(&driver->diag_cntl_mutex);
Shalabh Jain321c8b52012-02-22 12:37:06 -08002608
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002609 for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002610 driver->separate_cmdrsp[i] = 0;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002611 driver->peripheral_supports_stm[i] = DISABLE_STM;
Ravi Aravamudhan91391ce2013-10-01 17:09:50 -07002612 driver->rcvd_feature_mask[i] = 0;
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07002613 }
2614
2615 for (i = 0; i < NUM_STM_PROCESSORS; i++) {
2616 driver->stm_state_requested[i] = DISABLE_STM;
2617 driver->stm_state[i] = DISABLE_STM;
2618 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002619
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002620 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
2621 success = diag_smd_constructor(&driver->smd_data[i], i,
2622 SMD_DATA_TYPE);
2623 if (!success)
2624 goto err;
2625 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002626
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002627 if (driver->supports_separate_cmdrsp) {
2628 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
2629 success = diag_smd_constructor(&driver->smd_cmd[i], i,
2630 SMD_CMD_TYPE);
2631 if (!success)
2632 goto err;
2633 }
2634 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002635
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002636 if (driver->usb_buf_out == NULL &&
2637 (driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
2638 GFP_KERNEL)) == NULL)
2639 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002640 kmemleak_not_leak(driver->usb_buf_out);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002641 if (driver->hdlc_buf == NULL
2642 && (driver->hdlc_buf = kzalloc(HDLC_MAX, GFP_KERNEL)) == NULL)
2643 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002644 kmemleak_not_leak(driver->hdlc_buf);
Mohit Aggarwala0118b12013-12-05 17:14:35 +05302645 if (driver->user_space_data_buf == NULL)
2646 driver->user_space_data_buf = kzalloc(USER_SPACE_DATA,
2647 GFP_KERNEL);
2648 if (driver->user_space_data_buf == NULL)
2649 goto err;
2650 kmemleak_not_leak(driver->user_space_data_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002651 if (driver->client_map == NULL &&
2652 (driver->client_map = kzalloc
2653 ((driver->num_clients) * sizeof(struct diag_client_map),
2654 GFP_KERNEL)) == NULL)
2655 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002656 kmemleak_not_leak(driver->client_map);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002657 if (driver->buf_tbl == NULL)
Dixon Petersona6d98092013-05-16 12:26:26 -07002658 driver->buf_tbl = kzalloc(driver->buf_tbl_size *
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002659 sizeof(struct diag_write_device), GFP_KERNEL);
2660 if (driver->buf_tbl == NULL)
2661 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002662 kmemleak_not_leak(driver->buf_tbl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002663 if (driver->data_ready == NULL &&
2664 (driver->data_ready = kzalloc(driver->num_clients * sizeof(int)
2665 , GFP_KERNEL)) == NULL)
2666 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002667 kmemleak_not_leak(driver->data_ready);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002668 if (driver->table == NULL &&
Shalabh Jainfe02b0c2012-02-21 14:48:03 -08002669 (driver->table = kzalloc(diag_max_reg*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002670 sizeof(struct diag_master_table),
2671 GFP_KERNEL)) == NULL)
2672 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002673 kmemleak_not_leak(driver->table);
Ashay Jaiswal29620122012-03-21 12:02:36 +05302674
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002675 if (driver->usb_read_ptr == NULL) {
2676 driver->usb_read_ptr = kzalloc(
2677 sizeof(struct diag_request), GFP_KERNEL);
2678 if (driver->usb_read_ptr == NULL)
2679 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002680 kmemleak_not_leak(driver->usb_read_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002681 }
2682 if (driver->pkt_buf == NULL &&
2683 (driver->pkt_buf = kzalloc(PKT_SIZE,
2684 GFP_KERNEL)) == NULL)
2685 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002686 kmemleak_not_leak(driver->pkt_buf);
Katish Paran244514d2013-08-01 18:39:31 -07002687 if (driver->dci_pkt_buf == NULL) {
2688 driver->dci_pkt_buf = kzalloc(PKT_SIZE, GFP_KERNEL);
2689 if (!driver->dci_pkt_buf)
2690 goto err;
2691 }
2692 kmemleak_not_leak(driver->dci_pkt_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002693 if (driver->apps_rsp_buf == NULL) {
Shalabh Jain321c8b52012-02-22 12:37:06 -08002694 driver->apps_rsp_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002695 if (driver->apps_rsp_buf == NULL)
2696 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07002697 kmemleak_not_leak(driver->apps_rsp_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002698 }
2699 driver->diag_wq = create_singlethread_workqueue("diag_wq");
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08002700 driver->diag_usb_wq = create_singlethread_workqueue("diag_usb_wq");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002701#ifdef CONFIG_DIAG_OVER_USB
Mohit Aggarwalb4465772013-04-18 13:08:07 +05302702 INIT_WORK(&(driver->diag_usb_connect_work),
2703 diag_usb_connect_work_fn);
2704 INIT_WORK(&(driver->diag_usb_disconnect_work),
2705 diag_usb_disconnect_work_fn);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002706 INIT_WORK(&(driver->diag_proc_hdlc_work), diag_process_hdlc_fn);
2707 INIT_WORK(&(driver->diag_read_work), diag_read_work_fn);
2708 driver->legacy_ch = usb_diag_open(DIAG_LEGACY, driver,
2709 diag_usb_legacy_notifier);
2710 if (IS_ERR(driver->legacy_ch)) {
2711 printk(KERN_ERR "Unable to open USB diag legacy channel\n");
2712 goto err;
2713 }
2714#endif
2715 platform_driver_register(&msm_smd_ch1_driver);
2716 platform_driver_register(&diag_smd_lite_driver);
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002717
2718 if (driver->supports_separate_cmdrsp) {
2719 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++)
2720 platform_driver_register(&smd_lite_data_cmd_drivers[i]);
2721 }
2722
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002723 return;
2724err:
Dixon Petersond6a20a92012-09-27 15:58:50 -07002725 pr_err("diag: Could not initialize diag buffers");
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002726
2727 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
2728 diag_smd_destructor(&driver->smd_data[i]);
2729
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002730 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++)
2731 diag_smd_destructor(&driver->smd_cmd[i]);
2732
Dixon Petersond6a20a92012-09-27 15:58:50 -07002733 kfree(driver->buf_msg_mask_update);
2734 kfree(driver->buf_log_mask_update);
2735 kfree(driver->buf_event_mask_update);
2736 kfree(driver->usb_buf_out);
2737 kfree(driver->hdlc_buf);
2738 kfree(driver->client_map);
2739 kfree(driver->buf_tbl);
2740 kfree(driver->data_ready);
2741 kfree(driver->table);
2742 kfree(driver->pkt_buf);
Katish Paran244514d2013-08-01 18:39:31 -07002743 kfree(driver->dci_pkt_buf);
Dixon Petersond6a20a92012-09-27 15:58:50 -07002744 kfree(driver->usb_read_ptr);
2745 kfree(driver->apps_rsp_buf);
Mohit Aggarwala0118b12013-12-05 17:14:35 +05302746 kfree(driver->user_space_data_buf);
Dixon Petersond6a20a92012-09-27 15:58:50 -07002747 if (driver->diag_wq)
2748 destroy_workqueue(driver->diag_wq);
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08002749 if (driver->diag_usb_wq)
2750 destroy_workqueue(driver->diag_usb_wq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002751}
2752
2753void diagfwd_exit(void)
2754{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002755 int i;
2756
2757 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
2758 diag_smd_destructor(&driver->smd_data[i]);
2759
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002760#ifdef CONFIG_DIAG_OVER_USB
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002761 usb_diag_close(driver->legacy_ch);
2762#endif
2763 platform_driver_unregister(&msm_smd_ch1_driver);
2764 platform_driver_unregister(&diag_smd_lite_driver);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08002765
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08002766 if (driver->supports_separate_cmdrsp) {
2767 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
2768 diag_smd_destructor(&driver->smd_cmd[i]);
2769 platform_driver_unregister(
2770 &smd_lite_data_cmd_drivers[i]);
2771 }
2772 }
2773
Shalabh Jain321c8b52012-02-22 12:37:06 -08002774 kfree(driver->buf_msg_mask_update);
2775 kfree(driver->buf_log_mask_update);
2776 kfree(driver->buf_event_mask_update);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002777 kfree(driver->usb_buf_out);
2778 kfree(driver->hdlc_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002779 kfree(driver->client_map);
2780 kfree(driver->buf_tbl);
2781 kfree(driver->data_ready);
2782 kfree(driver->table);
2783 kfree(driver->pkt_buf);
Katish Paran244514d2013-08-01 18:39:31 -07002784 kfree(driver->dci_pkt_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002785 kfree(driver->usb_read_ptr);
2786 kfree(driver->apps_rsp_buf);
Mohit Aggarwala0118b12013-12-05 17:14:35 +05302787 kfree(driver->user_space_data_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002788 destroy_workqueue(driver->diag_wq);
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08002789 destroy_workqueue(driver->diag_usb_wq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002790}