blob: 6a141439b79f00150ca516c2927a47d81e29b556 [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 }
614 smd_write(driver->smd_data[index].ch,
615 buf, len);
616 } else {
617 pr_err("diag: In %s, smd channel %d not open\n",
618 __func__, index);
619 }
Shalabh Jainc9f35092011-07-28 18:36:17 -0700620 } else {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800621 pr_alert("diag: In %s, incorrect channel: %d",
622 __func__, entry.client_id);
Shalabh Jainc9f35092011-07-28 18:36:17 -0700623 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700624 }
625 }
626}
627
628static int diag_process_apps_pkt(unsigned char *buf, int len)
629{
630 uint16_t subsys_cmd_code;
631 int subsys_id, ssid_first, ssid_last, ssid_range;
Shalabh Jain3fd986f2012-05-30 18:42:26 -0700632 int packet_type = 1, i, cmd_code;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700633 unsigned char *temp = buf;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700634 int data_type;
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -0800635 int mask_ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700636#if defined(CONFIG_DIAG_OVER_USB)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637 unsigned char *ptr;
638#endif
639
Dixon Petersond6a20a92012-09-27 15:58:50 -0700640 /* Check if the command is a supported mask command */
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -0800641 mask_ret = diag_process_apps_masks(buf, len);
642 if (mask_ret <= 0)
643 return mask_ret;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700644
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700645 /* Check for registered clients and forward packet to apropriate proc */
646 cmd_code = (int)(*(char *)buf);
647 temp++;
648 subsys_id = (int)(*(char *)temp);
649 temp++;
650 subsys_cmd_code = *(uint16_t *)temp;
651 temp += 2;
652 data_type = APPS_DATA;
653 /* Dont send any command other than mode reset */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530654 if (chk_apps_master() && cmd_code == MODE_CMD) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655 if (subsys_id != RESET_ID)
656 data_type = MODEM_DATA;
657 }
658
659 pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
Shalabh Jainfe02b0c2012-02-21 14:48:03 -0800660 for (i = 0; i < diag_max_reg; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700661 entry = driver->table[i];
662 if (entry.process_id != NO_PROCESS) {
663 if (entry.cmd_code == cmd_code && entry.subsys_id ==
664 subsys_id && entry.cmd_code_lo <=
665 subsys_cmd_code &&
666 entry.cmd_code_hi >= subsys_cmd_code) {
667 diag_send_data(entry, buf, len, data_type);
668 packet_type = 0;
669 } else if (entry.cmd_code == 255
670 && cmd_code == 75) {
671 if (entry.subsys_id ==
672 subsys_id &&
673 entry.cmd_code_lo <=
674 subsys_cmd_code &&
675 entry.cmd_code_hi >=
676 subsys_cmd_code) {
677 diag_send_data(entry, buf, len,
678 data_type);
679 packet_type = 0;
680 }
681 } else if (entry.cmd_code == 255 &&
682 entry.subsys_id == 255) {
683 if (entry.cmd_code_lo <=
684 cmd_code &&
685 entry.
686 cmd_code_hi >= cmd_code) {
687 diag_send_data(entry, buf, len,
688 data_type);
689 packet_type = 0;
690 }
691 }
692 }
693 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700694#if defined(CONFIG_DIAG_OVER_USB)
Dixon Petersona2dd7352012-05-21 17:37:10 -0700695 /* Check for the command/respond msg for the maximum packet length */
696 if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
697 (*(uint16_t *)(buf+2) == 0x0055)) {
698 for (i = 0; i < 4; i++)
699 *(driver->apps_rsp_buf+i) = *(buf+i);
700 *(uint32_t *)(driver->apps_rsp_buf+4) = PKT_SIZE;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700701 encode_rsp_and_send(7);
Dixon Petersona2dd7352012-05-21 17:37:10 -0700702 return 0;
703 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700704 /* Check for Apps Only & get event mask request */
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800705 else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only() &&
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800706 *buf == 0x81) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700707 driver->apps_rsp_buf[0] = 0x81;
708 driver->apps_rsp_buf[1] = 0x0;
709 *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
710 *(uint16_t *)(driver->apps_rsp_buf + 4) = EVENT_LAST_ID + 1;
711 for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
712 *(unsigned char *)(driver->apps_rsp_buf + 6 + i) = 0x0;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700713 encode_rsp_and_send(6 + EVENT_LAST_ID/8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700714 return 0;
715 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700716 /* Get log ID range & Check for Apps Only */
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800717 else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700718 && (*buf == 0x73) && *(int *)(buf+4) == 1) {
719 driver->apps_rsp_buf[0] = 0x73;
720 *(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
721 *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success code */
722 *(int *)(driver->apps_rsp_buf + 12) = LOG_GET_ITEM_NUM(LOG_0);
723 *(int *)(driver->apps_rsp_buf + 16) = LOG_GET_ITEM_NUM(LOG_1);
724 *(int *)(driver->apps_rsp_buf + 20) = LOG_GET_ITEM_NUM(LOG_2);
725 *(int *)(driver->apps_rsp_buf + 24) = LOG_GET_ITEM_NUM(LOG_3);
726 *(int *)(driver->apps_rsp_buf + 28) = LOG_GET_ITEM_NUM(LOG_4);
727 *(int *)(driver->apps_rsp_buf + 32) = LOG_GET_ITEM_NUM(LOG_5);
728 *(int *)(driver->apps_rsp_buf + 36) = LOG_GET_ITEM_NUM(LOG_6);
729 *(int *)(driver->apps_rsp_buf + 40) = LOG_GET_ITEM_NUM(LOG_7);
730 *(int *)(driver->apps_rsp_buf + 44) = LOG_GET_ITEM_NUM(LOG_8);
731 *(int *)(driver->apps_rsp_buf + 48) = LOG_GET_ITEM_NUM(LOG_9);
732 *(int *)(driver->apps_rsp_buf + 52) = LOG_GET_ITEM_NUM(LOG_10);
733 *(int *)(driver->apps_rsp_buf + 56) = LOG_GET_ITEM_NUM(LOG_11);
734 *(int *)(driver->apps_rsp_buf + 60) = LOG_GET_ITEM_NUM(LOG_12);
735 *(int *)(driver->apps_rsp_buf + 64) = LOG_GET_ITEM_NUM(LOG_13);
736 *(int *)(driver->apps_rsp_buf + 68) = LOG_GET_ITEM_NUM(LOG_14);
737 *(int *)(driver->apps_rsp_buf + 72) = LOG_GET_ITEM_NUM(LOG_15);
Dixon Petersond6a20a92012-09-27 15:58:50 -0700738 encode_rsp_and_send(75);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700739 return 0;
740 }
741 /* Respond to Get SSID Range request message */
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800742 else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700743 && (*buf == 0x7d) && (*(buf+1) == 0x1)) {
744 driver->apps_rsp_buf[0] = 0x7d;
745 driver->apps_rsp_buf[1] = 0x1;
746 driver->apps_rsp_buf[2] = 0x1;
747 driver->apps_rsp_buf[3] = 0x0;
Shalabh Jain44b79b72012-06-15 13:39:27 -0700748 /* -1 to un-account for OEM SSID range */
749 *(int *)(driver->apps_rsp_buf + 4) = MSG_MASK_TBL_CNT - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700750 *(uint16_t *)(driver->apps_rsp_buf + 8) = MSG_SSID_0;
751 *(uint16_t *)(driver->apps_rsp_buf + 10) = MSG_SSID_0_LAST;
752 *(uint16_t *)(driver->apps_rsp_buf + 12) = MSG_SSID_1;
753 *(uint16_t *)(driver->apps_rsp_buf + 14) = MSG_SSID_1_LAST;
754 *(uint16_t *)(driver->apps_rsp_buf + 16) = MSG_SSID_2;
755 *(uint16_t *)(driver->apps_rsp_buf + 18) = MSG_SSID_2_LAST;
756 *(uint16_t *)(driver->apps_rsp_buf + 20) = MSG_SSID_3;
757 *(uint16_t *)(driver->apps_rsp_buf + 22) = MSG_SSID_3_LAST;
758 *(uint16_t *)(driver->apps_rsp_buf + 24) = MSG_SSID_4;
759 *(uint16_t *)(driver->apps_rsp_buf + 26) = MSG_SSID_4_LAST;
760 *(uint16_t *)(driver->apps_rsp_buf + 28) = MSG_SSID_5;
761 *(uint16_t *)(driver->apps_rsp_buf + 30) = MSG_SSID_5_LAST;
762 *(uint16_t *)(driver->apps_rsp_buf + 32) = MSG_SSID_6;
763 *(uint16_t *)(driver->apps_rsp_buf + 34) = MSG_SSID_6_LAST;
764 *(uint16_t *)(driver->apps_rsp_buf + 36) = MSG_SSID_7;
765 *(uint16_t *)(driver->apps_rsp_buf + 38) = MSG_SSID_7_LAST;
766 *(uint16_t *)(driver->apps_rsp_buf + 40) = MSG_SSID_8;
767 *(uint16_t *)(driver->apps_rsp_buf + 42) = MSG_SSID_8_LAST;
768 *(uint16_t *)(driver->apps_rsp_buf + 44) = MSG_SSID_9;
769 *(uint16_t *)(driver->apps_rsp_buf + 46) = MSG_SSID_9_LAST;
770 *(uint16_t *)(driver->apps_rsp_buf + 48) = MSG_SSID_10;
771 *(uint16_t *)(driver->apps_rsp_buf + 50) = MSG_SSID_10_LAST;
772 *(uint16_t *)(driver->apps_rsp_buf + 52) = MSG_SSID_11;
773 *(uint16_t *)(driver->apps_rsp_buf + 54) = MSG_SSID_11_LAST;
774 *(uint16_t *)(driver->apps_rsp_buf + 56) = MSG_SSID_12;
775 *(uint16_t *)(driver->apps_rsp_buf + 58) = MSG_SSID_12_LAST;
776 *(uint16_t *)(driver->apps_rsp_buf + 60) = MSG_SSID_13;
777 *(uint16_t *)(driver->apps_rsp_buf + 62) = MSG_SSID_13_LAST;
778 *(uint16_t *)(driver->apps_rsp_buf + 64) = MSG_SSID_14;
779 *(uint16_t *)(driver->apps_rsp_buf + 66) = MSG_SSID_14_LAST;
780 *(uint16_t *)(driver->apps_rsp_buf + 68) = MSG_SSID_15;
781 *(uint16_t *)(driver->apps_rsp_buf + 70) = MSG_SSID_15_LAST;
782 *(uint16_t *)(driver->apps_rsp_buf + 72) = MSG_SSID_16;
783 *(uint16_t *)(driver->apps_rsp_buf + 74) = MSG_SSID_16_LAST;
784 *(uint16_t *)(driver->apps_rsp_buf + 76) = MSG_SSID_17;
785 *(uint16_t *)(driver->apps_rsp_buf + 78) = MSG_SSID_17_LAST;
786 *(uint16_t *)(driver->apps_rsp_buf + 80) = MSG_SSID_18;
787 *(uint16_t *)(driver->apps_rsp_buf + 82) = MSG_SSID_18_LAST;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800788 *(uint16_t *)(driver->apps_rsp_buf + 84) = MSG_SSID_19;
789 *(uint16_t *)(driver->apps_rsp_buf + 86) = MSG_SSID_19_LAST;
790 *(uint16_t *)(driver->apps_rsp_buf + 88) = MSG_SSID_20;
791 *(uint16_t *)(driver->apps_rsp_buf + 90) = MSG_SSID_20_LAST;
792 *(uint16_t *)(driver->apps_rsp_buf + 92) = MSG_SSID_21;
793 *(uint16_t *)(driver->apps_rsp_buf + 94) = MSG_SSID_21_LAST;
794 *(uint16_t *)(driver->apps_rsp_buf + 96) = MSG_SSID_22;
795 *(uint16_t *)(driver->apps_rsp_buf + 98) = MSG_SSID_22_LAST;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700796 encode_rsp_and_send(99);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700797 return 0;
798 }
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700799 /* Check for Apps Only Respond to Get Subsys Build mask */
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800800 else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801 && (*buf == 0x7d) && (*(buf+1) == 0x2)) {
802 ssid_first = *(uint16_t *)(buf + 2);
803 ssid_last = *(uint16_t *)(buf + 4);
804 ssid_range = 4 * (ssid_last - ssid_first + 1);
805 /* frame response */
806 driver->apps_rsp_buf[0] = 0x7d;
807 driver->apps_rsp_buf[1] = 0x2;
808 *(uint16_t *)(driver->apps_rsp_buf + 2) = ssid_first;
809 *(uint16_t *)(driver->apps_rsp_buf + 4) = ssid_last;
810 driver->apps_rsp_buf[6] = 0x1;
811 driver->apps_rsp_buf[7] = 0x0;
812 ptr = driver->apps_rsp_buf + 8;
813 /* bld time masks */
814 switch (ssid_first) {
815 case MSG_SSID_0:
816 for (i = 0; i < ssid_range; i += 4)
817 *(int *)(ptr + i) = msg_bld_masks_0[i/4];
818 break;
819 case MSG_SSID_1:
820 for (i = 0; i < ssid_range; i += 4)
821 *(int *)(ptr + i) = msg_bld_masks_1[i/4];
822 break;
823 case MSG_SSID_2:
824 for (i = 0; i < ssid_range; i += 4)
825 *(int *)(ptr + i) = msg_bld_masks_2[i/4];
826 break;
827 case MSG_SSID_3:
828 for (i = 0; i < ssid_range; i += 4)
829 *(int *)(ptr + i) = msg_bld_masks_3[i/4];
830 break;
831 case MSG_SSID_4:
832 for (i = 0; i < ssid_range; i += 4)
833 *(int *)(ptr + i) = msg_bld_masks_4[i/4];
834 break;
835 case MSG_SSID_5:
836 for (i = 0; i < ssid_range; i += 4)
837 *(int *)(ptr + i) = msg_bld_masks_5[i/4];
838 break;
839 case MSG_SSID_6:
840 for (i = 0; i < ssid_range; i += 4)
841 *(int *)(ptr + i) = msg_bld_masks_6[i/4];
842 break;
843 case MSG_SSID_7:
844 for (i = 0; i < ssid_range; i += 4)
845 *(int *)(ptr + i) = msg_bld_masks_7[i/4];
846 break;
847 case MSG_SSID_8:
848 for (i = 0; i < ssid_range; i += 4)
849 *(int *)(ptr + i) = msg_bld_masks_8[i/4];
850 break;
851 case MSG_SSID_9:
852 for (i = 0; i < ssid_range; i += 4)
853 *(int *)(ptr + i) = msg_bld_masks_9[i/4];
854 break;
855 case MSG_SSID_10:
856 for (i = 0; i < ssid_range; i += 4)
857 *(int *)(ptr + i) = msg_bld_masks_10[i/4];
858 break;
859 case MSG_SSID_11:
860 for (i = 0; i < ssid_range; i += 4)
861 *(int *)(ptr + i) = msg_bld_masks_11[i/4];
862 break;
863 case MSG_SSID_12:
864 for (i = 0; i < ssid_range; i += 4)
865 *(int *)(ptr + i) = msg_bld_masks_12[i/4];
866 break;
867 case MSG_SSID_13:
868 for (i = 0; i < ssid_range; i += 4)
869 *(int *)(ptr + i) = msg_bld_masks_13[i/4];
870 break;
871 case MSG_SSID_14:
872 for (i = 0; i < ssid_range; i += 4)
873 *(int *)(ptr + i) = msg_bld_masks_14[i/4];
874 break;
875 case MSG_SSID_15:
876 for (i = 0; i < ssid_range; i += 4)
877 *(int *)(ptr + i) = msg_bld_masks_15[i/4];
878 break;
879 case MSG_SSID_16:
880 for (i = 0; i < ssid_range; i += 4)
881 *(int *)(ptr + i) = msg_bld_masks_16[i/4];
882 break;
883 case MSG_SSID_17:
884 for (i = 0; i < ssid_range; i += 4)
885 *(int *)(ptr + i) = msg_bld_masks_17[i/4];
886 break;
887 case MSG_SSID_18:
888 for (i = 0; i < ssid_range; i += 4)
889 *(int *)(ptr + i) = msg_bld_masks_18[i/4];
890 break;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800891 case MSG_SSID_19:
892 for (i = 0; i < ssid_range; i += 4)
893 *(int *)(ptr + i) = msg_bld_masks_19[i/4];
894 break;
895 case MSG_SSID_20:
896 for (i = 0; i < ssid_range; i += 4)
897 *(int *)(ptr + i) = msg_bld_masks_20[i/4];
898 break;
899 case MSG_SSID_21:
900 for (i = 0; i < ssid_range; i += 4)
901 *(int *)(ptr + i) = msg_bld_masks_21[i/4];
902 break;
903 case MSG_SSID_22:
904 for (i = 0; i < ssid_range; i += 4)
905 *(int *)(ptr + i) = msg_bld_masks_22[i/4];
906 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907 }
Dixon Petersond6a20a92012-09-27 15:58:50 -0700908 encode_rsp_and_send(8 + ssid_range - 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700909 return 0;
910 }
911 /* Check for download command */
Shalabh Jain10f5f432012-01-11 11:45:44 +0530912 else if ((cpu_is_msm8x60() || chk_apps_master()) && (*buf == 0x3A)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700913 /* send response back */
914 driver->apps_rsp_buf[0] = *buf;
Dixon Petersond6a20a92012-09-27 15:58:50 -0700915 encode_rsp_and_send(0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700916 msleep(5000);
917 /* call download API */
918 msm_set_restart_mode(RESTART_DLOAD);
919 printk(KERN_CRIT "diag: download mode set, Rebooting SoC..\n");
920 kernel_restart(NULL);
921 /* Not required, represents that command isnt sent to modem */
922 return 0;
923 }
Dixon Petersonb46bb992012-01-12 19:16:56 -0800924 /* Check for polling for Apps only DIAG */
925 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
926 (*(buf+2) == 0x03)) {
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800927 /* If no one has registered for polling */
Dixon Petersonb4618a42012-02-29 18:56:31 -0800928 if (chk_polling_response()) {
Dixon Petersonb46bb992012-01-12 19:16:56 -0800929 /* Respond to polling for Apps only DIAG */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700930 for (i = 0; i < 3; i++)
931 driver->apps_rsp_buf[i] = *(buf+i);
932 for (i = 0; i < 13; i++)
933 driver->apps_rsp_buf[i+3] = 0;
934
Dixon Petersond6a20a92012-09-27 15:58:50 -0700935 encode_rsp_and_send(15);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700936 return 0;
937 }
Dixon Petersonb46bb992012-01-12 19:16:56 -0800938 }
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -0800939 /* Return the Delayed Response Wrap Status */
940 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
941 (*(buf+2) == 0x04) && (*(buf+3) == 0x0)) {
942 memcpy(driver->apps_rsp_buf, buf, 4);
943 driver->apps_rsp_buf[4] = wrap_enabled;
944 encode_rsp_and_send(4);
945 return 0;
946 }
947 /* Wrap the Delayed Rsp ID */
948 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
949 (*(buf+2) == 0x05) && (*(buf+3) == 0x0)) {
950 wrap_enabled = true;
951 memcpy(driver->apps_rsp_buf, buf, 4);
952 driver->apps_rsp_buf[4] = wrap_count;
953 encode_rsp_and_send(5);
954 return 0;
955 }
Dixon Petersonb46bb992012-01-12 19:16:56 -0800956 /* Check for ID for NO MODEM present */
Dixon Petersonb4618a42012-02-29 18:56:31 -0800957 else if (chk_polling_response()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700958 /* respond to 0x0 command */
Dixon Petersonb46bb992012-01-12 19:16:56 -0800959 if (*buf == 0x00) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700960 for (i = 0; i < 55; i++)
961 driver->apps_rsp_buf[i] = 0;
962
Dixon Petersond6a20a92012-09-27 15:58:50 -0700963 encode_rsp_and_send(54);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700964 return 0;
965 }
966 /* respond to 0x7c command */
967 else if (*buf == 0x7c) {
968 driver->apps_rsp_buf[0] = 0x7c;
969 for (i = 1; i < 8; i++)
970 driver->apps_rsp_buf[i] = 0;
971 /* Tools ID for APQ 8060 */
972 *(int *)(driver->apps_rsp_buf + 8) =
973 chk_config_get_id();
974 *(unsigned char *)(driver->apps_rsp_buf + 12) = '\0';
975 *(unsigned char *)(driver->apps_rsp_buf + 13) = '\0';
Dixon Petersond6a20a92012-09-27 15:58:50 -0700976 encode_rsp_and_send(13);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700977 return 0;
978 }
979 }
980#endif
Dixon Petersond6a20a92012-09-27 15:58:50 -0700981 return packet_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700982}
983
984#ifdef CONFIG_DIAG_OVER_USB
985void diag_send_error_rsp(int index)
986{
987 int i;
Shalabh Jain1fedab92011-12-22 13:15:22 +0530988
989 if (index > 490) {
990 pr_err("diag: error response too huge, aborting\n");
991 return;
992 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700993 driver->apps_rsp_buf[0] = 0x13; /* error code 13 */
994 for (i = 0; i < index; i++)
995 driver->apps_rsp_buf[i+1] = *(driver->hdlc_buf+i);
Dixon Petersond6a20a92012-09-27 15:58:50 -0700996 encode_rsp_and_send(index - 3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700997}
998#else
999static inline void diag_send_error_rsp(int index) {}
1000#endif
1001
1002void diag_process_hdlc(void *data, unsigned len)
1003{
1004 struct diag_hdlc_decode_type hdlc;
1005 int ret, type = 0;
1006 pr_debug("diag: HDLC decode fn, len of data %d\n", len);
1007 hdlc.dest_ptr = driver->hdlc_buf;
1008 hdlc.dest_size = USB_MAX_OUT_BUF;
1009 hdlc.src_ptr = data;
1010 hdlc.src_size = len;
1011 hdlc.src_idx = 0;
1012 hdlc.dest_idx = 0;
1013 hdlc.escaping = 0;
1014
1015 ret = diag_hdlc_decode(&hdlc);
1016
Dixon Petersonb4f84242013-02-27 18:46:56 -08001017 /*
1018 * If the message is 3 bytes or less in length then the message is
1019 * too short. A message will need 4 bytes minimum, since there are
1020 * 2 bytes for the CRC and 1 byte for the ending 0x7e for the hdlc
1021 * encoding
1022 */
1023 if (hdlc.dest_idx < 4) {
1024 pr_err_ratelimited("diag: In %s, message is too short, len: %d, dest len: %d\n",
1025 __func__, len, hdlc.dest_idx);
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001026 return;
1027 }
Dixon Petersonb4f84242013-02-27 18:46:56 -08001028
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001029 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001030 type = diag_process_apps_pkt(driver->hdlc_buf,
1031 hdlc.dest_idx - 3);
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001032 if (type < 0)
1033 return;
1034 } else if (driver->debug_flag) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001035 printk(KERN_ERR "Packet dropped due to bad HDLC coding/CRC"
1036 " errors or partial packet received, packet"
1037 " length = %d\n", len);
1038 print_hex_dump(KERN_DEBUG, "Dropped Packet Data: ", 16, 1,
1039 DUMP_PREFIX_ADDRESS, data, len, 1);
1040 driver->debug_flag = 0;
1041 }
1042 /* send error responses from APPS for Central Routing */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001043 if (type == 1 && chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001044 diag_send_error_rsp(hdlc.dest_idx);
1045 type = 0;
1046 }
1047 /* implies this packet is NOT meant for apps */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001048 if (!(driver->smd_data[MODEM_DATA].ch) && type == 1) {
Shalabh Jainfb8e3c12011-10-19 17:29:42 -07001049 if (chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001050 diag_send_error_rsp(hdlc.dest_idx);
1051 } else { /* APQ 8060, Let Q6 respond */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001052 if (driver->smd_data[LPASS_DATA].ch)
1053 smd_write(driver->smd_data[LPASS_DATA].ch,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001054 driver->hdlc_buf,
1055 hdlc.dest_idx - 3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001056 }
1057 type = 0;
1058 }
1059
1060#ifdef DIAG_DEBUG
1061 pr_debug("diag: hdlc.dest_idx = %d", hdlc.dest_idx);
1062 for (i = 0; i < hdlc.dest_idx; i++)
1063 printk(KERN_DEBUG "\t%x", *(((unsigned char *)
1064 driver->hdlc_buf)+i));
1065#endif /* DIAG DEBUG */
1066 /* ignore 2 bytes for CRC, one for 7E and send */
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001067 if ((driver->smd_data[MODEM_DATA].ch) && (ret) && (type) &&
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001068 (hdlc.dest_idx > 3)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001069 APPEND_DEBUG('g');
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001070 smd_write(driver->smd_data[MODEM_DATA].ch,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001071 driver->hdlc_buf, hdlc.dest_idx - 3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072 APPEND_DEBUG('h');
1073#ifdef DIAG_DEBUG
1074 printk(KERN_INFO "writing data to SMD, pkt length %d\n", len);
1075 print_hex_dump(KERN_DEBUG, "Written Packet Data to SMD: ", 16,
1076 1, DUMP_PREFIX_ADDRESS, data, len, 1);
1077#endif /* DIAG DEBUG */
1078 }
1079}
1080
1081#ifdef CONFIG_DIAG_OVER_USB
Shalabh Jain8e9750a2011-09-09 13:06:29 -07001082/* 2+1 for modem ; 2 for LPASS ; 1 for WCNSS */
1083#define N_LEGACY_WRITE (driver->poolsize + 6)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001084#define N_LEGACY_READ 1
1085
1086int diagfwd_connect(void)
1087{
1088 int err;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001089 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001090
1091 printk(KERN_DEBUG "diag: USB connected\n");
1092 err = usb_diag_alloc_req(driver->legacy_ch, N_LEGACY_WRITE,
1093 N_LEGACY_READ);
1094 if (err)
1095 printk(KERN_ERR "diag: unable to alloc USB req on legacy ch");
1096
1097 driver->usb_connected = 1;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001098 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1099 driver->smd_data[i].in_busy_1 = 0;
1100 driver->smd_data[i].in_busy_2 = 0;
1101 /* Poll SMD data channels to check for data */
1102 queue_work(driver->diag_wq,
1103 &(driver->smd_data[i].diag_read_smd_work));
1104 /* Poll SMD CNTL channels to check for data */
1105 diag_smd_notify(&(driver->smd_cntl[i]), SMD_EVENT_DATA);
1106 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001108 /* Poll USB channel to check for data*/
1109 queue_work(driver->diag_wq, &(driver->diag_read_work));
1110#ifdef CONFIG_DIAG_SDIO_PIPE
1111 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
1112 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1113 diagfwd_connect_sdio();
1114 else
1115 printk(KERN_INFO "diag: No USB MDM ch");
1116 }
1117#endif
1118 return 0;
1119}
1120
1121int diagfwd_disconnect(void)
1122{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001123 int i;
1124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 printk(KERN_DEBUG "diag: USB disconnected\n");
1126 driver->usb_connected = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127 driver->debug_flag = 1;
1128 usb_diag_free_req(driver->legacy_ch);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001129 if (driver->logging_mode == USB_MODE) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001130 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1131 driver->smd_data[i].in_busy_1 = 1;
1132 driver->smd_data[i].in_busy_2 = 1;
1133 }
Shalabh Jain69890aa2011-10-10 12:59:16 -07001134 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135#ifdef CONFIG_DIAG_SDIO_PIPE
1136 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
1137 if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
1138 diagfwd_disconnect_sdio();
1139#endif
1140 /* TBD - notify and flow control SMD */
1141 return 0;
1142}
1143
1144int diagfwd_write_complete(struct diag_request *diag_write_ptr)
1145{
1146 unsigned char *buf = diag_write_ptr->buf;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001147 int found_it = 0;
1148 int i;
1149
1150 /* Determine if the write complete is for data from modem/apps/q6 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151 /* Need a context variable here instead */
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001152 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1153 struct diag_smd_info *data = &(driver->smd_data[i]);
1154 if (buf == (void *)data->buf_in_1) {
1155 data->in_busy_1 = 0;
1156 queue_work(driver->diag_wq,
1157 &(data->diag_read_smd_work));
1158 found_it = 1;
1159 break;
1160 } else if (buf == (void *)data->buf_in_2) {
1161 data->in_busy_2 = 0;
1162 queue_work(driver->diag_wq,
1163 &(data->diag_read_smd_work));
1164 found_it = 1;
1165 break;
1166 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167 }
1168#ifdef CONFIG_DIAG_SDIO_PIPE
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001169 if (!found_it) {
1170 if (buf == (void *)driver->buf_in_sdio) {
1171 if (machine_is_msm8x60_fusion() ||
1172 machine_is_msm8x60_fusn_ffa())
1173 diagfwd_write_complete_sdio();
1174 else
1175 pr_err("diag: Incorrect buffer pointer while WRITE");
1176 found_it = 1;
1177 }
1178 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001179#endif
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001180 if (!found_it) {
1181 diagmem_free(driver, (unsigned char *)buf,
1182 POOL_TYPE_HDLC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001183 diagmem_free(driver, (unsigned char *)diag_write_ptr,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001184 POOL_TYPE_WRITE_STRUCT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185 }
1186 return 0;
1187}
1188
1189int diagfwd_read_complete(struct diag_request *diag_read_ptr)
1190{
1191 int status = diag_read_ptr->status;
1192 unsigned char *buf = diag_read_ptr->buf;
1193
1194 /* Determine if the read complete is for data on legacy/mdm ch */
1195 if (buf == (void *)driver->usb_buf_out) {
1196 driver->read_len_legacy = diag_read_ptr->actual;
1197 APPEND_DEBUG('s');
1198#ifdef DIAG_DEBUG
1199 printk(KERN_INFO "read data from USB, pkt length %d",
1200 diag_read_ptr->actual);
1201 print_hex_dump(KERN_DEBUG, "Read Packet Data from USB: ", 16, 1,
1202 DUMP_PREFIX_ADDRESS, diag_read_ptr->buf,
1203 diag_read_ptr->actual, 1);
1204#endif /* DIAG DEBUG */
1205 if (driver->logging_mode == USB_MODE) {
1206 if (status != -ECONNRESET && status != -ESHUTDOWN)
1207 queue_work(driver->diag_wq,
1208 &(driver->diag_proc_hdlc_work));
1209 else
1210 queue_work(driver->diag_wq,
1211 &(driver->diag_read_work));
1212 }
1213 }
1214#ifdef CONFIG_DIAG_SDIO_PIPE
1215 else if (buf == (void *)driver->usb_buf_mdm_out) {
1216 if (machine_is_msm8x60_fusion() ||
Shalabh Jain482bf122011-12-06 03:54:47 -08001217 machine_is_msm8x60_fusn_ffa()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 driver->read_len_mdm = diag_read_ptr->actual;
1219 diagfwd_read_complete_sdio();
1220 } else
1221 pr_err("diag: Incorrect buffer pointer while READ");
1222 }
1223#endif
1224 else
1225 printk(KERN_ERR "diag: Unknown buffer ptr from USB");
1226
1227 return 0;
1228}
1229
1230void diag_read_work_fn(struct work_struct *work)
1231{
1232 APPEND_DEBUG('d');
1233 driver->usb_read_ptr->buf = driver->usb_buf_out;
1234 driver->usb_read_ptr->length = USB_MAX_OUT_BUF;
1235 usb_diag_read(driver->legacy_ch, driver->usb_read_ptr);
1236 APPEND_DEBUG('e');
1237}
1238
1239void diag_process_hdlc_fn(struct work_struct *work)
1240{
1241 APPEND_DEBUG('D');
1242 diag_process_hdlc(driver->usb_buf_out, driver->read_len_legacy);
1243 diag_read_work_fn(work);
1244 APPEND_DEBUG('E');
1245}
1246
1247void diag_usb_legacy_notifier(void *priv, unsigned event,
1248 struct diag_request *d_req)
1249{
1250 switch (event) {
1251 case USB_DIAG_CONNECT:
1252 diagfwd_connect();
1253 break;
1254 case USB_DIAG_DISCONNECT:
1255 diagfwd_disconnect();
1256 break;
1257 case USB_DIAG_READ_DONE:
1258 diagfwd_read_complete(d_req);
1259 break;
1260 case USB_DIAG_WRITE_DONE:
1261 diagfwd_write_complete(d_req);
1262 break;
1263 default:
1264 printk(KERN_ERR "Unknown event from USB diag\n");
1265 break;
1266 }
1267}
1268
1269#endif /* DIAG OVER USB */
1270
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001271void diag_smd_notify(void *ctxt, unsigned event)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001273 struct diag_smd_info *smd_info = (struct diag_smd_info *)ctxt;
1274 if (!smd_info)
Shalabh Jaineefee052011-11-08 23:46:03 -08001275 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001277 if (event == SMD_EVENT_CLOSE) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001278 smd_info->ch = 0;
Shalabh Jainc70b3b62012-08-31 19:11:20 -07001279 wake_up(&driver->smd_wait_q);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001280 if (smd_info->type == SMD_DATA_TYPE) {
1281 smd_info->notify_context = event;
1282 queue_work(driver->diag_cntl_wq,
1283 &(smd_info->diag_notify_update_smd_work));
1284 } else if (smd_info->type == SMD_DCI_TYPE) {
1285 /* Notify the clients of the close */
1286 diag_dci_notify_client(smd_info->peripheral_mask,
1287 DIAG_STATUS_CLOSED);
1288 }
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001289 return;
1290 } else if (event == SMD_EVENT_OPEN) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001291 if (smd_info->ch_save)
1292 smd_info->ch = smd_info->ch_save;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001293
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001294 if (smd_info->type == SMD_CNTL_TYPE) {
1295 smd_info->notify_context = event;
1296 queue_work(driver->diag_cntl_wq,
1297 &(smd_info->diag_notify_update_smd_work));
1298 } else if (smd_info->type == SMD_DCI_TYPE) {
1299 smd_info->notify_context = event;
1300 queue_work(driver->diag_dci_wq,
1301 &(smd_info->diag_notify_update_smd_work));
1302 /* Notify the clients of the open */
1303 diag_dci_notify_client(smd_info->peripheral_mask,
1304 DIAG_STATUS_OPEN);
1305 }
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001306 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001307
Shalabh Jainc70b3b62012-08-31 19:11:20 -07001308 wake_up(&driver->smd_wait_q);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001309
1310 if (smd_info->type == SMD_DCI_TYPE)
1311 queue_work(driver->diag_dci_wq,
1312 &(smd_info->diag_read_smd_work));
1313 else
1314 queue_work(driver->diag_wq, &(smd_info->diag_read_smd_work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001315}
1316
1317static int diag_smd_probe(struct platform_device *pdev)
1318{
1319 int r = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001320 int index = -1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001321
Shalabh Jaineefee052011-11-08 23:46:03 -08001322 if (pdev->id == SMD_APPS_MODEM) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001323 index = MODEM_DATA;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001324 r = smd_open("DIAG", &driver->smd_data[index].ch,
1325 &driver->smd_data[index],
1326 diag_smd_notify);
1327 driver->smd_data[index].ch_save =
1328 driver->smd_data[index].ch;
Shalabh Jaineefee052011-11-08 23:46:03 -08001329 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001330#if defined(CONFIG_MSM_N_WAY_SMD)
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001331 if (pdev->id == SMD_APPS_QDSP) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001332 index = LPASS_DATA;
Ashay Jaiswal8be3ce82012-09-13 16:01:54 -07001333 r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001334 &driver->smd_data[index].ch,
1335 &driver->smd_data[index],
1336 diag_smd_notify);
1337 driver->smd_data[index].ch_save =
1338 driver->smd_data[index].ch;
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001339 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001340#endif
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001341 if (pdev->id == SMD_APPS_WCNSS) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001342 index = WCNSS_DATA;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001343 r = smd_named_open_on_edge("APPS_RIVA_DATA",
1344 SMD_APPS_WCNSS,
1345 &driver->smd_data[index].ch,
1346 &driver->smd_data[index],
1347 diag_smd_notify);
1348 driver->smd_data[index].ch_save =
1349 driver->smd_data[index].ch;
Shalabh Jainc6c2b1d2011-12-20 04:32:34 -08001350 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001351
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001352 pm_runtime_set_active(&pdev->dev);
1353 pm_runtime_enable(&pdev->dev);
1354 pr_debug("diag: open SMD port, Id = %d, r = %d\n", pdev->id, r);
1355
1356 return 0;
1357}
1358
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001359static int diag_smd_runtime_suspend(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001360{
1361 dev_dbg(dev, "pm_runtime: suspending...\n");
1362 return 0;
1363}
1364
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001365static int diag_smd_runtime_resume(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366{
1367 dev_dbg(dev, "pm_runtime: resuming...\n");
1368 return 0;
1369}
1370
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001371static const struct dev_pm_ops diag_smd_dev_pm_ops = {
1372 .runtime_suspend = diag_smd_runtime_suspend,
1373 .runtime_resume = diag_smd_runtime_resume,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374};
1375
1376static struct platform_driver msm_smd_ch1_driver = {
1377
1378 .probe = diag_smd_probe,
1379 .driver = {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001380 .name = "DIAG",
1381 .owner = THIS_MODULE,
1382 .pm = &diag_smd_dev_pm_ops,
1383 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384};
1385
1386static struct platform_driver diag_smd_lite_driver = {
1387
1388 .probe = diag_smd_probe,
1389 .driver = {
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001390 .name = "APPS_RIVA_DATA",
1391 .owner = THIS_MODULE,
1392 .pm = &diag_smd_dev_pm_ops,
1393 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001394};
1395
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001396void diag_smd_destructor(struct diag_smd_info *smd_info)
1397{
1398 if (smd_info->ch)
1399 smd_close(smd_info->ch);
1400
1401 smd_info->ch = 0;
1402 smd_info->ch_save = 0;
1403 kfree(smd_info->buf_in_1);
1404 kfree(smd_info->buf_in_2);
1405 kfree(smd_info->write_ptr_1);
1406 kfree(smd_info->write_ptr_2);
1407}
1408
1409int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral,
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001410 int type)
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001411{
1412 smd_info->peripheral = peripheral;
1413 smd_info->type = type;
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001414
1415 switch (peripheral) {
1416 case MODEM_DATA:
1417 smd_info->peripheral_mask = DIAG_CON_MPSS;
1418 break;
1419 case LPASS_DATA:
1420 smd_info->peripheral_mask = DIAG_CON_LPASS;
1421 break;
1422 case WCNSS_DATA:
1423 smd_info->peripheral_mask = DIAG_CON_WCNSS;
1424 break;
1425 default:
1426 pr_err("diag: In %s, unknown peripheral, peripheral: %d\n",
1427 __func__, peripheral);
1428 goto err;
1429 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001430
1431 smd_info->ch = 0;
1432 smd_info->ch_save = 0;
1433
1434 if (smd_info->buf_in_1 == NULL) {
1435 smd_info->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1436 if (smd_info->buf_in_1 == NULL)
1437 goto err;
1438 kmemleak_not_leak(smd_info->buf_in_1);
1439 }
1440
1441 if (smd_info->write_ptr_1 == NULL) {
1442 smd_info->write_ptr_1 = kzalloc(sizeof(struct diag_request),
1443 GFP_KERNEL);
1444 if (smd_info->write_ptr_1 == NULL)
1445 goto err;
1446 kmemleak_not_leak(smd_info->write_ptr_1);
1447 }
1448
1449 /* The smd data type needs two buffers */
1450 if (smd_info->type == SMD_DATA_TYPE) {
1451 if (smd_info->buf_in_2 == NULL) {
1452 smd_info->buf_in_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
1453 if (smd_info->buf_in_2 == NULL)
1454 goto err;
1455 kmemleak_not_leak(smd_info->buf_in_2);
1456 }
1457 if (smd_info->write_ptr_2 == NULL) {
1458 smd_info->write_ptr_2 =
1459 kzalloc(sizeof(struct diag_request),
1460 GFP_KERNEL);
1461 if (smd_info->write_ptr_2 == NULL)
1462 goto err;
1463 kmemleak_not_leak(smd_info->write_ptr_2);
1464 }
1465 }
1466
1467 INIT_WORK(&(smd_info->diag_read_smd_work), diag_read_smd_work_fn);
1468
1469 /*
1470 * The update function assigned to the diag_notify_update_smd_work
1471 * work_struct is meant to be used for updating that is not to
1472 * be done in the context of the smd notify function. The
1473 * notify_context variable can be used for passing additional
1474 * information to the update function.
1475 */
1476 smd_info->notify_context = 0;
1477 if (type == SMD_DATA_TYPE)
1478 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
1479 diag_clean_reg_fn);
1480 else if (type == SMD_CNTL_TYPE)
1481 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
1482 diag_mask_update_fn);
1483 else if (type == SMD_DCI_TYPE)
1484 INIT_WORK(&(smd_info->diag_notify_update_smd_work),
1485 diag_update_smd_dci_work_fn);
1486 else {
1487 pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
1488 goto err;
1489 }
1490
1491 /*
1492 * Set function ptr for function to call to process the data that
1493 * was just read from the smd channel
1494 */
1495 if (type == SMD_DATA_TYPE)
1496 smd_info->process_smd_read_data = diag_process_smd_read_data;
1497 else if (type == SMD_CNTL_TYPE)
1498 smd_info->process_smd_read_data =
1499 diag_process_smd_cntl_read_data;
1500 else if (type == SMD_DCI_TYPE)
1501 smd_info->process_smd_read_data =
1502 diag_process_smd_dci_read_data;
1503 else {
1504 pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
1505 goto err;
1506 }
1507
1508 return 1;
1509err:
1510 kfree(smd_info->buf_in_1);
1511 kfree(smd_info->buf_in_2);
1512 kfree(smd_info->write_ptr_1);
1513 kfree(smd_info->write_ptr_2);
1514
1515 return 0;
1516}
1517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518void diagfwd_init(void)
1519{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001520 int success;
1521 int i;
1522
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -08001523 wrap_enabled = 0;
1524 wrap_count = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001525 diag_debug_buf_idx = 0;
1526 driver->read_len_legacy = 0;
Dixon Petersonb4618a42012-02-29 18:56:31 -08001527 driver->use_device_tree = has_device_tree();
Shalabh Jaina06c6d72012-04-30 13:40:35 -07001528 mutex_init(&driver->diag_cntl_mutex);
Shalabh Jain321c8b52012-02-22 12:37:06 -08001529
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001530 success = diag_smd_constructor(&driver->smd_data[MODEM_DATA],
1531 MODEM_DATA, SMD_DATA_TYPE);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001532 if (!success)
1533 goto err;
1534
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001535 success = diag_smd_constructor(&driver->smd_data[LPASS_DATA],
1536 LPASS_DATA, SMD_DATA_TYPE);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001537 if (!success)
1538 goto err;
1539
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001540 success = diag_smd_constructor(&driver->smd_data[WCNSS_DATA],
1541 WCNSS_DATA, SMD_DATA_TYPE);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001542 if (!success)
1543 goto err;
1544
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545 if (driver->usb_buf_out == NULL &&
1546 (driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
1547 GFP_KERNEL)) == NULL)
1548 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001549 kmemleak_not_leak(driver->usb_buf_out);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001550 if (driver->hdlc_buf == NULL
1551 && (driver->hdlc_buf = kzalloc(HDLC_MAX, GFP_KERNEL)) == NULL)
1552 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001553 kmemleak_not_leak(driver->hdlc_buf);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001554 if (driver->user_space_data == NULL)
1555 driver->user_space_data = kzalloc(USER_SPACE_DATA, GFP_KERNEL);
1556 if (driver->user_space_data == NULL)
1557 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001558 kmemleak_not_leak(driver->user_space_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001559 if (driver->client_map == NULL &&
1560 (driver->client_map = kzalloc
1561 ((driver->num_clients) * sizeof(struct diag_client_map),
1562 GFP_KERNEL)) == NULL)
1563 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001564 kmemleak_not_leak(driver->client_map);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001565 if (driver->buf_tbl == NULL)
1566 driver->buf_tbl = kzalloc(buf_tbl_size *
1567 sizeof(struct diag_write_device), GFP_KERNEL);
1568 if (driver->buf_tbl == NULL)
1569 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001570 kmemleak_not_leak(driver->buf_tbl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001571 if (driver->data_ready == NULL &&
1572 (driver->data_ready = kzalloc(driver->num_clients * sizeof(int)
1573 , GFP_KERNEL)) == NULL)
1574 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001575 kmemleak_not_leak(driver->data_ready);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001576 if (driver->table == NULL &&
Shalabh Jainfe02b0c2012-02-21 14:48:03 -08001577 (driver->table = kzalloc(diag_max_reg*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001578 sizeof(struct diag_master_table),
1579 GFP_KERNEL)) == NULL)
1580 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001581 kmemleak_not_leak(driver->table);
Ashay Jaiswal29620122012-03-21 12:02:36 +05301582
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001583 if (driver->usb_read_ptr == NULL) {
1584 driver->usb_read_ptr = kzalloc(
1585 sizeof(struct diag_request), GFP_KERNEL);
1586 if (driver->usb_read_ptr == NULL)
1587 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001588 kmemleak_not_leak(driver->usb_read_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001589 }
1590 if (driver->pkt_buf == NULL &&
1591 (driver->pkt_buf = kzalloc(PKT_SIZE,
1592 GFP_KERNEL)) == NULL)
1593 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001594 kmemleak_not_leak(driver->pkt_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595 if (driver->apps_rsp_buf == NULL) {
Shalabh Jain321c8b52012-02-22 12:37:06 -08001596 driver->apps_rsp_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001597 if (driver->apps_rsp_buf == NULL)
1598 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -07001599 kmemleak_not_leak(driver->apps_rsp_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001600 }
1601 driver->diag_wq = create_singlethread_workqueue("diag_wq");
1602#ifdef CONFIG_DIAG_OVER_USB
1603 INIT_WORK(&(driver->diag_proc_hdlc_work), diag_process_hdlc_fn);
1604 INIT_WORK(&(driver->diag_read_work), diag_read_work_fn);
1605 driver->legacy_ch = usb_diag_open(DIAG_LEGACY, driver,
1606 diag_usb_legacy_notifier);
1607 if (IS_ERR(driver->legacy_ch)) {
1608 printk(KERN_ERR "Unable to open USB diag legacy channel\n");
1609 goto err;
1610 }
1611#endif
1612 platform_driver_register(&msm_smd_ch1_driver);
1613 platform_driver_register(&diag_smd_lite_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614 return;
1615err:
Dixon Petersond6a20a92012-09-27 15:58:50 -07001616 pr_err("diag: Could not initialize diag buffers");
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001617
1618 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
1619 diag_smd_destructor(&driver->smd_data[i]);
1620
Dixon Petersond6a20a92012-09-27 15:58:50 -07001621 kfree(driver->buf_msg_mask_update);
1622 kfree(driver->buf_log_mask_update);
1623 kfree(driver->buf_event_mask_update);
1624 kfree(driver->usb_buf_out);
1625 kfree(driver->hdlc_buf);
1626 kfree(driver->client_map);
1627 kfree(driver->buf_tbl);
1628 kfree(driver->data_ready);
1629 kfree(driver->table);
1630 kfree(driver->pkt_buf);
Dixon Petersond6a20a92012-09-27 15:58:50 -07001631 kfree(driver->usb_read_ptr);
1632 kfree(driver->apps_rsp_buf);
1633 kfree(driver->user_space_data);
1634 if (driver->diag_wq)
1635 destroy_workqueue(driver->diag_wq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001636}
1637
1638void diagfwd_exit(void)
1639{
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001640 int i;
1641
1642 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
1643 diag_smd_destructor(&driver->smd_data[i]);
1644
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001645#ifdef CONFIG_DIAG_OVER_USB
1646 if (driver->usb_connected)
1647 usb_diag_free_req(driver->legacy_ch);
1648 usb_diag_close(driver->legacy_ch);
1649#endif
1650 platform_driver_unregister(&msm_smd_ch1_driver);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001651 platform_driver_unregister(&msm_diag_dci_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001652 platform_driver_unregister(&diag_smd_lite_driver);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001653
Shalabh Jain321c8b52012-02-22 12:37:06 -08001654 kfree(driver->buf_msg_mask_update);
1655 kfree(driver->buf_log_mask_update);
1656 kfree(driver->buf_event_mask_update);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001657 kfree(driver->usb_buf_out);
1658 kfree(driver->hdlc_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001659 kfree(driver->client_map);
1660 kfree(driver->buf_tbl);
1661 kfree(driver->data_ready);
1662 kfree(driver->table);
1663 kfree(driver->pkt_buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001664 kfree(driver->usb_read_ptr);
1665 kfree(driver->apps_rsp_buf);
Shalabh Jain69890aa2011-10-10 12:59:16 -07001666 kfree(driver->user_space_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001667 destroy_workqueue(driver->diag_wq);
1668}