blob: 79a73f392b1cf651def1d6b196bc62cde5f10d9a [file] [log] [blame]
Shalabh Jainb0037c02013-01-18 12:47:40 -08001/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070012#include <linux/slab.h>
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/err.h>
17#include <linux/platform_device.h>
18#include <linux/sched.h>
Dixon Peterson6beff2d2012-09-13 18:51:47 -070019#include <linux/ratelimit.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070020#include <linux/workqueue.h>
21#include <linux/pm_runtime.h>
22#include <linux/diagchar.h>
23#include <linux/delay.h>
24#include <linux/reboot.h>
Dixon Petersonb4618a42012-02-29 18:56:31 -080025#include <linux/of.h>
Dixon Petersoncc0bea772012-04-11 20:45:37 -070026#include <linux/kmemleak.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027#ifdef CONFIG_DIAG_OVER_USB
28#include <mach/usbdiag.h>
29#endif
30#include <mach/msm_smd.h>
31#include <mach/socinfo.h>
32#include <mach/restart.h>
33#include "diagmem.h"
34#include "diagchar.h"
35#include "diagfwd.h"
36#include "diagfwd_cntl.h"
Shalabh Jainb0037c02013-01-18 12:47:40 -080037#include "diagfwd_hsic.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038#include "diagchar_hdlc.h"
39#ifdef CONFIG_DIAG_SDIO_PIPE
40#include "diagfwd_sdio.h"
41#endif
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070042#include "diag_dci.h"
Dixon Petersond6a20a92012-09-27 15:58:50 -070043#include "diag_masks.h"
Shalabh Jain737fca72012-11-14 21:53:43 -080044#include "diagfwd_bridge.h"
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070045
Shalabh Jain6a2ca7c2012-04-10 14:35:15 -070046#define MODE_CMD 41
47#define RESET_ID 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070048
49int diag_debug_buf_idx;
50unsigned char diag_debug_buf[1024];
51static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
52struct diag_master_table entry;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
54struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -080055int wrap_enabled;
56uint16_t wrap_count;
Shalabh Jain6a2ca7c2012-04-10 14:35:15 -070057
Dixon Petersond6a20a92012-09-27 15:58:50 -070058void encode_rsp_and_send(int buf_length)
59{
Dixon Petersoneecbadb2012-12-10 21:59:28 -080060 struct diag_smd_info *data = &(driver->smd_data[MODEM_DATA]);
Dixon Petersond6a20a92012-09-27 15:58:50 -070061 send.state = DIAG_STATE_START;
62 send.pkt = driver->apps_rsp_buf;
63 send.last = (void *)(driver->apps_rsp_buf + buf_length);
64 send.terminate = 1;
Dixon Peterson66fb11b2012-12-04 20:30:54 -080065 if (!data->in_busy_1) {
66 enc.dest = data->buf_in_1;
67 enc.dest_last = (void *)(data->buf_in_1 + APPS_BUF_SIZE - 1);
Dixon Petersond6a20a92012-09-27 15:58:50 -070068 diag_hdlc_encode(&send, &enc);
Dixon Peterson66fb11b2012-12-04 20:30:54 -080069 data->write_ptr_1->buf = data->buf_in_1;
70 data->write_ptr_1->length = (int)(enc.dest -
71 (void *)(data->buf_in_1));
72 data->in_busy_1 = 1;
Dixon Petersoneecbadb2012-12-10 21:59:28 -080073 diag_device_write(data->buf_in_1, data->peripheral,
Dixon Peterson66fb11b2012-12-04 20:30:54 -080074 data->write_ptr_1);
Dixon Petersond6a20a92012-09-27 15:58:50 -070075 memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);
76 }
77}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070078
Dixon Petersonb4618a42012-02-29 18:56:31 -080079/* Determine if this device uses a device tree */
80#ifdef CONFIG_OF
81static int has_device_tree(void)
82{
83 struct device_node *node;
84
85 node = of_find_node_by_path("/");
86 if (node) {
87 of_node_put(node);
88 return 1;
89 }
90 return 0;
91}
92#else
93static int has_device_tree(void)
94{
95 return 0;
96}
97#endif
98
Shalabh Jainfb8e3c12011-10-19 17:29:42 -070099int chk_config_get_id(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700100{
Shashank Mittal24771632013-02-06 19:34:57 -0800101 /* For all Fusion targets, Modem will always be present */
Shalabh Jain482bf122011-12-06 03:54:47 -0800102 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
103 return 0;
104
Dixon Petersonb4618a42012-02-29 18:56:31 -0800105 if (driver->use_device_tree) {
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700106 if (machine_is_msm8974())
Dixon Petersonb4618a42012-02-29 18:56:31 -0800107 return MSM8974_TOOLS_ID;
108 else
109 return 0;
110 } else {
111 switch (socinfo_get_msm_cpu()) {
112 case MSM_CPU_8X60:
113 return APQ8060_TOOLS_ID;
114 case MSM_CPU_8960:
Stepan Moskovchenko9c749262012-07-09 19:30:44 -0700115 case MSM_CPU_8960AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800116 return AO8960_TOOLS_ID;
117 case MSM_CPU_8064:
Jay Chokshi11abd8b2012-09-20 14:35:17 -0700118 case MSM_CPU_8064AB:
Shashank Mittal24771632013-02-06 19:34:57 -0800119 case MSM_CPU_8064AA:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800120 return APQ8064_TOOLS_ID;
121 case MSM_CPU_8930:
Stepan Moskovchenko0df9bb22012-07-06 18:19:15 -0700122 case MSM_CPU_8930AA:
Stepan Moskovchenkoecb0d9b2012-10-16 18:35:34 -0700123 case MSM_CPU_8930AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800124 return MSM8930_TOOLS_ID;
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700125 case MSM_CPU_8974:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800126 return MSM8974_TOOLS_ID;
127 case MSM_CPU_8625:
128 return MSM8625_TOOLS_ID;
129 default:
130 return 0;
131 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700132 }
133}
134
135/*
Shalabh Jain321c8b52012-02-22 12:37:06 -0800136 * This will return TRUE for targets which support apps only mode and hence SSR.
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700137 * This applies to 8960 and newer targets.
138 */
139int chk_apps_only(void)
140{
Dixon Petersonb4618a42012-02-29 18:56:31 -0800141 if (driver->use_device_tree)
142 return 1;
143
144 switch (socinfo_get_msm_cpu()) {
145 case MSM_CPU_8960:
Stepan Moskovchenko9c749262012-07-09 19:30:44 -0700146 case MSM_CPU_8960AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800147 case MSM_CPU_8064:
Jay Chokshi11abd8b2012-09-20 14:35:17 -0700148 case MSM_CPU_8064AB:
Shashank Mittal24771632013-02-06 19:34:57 -0800149 case MSM_CPU_8064AA:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800150 case MSM_CPU_8930:
Stepan Moskovchenko0df9bb22012-07-06 18:19:15 -0700151 case MSM_CPU_8930AA:
Stepan Moskovchenkoecb0d9b2012-10-16 18:35:34 -0700152 case MSM_CPU_8930AB:
Dixon Petersonb4618a42012-02-29 18:56:31 -0800153 case MSM_CPU_8627:
154 case MSM_CPU_9615:
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700155 case MSM_CPU_8974:
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700156 return 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157 default:
158 return 0;
159 }
160}
161
Shalabh Jain10f5f432012-01-11 11:45:44 +0530162/*
163 * This will return TRUE for targets which support apps as master.
164 * Thus, SW DLOAD and Mode Reset are supported on apps processor.
165 * This applies to 8960 and newer targets.
166 */
167int chk_apps_master(void)
168{
Dixon Petersonb4618a42012-02-29 18:56:31 -0800169 if (driver->use_device_tree)
170 return 1;
Stepan Moskovchenko5b9e7762012-09-21 20:32:17 -0700171 else if (soc_class_is_msm8960() || soc_class_is_msm8930() ||
172 soc_class_is_apq8064() || cpu_is_msm9615())
Dixon Petersonb4618a42012-02-29 18:56:31 -0800173 return 1;
174 else
175 return 0;
176}
177
Dixon Peterson29aebee2012-04-06 12:44:08 -0700178int chk_polling_response(void)
Dixon Petersonb4618a42012-02-29 18:56:31 -0800179{
180 if (!(driver->polling_reg_flag) && chk_apps_master())
181 /*
182 * If the apps processor is master and no other processor
183 * has registered to respond for polling
184 */
185 return 1;
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800186 else if (!(driver->smd_data[MODEM_DATA].ch) &&
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800187 !(chk_apps_master()))
Dixon Petersonb4618a42012-02-29 18:56:31 -0800188 /*
189 * If the apps processor is not the master and the modem
190 * is not up
191 */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530192 return 1;
193 else
194 return 0;
195}
196
Dixon Peterson743a11e2012-07-30 17:42:20 -0700197/*
198 * This function should be called if you feel that the logging process may
199 * need to be woken up. For instance, if the logging mode is MEMORY_DEVICE MODE
200 * and while trying to read data from a SMD data channel there are no buffers
201 * available to read the data into, then this function should be called to
202 * determine if the logging process needs to be woken up.
203 */
204void chk_logging_wakeup(void)
205{
206 int i;
207
208 /* Find the index of the logging process */
209 for (i = 0; i < driver->num_clients; i++)
210 if (driver->client_map[i].pid ==
211 driver->logging_process_id)
212 break;
213
214 if (i < driver->num_clients) {
215 /* At very high logging rates a race condition can
216 * occur where the buffers containing the data from
217 * an smd channel are all in use, but the data_ready
218 * flag is cleared. In this case, the buffers never
219 * have their data read/logged. Detect and remedy this
220 * situation.
221 */
Shalabh Jain84e30342012-10-16 16:16:08 -0700222 if ((driver->data_ready[i] & USER_SPACE_DATA_TYPE) == 0) {
223 driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
Dixon Peterson743a11e2012-07-30 17:42:20 -0700224 pr_debug("diag: Force wakeup of logging process\n");
225 wake_up_interruptible(&driver->wait_q);
226 }
227 }
228}
229
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800230/* Process the data read from the smd data channel */
231int diag_process_smd_read_data(struct diag_smd_info *smd_info, void *buf,
232 int total_recd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234 struct diag_request *write_ptr_modem = NULL;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800235 int *in_busy_ptr = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700236
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800237 if (smd_info->buf_in_1 == buf) {
238 write_ptr_modem = smd_info->write_ptr_1;
239 in_busy_ptr = &smd_info->in_busy_1;
240 } else if (smd_info->buf_in_2 == buf) {
241 write_ptr_modem = smd_info->write_ptr_2;
242 in_busy_ptr = &smd_info->in_busy_2;
243 } else {
244 pr_err("diag: In %s, no match for in_busy_1\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245 }
246
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800247 if (write_ptr_modem) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800248 write_ptr_modem->length = total_recd;
249 *in_busy_ptr = 1;
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800250 diag_device_write(buf, smd_info->peripheral, write_ptr_modem);
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800251 }
252
253 return 0;
254}
255
256void diag_smd_send_req(struct diag_smd_info *smd_info)
257{
258 void *buf = NULL, *temp_buf = NULL;
259 int total_recd = 0, r = 0, pkt_len;
260 int loop_count = 0;
261 int notify = 0;
262
263 if (!smd_info) {
264 pr_err("diag: In %s, no smd info. Not able to read.\n",
265 __func__);
266 return;
267 }
268
269 if (!smd_info->in_busy_1)
270 buf = smd_info->buf_in_1;
271 else if ((smd_info->type == SMD_DATA_TYPE) && !smd_info->in_busy_2)
272 buf = smd_info->buf_in_2;
273
274 if (smd_info->ch && buf) {
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700275 temp_buf = buf;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800276 pkt_len = smd_cur_packet_size(smd_info->ch);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700278 while (pkt_len && (pkt_len != total_recd)) {
279 loop_count++;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800280 r = smd_read_avail(smd_info->ch);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700281 pr_debug("diag: In %s, received pkt %d %d\n",
282 __func__, r, total_recd);
283 if (!r) {
284 /* Nothing to read from SMD */
285 wait_event(driver->smd_wait_q,
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800286 ((smd_info->ch == 0) ||
287 smd_read_avail(smd_info->ch)));
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700288 /* If the smd channel is open */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800289 if (smd_info->ch) {
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700290 pr_debug("diag: In %s, return from wait_event\n",
291 __func__);
292 continue;
293 } else {
294 pr_debug("diag: In %s, return from wait_event ch closed\n",
295 __func__);
296 return;
297 }
298 }
299 total_recd += r;
300 if (total_recd > IN_BUF_SIZE) {
301 if (total_recd < MAX_IN_BUF_SIZE) {
302 pr_err("diag: In %s, SMD sending in packets up to %d bytes\n",
303 __func__, total_recd);
304 buf = krealloc(buf, total_recd,
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800305 GFP_KERNEL);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700306 } else {
307 pr_err("diag: In %s, SMD sending in packets more than %d bytes\n",
308 __func__, MAX_IN_BUF_SIZE);
309 return;
310 }
311 }
312 if (pkt_len < r) {
313 pr_err("diag: In %s, SMD sending incorrect pkt\n",
314 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 return;
316 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800317 if (pkt_len > r) {
318 pr_err("diag: In %s, SMD sending partial pkt %d %d %d %d %d %d\n",
319 __func__, pkt_len, r, total_recd, loop_count,
320 smd_info->peripheral, smd_info->type);
321 }
322
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700323 /* keep reading for complete packet */
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800324 smd_read(smd_info->ch, temp_buf, r);
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700325 temp_buf += r;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700326 }
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700327
328 if (total_recd > 0) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800329 if (!buf) {
Shalabh Jainc70b3b62012-08-31 19:11:20 -0700330 pr_err("diag: Out of diagmem for Modem\n");
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800331 } else if (smd_info->process_smd_read_data) {
332 notify = smd_info->process_smd_read_data(
333 smd_info, buf, total_recd);
334 /* Poll SMD channels to check for data */
335 if (notify)
336 diag_smd_notify(smd_info,
337 SMD_EVENT_DATA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700338 }
339 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800340 } else if (smd_info->ch && !buf &&
Dixon Peterson743a11e2012-07-30 17:42:20 -0700341 (driver->logging_mode == MEMORY_DEVICE_MODE)) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800342 chk_logging_wakeup();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343 }
344}
345
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800346void diag_read_smd_work_fn(struct work_struct *work)
347{
348 struct diag_smd_info *smd_info = container_of(work,
349 struct diag_smd_info,
350 diag_read_smd_work);
351 diag_smd_send_req(smd_info);
352}
353
Dixon Peterson13046ed2013-02-21 17:35:35 -0800354#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
355static void diag_mem_dev_mode_ready_update(int index, int hsic_updated)
356{
357 if (hsic_updated) {
358 unsigned long flags;
359 spin_lock_irqsave(&driver->hsic_ready_spinlock, flags);
360 driver->data_ready[index] |= USER_SPACE_DATA_TYPE;
361 spin_unlock_irqrestore(&driver->hsic_ready_spinlock, flags);
362 } else {
363 driver->data_ready[index] |= USER_SPACE_DATA_TYPE;
364 }
365}
366#else
367static void diag_mem_dev_mode_ready_update(int index, int hsic_updated)
368{
369 (void) hsic_updated;
370 driver->data_ready[index] |= USER_SPACE_DATA_TYPE;
371}
372#endif
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800373int diag_device_write(void *buf, int data_type, struct diag_request *write_ptr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700374{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800375 int i, err = 0, index;
376 index = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700377
378 if (driver->logging_mode == MEMORY_DEVICE_MODE) {
Dixon Peterson13046ed2013-02-21 17:35:35 -0800379 int hsic_updated = 0;
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800380 if (data_type == APPS_DATA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381 for (i = 0; i < driver->poolsize_write_struct; i++)
382 if (driver->buf_tbl[i].length == 0) {
383 driver->buf_tbl[i].buf = buf;
384 driver->buf_tbl[i].length =
385 driver->used;
386#ifdef DIAG_DEBUG
387 pr_debug("diag: ENQUEUE buf ptr"
388 " and length is %x , %d\n",
389 (unsigned int)(driver->buf_
390 tbl[i].buf), driver->buf_tbl[i].length);
391#endif
392 break;
393 }
394 }
Dixon Peterson938f8602012-08-17 20:02:57 -0700395
Shalabh Jain737fca72012-11-14 21:53:43 -0800396#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Shalabh Jainb0037c02013-01-18 12:47:40 -0800397 else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700398 unsigned long flags;
399 int foundIndex = -1;
Dixon Peterson13046ed2013-02-21 17:35:35 -0800400 hsic_updated = 1;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800401 index = data_type - HSIC_DATA;
402 spin_lock_irqsave(&diag_hsic[index].hsic_spinlock,
403 flags);
404 for (i = 0; i < diag_hsic[index].poolsize_hsic_write;
405 i++) {
406 if (diag_hsic[index].hsic_buf_tbl[i].length
407 == 0) {
408 diag_hsic[index].hsic_buf_tbl[i].buf
409 = buf;
410 diag_hsic[index].hsic_buf_tbl[i].length
411 = diag_bridge[index].write_len;
412 diag_hsic[index].
413 num_hsic_buf_tbl_entries++;
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700414 foundIndex = i;
Dixon Peterson938f8602012-08-17 20:02:57 -0700415 break;
416 }
417 }
Shalabh Jainb0037c02013-01-18 12:47:40 -0800418 spin_unlock_irqrestore(&diag_hsic[index].hsic_spinlock,
419 flags);
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700420 if (foundIndex == -1)
421 err = -1;
422 else
Shalabh Jainb0037c02013-01-18 12:47:40 -0800423 pr_debug("diag: ENQUEUE HSIC buf ptr and length is %x , %d, ch %d\n",
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700424 (unsigned int)buf,
Shalabh Jainb0037c02013-01-18 12:47:40 -0800425 diag_bridge[index].write_len, index);
Dixon Peterson938f8602012-08-17 20:02:57 -0700426 }
427#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428 for (i = 0; i < driver->num_clients; i++)
429 if (driver->client_map[i].pid ==
430 driver->logging_process_id)
431 break;
432 if (i < driver->num_clients) {
Dixon Peterson13046ed2013-02-21 17:35:35 -0800433 diag_mem_dev_mode_ready_update(i, hsic_updated);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700434 pr_debug("diag: wake up logging process\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435 wake_up_interruptible(&driver->wait_q);
436 } else
437 return -EINVAL;
438 } else if (driver->logging_mode == NO_LOGGING_MODE) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800439 if ((data_type >= 0) && (data_type < NUM_SMD_DATA_CHANNELS)) {
440 driver->smd_data[data_type].in_busy_1 = 0;
441 driver->smd_data[data_type].in_busy_2 = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800442 queue_work(driver->diag_wq,
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800443 &(driver->smd_data[data_type].
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800444 diag_read_smd_work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445 }
Shalabh Jain482bf122011-12-06 03:54:47 -0800446#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800447 else if (data_type == SDIO_DATA) {
Shalabh Jain482bf122011-12-06 03:54:47 -0800448 driver->in_busy_sdio = 0;
449 queue_work(driver->diag_sdio_wq,
450 &(driver->diag_read_sdio_work));
451 }
452#endif
Shalabh Jain737fca72012-11-14 21:53:43 -0800453#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Shalabh Jainb0037c02013-01-18 12:47:40 -0800454 else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
455 index = data_type - HSIC_DATA;
456 if (diag_hsic[index].hsic_ch)
457 queue_work(diag_bridge[index].wq,
458 &(diag_hsic[index].
459 diag_read_hsic_work));
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700460 }
461#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700462 err = -1;
463 }
464#ifdef CONFIG_DIAG_OVER_USB
465 else if (driver->logging_mode == USB_MODE) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800466 if (data_type == APPS_DATA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700467 driver->write_ptr_svc = (struct diag_request *)
468 (diagmem_alloc(driver, sizeof(struct diag_request),
469 POOL_TYPE_WRITE_STRUCT));
470 if (driver->write_ptr_svc) {
471 driver->write_ptr_svc->length = driver->used;
472 driver->write_ptr_svc->buf = buf;
473 err = usb_diag_write(driver->legacy_ch,
474 driver->write_ptr_svc);
475 } else
476 err = -1;
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800477 } else if ((data_type >= 0) &&
478 (data_type < NUM_SMD_DATA_CHANNELS)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700479 write_ptr->buf = buf;
480#ifdef DIAG_DEBUG
481 printk(KERN_INFO "writing data to USB,"
482 "pkt length %d\n", write_ptr->length);
483 print_hex_dump(KERN_DEBUG, "Written Packet Data to"
484 " USB: ", 16, 1, DUMP_PREFIX_ADDRESS,
485 buf, write_ptr->length, 1);
486#endif /* DIAG DEBUG */
487 err = usb_diag_write(driver->legacy_ch, write_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488 }
489#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800490 else if (data_type == SDIO_DATA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700491 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -0800492 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700493 write_ptr->buf = buf;
494 err = usb_diag_write(driver->mdm_ch, write_ptr);
495 } else
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800496 pr_err("diag: Incorrect sdio data "
497 "while USB write\n");
498 }
499#endif
Shalabh Jain737fca72012-11-14 21:53:43 -0800500#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Shalabh Jainb0037c02013-01-18 12:47:40 -0800501 else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
502 index = data_type - HSIC_DATA;
503 if (diag_hsic[index].hsic_device_enabled) {
Dixon Peterson938f8602012-08-17 20:02:57 -0700504 struct diag_request *write_ptr_mdm;
505 write_ptr_mdm = (struct diag_request *)
506 diagmem_alloc(driver,
507 sizeof(struct diag_request),
Shalabh Jainb0037c02013-01-18 12:47:40 -0800508 index +
Dixon Peterson938f8602012-08-17 20:02:57 -0700509 POOL_TYPE_HSIC_WRITE);
510 if (write_ptr_mdm) {
511 write_ptr_mdm->buf = buf;
512 write_ptr_mdm->length =
Shalabh Jainb0037c02013-01-18 12:47:40 -0800513 diag_bridge[index].write_len;
514 write_ptr_mdm->context = (void *)index;
Shalabh Jain737fca72012-11-14 21:53:43 -0800515 err = usb_diag_write(
Shalabh Jainb0037c02013-01-18 12:47:40 -0800516 diag_bridge[index].ch, write_ptr_mdm);
Dixon Peterson938f8602012-08-17 20:02:57 -0700517 /* Return to the pool immediately */
518 if (err) {
519 diagmem_free(driver,
520 write_ptr_mdm,
Shalabh Jainb0037c02013-01-18 12:47:40 -0800521 index +
Dixon Peterson938f8602012-08-17 20:02:57 -0700522 POOL_TYPE_HSIC_WRITE);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800523 pr_err_ratelimited("diag: HSIC write failure, err: %d, ch %d\n",
524 err, index);
Dixon Peterson938f8602012-08-17 20:02:57 -0700525 }
526 } else {
527 pr_err("diag: allocate write fail\n");
528 err = -1;
529 }
530 } else {
Shalabh Jain737fca72012-11-14 21:53:43 -0800531 pr_err("diag: Incorrect HSIC data "
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800532 "while USB write\n");
Dixon Peterson938f8602012-08-17 20:02:57 -0700533 err = -1;
534 }
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800535 } else if (data_type == SMUX_DATA) {
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700536 write_ptr->buf = buf;
Shalabh Jain737fca72012-11-14 21:53:43 -0800537 write_ptr->context = (void *)SMUX;
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700538 pr_debug("diag: writing SMUX data\n");
Shalabh Jain737fca72012-11-14 21:53:43 -0800539 err = usb_diag_write(diag_bridge[SMUX].ch,
540 write_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700541 }
542#endif
543 APPEND_DEBUG('d');
544 }
545#endif /* DIAG OVER USB */
546 return err;
547}
548
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700549static void diag_update_pkt_buffer(unsigned char *buf)
550{
551 unsigned char *ptr = driver->pkt_buf;
552 unsigned char *temp = buf;
553
554 mutex_lock(&driver->diagchar_mutex);
555 if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, driver->pkt_length))
556 memcpy(ptr, temp , driver->pkt_length);
557 else
558 printk(KERN_CRIT " Not enough buffer space for PKT_RESP\n");
559 mutex_unlock(&driver->diagchar_mutex);
560}
561
562void diag_update_userspace_clients(unsigned int type)
563{
564 int i;
565
566 mutex_lock(&driver->diagchar_mutex);
567 for (i = 0; i < driver->num_clients; i++)
568 if (driver->client_map[i].pid != 0)
569 driver->data_ready[i] |= type;
570 wake_up_interruptible(&driver->wait_q);
571 mutex_unlock(&driver->diagchar_mutex);
572}
573
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700574void diag_update_sleeping_process(int process_id, int data_type)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700575{
576 int i;
577
578 mutex_lock(&driver->diagchar_mutex);
579 for (i = 0; i < driver->num_clients; i++)
580 if (driver->client_map[i].pid == process_id) {
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700581 driver->data_ready[i] |= data_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700582 break;
583 }
584 wake_up_interruptible(&driver->wait_q);
585 mutex_unlock(&driver->diagchar_mutex);
586}
587
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800588static int diag_check_mode_reset(unsigned char *buf)
589{
590 int is_mode_reset = 0;
591 if (chk_apps_master() && (int)(*(char *)buf) == MODE_CMD)
592 if ((int)(*(char *)(buf+1)) == RESET_ID)
593 is_mode_reset = 1;
594 return is_mode_reset;
595}
596
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700597void diag_send_data(struct diag_master_table entry, unsigned char *buf,
598 int len, int type)
599{
600 driver->pkt_length = len;
601 if (entry.process_id != NON_APPS_PROC && type != MODEM_DATA) {
602 diag_update_pkt_buffer(buf);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700603 diag_update_sleeping_process(entry.process_id, PKT_TYPE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700604 } else {
605 if (len > 0) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800606 if ((entry.client_id >= 0) &&
607 (entry.client_id < NUM_SMD_DATA_CHANNELS)) {
608 int index = entry.client_id;
609 if (driver->smd_data[index].ch) {
610 if ((index == MODEM_DATA) &&
611 diag_check_mode_reset(buf)) {
Shalabh Jainc9f35092011-07-28 18:36:17 -0700612 return;
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800613 }
Dixon Peterson25f042b2013-02-27 13:00:08 -0800614 mutex_lock(&driver->smd_data[index].
615 smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800616 smd_write(driver->smd_data[index].ch,
617 buf, len);
Dixon Peterson25f042b2013-02-27 13:00:08 -0800618 mutex_unlock(&driver->smd_data[index].
619 smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800620 } else {
621 pr_err("diag: In %s, smd channel %d not open\n",
622 __func__, index);
623 }
Shalabh Jainc9f35092011-07-28 18:36:17 -0700624 } else {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800625 pr_alert("diag: In %s, incorrect channel: %d",
626 __func__, entry.client_id);
Shalabh Jainc9f35092011-07-28 18:36:17 -0700627 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700628 }
629 }
630}
631
632static int diag_process_apps_pkt(unsigned char *buf, int len)
633{
634 uint16_t subsys_cmd_code;
635 int subsys_id, ssid_first, ssid_last, ssid_range;
Shalabh Jain3fd986f2012-05-30 18:42:26 -0700636 int packet_type = 1, i, cmd_code;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637 unsigned char *temp = buf;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700638 int data_type;
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -0800639 int mask_ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700640#if defined(CONFIG_DIAG_OVER_USB)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700641 unsigned char *ptr;
642#endif
643
Dixon Petersond6a20a92012-09-27 15:58:50 -0700644 /* Check if the command is a supported mask command */
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -0800645 mask_ret = diag_process_apps_masks(buf, len);
646 if (mask_ret <= 0)
647 return mask_ret;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700648
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700649 /* Check for registered clients and forward packet to apropriate proc */
650 cmd_code = (int)(*(char *)buf);
651 temp++;
652 subsys_id = (int)(*(char *)temp);
653 temp++;
654 subsys_cmd_code = *(uint16_t *)temp;
655 temp += 2;
656 data_type = APPS_DATA;
657 /* Dont send any command other than mode reset */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530658 if (chk_apps_master() && cmd_code == MODE_CMD) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700659 if (subsys_id != RESET_ID)
660 data_type = MODEM_DATA;
661 }
662
663 pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
Shalabh Jainfe02b0c2012-02-21 14:48:03 -0800664 for (i = 0; i < diag_max_reg; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665 entry = driver->table[i];
666 if (entry.process_id != NO_PROCESS) {
667 if (entry.cmd_code == cmd_code && entry.subsys_id ==
668 subsys_id && entry.cmd_code_lo <=
669 subsys_cmd_code &&
670 entry.cmd_code_hi >= subsys_cmd_code) {
671 diag_send_data(entry, buf, len, data_type);
672 packet_type = 0;
673 } else if (entry.cmd_code == 255
674 && cmd_code == 75) {
675 if (entry.subsys_id ==
676 subsys_id &&
677 entry.cmd_code_lo <=
678 subsys_cmd_code &&
679 entry.cmd_code_hi >=
680 subsys_cmd_code) {
681 diag_send_data(entry, buf, len,
682 data_type);
683 packet_type = 0;
684 }
685 } else if (entry.cmd_code == 255 &&
686 entry.subsys_id == 255) {
687 if (entry.cmd_code_lo <=
688 cmd_code &&
689 entry.
690 cmd_code_hi >= cmd_code) {
691 diag_send_data(entry, buf, len,
692 data_type);
693 packet_type = 0;
694 }
695 }
696 }
697 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700698#if defined(CONFIG_DIAG_OVER_USB)
Dixon Petersona2dd7352012-05-21 17:37:10 -0700699 /* Check for the command/respond msg for the maximum packet length */
700 if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
701 (*(uint16_t *)(buf+2) == 0x0055)) {
702 for (i = 0; i < 4; i++)
703 *(driver->apps_rsp_buf+i) = *(buf+i);
704 *(uint32_t *)(driver->apps_rsp_buf+4) = PKT_SIZE;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700705 encode_rsp_and_send(7);
Dixon Petersona2dd7352012-05-21 17:37:10 -0700706 return 0;
707 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700708 /* Check for Apps Only & get event mask request */
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800709 else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only() &&
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800710 *buf == 0x81) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700711 driver->apps_rsp_buf[0] = 0x81;
712 driver->apps_rsp_buf[1] = 0x0;
713 *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
714 *(uint16_t *)(driver->apps_rsp_buf + 4) = EVENT_LAST_ID + 1;
715 for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
716 *(unsigned char *)(driver->apps_rsp_buf + 6 + i) = 0x0;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700717 encode_rsp_and_send(6 + EVENT_LAST_ID/8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700718 return 0;
719 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700720 /* Get log ID range & Check for Apps Only */
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800721 else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722 && (*buf == 0x73) && *(int *)(buf+4) == 1) {
723 driver->apps_rsp_buf[0] = 0x73;
724 *(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
725 *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success code */
726 *(int *)(driver->apps_rsp_buf + 12) = LOG_GET_ITEM_NUM(LOG_0);
727 *(int *)(driver->apps_rsp_buf + 16) = LOG_GET_ITEM_NUM(LOG_1);
728 *(int *)(driver->apps_rsp_buf + 20) = LOG_GET_ITEM_NUM(LOG_2);
729 *(int *)(driver->apps_rsp_buf + 24) = LOG_GET_ITEM_NUM(LOG_3);
730 *(int *)(driver->apps_rsp_buf + 28) = LOG_GET_ITEM_NUM(LOG_4);
731 *(int *)(driver->apps_rsp_buf + 32) = LOG_GET_ITEM_NUM(LOG_5);
732 *(int *)(driver->apps_rsp_buf + 36) = LOG_GET_ITEM_NUM(LOG_6);
733 *(int *)(driver->apps_rsp_buf + 40) = LOG_GET_ITEM_NUM(LOG_7);
734 *(int *)(driver->apps_rsp_buf + 44) = LOG_GET_ITEM_NUM(LOG_8);
735 *(int *)(driver->apps_rsp_buf + 48) = LOG_GET_ITEM_NUM(LOG_9);
736 *(int *)(driver->apps_rsp_buf + 52) = LOG_GET_ITEM_NUM(LOG_10);
737 *(int *)(driver->apps_rsp_buf + 56) = LOG_GET_ITEM_NUM(LOG_11);
738 *(int *)(driver->apps_rsp_buf + 60) = LOG_GET_ITEM_NUM(LOG_12);
739 *(int *)(driver->apps_rsp_buf + 64) = LOG_GET_ITEM_NUM(LOG_13);
740 *(int *)(driver->apps_rsp_buf + 68) = LOG_GET_ITEM_NUM(LOG_14);
741 *(int *)(driver->apps_rsp_buf + 72) = LOG_GET_ITEM_NUM(LOG_15);
Dixon Petersond6a20a92012-09-27 15:58:50 -0700742 encode_rsp_and_send(75);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700743 return 0;
744 }
745 /* Respond to Get SSID Range request message */
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800746 else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700747 && (*buf == 0x7d) && (*(buf+1) == 0x1)) {
748 driver->apps_rsp_buf[0] = 0x7d;
749 driver->apps_rsp_buf[1] = 0x1;
750 driver->apps_rsp_buf[2] = 0x1;
751 driver->apps_rsp_buf[3] = 0x0;
Shalabh Jain44b79b72012-06-15 13:39:27 -0700752 /* -1 to un-account for OEM SSID range */
753 *(int *)(driver->apps_rsp_buf + 4) = MSG_MASK_TBL_CNT - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700754 *(uint16_t *)(driver->apps_rsp_buf + 8) = MSG_SSID_0;
755 *(uint16_t *)(driver->apps_rsp_buf + 10) = MSG_SSID_0_LAST;
756 *(uint16_t *)(driver->apps_rsp_buf + 12) = MSG_SSID_1;
757 *(uint16_t *)(driver->apps_rsp_buf + 14) = MSG_SSID_1_LAST;
758 *(uint16_t *)(driver->apps_rsp_buf + 16) = MSG_SSID_2;
759 *(uint16_t *)(driver->apps_rsp_buf + 18) = MSG_SSID_2_LAST;
760 *(uint16_t *)(driver->apps_rsp_buf + 20) = MSG_SSID_3;
761 *(uint16_t *)(driver->apps_rsp_buf + 22) = MSG_SSID_3_LAST;
762 *(uint16_t *)(driver->apps_rsp_buf + 24) = MSG_SSID_4;
763 *(uint16_t *)(driver->apps_rsp_buf + 26) = MSG_SSID_4_LAST;
764 *(uint16_t *)(driver->apps_rsp_buf + 28) = MSG_SSID_5;
765 *(uint16_t *)(driver->apps_rsp_buf + 30) = MSG_SSID_5_LAST;
766 *(uint16_t *)(driver->apps_rsp_buf + 32) = MSG_SSID_6;
767 *(uint16_t *)(driver->apps_rsp_buf + 34) = MSG_SSID_6_LAST;
768 *(uint16_t *)(driver->apps_rsp_buf + 36) = MSG_SSID_7;
769 *(uint16_t *)(driver->apps_rsp_buf + 38) = MSG_SSID_7_LAST;
770 *(uint16_t *)(driver->apps_rsp_buf + 40) = MSG_SSID_8;
771 *(uint16_t *)(driver->apps_rsp_buf + 42) = MSG_SSID_8_LAST;
772 *(uint16_t *)(driver->apps_rsp_buf + 44) = MSG_SSID_9;
773 *(uint16_t *)(driver->apps_rsp_buf + 46) = MSG_SSID_9_LAST;
774 *(uint16_t *)(driver->apps_rsp_buf + 48) = MSG_SSID_10;
775 *(uint16_t *)(driver->apps_rsp_buf + 50) = MSG_SSID_10_LAST;
776 *(uint16_t *)(driver->apps_rsp_buf + 52) = MSG_SSID_11;
777 *(uint16_t *)(driver->apps_rsp_buf + 54) = MSG_SSID_11_LAST;
778 *(uint16_t *)(driver->apps_rsp_buf + 56) = MSG_SSID_12;
779 *(uint16_t *)(driver->apps_rsp_buf + 58) = MSG_SSID_12_LAST;
780 *(uint16_t *)(driver->apps_rsp_buf + 60) = MSG_SSID_13;
781 *(uint16_t *)(driver->apps_rsp_buf + 62) = MSG_SSID_13_LAST;
782 *(uint16_t *)(driver->apps_rsp_buf + 64) = MSG_SSID_14;
783 *(uint16_t *)(driver->apps_rsp_buf + 66) = MSG_SSID_14_LAST;
784 *(uint16_t *)(driver->apps_rsp_buf + 68) = MSG_SSID_15;
785 *(uint16_t *)(driver->apps_rsp_buf + 70) = MSG_SSID_15_LAST;
786 *(uint16_t *)(driver->apps_rsp_buf + 72) = MSG_SSID_16;
787 *(uint16_t *)(driver->apps_rsp_buf + 74) = MSG_SSID_16_LAST;
788 *(uint16_t *)(driver->apps_rsp_buf + 76) = MSG_SSID_17;
789 *(uint16_t *)(driver->apps_rsp_buf + 78) = MSG_SSID_17_LAST;
790 *(uint16_t *)(driver->apps_rsp_buf + 80) = MSG_SSID_18;
791 *(uint16_t *)(driver->apps_rsp_buf + 82) = MSG_SSID_18_LAST;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800792 *(uint16_t *)(driver->apps_rsp_buf + 84) = MSG_SSID_19;
793 *(uint16_t *)(driver->apps_rsp_buf + 86) = MSG_SSID_19_LAST;
794 *(uint16_t *)(driver->apps_rsp_buf + 88) = MSG_SSID_20;
795 *(uint16_t *)(driver->apps_rsp_buf + 90) = MSG_SSID_20_LAST;
796 *(uint16_t *)(driver->apps_rsp_buf + 92) = MSG_SSID_21;
797 *(uint16_t *)(driver->apps_rsp_buf + 94) = MSG_SSID_21_LAST;
798 *(uint16_t *)(driver->apps_rsp_buf + 96) = MSG_SSID_22;
799 *(uint16_t *)(driver->apps_rsp_buf + 98) = MSG_SSID_22_LAST;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700800 encode_rsp_and_send(99);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801 return 0;
802 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700803 /* Check for Apps Only Respond to Get Subsys Build mask */
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800804 else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805 && (*buf == 0x7d) && (*(buf+1) == 0x2)) {
806 ssid_first = *(uint16_t *)(buf + 2);
807 ssid_last = *(uint16_t *)(buf + 4);
808 ssid_range = 4 * (ssid_last - ssid_first + 1);
809 /* frame response */
810 driver->apps_rsp_buf[0] = 0x7d;
811 driver->apps_rsp_buf[1] = 0x2;
812 *(uint16_t *)(driver->apps_rsp_buf + 2) = ssid_first;
813 *(uint16_t *)(driver->apps_rsp_buf + 4) = ssid_last;
814 driver->apps_rsp_buf[6] = 0x1;
815 driver->apps_rsp_buf[7] = 0x0;
816 ptr = driver->apps_rsp_buf + 8;
817 /* bld time masks */
818 switch (ssid_first) {
819 case MSG_SSID_0:
820 for (i = 0; i < ssid_range; i += 4)
821 *(int *)(ptr + i) = msg_bld_masks_0[i/4];
822 break;
823 case MSG_SSID_1:
824 for (i = 0; i < ssid_range; i += 4)
825 *(int *)(ptr + i) = msg_bld_masks_1[i/4];
826 break;
827 case MSG_SSID_2:
828 for (i = 0; i < ssid_range; i += 4)
829 *(int *)(ptr + i) = msg_bld_masks_2[i/4];
830 break;
831 case MSG_SSID_3:
832 for (i = 0; i < ssid_range; i += 4)
833 *(int *)(ptr + i) = msg_bld_masks_3[i/4];
834 break;
835 case MSG_SSID_4:
836 for (i = 0; i < ssid_range; i += 4)
837 *(int *)(ptr + i) = msg_bld_masks_4[i/4];
838 break;
839 case MSG_SSID_5:
840 for (i = 0; i < ssid_range; i += 4)
841 *(int *)(ptr + i) = msg_bld_masks_5[i/4];
842 break;
843 case MSG_SSID_6:
844 for (i = 0; i < ssid_range; i += 4)
845 *(int *)(ptr + i) = msg_bld_masks_6[i/4];
846 break;
847 case MSG_SSID_7:
848 for (i = 0; i < ssid_range; i += 4)
849 *(int *)(ptr + i) = msg_bld_masks_7[i/4];
850 break;
851 case MSG_SSID_8:
852 for (i = 0; i < ssid_range; i += 4)
853 *(int *)(ptr + i) = msg_bld_masks_8[i/4];
854 break;
855 case MSG_SSID_9:
856 for (i = 0; i < ssid_range; i += 4)
857 *(int *)(ptr + i) = msg_bld_masks_9[i/4];
858 break;
859 case MSG_SSID_10:
860 for (i = 0; i < ssid_range; i += 4)
861 *(int *)(ptr + i) = msg_bld_masks_10[i/4];
862 break;
863 case MSG_SSID_11:
864 for (i = 0; i < ssid_range; i += 4)
865 *(int *)(ptr + i) = msg_bld_masks_11[i/4];
866 break;
867 case MSG_SSID_12:
868 for (i = 0; i < ssid_range; i += 4)
869 *(int *)(ptr + i) = msg_bld_masks_12[i/4];
870 break;
871 case MSG_SSID_13:
872 for (i = 0; i < ssid_range; i += 4)
873 *(int *)(ptr + i) = msg_bld_masks_13[i/4];
874 break;
875 case MSG_SSID_14:
876 for (i = 0; i < ssid_range; i += 4)
877 *(int *)(ptr + i) = msg_bld_masks_14[i/4];
878 break;
879 case MSG_SSID_15:
880 for (i = 0; i < ssid_range; i += 4)
881 *(int *)(ptr + i) = msg_bld_masks_15[i/4];
882 break;
883 case MSG_SSID_16:
884 for (i = 0; i < ssid_range; i += 4)
885 *(int *)(ptr + i) = msg_bld_masks_16[i/4];
886 break;
887 case MSG_SSID_17:
888 for (i = 0; i < ssid_range; i += 4)
889 *(int *)(ptr + i) = msg_bld_masks_17[i/4];
890 break;
891 case MSG_SSID_18:
892 for (i = 0; i < ssid_range; i += 4)
893 *(int *)(ptr + i) = msg_bld_masks_18[i/4];
894 break;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800895 case MSG_SSID_19:
896 for (i = 0; i < ssid_range; i += 4)
897 *(int *)(ptr + i) = msg_bld_masks_19[i/4];
898 break;
899 case MSG_SSID_20:
900 for (i = 0; i < ssid_range; i += 4)
901 *(int *)(ptr + i) = msg_bld_masks_20[i/4];
902 break;
903 case MSG_SSID_21:
904 for (i = 0; i < ssid_range; i += 4)
905 *(int *)(ptr + i) = msg_bld_masks_21[i/4];
906 break;
907 case MSG_SSID_22:
908 for (i = 0; i < ssid_range; i += 4)
909 *(int *)(ptr + i) = msg_bld_masks_22[i/4];
910 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700911 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700912 encode_rsp_and_send(8 + ssid_range - 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700913 return 0;
914 }
915 /* Check for download command */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530916 else if ((cpu_is_msm8x60() || chk_apps_master()) && (*buf == 0x3A)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700917 /* send response back */
918 driver->apps_rsp_buf[0] = *buf;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700919 encode_rsp_and_send(0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700920 msleep(5000);
921 /* call download API */
922 msm_set_restart_mode(RESTART_DLOAD);
923 printk(KERN_CRIT "diag: download mode set, Rebooting SoC..\n");
924 kernel_restart(NULL);
925 /* Not required, represents that command isnt sent to modem */
926 return 0;
927 }
Dixon Petersonb46bb992012-01-12 19:16:56 -0800928 /* Check for polling for Apps only DIAG */
929 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
930 (*(buf+2) == 0x03)) {
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800931 /* If no one has registered for polling */
Dixon Petersonb4618a42012-02-29 18:56:31 -0800932 if (chk_polling_response()) {
Dixon Petersonb46bb992012-01-12 19:16:56 -0800933 /* Respond to polling for Apps only DIAG */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700934 for (i = 0; i < 3; i++)
935 driver->apps_rsp_buf[i] = *(buf+i);
936 for (i = 0; i < 13; i++)
937 driver->apps_rsp_buf[i+3] = 0;
938
Dixon Petersond6a20a92012-09-27 15:58:50 -0700939 encode_rsp_and_send(15);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700940 return 0;
941 }
Dixon Petersonb46bb992012-01-12 19:16:56 -0800942 }
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -0800943 /* Return the Delayed Response Wrap Status */
944 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
945 (*(buf+2) == 0x04) && (*(buf+3) == 0x0)) {
946 memcpy(driver->apps_rsp_buf, buf, 4);
947 driver->apps_rsp_buf[4] = wrap_enabled;
948 encode_rsp_and_send(4);
949 return 0;
950 }
951 /* Wrap the Delayed Rsp ID */
952 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
953 (*(buf+2) == 0x05) && (*(buf+3) == 0x0)) {
954 wrap_enabled = true;
955 memcpy(driver->apps_rsp_buf, buf, 4);
956 driver->apps_rsp_buf[4] = wrap_count;
957 encode_rsp_and_send(5);
958 return 0;
959 }
Dixon Petersonb46bb992012-01-12 19:16:56 -0800960 /* Check for ID for NO MODEM present */
Dixon Petersonb4618a42012-02-29 18:56:31 -0800961 else if (chk_polling_response()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700962 /* respond to 0x0 command */
Dixon Petersonb46bb992012-01-12 19:16:56 -0800963 if (*buf == 0x00) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700964 for (i = 0; i < 55; i++)
965 driver->apps_rsp_buf[i] = 0;
966
Dixon Petersond6a20a92012-09-27 15:58:50 -0700967 encode_rsp_and_send(54);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700968 return 0;
969 }
970 /* respond to 0x7c command */
971 else if (*buf == 0x7c) {
972 driver->apps_rsp_buf[0] = 0x7c;
973 for (i = 1; i < 8; i++)
974 driver->apps_rsp_buf[i] = 0;
975 /* Tools ID for APQ 8060 */
976 *(int *)(driver->apps_rsp_buf + 8) =
977 chk_config_get_id();
978 *(unsigned char *)(driver->apps_rsp_buf + 12) = '\0';
979 *(unsigned char *)(driver->apps_rsp_buf + 13) = '\0';
Dixon Petersond6a20a92012-09-27 15:58:50 -0700980 encode_rsp_and_send(13);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700981 return 0;
982 }
983 }
984#endif
Dixon Petersond6a20a92012-09-27 15:58:50 -0700985 return packet_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700986}
987
988#ifdef CONFIG_DIAG_OVER_USB
989void diag_send_error_rsp(int index)
990{
991 int i;
Shalabh Jain1fedab92011-12-22 13:15:22 +0530992
993 if (index > 490) {
994 pr_err("diag: error response too huge, aborting\n");
995 return;
996 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700997 driver->apps_rsp_buf[0] = 0x13; /* error code 13 */
998 for (i = 0; i < index; i++)
999 driver->apps_rsp_buf[i+1] = *(driver->hdlc_buf+i);
Dixon Petersond6a20a92012-09-27 15:58:50 -07001000 encode_rsp_and_send(index - 3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001001}
1002#else
1003static inline void diag_send_error_rsp(int index) {}
1004#endif
1005
1006void diag_process_hdlc(void *data, unsigned len)
1007{
1008 struct diag_hdlc_decode_type hdlc;
1009 int ret, type = 0;
Dixon Peterson25f042b2013-02-27 13:00:08 -08001010
1011 mutex_lock(&driver->diag_hdlc_mutex);
1012
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001013 pr_debug("diag: HDLC decode fn, len of data %d\n", len);
1014 hdlc.dest_ptr = driver->hdlc_buf;
1015 hdlc.dest_size = USB_MAX_OUT_BUF;
1016 hdlc.src_ptr = data;
1017 hdlc.src_size = len;
1018 hdlc.src_idx = 0;
1019 hdlc.dest_idx = 0;
1020 hdlc.escaping = 0;
1021
1022 ret = diag_hdlc_decode(&hdlc);
1023
Dixon Petersonb4f84242013-02-27 18:46:56 -08001024 /*
1025 * If the message is 3 bytes or less in length then the message is
1026 * too short. A message will need 4 bytes minimum, since there are
1027 * 2 bytes for the CRC and 1 byte for the ending 0x7e for the hdlc
1028 * encoding
1029 */
1030 if (hdlc.dest_idx < 4) {
1031 pr_err_ratelimited("diag: In %s, message is too short, len: %d, dest len: %d\n",
1032 __func__, len, hdlc.dest_idx);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001033 mutex_unlock(&driver->diag_hdlc_mutex);
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001034 return;
1035 }
Dixon Petersonb4f84242013-02-27 18:46:56 -08001036
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001037 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001038 type = diag_process_apps_pkt(driver->hdlc_buf,
1039 hdlc.dest_idx - 3);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001040 if (type < 0) {
1041 mutex_unlock(&driver->diag_hdlc_mutex);
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001042 return;
Dixon Peterson25f042b2013-02-27 13:00:08 -08001043 }
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001044 } else if (driver->debug_flag) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001045 printk(KERN_ERR "Packet dropped due to bad HDLC coding/CRC"
1046 " errors or partial packet received, packet"
1047 " length = %d\n", len);
1048 print_hex_dump(KERN_DEBUG, "Dropped Packet Data: ", 16, 1,
1049 DUMP_PREFIX_ADDRESS, data, len, 1);
1050 driver->debug_flag = 0;
1051 }
1052 /* send error responses from APPS for Central Routing */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001053 if (type == 1 && chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001054 diag_send_error_rsp(hdlc.dest_idx);
1055 type = 0;
1056 }
1057 /* implies this packet is NOT meant for apps */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001058 if (!(driver->smd_data[MODEM_DATA].ch) && type == 1) {
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001059 if (chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001060 diag_send_error_rsp(hdlc.dest_idx);
1061 } else { /* APQ 8060, Let Q6 respond */
Dixon Peterson25f042b2013-02-27 13:00:08 -08001062 if (driver->smd_data[LPASS_DATA].ch) {
1063 mutex_lock(&driver->smd_data[LPASS_DATA].
1064 smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001065 smd_write(driver->smd_data[LPASS_DATA].ch,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001066 driver->hdlc_buf,
1067 hdlc.dest_idx - 3);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001068 mutex_unlock(&driver->smd_data[LPASS_DATA].
1069 smd_ch_mutex);
1070 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001071 }
1072 type = 0;
1073 }
1074
1075#ifdef DIAG_DEBUG
1076 pr_debug("diag: hdlc.dest_idx = %d", hdlc.dest_idx);
1077 for (i = 0; i < hdlc.dest_idx; i++)
1078 printk(KERN_DEBUG "\t%x", *(((unsigned char *)
1079 driver->hdlc_buf)+i));
1080#endif /* DIAG DEBUG */
1081 /* ignore 2 bytes for CRC, one for 7E and send */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001082 if ((driver->smd_data[MODEM_DATA].ch) && (ret) && (type) &&
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001083 (hdlc.dest_idx > 3)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001084 APPEND_DEBUG('g');
Dixon Peterson25f042b2013-02-27 13:00:08 -08001085 mutex_lock(&driver->smd_data[MODEM_DATA].smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001086 smd_write(driver->smd_data[MODEM_DATA].ch,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001087 driver->hdlc_buf, hdlc.dest_idx - 3);
Dixon Peterson25f042b2013-02-27 13:00:08 -08001088 mutex_unlock(&driver->smd_data[MODEM_DATA].smd_ch_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001089 APPEND_DEBUG('h');
1090#ifdef DIAG_DEBUG
1091 printk(KERN_INFO "writing data to SMD, pkt length %d\n", len);
1092 print_hex_dump(KERN_DEBUG, "Written Packet Data to SMD: ", 16,
1093 1, DUMP_PREFIX_ADDRESS, data, len, 1);
1094#endif /* DIAG DEBUG */
1095 }
Dixon Peterson25f042b2013-02-27 13:00:08 -08001096 mutex_unlock(&driver->diag_hdlc_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001097}
1098
1099#ifdef CONFIG_DIAG_OVER_USB
Shalabh Jain8e9750a2011-09-09 13:06:29 -07001100/* 2+1 for modem ; 2 for LPASS ; 1 for WCNSS */
1101#define N_LEGACY_WRITE (driver->poolsize + 6)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001102#define N_LEGACY_READ 1
1103
1104int diagfwd_connect(void)
1105{
1106 int err;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001107 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001108
1109 printk(KERN_DEBUG "diag: USB connected\n");
1110 err = usb_diag_alloc_req(driver->legacy_ch, N_LEGACY_WRITE,
1111 N_LEGACY_READ);
1112 if (err)
1113 printk(KERN_ERR "diag: unable to alloc USB req on legacy ch");
1114
1115 driver->usb_connected = 1;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001116 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1117 driver->smd_data[i].in_busy_1 = 0;
1118 driver->smd_data[i].in_busy_2 = 0;
1119 /* Poll SMD data channels to check for data */
1120 queue_work(driver->diag_wq,
1121 &(driver->smd_data[i].diag_read_smd_work));
1122 /* Poll SMD CNTL channels to check for data */
1123 diag_smd_notify(&(driver->smd_cntl[i]), SMD_EVENT_DATA);
1124 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001126 /* Poll USB channel to check for data*/
1127 queue_work(driver->diag_wq, &(driver->diag_read_work));
1128#ifdef CONFIG_DIAG_SDIO_PIPE
1129 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
1130 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1131 diagfwd_connect_sdio();
1132 else
1133 printk(KERN_INFO "diag: No USB MDM ch");
1134 }
1135#endif
1136 return 0;
1137}
1138
1139int diagfwd_disconnect(void)
1140{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001141 int i;
1142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001143 printk(KERN_DEBUG "diag: USB disconnected\n");
1144 driver->usb_connected = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001145 driver->debug_flag = 1;
1146 usb_diag_free_req(driver->legacy_ch);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001147 if (driver->logging_mode == USB_MODE) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001148 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1149 driver->smd_data[i].in_busy_1 = 1;
1150 driver->smd_data[i].in_busy_2 = 1;
1151 }
Shalabh Jain69890aa2011-10-10 12:59:16 -07001152 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001153#ifdef CONFIG_DIAG_SDIO_PIPE
1154 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
1155 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1156 diagfwd_disconnect_sdio();
1157#endif
1158 /* TBD - notify and flow control SMD */
1159 return 0;
1160}
1161
1162int diagfwd_write_complete(struct diag_request *diag_write_ptr)
1163{
1164 unsigned char *buf = diag_write_ptr->buf;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001165 int found_it = 0;
1166 int i;
1167
1168 /* Determine if the write complete is for data from modem/apps/q6 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001169 /* Need a context variable here instead */
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001170 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1171 struct diag_smd_info *data = &(driver->smd_data[i]);
1172 if (buf == (void *)data->buf_in_1) {
1173 data->in_busy_1 = 0;
1174 queue_work(driver->diag_wq,
1175 &(data->diag_read_smd_work));
1176 found_it = 1;
1177 break;
1178 } else if (buf == (void *)data->buf_in_2) {
1179 data->in_busy_2 = 0;
1180 queue_work(driver->diag_wq,
1181 &(data->diag_read_smd_work));
1182 found_it = 1;
1183 break;
1184 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185 }
1186#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001187 if (!found_it) {
1188 if (buf == (void *)driver->buf_in_sdio) {
1189 if (machine_is_msm8x60_fusion() ||
1190 machine_is_msm8x60_fusn_ffa())
1191 diagfwd_write_complete_sdio();
1192 else
1193 pr_err("diag: Incorrect buffer pointer while WRITE");
1194 found_it = 1;
1195 }
1196 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001197#endif
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001198 if (!found_it) {
1199 diagmem_free(driver, (unsigned char *)buf,
1200 POOL_TYPE_HDLC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001201 diagmem_free(driver, (unsigned char *)diag_write_ptr,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001202 POOL_TYPE_WRITE_STRUCT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203 }
1204 return 0;
1205}
1206
1207int diagfwd_read_complete(struct diag_request *diag_read_ptr)
1208{
1209 int status = diag_read_ptr->status;
1210 unsigned char *buf = diag_read_ptr->buf;
1211
1212 /* Determine if the read complete is for data on legacy/mdm ch */
1213 if (buf == (void *)driver->usb_buf_out) {
1214 driver->read_len_legacy = diag_read_ptr->actual;
1215 APPEND_DEBUG('s');
1216#ifdef DIAG_DEBUG
1217 printk(KERN_INFO "read data from USB, pkt length %d",
1218 diag_read_ptr->actual);
1219 print_hex_dump(KERN_DEBUG, "Read Packet Data from USB: ", 16, 1,
1220 DUMP_PREFIX_ADDRESS, diag_read_ptr->buf,
1221 diag_read_ptr->actual, 1);
1222#endif /* DIAG DEBUG */
1223 if (driver->logging_mode == USB_MODE) {
1224 if (status != -ECONNRESET && status != -ESHUTDOWN)
1225 queue_work(driver->diag_wq,
1226 &(driver->diag_proc_hdlc_work));
1227 else
1228 queue_work(driver->diag_wq,
1229 &(driver->diag_read_work));
1230 }
1231 }
1232#ifdef CONFIG_DIAG_SDIO_PIPE
1233 else if (buf == (void *)driver->usb_buf_mdm_out) {
1234 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -08001235 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001236 driver->read_len_mdm = diag_read_ptr->actual;
1237 diagfwd_read_complete_sdio();
1238 } else
1239 pr_err("diag: Incorrect buffer pointer while READ");
1240 }
1241#endif
1242 else
1243 printk(KERN_ERR "diag: Unknown buffer ptr from USB");
1244
1245 return 0;
1246}
1247
1248void diag_read_work_fn(struct work_struct *work)
1249{
1250 APPEND_DEBUG('d');
1251 driver->usb_read_ptr->buf = driver->usb_buf_out;
1252 driver->usb_read_ptr->length = USB_MAX_OUT_BUF;
1253 usb_diag_read(driver->legacy_ch, driver->usb_read_ptr);
1254 APPEND_DEBUG('e');
1255}
1256
1257void diag_process_hdlc_fn(struct work_struct *work)
1258{
1259 APPEND_DEBUG('D');
1260 diag_process_hdlc(driver->usb_buf_out, driver->read_len_legacy);
1261 diag_read_work_fn(work);
1262 APPEND_DEBUG('E');
1263}
1264
1265void diag_usb_legacy_notifier(void *priv, unsigned event,
1266 struct diag_request *d_req)
1267{
1268 switch (event) {
1269 case USB_DIAG_CONNECT:
1270 diagfwd_connect();
1271 break;
1272 case USB_DIAG_DISCONNECT:
1273 diagfwd_disconnect();
1274 break;
1275 case USB_DIAG_READ_DONE:
1276 diagfwd_read_complete(d_req);
1277 break;
1278 case USB_DIAG_WRITE_DONE:
1279 diagfwd_write_complete(d_req);
1280 break;
1281 default:
1282 printk(KERN_ERR "Unknown event from USB diag\n");
1283 break;
1284 }
1285}
1286
1287#endif /* DIAG OVER USB */
1288
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001289void diag_smd_notify(void *ctxt, unsigned event)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001290{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001291 struct diag_smd_info *smd_info = (struct diag_smd_info *)ctxt;
1292 if (!smd_info)
Shalabh Jaineefee052011-11-08 23:46:03 -08001293 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001294
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001295 if (event == SMD_EVENT_CLOSE) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001296 smd_info->ch = 0;
Shalabh Jainc70b3b62012-08-31 19:11:20 -07001297 wake_up(&driver->smd_wait_q);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001298 if (smd_info->type == SMD_DATA_TYPE) {
1299 smd_info->notify_context = event;
1300 queue_work(driver->diag_cntl_wq,
1301 &(smd_info->diag_notify_update_smd_work));
1302 } else if (smd_info->type == SMD_DCI_TYPE) {
1303 /* Notify the clients of the close */
1304 diag_dci_notify_client(smd_info->peripheral_mask,
1305 DIAG_STATUS_CLOSED);
1306 }
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001307 return;
1308 } else if (event == SMD_EVENT_OPEN) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001309 if (smd_info->ch_save)
1310 smd_info->ch = smd_info->ch_save;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001311
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001312 if (smd_info->type == SMD_CNTL_TYPE) {
1313 smd_info->notify_context = event;
1314 queue_work(driver->diag_cntl_wq,
1315 &(smd_info->diag_notify_update_smd_work));
1316 } else if (smd_info->type == SMD_DCI_TYPE) {
1317 smd_info->notify_context = event;
1318 queue_work(driver->diag_dci_wq,
1319 &(smd_info->diag_notify_update_smd_work));
1320 /* Notify the clients of the open */
1321 diag_dci_notify_client(smd_info->peripheral_mask,
1322 DIAG_STATUS_OPEN);
1323 }
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001324 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001325
Shalabh Jainc70b3b62012-08-31 19:11:20 -07001326 wake_up(&driver->smd_wait_q);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001327
1328 if (smd_info->type == SMD_DCI_TYPE)
1329 queue_work(driver->diag_dci_wq,
1330 &(smd_info->diag_read_smd_work));
1331 else
1332 queue_work(driver->diag_wq, &(smd_info->diag_read_smd_work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001333}
1334
1335static int diag_smd_probe(struct platform_device *pdev)
1336{
1337 int r = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001338 int index = -1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001339
Shalabh Jaineefee052011-11-08 23:46:03 -08001340 if (pdev->id == SMD_APPS_MODEM) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001341 index = MODEM_DATA;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001342 r = smd_open("DIAG", &driver->smd_data[index].ch,
1343 &driver->smd_data[index],
1344 diag_smd_notify);
1345 driver->smd_data[index].ch_save =
1346 driver->smd_data[index].ch;
Shalabh Jaineefee052011-11-08 23:46:03 -08001347 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001348#if defined(CONFIG_MSM_N_WAY_SMD)
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001349 if (pdev->id == SMD_APPS_QDSP) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001350 index = LPASS_DATA;
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001351 r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001352 &driver->smd_data[index].ch,
1353 &driver->smd_data[index],
1354 diag_smd_notify);
1355 driver->smd_data[index].ch_save =
1356 driver->smd_data[index].ch;
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001357 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001358#endif
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001359 if (pdev->id == SMD_APPS_WCNSS) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001360 index = WCNSS_DATA;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001361 r = smd_named_open_on_edge("APPS_RIVA_DATA",
1362 SMD_APPS_WCNSS,
1363 &driver->smd_data[index].ch,
1364 &driver->smd_data[index],
1365 diag_smd_notify);
1366 driver->smd_data[index].ch_save =
1367 driver->smd_data[index].ch;
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001368 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001369
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001370 pm_runtime_set_active(&pdev->dev);
1371 pm_runtime_enable(&pdev->dev);
1372 pr_debug("diag: open SMD port, Id = %d, r = %d\n", pdev->id, r);
1373
1374 return 0;
1375}
1376
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001377static int diag_smd_runtime_suspend(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001378{
1379 dev_dbg(dev, "pm_runtime: suspending...\n");
1380 return 0;
1381}
1382
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001383static int diag_smd_runtime_resume(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384{
1385 dev_dbg(dev, "pm_runtime: resuming...\n");
1386 return 0;
1387}
1388
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001389static const struct dev_pm_ops diag_smd_dev_pm_ops = {
1390 .runtime_suspend = diag_smd_runtime_suspend,
1391 .runtime_resume = diag_smd_runtime_resume,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001392};
1393
1394static struct platform_driver msm_smd_ch1_driver = {
1395
1396 .probe = diag_smd_probe,
1397 .driver = {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001398 .name = "DIAG",
1399 .owner = THIS_MODULE,
1400 .pm = &diag_smd_dev_pm_ops,
1401 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402};
1403
1404static struct platform_driver diag_smd_lite_driver = {
1405
1406 .probe = diag_smd_probe,
1407 .driver = {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001408 .name = "APPS_RIVA_DATA",
1409 .owner = THIS_MODULE,
1410 .pm = &diag_smd_dev_pm_ops,
1411 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001412};
1413
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001414void diag_smd_destructor(struct diag_smd_info *smd_info)
1415{
1416 if (smd_info->ch)
1417 smd_close(smd_info->ch);
1418
1419 smd_info->ch = 0;
1420 smd_info->ch_save = 0;
1421 kfree(smd_info->buf_in_1);
1422 kfree(smd_info->buf_in_2);
1423 kfree(smd_info->write_ptr_1);
1424 kfree(smd_info->write_ptr_2);
1425}
1426
1427int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral,
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001428 int type)
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001429{
1430 smd_info->peripheral = peripheral;
1431 smd_info->type = type;
Dixon Peterson25f042b2013-02-27 13:00:08 -08001432 mutex_init(&smd_info->smd_ch_mutex);
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001433
1434 switch (peripheral) {
1435 case MODEM_DATA:
1436 smd_info->peripheral_mask = DIAG_CON_MPSS;
1437 break;
1438 case LPASS_DATA:
1439 smd_info->peripheral_mask = DIAG_CON_LPASS;
1440 break;
1441 case WCNSS_DATA:
1442 smd_info->peripheral_mask = DIAG_CON_WCNSS;
1443 break;
1444 default:
1445 pr_err("diag: In %s, unknown peripheral, peripheral: %d\n",
1446 __func__, peripheral);
1447 goto err;
1448 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001449
1450 smd_info->ch = 0;
1451 smd_info->ch_save = 0;
1452
1453 if (smd_info->buf_in_1 == NULL) {
1454 smd_info->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1455 if (smd_info->buf_in_1 == NULL)
1456 goto err;
1457 kmemleak_not_leak(smd_info->buf_in_1);
1458 }
1459
1460 if (smd_info->write_ptr_1 == NULL) {
1461 smd_info->write_ptr_1 = kzalloc(sizeof(struct diag_request),
1462 GFP_KERNEL);
1463 if (smd_info->write_ptr_1 == NULL)
1464 goto err;
1465 kmemleak_not_leak(smd_info->write_ptr_1);
1466 }
1467
1468 /* The smd data type needs two buffers */
1469 if (smd_info->type == SMD_DATA_TYPE) {
1470 if (smd_info->buf_in_2 == NULL) {
1471 smd_info->buf_in_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1472 if (smd_info->buf_in_2 == NULL)
1473 goto err;
1474 kmemleak_not_leak(smd_info->buf_in_2);
1475 }
1476 if (smd_info->write_ptr_2 == NULL) {
1477 smd_info->write_ptr_2 =
1478 kzalloc(sizeof(struct diag_request),
1479 GFP_KERNEL);
1480 if (smd_info->write_ptr_2 == NULL)
1481 goto err;
1482 kmemleak_not_leak(smd_info->write_ptr_2);
1483 }
1484 }
1485
1486 INIT_WORK(&(smd_info->diag_read_smd_work), diag_read_smd_work_fn);
1487
1488 /*
1489 * The update function assigned to the diag_notify_update_smd_work
1490 * work_struct is meant to be used for updating that is not to
1491 * be done in the context of the smd notify function. The
1492 * notify_context variable can be used for passing additional
1493 * information to the update function.
1494 */
1495 smd_info->notify_context = 0;
1496 if (type == SMD_DATA_TYPE)
1497 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
1498 diag_clean_reg_fn);
1499 else if (type == SMD_CNTL_TYPE)
1500 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
1501 diag_mask_update_fn);
1502 else if (type == SMD_DCI_TYPE)
1503 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
1504 diag_update_smd_dci_work_fn);
1505 else {
1506 pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
1507 goto err;
1508 }
1509
1510 /*
1511 * Set function ptr for function to call to process the data that
1512 * was just read from the smd channel
1513 */
1514 if (type == SMD_DATA_TYPE)
1515 smd_info->process_smd_read_data = diag_process_smd_read_data;
1516 else if (type == SMD_CNTL_TYPE)
1517 smd_info->process_smd_read_data =
1518 diag_process_smd_cntl_read_data;
1519 else if (type == SMD_DCI_TYPE)
1520 smd_info->process_smd_read_data =
1521 diag_process_smd_dci_read_data;
1522 else {
1523 pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
1524 goto err;
1525 }
1526
1527 return 1;
1528err:
1529 kfree(smd_info->buf_in_1);
1530 kfree(smd_info->buf_in_2);
1531 kfree(smd_info->write_ptr_1);
1532 kfree(smd_info->write_ptr_2);
1533
1534 return 0;
1535}
1536
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001537void diagfwd_init(void)
1538{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001539 int success;
1540 int i;
1541
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -08001542 wrap_enabled = 0;
1543 wrap_count = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544 diag_debug_buf_idx = 0;
1545 driver->read_len_legacy = 0;
Dixon Petersonb4618a42012-02-29 18:56:31 -08001546 driver->use_device_tree = has_device_tree();
Dixon Peterson25f042b2013-02-27 13:00:08 -08001547 mutex_init(&driver->diag_hdlc_mutex);
Shalabh Jaina06c6d72012-04-30 13:40:35 -07001548 mutex_init(&driver->diag_cntl_mutex);
Shalabh Jain321c8b52012-02-22 12:37:06 -08001549
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001550 success = diag_smd_constructor(&driver->smd_data[MODEM_DATA],
1551 MODEM_DATA, SMD_DATA_TYPE);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001552 if (!success)
1553 goto err;
1554
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001555 success = diag_smd_constructor(&driver->smd_data[LPASS_DATA],
1556 LPASS_DATA, SMD_DATA_TYPE);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001557 if (!success)
1558 goto err;
1559
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001560 success = diag_smd_constructor(&driver->smd_data[WCNSS_DATA],
1561 WCNSS_DATA, SMD_DATA_TYPE);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001562 if (!success)
1563 goto err;
1564
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001565 if (driver->usb_buf_out == NULL &&
1566 (driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
1567 GFP_KERNEL)) == NULL)
1568 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001569 kmemleak_not_leak(driver->usb_buf_out);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001570 if (driver->hdlc_buf == NULL
1571 && (driver->hdlc_buf = kzalloc(HDLC_MAX, GFP_KERNEL)) == NULL)
1572 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001573 kmemleak_not_leak(driver->hdlc_buf);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001574 if (driver->user_space_data == NULL)
1575 driver->user_space_data = kzalloc(USER_SPACE_DATA, GFP_KERNEL);
1576 if (driver->user_space_data == NULL)
1577 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001578 kmemleak_not_leak(driver->user_space_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001579 if (driver->client_map == NULL &&
1580 (driver->client_map = kzalloc
1581 ((driver->num_clients) * sizeof(struct diag_client_map),
1582 GFP_KERNEL)) == NULL)
1583 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001584 kmemleak_not_leak(driver->client_map);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001585 if (driver->buf_tbl == NULL)
1586 driver->buf_tbl = kzalloc(buf_tbl_size *
1587 sizeof(struct diag_write_device), GFP_KERNEL);
1588 if (driver->buf_tbl == NULL)
1589 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001590 kmemleak_not_leak(driver->buf_tbl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001591 if (driver->data_ready == NULL &&
1592 (driver->data_ready = kzalloc(driver->num_clients * sizeof(int)
1593 , GFP_KERNEL)) == NULL)
1594 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001595 kmemleak_not_leak(driver->data_ready);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001596 if (driver->table == NULL &&
Shalabh Jainfe02b0c2012-02-21 14:48:03 -08001597 (driver->table = kzalloc(diag_max_reg*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001598 sizeof(struct diag_master_table),
1599 GFP_KERNEL)) == NULL)
1600 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001601 kmemleak_not_leak(driver->table);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301602
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001603 if (driver->usb_read_ptr == NULL) {
1604 driver->usb_read_ptr = kzalloc(
1605 sizeof(struct diag_request), GFP_KERNEL);
1606 if (driver->usb_read_ptr == NULL)
1607 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001608 kmemleak_not_leak(driver->usb_read_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001609 }
1610 if (driver->pkt_buf == NULL &&
1611 (driver->pkt_buf = kzalloc(PKT_SIZE,
1612 GFP_KERNEL)) == NULL)
1613 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001614 kmemleak_not_leak(driver->pkt_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001615 if (driver->apps_rsp_buf == NULL) {
Shalabh Jain321c8b52012-02-22 12:37:06 -08001616 driver->apps_rsp_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001617 if (driver->apps_rsp_buf == NULL)
1618 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001619 kmemleak_not_leak(driver->apps_rsp_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001620 }
1621 driver->diag_wq = create_singlethread_workqueue("diag_wq");
1622#ifdef CONFIG_DIAG_OVER_USB
1623 INIT_WORK(&(driver->diag_proc_hdlc_work), diag_process_hdlc_fn);
1624 INIT_WORK(&(driver->diag_read_work), diag_read_work_fn);
1625 driver->legacy_ch = usb_diag_open(DIAG_LEGACY, driver,
1626 diag_usb_legacy_notifier);
1627 if (IS_ERR(driver->legacy_ch)) {
1628 printk(KERN_ERR "Unable to open USB diag legacy channel\n");
1629 goto err;
1630 }
1631#endif
1632 platform_driver_register(&msm_smd_ch1_driver);
1633 platform_driver_register(&diag_smd_lite_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001634 return;
1635err:
Dixon Petersond6a20a92012-09-27 15:58:50 -07001636 pr_err("diag: Could not initialize diag buffers");
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001637
1638 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
1639 diag_smd_destructor(&driver->smd_data[i]);
1640
Dixon Petersond6a20a92012-09-27 15:58:50 -07001641 kfree(driver->buf_msg_mask_update);
1642 kfree(driver->buf_log_mask_update);
1643 kfree(driver->buf_event_mask_update);
1644 kfree(driver->usb_buf_out);
1645 kfree(driver->hdlc_buf);
1646 kfree(driver->client_map);
1647 kfree(driver->buf_tbl);
1648 kfree(driver->data_ready);
1649 kfree(driver->table);
1650 kfree(driver->pkt_buf);
Dixon Petersond6a20a92012-09-27 15:58:50 -07001651 kfree(driver->usb_read_ptr);
1652 kfree(driver->apps_rsp_buf);
1653 kfree(driver->user_space_data);
1654 if (driver->diag_wq)
1655 destroy_workqueue(driver->diag_wq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001656}
1657
1658void diagfwd_exit(void)
1659{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001660 int i;
1661
1662 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
1663 diag_smd_destructor(&driver->smd_data[i]);
1664
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001665#ifdef CONFIG_DIAG_OVER_USB
1666 if (driver->usb_connected)
1667 usb_diag_free_req(driver->legacy_ch);
1668 usb_diag_close(driver->legacy_ch);
1669#endif
1670 platform_driver_unregister(&msm_smd_ch1_driver);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001671 platform_driver_unregister(&msm_diag_dci_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001672 platform_driver_unregister(&diag_smd_lite_driver);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001673
Shalabh Jain321c8b52012-02-22 12:37:06 -08001674 kfree(driver->buf_msg_mask_update);
1675 kfree(driver->buf_log_mask_update);
1676 kfree(driver->buf_event_mask_update);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001677 kfree(driver->usb_buf_out);
1678 kfree(driver->hdlc_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001679 kfree(driver->client_map);
1680 kfree(driver->buf_tbl);
1681 kfree(driver->data_ready);
1682 kfree(driver->table);
1683 kfree(driver->pkt_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001684 kfree(driver->usb_read_ptr);
1685 kfree(driver->apps_rsp_buf);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001686 kfree(driver->user_space_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001687 destroy_workqueue(driver->diag_wq);
1688}