blob: 263715d0b4da8c16b7f2caa5b591da637a9739f2 [file] [log] [blame]
Sreelakshmi Gownipallie7c171e2013-12-26 17:19:31 -08001/* Copyright (c) 2008-2014, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/slab.h>
14#include <linux/init.h>
15#include <linux/module.h>
16#include <linux/cdev.h>
17#include <linux/fs.h>
18#include <linux/device.h>
Ravi Aravamudhan3dc66352013-06-14 10:46:19 -070019#include <linux/delay.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070020#include <linux/uaccess.h>
21#include <linux/diagchar.h>
Shalabh Jainb0037c02013-01-18 12:47:40 -080022#include <linux/platform_device.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023#include <linux/sched.h>
Dixon Petersonf2d449c2013-02-01 18:02:20 -080024#include <linux/ratelimit.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#ifdef CONFIG_DIAG_OVER_USB
26#include <mach/usbdiag.h>
27#endif
28#include <asm/current.h>
29#include "diagchar_hdlc.h"
30#include "diagmem.h"
31#include "diagchar.h"
32#include "diagfwd.h"
33#include "diagfwd_cntl.h"
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070034#include "diag_dci.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035#ifdef CONFIG_DIAG_SDIO_PIPE
36#include "diagfwd_sdio.h"
37#endif
Shalabh Jain737fca72012-11-14 21:53:43 -080038#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Dixon Peterson32e70bb2011-12-16 13:26:45 -080039#include "diagfwd_hsic.h"
Shalabh Jainf7228dc2012-05-23 17:32:05 -070040#include "diagfwd_smux.h"
Dixon Peterson32e70bb2011-12-16 13:26:45 -080041#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042#include <linux/timer.h>
Dixon Petersond6a20a92012-09-27 15:58:50 -070043#include "diag_debugfs.h"
44#include "diag_masks.h"
Shalabh Jain737fca72012-11-14 21:53:43 -080045#include "diagfwd_bridge.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046
Dixon Peterson15a6ecb2013-06-25 12:36:33 -070047#include <linux/coresight-stm.h>
48#include <linux/kernel.h>
49
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070050MODULE_DESCRIPTION("Diag Char Driver");
51MODULE_LICENSE("GPL v2");
52MODULE_VERSION("1.0");
53
Katish Paran3e200902013-12-24 17:46:29 +053054#define MIN_SIZ_ALLOW 4
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055#define INIT 1
56#define EXIT -1
57struct diagchar_dev *driver;
58struct diagchar_priv {
59 int pid;
60};
61/* The following variables can be specified by module options */
62 /* for copy buffer */
Ashay Jaiswal1fe33272012-02-29 18:19:29 +053063static unsigned int itemsize = 4096; /*Size of item in the mempool */
Dixon Peterson6dba7572013-04-12 18:45:16 -070064static unsigned int poolsize = 12; /*Number of items in the mempool */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065/* for hdlc buffer */
66static unsigned int itemsize_hdlc = 8192; /*Size of item in the mempool */
Dixon Peterson6dba7572013-04-12 18:45:16 -070067static unsigned int poolsize_hdlc = 10; /*Number of items in the mempool */
68/* for user buffer */
69static unsigned int itemsize_user = 8192; /*Size of item in the mempool */
70static unsigned int poolsize_user = 8; /*Number of items in the mempool */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071/* for write structure buffer */
72static unsigned int itemsize_write_struct = 20; /*Size of item in the mempool */
Dixon Peterson6dba7572013-04-12 18:45:16 -070073static unsigned int poolsize_write_struct = 10;/* Num of items in the mempool */
Katish Paran244514d2013-08-01 18:39:31 -070074/* For the dci memory pool */
75static unsigned int itemsize_dci = IN_BUF_SIZE; /*Size of item in the mempool */
76static unsigned int poolsize_dci = 10; /*Number of items in the mempool */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070077/* This is the max number of user-space clients supported at initialization*/
78static unsigned int max_clients = 15;
79static unsigned int threshold_client_limit = 30;
80/* This is the maximum number of pkt registrations supported at initialization*/
Mohit Aggarwal3aa45862013-03-05 18:37:58 +053081int diag_max_reg = 600;
82int diag_threshold_reg = 750;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070083
84/* Timer variables */
85static struct timer_list drain_timer;
86static int timer_in_progress;
87void *buf_hdlc;
88module_param(itemsize, uint, 0);
89module_param(poolsize, uint, 0);
90module_param(max_clients, uint, 0);
91
92/* delayed_rsp_id 0 represents no delay in the response. Any other number
93 means that the diag packet has a delayed response. */
94static uint16_t delayed_rsp_id = 1;
Ashay Jaiswala372f8c2012-12-12 14:02:38 +053095
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070096#define DIAGPKT_MAX_DELAYED_RSP 0xFFFF
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070097
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -080098/* returns the next delayed rsp id - rollsover the id if wrapping is
99 enabled. */
100uint16_t diagpkt_next_delayed_rsp_id(uint16_t rspid)
101{
102 if (rspid < DIAGPKT_MAX_DELAYED_RSP)
103 rspid++;
104 else {
105 if (wrap_enabled) {
106 rspid = 1;
107 wrap_count++;
108 } else
109 rspid = DIAGPKT_MAX_DELAYED_RSP;
110 }
111 delayed_rsp_id = rspid;
112 return delayed_rsp_id;
113}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700114
115#define COPY_USER_SPACE_OR_EXIT(buf, data, length) \
116do { \
117 if ((count < ret+length) || (copy_to_user(buf, \
118 (void *)&data, length))) { \
119 ret = -EFAULT; \
120 goto exit; \
121 } \
122 ret += length; \
123} while (0)
124
125static void drain_timer_func(unsigned long data)
126{
127 queue_work(driver->diag_wq , &(driver->diag_drain_work));
128}
129
130void diag_drain_work_fn(struct work_struct *work)
131{
132 int err = 0;
133 timer_in_progress = 0;
134
135 mutex_lock(&driver->diagchar_mutex);
136 if (buf_hdlc) {
137 err = diag_device_write(buf_hdlc, APPS_DATA, NULL);
Ravi Aravamudhand995a7f2013-07-03 13:06:15 -0700138 if (err)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139 diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140 buf_hdlc = NULL;
141#ifdef DIAG_DEBUG
142 pr_debug("diag: Number of bytes written "
143 "from timer is %d ", driver->used);
144#endif
145 driver->used = 0;
146 }
147 mutex_unlock(&driver->diagchar_mutex);
148}
149
Katish Paran244514d2013-08-01 18:39:31 -0700150void check_drain_timer(void)
151{
152 int ret = 0;
153
154 if (!timer_in_progress) {
155 timer_in_progress = 1;
156 ret = mod_timer(&drain_timer, jiffies + msecs_to_jiffies(500));
157 }
158}
159
Shalabh Jain737fca72012-11-14 21:53:43 -0800160#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700161void diag_clear_hsic_tbl(void)
162{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800163 int i, j;
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700164
Shalabh Jainb0037c02013-01-18 12:47:40 -0800165 /* Clear for all active HSIC bridges */
166 for (j = 0; j < MAX_HSIC_CH; j++) {
167 if (diag_hsic[j].hsic_ch) {
168 diag_hsic[j].num_hsic_buf_tbl_entries = 0;
169 for (i = 0; i < diag_hsic[j].poolsize_hsic_write; i++) {
170 if (diag_hsic[j].hsic_buf_tbl[i].buf) {
171 /* Return the buffer to the pool */
172 diagmem_free(driver, (unsigned char *)
173 (diag_hsic[j].hsic_buf_tbl[i].
Dixon Petersonb9684ed2013-02-11 18:58:26 -0800174 buf), j+POOL_TYPE_HSIC);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800175 diag_hsic[j].hsic_buf_tbl[i].buf = 0;
176 }
177 diag_hsic[j].hsic_buf_tbl[i].length = 0;
178 }
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700179 }
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700180 }
181}
182#else
183void diag_clear_hsic_tbl(void) { }
184#endif
185
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186void diag_add_client(int i, struct file *file)
187{
188 struct diagchar_priv *diagpriv_data;
189
190 driver->client_map[i].pid = current->tgid;
191 diagpriv_data = kmalloc(sizeof(struct diagchar_priv),
192 GFP_KERNEL);
193 if (diagpriv_data)
194 diagpriv_data->pid = current->tgid;
195 file->private_data = diagpriv_data;
Shalabh Jain9c07c4b2011-10-20 13:27:20 -0700196 strlcpy(driver->client_map[i].name, current->comm, 20);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197 driver->client_map[i].name[19] = '\0';
198}
199
200static int diagchar_open(struct inode *inode, struct file *file)
201{
202 int i = 0;
203 void *temp;
204
205 if (driver) {
206 mutex_lock(&driver->diagchar_mutex);
207
208 for (i = 0; i < driver->num_clients; i++)
209 if (driver->client_map[i].pid == 0)
210 break;
211
212 if (i < driver->num_clients) {
213 diag_add_client(i, file);
214 } else {
215 if (i < threshold_client_limit) {
216 driver->num_clients++;
217 temp = krealloc(driver->client_map
218 , (driver->num_clients) * sizeof(struct
219 diag_client_map), GFP_KERNEL);
220 if (!temp)
221 goto fail;
222 else
223 driver->client_map = temp;
224 temp = krealloc(driver->data_ready
225 , (driver->num_clients) * sizeof(int),
226 GFP_KERNEL);
227 if (!temp)
228 goto fail;
229 else
230 driver->data_ready = temp;
231 diag_add_client(i, file);
232 } else {
233 mutex_unlock(&driver->diagchar_mutex);
234 pr_alert("Max client limit for DIAG reached\n");
235 pr_info("Cannot open handle %s"
236 " %d", current->comm, current->tgid);
237 for (i = 0; i < driver->num_clients; i++)
238 pr_debug("%d) %s PID=%d", i, driver->
239 client_map[i].name,
240 driver->client_map[i].pid);
241 return -ENOMEM;
242 }
243 }
Ashay Jaiswal6bac2722012-05-04 12:56:31 +0530244 driver->data_ready[i] = 0x0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245 driver->data_ready[i] |= MSG_MASKS_TYPE;
246 driver->data_ready[i] |= EVENT_MASKS_TYPE;
247 driver->data_ready[i] |= LOG_MASKS_TYPE;
248
249 if (driver->ref_count == 0)
250 diagmem_init(driver);
251 driver->ref_count++;
252 mutex_unlock(&driver->diagchar_mutex);
253 return 0;
254 }
255 return -ENOMEM;
256
257fail:
258 mutex_unlock(&driver->diagchar_mutex);
259 driver->num_clients--;
260 pr_alert("diag: Insufficient memory for new client");
261 return -ENOMEM;
262}
263
264static int diagchar_close(struct inode *inode, struct file *file)
265{
Mohit Aggarwal65b69cf2013-02-15 11:33:04 -0800266 int i = -1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267 struct diagchar_priv *diagpriv_data = file->private_data;
268
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700269 pr_debug("diag: process exit %s\n", current->comm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270 if (!(file->private_data)) {
271 pr_alert("diag: Invalid file pointer");
272 return -ENOMEM;
273 }
Ravi Aravamudhane1412e12013-01-08 17:15:08 -0800274
275 if (!driver)
276 return -ENOMEM;
277
Shalabh Jaina1c69a42012-10-23 12:51:30 -0700278 /* clean up any DCI registrations, if this is a DCI client
Shalabh Jain1c99e4c2012-03-26 18:47:59 -0700279 * This will specially help in case of ungraceful exit of any DCI client
280 * This call will remove any pending registrations of such client
281 */
Katish Paran244514d2013-08-01 18:39:31 -0700282 diag_dci_deinit_client();
Dixon Peterson625ee652012-06-21 22:03:49 -0700283 /* If the exiting process is the socket process */
Ashay Jaiswalcdeeaa62013-06-26 13:49:26 +0530284 mutex_lock(&driver->diagchar_mutex);
Dixon Peterson625ee652012-06-21 22:03:49 -0700285 if (driver->socket_process &&
286 (driver->socket_process->tgid == current->tgid)) {
287 driver->socket_process = NULL;
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -0700288 diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_DOWN);
Dixon Peterson625ee652012-06-21 22:03:49 -0700289 }
Shalabh Jain84e30342012-10-16 16:16:08 -0700290 if (driver->callback_process &&
291 (driver->callback_process->tgid == current->tgid)) {
292 driver->callback_process = NULL;
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -0700293 diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_DOWN);
Shalabh Jain84e30342012-10-16 16:16:08 -0700294 }
Ashay Jaiswalcdeeaa62013-06-26 13:49:26 +0530295 mutex_unlock(&driver->diagchar_mutex);
Dixon Peterson625ee652012-06-21 22:03:49 -0700296
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297#ifdef CONFIG_DIAG_OVER_USB
298 /* If the SD logging process exits, change logging to USB mode */
299 if (driver->logging_process_id == current->tgid) {
300 driver->logging_mode = USB_MODE;
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -0700301 diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_DOWN);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302 diagfwd_connect();
Shalabh Jain737fca72012-11-14 21:53:43 -0800303#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700304 diag_clear_hsic_tbl();
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800305 diagfwd_cancel_hsic(REOPEN_HSIC);
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700306 diagfwd_connect_bridge(0);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700307#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308 }
309#endif /* DIAG over USB */
310 /* Delete the pkt response table entry for the exiting process */
Shalabh Jainfe02b0c2012-02-21 14:48:03 -0800311 for (i = 0; i < diag_max_reg; i++)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312 if (driver->table[i].process_id == current->tgid)
313 driver->table[i].process_id = 0;
314
Ravi Aravamudhane1412e12013-01-08 17:15:08 -0800315 mutex_lock(&driver->diagchar_mutex);
316 driver->ref_count--;
Katish Paran244514d2013-08-01 18:39:31 -0700317 /* On Client exit, try to destroy all 5 pools */
Ravi Aravamudhane1412e12013-01-08 17:15:08 -0800318 diagmem_exit(driver, POOL_TYPE_COPY);
319 diagmem_exit(driver, POOL_TYPE_HDLC);
Ravi Aravamudhan4207b652013-06-07 17:37:37 -0700320 diagmem_exit(driver, POOL_TYPE_USER);
Ravi Aravamudhane1412e12013-01-08 17:15:08 -0800321 diagmem_exit(driver, POOL_TYPE_WRITE_STRUCT);
Katish Paran244514d2013-08-01 18:39:31 -0700322 diagmem_exit(driver, POOL_TYPE_DCI);
Ravi Aravamudhane1412e12013-01-08 17:15:08 -0800323 for (i = 0; i < driver->num_clients; i++) {
324 if (NULL != diagpriv_data && diagpriv_data->pid ==
Shalabh Jainb0037c02013-01-18 12:47:40 -0800325 driver->client_map[i].pid) {
Ravi Aravamudhane1412e12013-01-08 17:15:08 -0800326 driver->client_map[i].pid = 0;
327 kfree(diagpriv_data);
328 diagpriv_data = NULL;
329 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700331 }
Ravi Aravamudhane1412e12013-01-08 17:15:08 -0800332 mutex_unlock(&driver->diagchar_mutex);
333 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700334}
335
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800336int diag_find_polling_reg(int i)
337{
338 uint16_t subsys_id, cmd_code_lo, cmd_code_hi;
339
340 subsys_id = driver->table[i].subsys_id;
341 cmd_code_lo = driver->table[i].cmd_code_lo;
342 cmd_code_hi = driver->table[i].cmd_code_hi;
Ravi Aravamudhan8081a132013-08-02 12:19:28 -0700343
344 if (driver->table[i].cmd_code == 0xFF) {
345 if (subsys_id == 0xFF && cmd_code_hi >= 0x0C &&
346 cmd_code_lo <= 0x0C)
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800347 return 1;
Ravi Aravamudhan8081a132013-08-02 12:19:28 -0700348 if (subsys_id == 0x04 && cmd_code_hi >= 0x0E &&
349 cmd_code_lo <= 0x0E)
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800350 return 1;
Ravi Aravamudhan8081a132013-08-02 12:19:28 -0700351 else if (subsys_id == 0x08 && cmd_code_hi >= 0x02 &&
352 cmd_code_lo <= 0x02)
353 return 1;
354 else if (subsys_id == 0x32 && cmd_code_hi >= 0x03 &&
355 cmd_code_lo <= 0x03)
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800356 return 1;
Ravi Aravamudhane674cb62014-01-21 14:31:08 -0800357 else if (subsys_id == 0x57 && cmd_code_hi >= 0x0E &&
358 cmd_code_lo <= 0x0E)
359 return 1;
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800360 }
361 return 0;
362}
363
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800364void diag_clear_reg(int peripheral)
Shalabh Jainc2ec8292011-10-14 12:34:55 -0700365{
366 int i;
367
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800368 mutex_lock(&driver->diagchar_mutex);
369 /* reset polling flag */
370 driver->polling_reg_flag = 0;
Shalabh Jainfe02b0c2012-02-21 14:48:03 -0800371 for (i = 0; i < diag_max_reg; i++) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800372 if (driver->table[i].client_id == peripheral)
Shalabh Jainc2ec8292011-10-14 12:34:55 -0700373 driver->table[i].process_id = 0;
Shalabh Jainc2ec8292011-10-14 12:34:55 -0700374 }
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800375 /* re-scan the registration table */
Shalabh Jainfe02b0c2012-02-21 14:48:03 -0800376 for (i = 0; i < diag_max_reg; i++) {
Ravi Aravamudhan8081a132013-08-02 12:19:28 -0700377 if (driver->table[i].process_id != 0 &&
378 diag_find_polling_reg(i) == 1) {
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800379 driver->polling_reg_flag = 1;
380 break;
381 }
382 }
383 mutex_unlock(&driver->diagchar_mutex);
Shalabh Jainc2ec8292011-10-14 12:34:55 -0700384}
385
386void diag_add_reg(int j, struct bindpkt_params *params,
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -0800387 int *success, unsigned int *count_entries)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388{
389 *success = 1;
390 driver->table[j].cmd_code = params->cmd_code;
391 driver->table[j].subsys_id = params->subsys_id;
392 driver->table[j].cmd_code_lo = params->cmd_code_lo;
393 driver->table[j].cmd_code_hi = params->cmd_code_hi;
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800394
395 /* check if incoming reg is polling & polling is yet not registered */
396 if (driver->polling_reg_flag == 0)
397 if (diag_find_polling_reg(j) == 1)
398 driver->polling_reg_flag = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399 if (params->proc_id == APPS_PROC) {
400 driver->table[j].process_id = current->tgid;
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800401 driver->table[j].client_id = APPS_DATA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700402 } else {
403 driver->table[j].process_id = NON_APPS_PROC;
404 driver->table[j].client_id = params->client_id;
405 }
406 (*count_entries)++;
407}
408
Ravi Aravamudhan3dc66352013-06-14 10:46:19 -0700409void diag_get_timestamp(char *time_str)
410{
411 struct timeval t;
412 struct tm broken_tm;
413 do_gettimeofday(&t);
414 if (!time_str)
415 return;
416 time_to_tm(t.tv_sec, 0, &broken_tm);
417 scnprintf(time_str, DIAG_TS_SIZE, "%d:%d:%d:%ld", broken_tm.tm_hour,
418 broken_tm.tm_min, broken_tm.tm_sec, t.tv_usec);
419}
420
Dixon Petersonf82952c2013-01-11 19:19:10 -0800421static int diag_get_remote(int remote_info)
Ashay Jaiswala372f8c2012-12-12 14:02:38 +0530422{
Dixon Petersonf82952c2013-01-11 19:19:10 -0800423 int val = (remote_info < 0) ? -remote_info : remote_info;
424 int remote_val;
Ashay Jaiswala372f8c2012-12-12 14:02:38 +0530425
Dixon Petersonf82952c2013-01-11 19:19:10 -0800426 switch (val) {
427 case MDM:
Dixon Petersonf90f3582013-01-26 18:14:17 -0800428 case MDM2:
429 case MDM3:
430 case MDM4:
Dixon Petersonf82952c2013-01-11 19:19:10 -0800431 case QSC:
432 remote_val = -remote_info;
433 break;
434 default:
435 remote_val = 0;
436 break;
437 }
Ashay Jaiswala372f8c2012-12-12 14:02:38 +0530438
Dixon Petersonf82952c2013-01-11 19:19:10 -0800439 return remote_val;
Ashay Jaiswala372f8c2012-12-12 14:02:38 +0530440}
441
Dixon Petersonf90f3582013-01-26 18:14:17 -0800442#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
443uint16_t diag_get_remote_device_mask(void)
444{
445 uint16_t remote_dev = 0;
446 int i;
447
448 /* Check for MDM processor */
449 for (i = 0; i < MAX_HSIC_CH; i++)
450 if (diag_hsic[i].hsic_inited)
451 remote_dev |= 1 << i;
452
453 /* Check for QSC processor */
454 if (driver->diag_smux_enabled)
455 remote_dev |= 1 << SMUX;
456
457 return remote_dev;
458}
459
460int diag_copy_remote(char __user *buf, size_t count, int *pret, int *pnum_data)
461{
462 int i;
463 int index;
464 int exit_stat = 1;
465 int ret = *pret;
466 int num_data = *pnum_data;
467 int remote_token;
468 unsigned long spin_lock_flags;
469 struct diag_write_device hsic_buf_tbl[NUM_HSIC_BUF_TBL_ENTRIES];
470
471 remote_token = diag_get_remote(MDM);
472 for (index = 0; index < MAX_HSIC_CH; index++) {
473 if (!diag_hsic[index].hsic_inited) {
474 remote_token--;
475 continue;
476 }
477
478 spin_lock_irqsave(&diag_hsic[index].hsic_spinlock,
479 spin_lock_flags);
480 for (i = 0; i < diag_hsic[index].poolsize_hsic_write; i++) {
481 hsic_buf_tbl[i].buf =
482 diag_hsic[index].hsic_buf_tbl[i].buf;
483 diag_hsic[index].hsic_buf_tbl[i].buf = 0;
484 hsic_buf_tbl[i].length =
485 diag_hsic[index].hsic_buf_tbl[i].length;
Dixon Peterson175f1c12013-02-08 18:51:42 -0800486 diag_hsic[index].hsic_buf_tbl[i].length = 0;
Dixon Petersonf90f3582013-01-26 18:14:17 -0800487 }
488 diag_hsic[index].num_hsic_buf_tbl_entries = 0;
Dixon Peterson175f1c12013-02-08 18:51:42 -0800489 spin_unlock_irqrestore(&diag_hsic[index].hsic_spinlock,
Dixon Petersonf90f3582013-01-26 18:14:17 -0800490 spin_lock_flags);
491
492 for (i = 0; i < diag_hsic[index].poolsize_hsic_write; i++) {
493 if (hsic_buf_tbl[i].length > 0) {
Ravi Aravamudhan910f5662014-01-21 10:07:06 -0800494 pr_debug("diag: HSIC copy to user, i: %d, buf: %p, len: %d\n",
495 i, hsic_buf_tbl[i].buf,
Dixon Petersonf90f3582013-01-26 18:14:17 -0800496 hsic_buf_tbl[i].length);
497 num_data++;
498
499 /* Copy the negative token */
500 if (copy_to_user(buf+ret,
501 &remote_token, 4)) {
502 num_data--;
503 goto drop_hsic;
504 }
505 ret += 4;
506
507 /* Copy the length of data being passed */
508 if (copy_to_user(buf+ret,
509 (void *)&(hsic_buf_tbl[i].length),
510 4)) {
511 num_data--;
512 goto drop_hsic;
513 }
514 ret += 4;
515
516 /* Copy the actual data being passed */
517 if (copy_to_user(buf+ret,
518 (void *)hsic_buf_tbl[i].buf,
519 hsic_buf_tbl[i].length)) {
520 ret -= 4;
521 num_data--;
522 goto drop_hsic;
523 }
524 ret += hsic_buf_tbl[i].length;
525drop_hsic:
526 /* Return the buffer to the pool */
527 diagmem_free(driver,
528 (unsigned char *)(hsic_buf_tbl[i].buf),
Dixon Petersonb9684ed2013-02-11 18:58:26 -0800529 index+POOL_TYPE_HSIC);
Dixon Petersonf90f3582013-01-26 18:14:17 -0800530
531 /* Call the write complete function */
532 diagfwd_write_complete_hsic(NULL, index);
533 }
534 }
535 remote_token--;
536 }
537 if (driver->in_busy_smux == 1) {
538 remote_token = diag_get_remote(QSC);
539 num_data++;
540
541 /* Copy the negative token of data being passed */
542 COPY_USER_SPACE_OR_EXIT(buf+ret,
543 remote_token, 4);
544 /* Copy the length of data being passed */
545 COPY_USER_SPACE_OR_EXIT(buf+ret,
546 (driver->write_ptr_mdm->length), 4);
547 /* Copy the actual data being passed */
548 COPY_USER_SPACE_OR_EXIT(buf+ret,
549 *(driver->buf_in_smux),
550 driver->write_ptr_mdm->length);
551 pr_debug("diag: SMUX data copied\n");
552 driver->in_busy_smux = 0;
553 }
554 exit_stat = 0;
555exit:
556 *pret = ret;
557 *pnum_data = num_data;
558 return exit_stat;
559}
Dixon Peterson13046ed2013-02-21 17:35:35 -0800560
Dixon Petersonf90f3582013-01-26 18:14:17 -0800561#else
562inline uint16_t diag_get_remote_device_mask(void) { return 0; }
563inline int diag_copy_remote(char __user *buf, size_t count, int *pret,
564 int *pnum_data) { return 0; }
565#endif
566
Katish Paran244514d2013-08-01 18:39:31 -0700567static int diag_copy_dci(char __user *buf, size_t count,
568 struct diag_dci_client_tbl *entry, int *pret)
569{
570 int total_data_len = 0;
571 int ret = 0;
572 int exit_stat = 1;
573 struct diag_dci_buffer_t *buf_entry, *temp;
574 struct diag_smd_info *smd_info = NULL;
575
576 if (!buf || !entry || !pret)
577 return exit_stat;
578
579 ret = *pret;
580
581 ret += 4;
582
583 mutex_lock(&entry->write_buf_mutex);
584 list_for_each_entry_safe(buf_entry, temp, &entry->list_write_buf,
585 buf_track) {
586 list_del(&buf_entry->buf_track);
587 mutex_lock(&buf_entry->data_mutex);
588 if ((buf_entry->data_len > 0) &&
589 (buf_entry->in_busy) &&
590 (buf_entry->data)) {
591 if (copy_to_user(buf+ret, (void *)buf_entry->data,
592 buf_entry->data_len))
593 goto drop;
594 ret += buf_entry->data_len;
595 total_data_len += buf_entry->data_len;
596drop:
597 buf_entry->in_busy = 0;
598 buf_entry->data_len = 0;
599 buf_entry->in_list = 0;
600 if (buf_entry->buf_type == DCI_BUF_CMD) {
601 if (buf_entry->data_source == APPS_DATA) {
602 mutex_unlock(&buf_entry->data_mutex);
603 continue;
604 }
605 if (driver->separate_cmdrsp[
606 buf_entry->data_source]) {
607 smd_info = &driver->smd_dci_cmd[
608 buf_entry->data_source];
609 } else {
610 smd_info = &driver->smd_dci[
611 buf_entry->data_source];
612 }
613 smd_info->in_busy_1 = 0;
614 mutex_unlock(&buf_entry->data_mutex);
615 continue;
616 } else if (buf_entry->buf_type == DCI_BUF_SECONDARY) {
617 diagmem_free(driver, buf_entry->data,
618 POOL_TYPE_DCI);
619 buf_entry->data = NULL;
620 mutex_unlock(&buf_entry->data_mutex);
621 kfree(buf_entry);
622 continue;
623 }
624
625 }
626 mutex_unlock(&buf_entry->data_mutex);
627 }
628
629 if (total_data_len > 0) {
630 /* Copy the total data length */
631 COPY_USER_SPACE_OR_EXIT(buf+4, total_data_len, 4);
632 ret -= 4;
633 } else {
634 pr_debug("diag: In %s, Trying to copy ZERO bytes, total_data_len: %d\n",
635 __func__, total_data_len);
636 }
637
638 entry->in_service = 0;
639 mutex_unlock(&entry->write_buf_mutex);
640
641 exit_stat = 0;
642exit:
643 *pret = ret;
644
645 return exit_stat;
646}
647
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530648int diag_command_reg(unsigned long ioarg)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700649{
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530650 int i = 0, success = -EINVAL, j;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700651 void *temp_buf;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530652 unsigned int count_entries = 0, interim_count = 0;
653 struct bindpkt_params_per_process pkt_params;
654 struct bindpkt_params *params;
655 struct bindpkt_params *head_params;
656 if (copy_from_user(&pkt_params, (void *)ioarg,
657 sizeof(struct bindpkt_params_per_process))) {
658 return -EFAULT;
659 }
660 if ((UINT_MAX/sizeof(struct bindpkt_params)) <
661 pkt_params.count) {
662 pr_warn("diag: integer overflow while multiply\n");
663 return -EFAULT;
664 }
665 head_params = kzalloc(pkt_params.count*sizeof(
666 struct bindpkt_params), GFP_KERNEL);
Ashay Jaiswalf7e265a2013-06-05 13:24:38 +0530667 if (ZERO_OR_NULL_PTR(head_params)) {
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530668 pr_err("diag: unable to alloc memory\n");
669 return -ENOMEM;
670 } else
671 params = head_params;
672 if (copy_from_user(params, pkt_params.params,
673 pkt_params.count*sizeof(struct bindpkt_params))) {
674 kfree(head_params);
675 return -EFAULT;
676 }
677 mutex_lock(&driver->diagchar_mutex);
678 for (i = 0; i < diag_max_reg; i++) {
679 if (driver->table[i].process_id == 0) {
680 diag_add_reg(i, params, &success,
681 &count_entries);
682 if (pkt_params.count > count_entries) {
683 params++;
684 } else {
685 kfree(head_params);
686 mutex_unlock(&driver->diagchar_mutex);
687 return success;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688 }
689 }
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530690 }
691 if (i < diag_threshold_reg) {
692 /* Increase table size by amount required */
693 if (pkt_params.count >= count_entries) {
694 interim_count = pkt_params.count -
695 count_entries;
696 } else {
697 pr_warn("diag: error in params count\n");
698 kfree(head_params);
699 mutex_unlock(&driver->diagchar_mutex);
700 return -EFAULT;
701 }
702 if (UINT_MAX - diag_max_reg >=
703 interim_count) {
704 diag_max_reg += interim_count;
705 } else {
706 pr_warn("diag: Integer overflow\n");
707 kfree(head_params);
708 mutex_unlock(&driver->diagchar_mutex);
709 return -EFAULT;
710 }
711 /* Make sure size doesnt go beyond threshold */
712 if (diag_max_reg > diag_threshold_reg) {
713 diag_max_reg = diag_threshold_reg;
714 pr_err("diag: best case memory allocation\n");
715 }
716 if (UINT_MAX/sizeof(struct diag_master_table) <
717 diag_max_reg) {
718 pr_warn("diag: integer overflow\n");
719 kfree(head_params);
720 mutex_unlock(&driver->diagchar_mutex);
721 return -EFAULT;
722 }
723 temp_buf = krealloc(driver->table,
724 diag_max_reg*sizeof(struct
725 diag_master_table), GFP_KERNEL);
726 if (!temp_buf) {
727 pr_err("diag: Insufficient memory for reg.\n");
728
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -0800729 if (pkt_params.count >= count_entries) {
730 interim_count = pkt_params.count -
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700731 count_entries;
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -0800732 } else {
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530733 pr_warn("diag: params count error\n");
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -0800734 kfree(head_params);
735 mutex_unlock(&driver->diagchar_mutex);
736 return -EFAULT;
737 }
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530738 if (diag_max_reg >= interim_count) {
739 diag_max_reg -= interim_count;
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -0800740 } else {
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530741 pr_warn("diag: Integer underflow\n");
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -0800742 kfree(head_params);
743 mutex_unlock(&driver->diagchar_mutex);
744 return -EFAULT;
745 }
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -0800746 kfree(head_params);
Shalabh Jainfe02b0c2012-02-21 14:48:03 -0800747 mutex_unlock(&driver->diagchar_mutex);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530748 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700749 } else {
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530750 driver->table = temp_buf;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700751 }
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530752 for (j = i; j < diag_max_reg; j++) {
753 diag_add_reg(j, params, &success,
754 &count_entries);
755 if (pkt_params.count > count_entries) {
756 params++;
757 } else {
758 kfree(head_params);
759 mutex_unlock(&driver->diagchar_mutex);
760 return success;
761 }
762 }
763 kfree(head_params);
764 mutex_unlock(&driver->diagchar_mutex);
765 } else {
766 kfree(head_params);
767 mutex_unlock(&driver->diagchar_mutex);
768 pr_err("Max size reached, Pkt Registration failed for Process %d",
769 current->tgid);
770 }
771 success = 0;
772 return success;
773}
774
775#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
776void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode)
777{
778 if (old_mode == MEMORY_DEVICE_MODE && new_mode
779 == NO_LOGGING_MODE) {
780 diagfwd_disconnect_bridge(0);
781 diag_clear_hsic_tbl();
782 } else if (old_mode == NO_LOGGING_MODE && new_mode
783 == MEMORY_DEVICE_MODE) {
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800784 int i;
785 for (i = 0; i < MAX_HSIC_CH; i++)
786 if (diag_hsic[i].hsic_inited)
787 diag_hsic[i].hsic_data_requested =
788 driver->real_time_mode ? 1 : 0;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530789 diagfwd_connect_bridge(0);
790 } else if (old_mode == USB_MODE && new_mode
791 == NO_LOGGING_MODE) {
792 diagfwd_disconnect_bridge(0);
793 } else if (old_mode == NO_LOGGING_MODE && new_mode
794 == USB_MODE) {
795 diagfwd_connect_bridge(0);
796 } else if (old_mode == USB_MODE && new_mode
797 == MEMORY_DEVICE_MODE) {
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800798 if (driver->real_time_mode)
799 diagfwd_cancel_hsic(REOPEN_HSIC);
800 else
801 diagfwd_cancel_hsic(DONT_REOPEN_HSIC);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530802 diagfwd_connect_bridge(0);
803 } else if (old_mode == MEMORY_DEVICE_MODE && new_mode
804 == USB_MODE) {
805 diag_clear_hsic_tbl();
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800806 diagfwd_cancel_hsic(REOPEN_HSIC);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530807 diagfwd_connect_bridge(0);
808 }
809}
810#else
811void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode)
812{
813
814}
815#endif
816
817#ifdef CONFIG_DIAG_SDIO_PIPE
818void diag_cmp_logging_modes_sdio_pipe(int old_mode, int new_mode)
819{
820 if (old_mode == MEMORY_DEVICE_MODE && new_mode
821 == NO_LOGGING_MODE) {
822 mutex_lock(&driver->diagchar_mutex);
823 driver->in_busy_sdio = 1;
824 mutex_unlock(&driver->diagchar_mutex);
825 } else if (old_mode == NO_LOGGING_MODE && new_mode
826 == MEMORY_DEVICE_MODE) {
827 mutex_lock(&driver->diagchar_mutex);
828 driver->in_busy_sdio = 0;
829 mutex_unlock(&driver->diagchar_mutex);
830 /* Poll SDIO channel to check for data */
831 if (driver->sdio_ch)
832 queue_work(driver->diag_sdio_wq,
833 &(driver->diag_read_sdio_work));
834 } else if (old_mode == USB_MODE && new_mode
835 == MEMORY_DEVICE_MODE) {
836 mutex_lock(&driver->diagchar_mutex);
837 driver->in_busy_sdio = 0;
838 mutex_unlock(&driver->diagchar_mutex);
839 /* Poll SDIO channel to check for data */
840 if (driver->sdio_ch)
841 queue_work(driver->diag_sdio_wq,
842 &(driver->diag_read_sdio_work));
843 }
844}
845#else
846void diag_cmp_logging_modes_sdio_pipe(int old_mode, int new_mode)
847{
848
849}
850#endif
851
852int diag_switch_logging(unsigned long ioarg)
853{
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800854 int temp = 0, success = -EINVAL, status = 0;
Dixon Peterson6dba7572013-04-12 18:45:16 -0700855 int requested_mode = (int)ioarg;
856
857 switch (requested_mode) {
858 case USB_MODE:
859 case MEMORY_DEVICE_MODE:
860 case NO_LOGGING_MODE:
861 case UART_MODE:
862 case SOCKET_MODE:
863 case CALLBACK_MODE:
Dixon Peterson6dba7572013-04-12 18:45:16 -0700864 break;
865 default:
866 pr_err("diag: In %s, request to switch to invalid mode: %d\n",
867 __func__, requested_mode);
868 return -EINVAL;
869 }
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800870
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -0700871 if (requested_mode == driver->logging_mode) {
872 if (requested_mode != MEMORY_DEVICE_MODE ||
873 driver->real_time_mode)
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800874 pr_info_ratelimited("diag: Already in logging mode change requested, mode: %d\n",
875 driver->logging_mode);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530876 return 0;
877 }
878
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -0700879 diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_UP);
880 if (requested_mode != MEMORY_DEVICE_MODE)
881 diag_update_real_time_vote(DIAG_PROC_MEMORY_DEVICE,
882 MODE_REALTIME);
883
884 if (!(requested_mode == MEMORY_DEVICE_MODE &&
885 driver->logging_mode == USB_MODE))
886 queue_work(driver->diag_real_time_wq,
887 &driver->diag_real_time_work);
888
889 mutex_lock(&driver->diagchar_mutex);
890 temp = driver->logging_mode;
891 driver->logging_mode = requested_mode;
892
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530893 if (driver->logging_mode == MEMORY_DEVICE_MODE) {
894 diag_clear_hsic_tbl();
895 driver->mask_check = 1;
896 if (driver->socket_process) {
897 /*
898 * Notify the socket logging process that we
899 * are switching to MEMORY_DEVICE_MODE
900 */
901 status = send_sig(SIGCONT,
902 driver->socket_process, 0);
903 if (status) {
904 pr_err("diag: %s, Error notifying ",
905 __func__);
906 pr_err("socket process, status: %d\n",
907 status);
908 }
909 }
910 } else if (driver->logging_mode == SOCKET_MODE) {
911 driver->socket_process = current;
912 } else if (driver->logging_mode == CALLBACK_MODE) {
913 driver->callback_process = current;
914 }
915
916 if (driver->logging_mode == UART_MODE ||
917 driver->logging_mode == SOCKET_MODE ||
918 driver->logging_mode == CALLBACK_MODE) {
919 diag_clear_hsic_tbl();
920 driver->mask_check = 0;
921 driver->logging_mode = MEMORY_DEVICE_MODE;
922 }
923
924 driver->logging_process_id = current->tgid;
925 mutex_unlock(&driver->diagchar_mutex);
926
927 if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
928 == NO_LOGGING_MODE) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800929 diag_reset_smd_data(RESET_AND_NO_QUEUE);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530930 diag_cmp_logging_modes_sdio_pipe(temp, driver->logging_mode);
931 diag_cmp_logging_modes_diagfwd_bridge(temp,
932 driver->logging_mode);
933 } else if (temp == NO_LOGGING_MODE && driver->logging_mode
934 == MEMORY_DEVICE_MODE) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800935 diag_reset_smd_data(RESET_AND_QUEUE);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530936 diag_cmp_logging_modes_sdio_pipe(temp,
937 driver->logging_mode);
938 diag_cmp_logging_modes_diagfwd_bridge(temp,
939 driver->logging_mode);
940 } else if (temp == USB_MODE && driver->logging_mode
941 == NO_LOGGING_MODE) {
942 diagfwd_disconnect();
943 diag_cmp_logging_modes_diagfwd_bridge(temp,
944 driver->logging_mode);
945 } else if (temp == NO_LOGGING_MODE && driver->logging_mode
946 == USB_MODE) {
947 diagfwd_connect();
948 diag_cmp_logging_modes_diagfwd_bridge(temp,
949 driver->logging_mode);
950 } else if (temp == USB_MODE && driver->logging_mode
951 == MEMORY_DEVICE_MODE) {
952 diagfwd_disconnect();
Dixon Peterson3ff84ea2012-12-21 20:16:18 -0800953 diag_reset_smd_data(RESET_AND_QUEUE);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530954 diag_cmp_logging_modes_sdio_pipe(temp, driver->logging_mode);
955 diag_cmp_logging_modes_diagfwd_bridge(temp,
956 driver->logging_mode);
957 } else if (temp == MEMORY_DEVICE_MODE &&
958 driver->logging_mode == USB_MODE) {
959 diagfwd_connect();
960 diag_cmp_logging_modes_diagfwd_bridge(temp,
961 driver->logging_mode);
962 }
963 success = 1;
964 return success;
965}
966
967long diagchar_ioctl(struct file *filp,
968 unsigned int iocmd, unsigned long ioarg)
969{
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -0700970 int i, result = -EINVAL, interim_size = 0, client_id = 0, real_time = 0;
971 int retry_count = 0, timer = 0;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530972 uint16_t support_list = 0, interim_rsp_id, remote_dev;
Katish Paran244514d2013-08-01 18:39:31 -0700973 struct diag_dci_reg_tbl_t *dci_reg_params;
974 struct diag_dci_health_stats_proc stats;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530975 struct diag_log_event_stats le_stats;
976 struct diagpkt_delay_params delay_params;
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -0700977 struct real_time_vote_t rt_vote;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530978
979 switch (iocmd) {
980 case DIAG_IOCTL_COMMAND_REG:
981 result = diag_command_reg(ioarg);
982 break;
983 case DIAG_IOCTL_GET_DELAYED_RSP_ID:
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -0800984 if (copy_from_user(&delay_params, (void *)ioarg,
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530985 sizeof(struct diagpkt_delay_params)))
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -0800986 return -EFAULT;
987 if ((delay_params.rsp_ptr) &&
988 (delay_params.size == sizeof(delayed_rsp_id)) &&
989 (delay_params.num_bytes_ptr)) {
Ravi Aravamudhanf55dc1d2012-12-27 11:51:42 -0800990 interim_rsp_id = diagpkt_next_delayed_rsp_id(
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -0800991 delayed_rsp_id);
992 if (copy_to_user((void *)delay_params.rsp_ptr,
993 &interim_rsp_id, sizeof(uint16_t)))
994 return -EFAULT;
995 interim_size = sizeof(delayed_rsp_id);
996 if (copy_to_user((void *)delay_params.num_bytes_ptr,
997 &interim_size, sizeof(int)))
998 return -EFAULT;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +0530999 result = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001000 }
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301001 break;
1002 case DIAG_IOCTL_DCI_REG:
Katish Paran244514d2013-08-01 18:39:31 -07001003 dci_reg_params = kzalloc(sizeof(struct diag_dci_reg_tbl_t),
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -08001004 GFP_KERNEL);
Katish Paran244514d2013-08-01 18:39:31 -07001005 if (dci_reg_params == NULL) {
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -08001006 pr_err("diag: unable to alloc memory\n");
1007 return -ENOMEM;
1008 }
Katish Paran244514d2013-08-01 18:39:31 -07001009 if (copy_from_user(dci_reg_params, (void *)ioarg,
1010 sizeof(struct diag_dci_reg_tbl_t))) {
1011 kfree(dci_reg_params);
Shalabh Jaina1c69a42012-10-23 12:51:30 -07001012 return -EFAULT;
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001013 }
Katish Paran244514d2013-08-01 18:39:31 -07001014 result = diag_dci_register_client(dci_reg_params);
1015 kfree(dci_reg_params);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301016 break;
1017 case DIAG_IOCTL_DCI_DEINIT:
Katish Paran244514d2013-08-01 18:39:31 -07001018 result = diag_dci_deinit_client();
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301019 break;
1020 case DIAG_IOCTL_DCI_SUPPORT:
Katish Paran244514d2013-08-01 18:39:31 -07001021 support_list |= DIAG_CON_APSS;
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001022 for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
1023 if (driver->smd_dci[i].ch)
1024 support_list |=
1025 driver->smd_dci[i].peripheral_mask;
1026 }
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -08001027 if (copy_to_user((void *)ioarg, &support_list,
1028 sizeof(uint16_t)))
1029 return -EFAULT;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301030 result = DIAG_DCI_NO_ERROR;
1031 break;
1032 case DIAG_IOCTL_DCI_HEALTH_STATS:
Shalabh Jaina1c69a42012-10-23 12:51:30 -07001033 if (copy_from_user(&stats, (void *)ioarg,
Katish Paran244514d2013-08-01 18:39:31 -07001034 sizeof(struct diag_dci_health_stats_proc)))
Shalabh Jaina1c69a42012-10-23 12:51:30 -07001035 return -EFAULT;
Katish Paran244514d2013-08-01 18:39:31 -07001036
1037 result = diag_dci_copy_health_stats(stats.health,
1038 stats.proc);
1039 if (result != DIAG_DCI_NO_ERROR)
1040 break;
1041
Shalabh Jaina1c69a42012-10-23 12:51:30 -07001042 if (copy_to_user((void *)ioarg, &stats,
Katish Paran244514d2013-08-01 18:39:31 -07001043 sizeof(struct diag_dci_health_stats_proc)))
Shalabh Jaina1c69a42012-10-23 12:51:30 -07001044 return -EFAULT;
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301045 result = DIAG_DCI_NO_ERROR;
1046 break;
1047 case DIAG_IOCTL_DCI_LOG_STATUS:
1048 if (copy_from_user(&le_stats, (void *)ioarg,
1049 sizeof(struct diag_log_event_stats)))
1050 return -EFAULT;
1051 le_stats.is_set = diag_dci_query_log_mask(le_stats.code);
1052 if (copy_to_user((void *)ioarg, &le_stats,
1053 sizeof(struct diag_log_event_stats)))
1054 return -EFAULT;
1055 result = DIAG_DCI_NO_ERROR;
1056 break;
1057 case DIAG_IOCTL_DCI_EVENT_STATUS:
1058 if (copy_from_user(&le_stats, (void *)ioarg,
1059 sizeof(struct diag_log_event_stats)))
1060 return -EFAULT;
1061 le_stats.is_set = diag_dci_query_event_mask(le_stats.code);
1062 if (copy_to_user((void *)ioarg, &le_stats,
1063 sizeof(struct diag_log_event_stats)))
1064 return -EFAULT;
1065 result = DIAG_DCI_NO_ERROR;
1066 break;
1067 case DIAG_IOCTL_DCI_CLEAR_LOGS:
1068 if (copy_from_user((void *)&client_id, (void *)ioarg,
1069 sizeof(int)))
1070 return -EFAULT;
1071 result = diag_dci_clear_log_mask();
1072 break;
1073 case DIAG_IOCTL_DCI_CLEAR_EVENTS:
1074 if (copy_from_user(&client_id, (void *)ioarg,
1075 sizeof(int)))
1076 return -EFAULT;
1077 result = diag_dci_clear_event_mask();
1078 break;
1079 case DIAG_IOCTL_LSM_DEINIT:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001080 for (i = 0; i < driver->num_clients; i++)
1081 if (driver->client_map[i].pid == current->tgid)
1082 break;
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -08001083 if (i == driver->num_clients)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001084 return -EINVAL;
1085 driver->data_ready[i] |= DEINIT_TYPE;
1086 wake_up_interruptible(&driver->wait_q);
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301087 result = 1;
1088 break;
1089 case DIAG_IOCTL_SWITCH_LOGGING:
1090 result = diag_switch_logging(ioarg);
1091 break;
1092 case DIAG_IOCTL_REMOTE_DEV:
1093 remote_dev = diag_get_remote_device_mask();
Dixon Peterson70170f72012-11-05 20:25:11 -08001094 if (copy_to_user((void *)ioarg, &remote_dev, sizeof(uint16_t)))
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301095 result = -EFAULT;
Dixon Peterson70170f72012-11-05 20:25:11 -08001096 else
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301097 result = 1;
1098 break;
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001099 case DIAG_IOCTL_VOTE_REAL_TIME:
1100 if (copy_from_user(&rt_vote, (void *)ioarg, sizeof(struct
1101 real_time_vote_t)))
Ravi Aravamudhanf4162ab2013-12-10 20:04:33 -08001102 return -EFAULT;
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001103 driver->real_time_update_busy++;
1104 if (rt_vote.proc == DIAG_PROC_DCI) {
Katish Paran244514d2013-08-01 18:39:31 -07001105 diag_dci_set_real_time(rt_vote.real_time_vote);
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001106 real_time = diag_dci_get_cumulative_real_time();
1107 } else {
1108 real_time = rt_vote.real_time_vote;
1109 }
1110 diag_update_real_time_vote(rt_vote.proc, real_time);
1111 queue_work(driver->diag_real_time_wq,
1112 &driver->diag_real_time_work);
1113 result = 0;
1114 break;
1115 case DIAG_IOCTL_GET_REAL_TIME:
1116 if (copy_from_user(&real_time, (void *)ioarg, sizeof(int)))
1117 return -EFAULT;
1118 while (retry_count < 3) {
1119 if (driver->real_time_update_busy > 0) {
1120 retry_count++;
1121 /* The value 10000 was chosen empirically as an
1122 optimum value in order to give the work in
1123 diag_real_time_wq to complete processing.*/
1124 for (timer = 0; timer < 5; timer++)
1125 usleep_range(10000, 10100);
1126 } else {
1127 real_time = driver->real_time_mode;
1128 if (copy_to_user((void *)ioarg, &real_time,
1129 sizeof(int)))
1130 return -EFAULT;
1131 result = 0;
1132 break;
1133 }
1134 }
1135 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001136 }
Mohit Aggarwal3aa45862013-03-05 18:37:58 +05301137 return result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138}
1139
1140static int diagchar_read(struct file *file, char __user *buf, size_t count,
1141 loff_t *ppos)
1142{
Shalabh Jain16794902012-09-14 10:56:49 -07001143 struct diag_dci_client_tbl *entry;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001144 int index = -1, i = 0, ret = 0;
1145 int num_data = 0, data_type;
Dixon Petersonf82952c2013-01-11 19:19:10 -08001146 int remote_token;
Dixon Petersonf90f3582013-01-26 18:14:17 -08001147 int exit_stat;
Dixon Petersonf2d449c2013-02-01 18:02:20 -08001148 int clear_read_wakelock;
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001149 unsigned long flags;
Ashay Jaiswala01e65f2012-09-12 11:35:03 +05301150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151 for (i = 0; i < driver->num_clients; i++)
1152 if (driver->client_map[i].pid == current->tgid)
1153 index = i;
1154
1155 if (index == -1) {
1156 pr_err("diag: Client PID not found in table");
1157 return -EINVAL;
1158 }
Katish Paran244514d2013-08-01 18:39:31 -07001159 if (!buf) {
1160 pr_err("diag: bad address from user side\n");
1161 return -EFAULT;
1162 }
Dixon Petersonbba99ca2013-07-10 17:25:20 -07001163 wait_event_interruptible(driver->wait_q, driver->data_ready[index]);
1164
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001165 mutex_lock(&driver->diagchar_mutex);
1166
Dixon Petersonf2d449c2013-02-01 18:02:20 -08001167 clear_read_wakelock = 0;
Shalabh Jain84e30342012-10-16 16:16:08 -07001168 if ((driver->data_ready[index] & USER_SPACE_DATA_TYPE) && (driver->
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001169 logging_mode == MEMORY_DEVICE_MODE)) {
Dixon Petersonf82952c2013-01-11 19:19:10 -08001170 remote_token = 0;
Dixon Petersonf79b66f2012-04-26 13:21:26 -07001171 pr_debug("diag: process woken up\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 /*Copy the type of data being passed*/
Shalabh Jain84e30342012-10-16 16:16:08 -07001173 data_type = driver->data_ready[index] & USER_SPACE_DATA_TYPE;
Dixon Petersonbba99ca2013-07-10 17:25:20 -07001174 driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001175 COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
1176 /* place holder for number of data field */
1177 ret += 4;
1178
Dixon Petersona6d98092013-05-16 12:26:26 -07001179 for (i = 0; i < driver->buf_tbl_size; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 if (driver->buf_tbl[i].length > 0) {
1181#ifdef DIAG_DEBUG
Ravi Aravamudhan910f5662014-01-21 10:07:06 -08001182 pr_debug("diag: WRITING the buf address and length is %p , %d\n",
1183 driver->buf_tbl[i].buf,
1184 driver->buf_tbl[i].length);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185#endif
1186 num_data++;
1187 /* Copy the length of data being passed */
1188 if (copy_to_user(buf+ret, (void *)&(driver->
1189 buf_tbl[i].length), 4)) {
1190 num_data--;
1191 goto drop;
1192 }
1193 ret += 4;
1194
1195 /* Copy the actual data being passed */
1196 if (copy_to_user(buf+ret, (void *)driver->
1197 buf_tbl[i].buf, driver->buf_tbl[i].length)) {
1198 ret -= 4;
1199 num_data--;
1200 goto drop;
1201 }
1202 ret += driver->buf_tbl[i].length;
1203drop:
1204#ifdef DIAG_DEBUG
Ravi Aravamudhan910f5662014-01-21 10:07:06 -08001205 pr_debug("diag: DEQUEUE buf address and length is %p, %d\n",
1206 driver->buf_tbl[i].buf,
1207 driver->buf_tbl[i].length);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208#endif
1209 diagmem_free(driver, (unsigned char *)
1210 (driver->buf_tbl[i].buf), POOL_TYPE_HDLC);
1211 driver->buf_tbl[i].length = 0;
1212 driver->buf_tbl[i].buf = 0;
1213 }
1214 }
1215
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001216 /* Copy peripheral data */
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001217 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1218 struct diag_smd_info *data = &driver->smd_data[i];
1219 if (data->in_busy_1 == 1) {
1220 num_data++;
1221 /*Copy the length of data being passed*/
1222 COPY_USER_SPACE_OR_EXIT(buf+ret,
1223 (data->write_ptr_1->length), 4);
1224 /*Copy the actual data being passed*/
1225 COPY_USER_SPACE_OR_EXIT(buf+ret,
1226 *(data->buf_in_1),
1227 data->write_ptr_1->length);
Dixon Petersonf2d449c2013-02-01 18:02:20 -08001228 if (!driver->real_time_mode) {
1229 process_lock_on_copy(&data->nrt_lock);
1230 clear_read_wakelock++;
1231 }
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001232 spin_lock_irqsave(&data->in_busy_lock, flags);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001233 data->in_busy_1 = 0;
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001234 spin_unlock_irqrestore(&data->in_busy_lock,
1235 flags);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001236 }
1237 if (data->in_busy_2 == 1) {
1238 num_data++;
1239 /*Copy the length of data being passed*/
1240 COPY_USER_SPACE_OR_EXIT(buf+ret,
1241 (data->write_ptr_2->length), 4);
1242 /*Copy the actual data being passed*/
1243 COPY_USER_SPACE_OR_EXIT(buf+ret,
1244 *(data->buf_in_2),
1245 data->write_ptr_2->length);
Dixon Petersonf2d449c2013-02-01 18:02:20 -08001246 if (!driver->real_time_mode) {
1247 process_lock_on_copy(&data->nrt_lock);
1248 clear_read_wakelock++;
1249 }
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001250 spin_lock_irqsave(&data->in_busy_lock, flags);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001251 data->in_busy_2 = 0;
Ravi Aravamudhan3db73922013-11-15 12:26:22 -08001252 spin_unlock_irqrestore(&data->in_busy_lock,
1253 flags);
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001254 }
Shalabh Jain69890aa2011-10-10 12:59:16 -07001255 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001256 if (driver->supports_separate_cmdrsp) {
1257 for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
1258 struct diag_smd_info *data =
1259 &driver->smd_cmd[i];
1260 if (!driver->separate_cmdrsp[i])
1261 continue;
1262
1263 if (data->in_busy_1 == 1) {
1264 num_data++;
1265 /*Copy the length of data being passed*/
1266 COPY_USER_SPACE_OR_EXIT(buf+ret,
1267 (data->write_ptr_1->length), 4);
1268 /*Copy the actual data being passed*/
1269 COPY_USER_SPACE_OR_EXIT(buf+ret,
1270 *(data->buf_in_1),
1271 data->write_ptr_1->length);
1272 data->in_busy_1 = 0;
1273 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001274 }
1275 }
Shalabh Jain482bf122011-12-06 03:54:47 -08001276#ifdef CONFIG_DIAG_SDIO_PIPE
1277 /* copy 9K data over SDIO */
1278 if (driver->in_busy_sdio == 1) {
Dixon Petersonf82952c2013-01-11 19:19:10 -08001279 remote_token = diag_get_remote(MDM);
Shalabh Jain482bf122011-12-06 03:54:47 -08001280 num_data++;
Dixon Petersonf82952c2013-01-11 19:19:10 -08001281
1282 /*Copy the negative token of data being passed*/
1283 COPY_USER_SPACE_OR_EXIT(buf+ret,
1284 remote_token, 4);
Shalabh Jain482bf122011-12-06 03:54:47 -08001285 /*Copy the length of data being passed*/
1286 COPY_USER_SPACE_OR_EXIT(buf+ret,
1287 (driver->write_ptr_mdm->length), 4);
1288 /*Copy the actual data being passed*/
1289 COPY_USER_SPACE_OR_EXIT(buf+ret,
1290 *(driver->buf_in_sdio),
1291 driver->write_ptr_mdm->length);
1292 driver->in_busy_sdio = 0;
1293 }
1294#endif
Dixon Petersonf90f3582013-01-26 18:14:17 -08001295 /* Copy date from remote processors */
1296 exit_stat = diag_copy_remote(buf, count, &ret, &num_data);
1297 if (exit_stat == 1)
1298 goto exit;
Dixon Peterson938f8602012-08-17 20:02:57 -07001299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300 /* copy number of data fields */
1301 COPY_USER_SPACE_OR_EXIT(buf+4, num_data, 4);
1302 ret -= 4;
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001303 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
1304 if (driver->smd_data[i].ch)
Dixon Petersonbba99ca2013-07-10 17:25:20 -07001305 queue_work(driver->smd_data[i].wq,
Dixon Peterson66fb11b2012-12-04 20:30:54 -08001306 &(driver->smd_data[i].diag_read_smd_work));
1307 }
Shalabh Jain482bf122011-12-06 03:54:47 -08001308#ifdef CONFIG_DIAG_SDIO_PIPE
1309 if (driver->sdio_ch)
1310 queue_work(driver->diag_sdio_wq,
1311 &(driver->diag_read_sdio_work));
1312#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313 APPEND_DEBUG('n');
1314 goto exit;
Shalabh Jain84e30342012-10-16 16:16:08 -07001315 } else if (driver->data_ready[index] & USER_SPACE_DATA_TYPE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316 /* In case, the thread wakes up and the logging mode is
1317 not memory device any more, the condition needs to be cleared */
Shalabh Jain84e30342012-10-16 16:16:08 -07001318 driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001319 }
1320
1321 if (driver->data_ready[index] & DEINIT_TYPE) {
1322 /*Copy the type of data being passed*/
1323 data_type = driver->data_ready[index] & DEINIT_TYPE;
1324 COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
1325 driver->data_ready[index] ^= DEINIT_TYPE;
1326 goto exit;
1327 }
1328
1329 if (driver->data_ready[index] & MSG_MASKS_TYPE) {
1330 /*Copy the type of data being passed*/
1331 data_type = driver->data_ready[index] & MSG_MASKS_TYPE;
1332 COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
1333 COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->msg_masks),
1334 MSG_MASK_SIZE);
1335 driver->data_ready[index] ^= MSG_MASKS_TYPE;
1336 goto exit;
1337 }
1338
1339 if (driver->data_ready[index] & EVENT_MASKS_TYPE) {
1340 /*Copy the type of data being passed*/
1341 data_type = driver->data_ready[index] & EVENT_MASKS_TYPE;
1342 COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
1343 COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->event_masks),
1344 EVENT_MASK_SIZE);
1345 driver->data_ready[index] ^= EVENT_MASKS_TYPE;
1346 goto exit;
1347 }
1348
1349 if (driver->data_ready[index] & LOG_MASKS_TYPE) {
1350 /*Copy the type of data being passed*/
1351 data_type = driver->data_ready[index] & LOG_MASKS_TYPE;
1352 COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
1353 COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->log_masks),
1354 LOG_MASK_SIZE);
1355 driver->data_ready[index] ^= LOG_MASKS_TYPE;
1356 goto exit;
1357 }
1358
1359 if (driver->data_ready[index] & PKT_TYPE) {
1360 /*Copy the type of data being passed*/
1361 data_type = driver->data_ready[index] & PKT_TYPE;
1362 COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
1363 COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->pkt_buf),
1364 driver->pkt_length);
1365 driver->data_ready[index] ^= PKT_TYPE;
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001366 driver->in_busy_pktdata = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001367 goto exit;
1368 }
1369
Katish Paran244514d2013-08-01 18:39:31 -07001370 if (driver->data_ready[index] & DCI_PKT_TYPE) {
1371 /* Copy the type of data being passed */
1372 data_type = driver->data_ready[index] & DCI_PKT_TYPE;
1373 COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
1374 COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->dci_pkt_buf),
1375 driver->dci_pkt_length);
1376 driver->data_ready[index] ^= DCI_PKT_TYPE;
1377 driver->in_busy_dcipktdata = 0;
1378 goto exit;
1379 }
1380
1381 if (driver->data_ready[index] & DCI_EVENT_MASKS_TYPE) {
1382 /*Copy the type of data being passed*/
1383 data_type = driver->data_ready[index] & DCI_EVENT_MASKS_TYPE;
1384 COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
1385 COPY_USER_SPACE_OR_EXIT(buf+4, driver->num_dci_client, 4);
1386 COPY_USER_SPACE_OR_EXIT(buf+8, *(dci_cumulative_event_mask),
1387 DCI_EVENT_MASK_SIZE);
1388 driver->data_ready[index] ^= DCI_EVENT_MASKS_TYPE;
1389 goto exit;
1390 }
1391
1392 if (driver->data_ready[index] & DCI_LOG_MASKS_TYPE) {
1393 /*Copy the type of data being passed*/
1394 data_type = driver->data_ready[index] & DCI_LOG_MASKS_TYPE;
1395 COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
1396 COPY_USER_SPACE_OR_EXIT(buf+4, driver->num_dci_client, 4);
1397 COPY_USER_SPACE_OR_EXIT(buf+8, *(dci_cumulative_log_mask),
1398 DCI_LOG_MASK_SIZE);
1399 driver->data_ready[index] ^= DCI_LOG_MASKS_TYPE;
1400 goto exit;
1401 }
1402
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001403 if (driver->data_ready[index] & DCI_DATA_TYPE) {
Shalabh Jain16794902012-09-14 10:56:49 -07001404 /* Copy the type of data being passed */
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001405 data_type = driver->data_ready[index] & DCI_DATA_TYPE;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001406 driver->data_ready[index] ^= DCI_DATA_TYPE;
Katish Paran244514d2013-08-01 18:39:31 -07001407 /* check the current client and copy its data */
1408 entry = diag_dci_get_client_entry();
1409 if (entry) {
1410 if (!entry->in_service)
1411 goto exit;
1412 COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
1413 exit_stat = diag_copy_dci(buf, count, entry, &ret);
1414 if (exit_stat == 1)
1415 goto exit;
1416 }
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001417 for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07001418 if (driver->smd_dci[i].ch) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001419 queue_work(driver->diag_dci_wq,
1420 &(driver->smd_dci[i].diag_read_smd_work));
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07001421 }
Dixon Petersoneecbadb2012-12-10 21:59:28 -08001422 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001423 if (driver->supports_separate_cmdrsp) {
1424 for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++) {
1425 if (!driver->separate_cmdrsp[i])
1426 continue;
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07001427 if (driver->smd_dci_cmd[i].ch) {
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001428 queue_work(driver->diag_dci_wq,
1429 &(driver->smd_dci_cmd[i].
1430 diag_read_smd_work));
Ravi Aravamudhan37903fe2013-06-03 12:35:05 -07001431 }
Dixon Peterson3ff84ea2012-12-21 20:16:18 -08001432 }
1433 }
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001434 goto exit;
1435 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436exit:
Dixon Petersonf2d449c2013-02-01 18:02:20 -08001437 if (clear_read_wakelock) {
1438 for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
1439 process_lock_on_copy_complete(
1440 &driver->smd_data[i].nrt_lock);
1441 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001442 mutex_unlock(&driver->diagchar_mutex);
1443 return ret;
1444}
1445
1446static int diagchar_write(struct file *file, const char __user *buf,
Shalabh Jain16794902012-09-14 10:56:49 -07001447 size_t count, loff_t *ppos)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001448{
Ashay Jaiswalfdb9bd42012-10-30 19:55:06 +05301449 int err, ret = 0, pkt_type, token_offset = 0;
Katish Paran244514d2013-08-01 18:39:31 -07001450 int remote_proc = 0, data_type;
Ravi Aravamudhan7902c5a2013-06-27 10:26:34 -07001451 uint8_t index;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452#ifdef DIAG_DEBUG
1453 int length = 0, i;
1454#endif
1455 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
1456 struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
1457 void *buf_copy = NULL;
Dixon Peterson6dba7572013-04-12 18:45:16 -07001458 void *user_space_data = NULL;
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -08001459 unsigned int payload_size;
Ravi Aravamudhan3365bc02013-03-05 16:51:28 -08001460
Shalabh Jainb0037c02013-01-18 12:47:40 -08001461 index = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001462 /* Get the packet type F3/log/event/Pkt response */
1463 err = copy_from_user((&pkt_type), buf, 4);
Katish Paran3e200902013-12-24 17:46:29 +05301464 if (err) {
1465 pr_alert("diag: copy failed for pkt_type\n");
1466 return -EAGAIN;
1467 }
Shalabh Jain69890aa2011-10-10 12:59:16 -07001468 /* First 4 bytes indicate the type of payload - ignore these */
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -08001469 if (count < 4) {
1470 pr_err("diag: Client sending short data\n");
1471 return -EBADMSG;
1472 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 payload_size = count - 4;
Ravi Aravamudhan77ad4832012-11-15 16:04:04 -08001474 if (payload_size > USER_SPACE_DATA) {
1475 pr_err("diag: Dropping packet, packet payload size crosses 8KB limit. Current payload size %d\n",
1476 payload_size);
1477 driver->dropped_count++;
1478 return -EBADMSG;
1479 }
Ravi Aravamudhan3365bc02013-03-05 16:51:28 -08001480#ifdef CONFIG_DIAG_OVER_USB
Katish Paran244514d2013-08-01 18:39:31 -07001481 if (driver->logging_mode == NO_LOGGING_MODE ||
1482 (!((pkt_type == DCI_DATA_TYPE) ||
1483 ((pkt_type & (DATA_TYPE_DCI_LOG | DATA_TYPE_DCI_EVENT)) == 0))
1484 && (driver->logging_mode == USB_MODE) &&
1485 (!driver->usb_connected))) {
Ravi Aravamudhan3365bc02013-03-05 16:51:28 -08001486 /*Drop the diag payload */
1487 return -EIO;
1488 }
1489#endif /* DIAG over USB */
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001490 if (pkt_type == DCI_DATA_TYPE) {
Dixon Peterson6dba7572013-04-12 18:45:16 -07001491 user_space_data = diagmem_alloc(driver, payload_size,
1492 POOL_TYPE_USER);
1493 if (!user_space_data) {
1494 driver->dropped_count++;
1495 return -ENOMEM;
1496 }
1497 err = copy_from_user(user_space_data, buf + 4, payload_size);
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001498 if (err) {
1499 pr_alert("diag: copy failed for DCI data\n");
Ravi Aravamudhan4207b652013-06-07 17:37:37 -07001500 diagmem_free(driver, user_space_data, POOL_TYPE_USER);
1501 user_space_data = NULL;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001502 return DIAG_DCI_SEND_DATA_FAIL;
1503 }
Dixon Peterson6dba7572013-04-12 18:45:16 -07001504 err = diag_process_dci_transaction(user_space_data,
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001505 payload_size);
Dixon Peterson6dba7572013-04-12 18:45:16 -07001506 diagmem_free(driver, user_space_data, POOL_TYPE_USER);
Ravi Aravamudhan4207b652013-06-07 17:37:37 -07001507 user_space_data = NULL;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001508 return err;
1509 }
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001510 if (pkt_type == CALLBACK_DATA_TYPE) {
Katish Paranfc770452014-02-27 12:53:36 +05301511 if (payload_size > driver->itemsize) {
Katish Paran3e200902013-12-24 17:46:29 +05301512 pr_err("diag: Dropping packet, invalid packet size. Current payload size %d\n",
Dixon Peterson6dba7572013-04-12 18:45:16 -07001513 payload_size);
1514 driver->dropped_count++;
1515 return -EBADMSG;
1516 }
1517
1518 buf_copy = diagmem_alloc(driver, payload_size, POOL_TYPE_COPY);
1519 if (!buf_copy) {
1520 driver->dropped_count++;
1521 return -ENOMEM;
1522 }
1523
1524 err = copy_from_user(buf_copy, buf + 4, payload_size);
1525 if (err) {
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001526 pr_err("diag: copy failed for user space data\n");
Ravi Aravamudhan47078312013-10-24 15:51:51 -07001527 diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
1528 buf_copy = NULL;
1529 return -EIO;
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001530 }
1531 /* Check for proc_type */
Dixon Peterson6dba7572013-04-12 18:45:16 -07001532 remote_proc = diag_get_remote(*(int *)buf_copy);
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001533
1534 if (!remote_proc) {
1535 wait_event_interruptible(driver->wait_q,
1536 (driver->in_busy_pktdata == 0));
Dixon Peterson6dba7572013-04-12 18:45:16 -07001537 ret = diag_process_apps_pkt(buf_copy, payload_size);
Ravi Aravamudhan47078312013-10-24 15:51:51 -07001538 diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
1539 buf_copy = NULL;
1540 return ret;
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001541 }
1542 /* The packet is for the remote processor */
Katish Paranfc770452014-02-27 12:53:36 +05301543 if (payload_size <= MIN_SIZ_ALLOW) {
Katish Paran244514d2013-08-01 18:39:31 -07001544 pr_err("diag: Integer underflow in %s, payload size: %d",
1545 __func__, payload_size);
1546 return -EBADMSG;
Katish Paranfc770452014-02-27 12:53:36 +05301547 }
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001548 token_offset = 4;
1549 payload_size -= 4;
1550 buf += 4;
1551 /* Perform HDLC encoding on incoming data */
1552 send.state = DIAG_STATE_START;
Dixon Peterson6dba7572013-04-12 18:45:16 -07001553 send.pkt = (void *)(buf_copy + token_offset);
1554 send.last = (void *)(buf_copy + token_offset -
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001555 1 + payload_size);
1556 send.terminate = 1;
1557
Ravi Aravamudhan47078312013-10-24 15:51:51 -07001558 mutex_lock(&driver->diagchar_mutex);
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001559 if (!buf_hdlc)
1560 buf_hdlc = diagmem_alloc(driver, HDLC_OUT_BUF_SIZE,
1561 POOL_TYPE_HDLC);
1562 if (!buf_hdlc) {
1563 ret = -ENOMEM;
Ravi Aravamudhan4207b652013-06-07 17:37:37 -07001564 driver->used = 0;
1565 goto fail_free_copy;
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001566 }
1567 if (HDLC_OUT_BUF_SIZE < (2 * payload_size) + 3) {
1568 pr_err("diag: Dropping packet, HDLC encoded packet payload size crosses buffer limit. Current payload size %d\n",
1569 ((2*payload_size) + 3));
1570 driver->dropped_count++;
1571 ret = -EBADMSG;
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001572 goto fail_free_hdlc;
1573 }
1574 enc.dest = buf_hdlc + driver->used;
1575 enc.dest_last = (void *)(buf_hdlc + driver->used +
1576 (2 * payload_size) + token_offset - 1);
1577 diag_hdlc_encode(&send, &enc);
1578
1579#ifdef CONFIG_DIAG_SDIO_PIPE
1580 /* send masks to 9k too */
1581 if (driver->sdio_ch && (remote_proc == MDM)) {
1582 wait_event_interruptible(driver->wait_q,
1583 (sdio_write_avail(driver->sdio_ch) >=
1584 payload_size));
1585 if (driver->sdio_ch && (payload_size > 0)) {
1586 sdio_write(driver->sdio_ch, (void *)
1587 (char *)buf_hdlc, payload_size + 3);
1588 }
1589 }
1590#endif
1591#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
1592 /* send masks to All 9k */
1593 if ((remote_proc >= MDM) && (remote_proc <= MDM4)) {
1594 index = remote_proc - MDM;
1595 if (diag_hsic[index].hsic_ch && (payload_size > 0)) {
1596 /* wait sending mask updates
1597 * if HSIC ch not ready */
Dixon Peterson981313b2013-07-01 13:44:48 -07001598 while (diag_hsic[index].in_busy_hsic_write) {
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001599 wait_event_interruptible(driver->wait_q,
1600 (diag_hsic[index].
1601 in_busy_hsic_write != 1));
Dixon Peterson981313b2013-07-01 13:44:48 -07001602 }
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001603 diag_hsic[index].in_busy_hsic_write = 1;
1604 diag_hsic[index].in_busy_hsic_read_on_device =
1605 0;
1606 err = diag_bridge_write(index,
1607 (char *)buf_hdlc, payload_size + 3);
1608 if (err) {
1609 pr_err("diag: err sending mask to MDM: %d\n",
1610 err);
1611 /*
1612 * If the error is recoverable, then
1613 * clear the write flag, so we will
1614 * resubmit a write on the next frame.
1615 * Otherwise, don't resubmit a write
1616 * on the next frame.
1617 */
1618 if ((-ESHUTDOWN) != err)
1619 diag_hsic[index].
1620 in_busy_hsic_write = 0;
1621 }
1622 }
1623 }
1624 if (driver->diag_smux_enabled && (remote_proc == QSC)
1625 && driver->lcid) {
1626 if (payload_size > 0) {
1627 err = msm_smux_write(driver->lcid, NULL,
1628 (char *)buf_hdlc, payload_size + 3);
1629 if (err) {
1630 pr_err("diag:send mask to MDM err %d",
1631 err);
1632 ret = err;
1633 }
1634 }
1635 }
1636#endif
Ravi Aravamudhan4207b652013-06-07 17:37:37 -07001637 goto fail_free_hdlc;
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07001638 }
Shalabh Jain84e30342012-10-16 16:16:08 -07001639 if (pkt_type == USER_SPACE_DATA_TYPE) {
Mohit Aggarwala0118b12013-12-05 17:14:35 +05301640 err = copy_from_user(driver->user_space_data_buf, buf + 4,
Shalabh Jain69890aa2011-10-10 12:59:16 -07001641 payload_size);
Ravi Aravamudhan5d2a4a82013-02-11 18:56:36 -08001642 if (err) {
1643 pr_err("diag: copy failed for user space data\n");
1644 return -EIO;
1645 }
Ashay Jaiswalfdb9bd42012-10-30 19:55:06 +05301646 /* Check for proc_type */
Mohit Aggarwala0118b12013-12-05 17:14:35 +05301647 remote_proc =
1648 diag_get_remote(*(int *)driver->user_space_data_buf);
Ashay Jaiswala372f8c2012-12-12 14:02:38 +05301649
1650 if (remote_proc) {
Katish Paran3e200902013-12-24 17:46:29 +05301651 if (payload_size <= MIN_SIZ_ALLOW) {
1652 pr_err("diag: Integer underflow in %s, payload size: %d",
1653 __func__, payload_size);
1654 return -EBADMSG;
1655 }
Ashay Jaiswalfdb9bd42012-10-30 19:55:06 +05301656 token_offset = 4;
1657 payload_size -= 4;
1658 buf += 4;
1659 }
1660
Shalabh Jain69890aa2011-10-10 12:59:16 -07001661 /* Check masks for On-Device logging */
Shalabh Jainc236f982011-12-15 22:55:20 -08001662 if (driver->mask_check) {
Mohit Aggarwala0118b12013-12-05 17:14:35 +05301663 if (!mask_request_validate(driver->user_space_data_buf +
Shalabh Jain737fca72012-11-14 21:53:43 -08001664 token_offset)) {
Shalabh Jain69890aa2011-10-10 12:59:16 -07001665 pr_alert("diag: mask request Invalid\n");
1666 return -EFAULT;
1667 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001668 }
1669 buf = buf + 4;
1670#ifdef DIAG_DEBUG
Shalabh Jain69890aa2011-10-10 12:59:16 -07001671 pr_debug("diag: user space data %d\n", payload_size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001672 for (i = 0; i < payload_size; i++)
Mohit Aggarwala0118b12013-12-05 17:14:35 +05301673 pr_debug("\t %x", *((driver->user_space_data_buf
Ashay Jaiswalfdb9bd42012-10-30 19:55:06 +05301674 + token_offset)+i));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001675#endif
Shalabh Jain482bf122011-12-06 03:54:47 -08001676#ifdef CONFIG_DIAG_SDIO_PIPE
1677 /* send masks to 9k too */
Dixon Petersonf82952c2013-01-11 19:19:10 -08001678 if (driver->sdio_ch && (remote_proc == MDM)) {
Shalabh Jain482bf122011-12-06 03:54:47 -08001679 wait_event_interruptible(driver->wait_q,
1680 (sdio_write_avail(driver->sdio_ch) >=
1681 payload_size));
1682 if (driver->sdio_ch && (payload_size > 0)) {
1683 sdio_write(driver->sdio_ch, (void *)
Mohit Aggarwala0118b12013-12-05 17:14:35 +05301684 (driver->user_space_data_buf + token_offset),
Ashay Jaiswalfdb9bd42012-10-30 19:55:06 +05301685 payload_size);
Shalabh Jain482bf122011-12-06 03:54:47 -08001686 }
1687 }
1688#endif
Shalabh Jain737fca72012-11-14 21:53:43 -08001689#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Shalabh Jainb0037c02013-01-18 12:47:40 -08001690 /* send masks to All 9k */
Dixon Petersonf2d449c2013-02-01 18:02:20 -08001691 if ((remote_proc >= MDM) && (remote_proc <= MDM4) &&
1692 (payload_size > 0)) {
Dixon Petersonf90f3582013-01-26 18:14:17 -08001693 index = remote_proc - MDM;
Dixon Petersonf2d449c2013-02-01 18:02:20 -08001694 /*
1695 * If hsic data is being requested for this remote
1696 * processor and its hsic in not open
1697 */
1698 if (!diag_hsic[index].hsic_device_opened) {
1699 diag_hsic[index].hsic_data_requested = 1;
1700 connect_bridge(0, index);
1701 }
1702
1703 if (diag_hsic[index].hsic_ch) {
Shalabh Jainb0037c02013-01-18 12:47:40 -08001704 /* wait sending mask updates
1705 * if HSIC ch not ready */
Dixon Peterson981313b2013-07-01 13:44:48 -07001706 while (diag_hsic[index].in_busy_hsic_write) {
Shalabh Jainb0037c02013-01-18 12:47:40 -08001707 wait_event_interruptible(driver->wait_q,
1708 (diag_hsic[index].
1709 in_busy_hsic_write != 1));
Dixon Peterson981313b2013-07-01 13:44:48 -07001710 }
Shalabh Jainb0037c02013-01-18 12:47:40 -08001711 diag_hsic[index].in_busy_hsic_write = 1;
1712 diag_hsic[index].in_busy_hsic_read_on_device =
1713 0;
1714 err = diag_bridge_write(index,
Mohit Aggarwala0118b12013-12-05 17:14:35 +05301715 driver->user_space_data_buf +
1716 token_offset, payload_size);
Shalabh Jainb0037c02013-01-18 12:47:40 -08001717 if (err) {
1718 pr_err("diag: err sending mask to MDM: %d\n",
1719 err);
1720 /*
1721 * If the error is recoverable, then
1722 * clear the write flag, so we will
1723 * resubmit a write on the next frame.
1724 * Otherwise, don't resubmit a write
1725 * on the next frame.
1726 */
1727 if ((-ESHUTDOWN) != err)
1728 diag_hsic[index].
1729 in_busy_hsic_write = 0;
1730 }
1731 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -07001732 }
Dixon Petersonf82952c2013-01-11 19:19:10 -08001733 if (driver->diag_smux_enabled && (remote_proc == QSC)
Ashay Jaiswalfdb9bd42012-10-30 19:55:06 +05301734 && driver->lcid) {
Ashay Jaiswala01e65f2012-09-12 11:35:03 +05301735 if (payload_size > 0) {
1736 err = msm_smux_write(driver->lcid, NULL,
Mohit Aggarwala0118b12013-12-05 17:14:35 +05301737 driver->user_space_data_buf +
1738 token_offset,
Ashay Jaiswalfdb9bd42012-10-30 19:55:06 +05301739 payload_size);
Ashay Jaiswala01e65f2012-09-12 11:35:03 +05301740 if (err) {
1741 pr_err("diag:send mask to MDM err %d",
1742 err);
1743 return err;
1744 }
1745 }
1746 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -07001747#endif
1748 /* send masks to 8k now */
Ashay Jaiswala372f8c2012-12-12 14:02:38 +05301749 if (!remote_proc)
Ashay Jaiswalfdb9bd42012-10-30 19:55:06 +05301750 diag_process_hdlc((void *)
Mohit Aggarwala0118b12013-12-05 17:14:35 +05301751 (driver->user_space_data_buf + token_offset),
1752 payload_size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001753 return 0;
1754 }
1755
Ashay Jaiswal1fe33272012-02-29 18:19:29 +05301756 if (payload_size > itemsize) {
1757 pr_err("diag: Dropping packet, packet payload size crosses"
1758 "4KB limit. Current payload size %d\n",
1759 payload_size);
1760 driver->dropped_count++;
1761 return -EBADMSG;
1762 }
1763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001764 buf_copy = diagmem_alloc(driver, payload_size, POOL_TYPE_COPY);
1765 if (!buf_copy) {
1766 driver->dropped_count++;
1767 return -ENOMEM;
1768 }
1769
1770 err = copy_from_user(buf_copy, buf + 4, payload_size);
1771 if (err) {
1772 printk(KERN_INFO "diagchar : copy_from_user failed\n");
Katish Paran244514d2013-08-01 18:39:31 -07001773 diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
1774 buf_copy = NULL;
1775 return -EFAULT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001776 }
Katish Paran244514d2013-08-01 18:39:31 -07001777
1778 data_type = pkt_type &
1779 (DATA_TYPE_DCI_LOG | DATA_TYPE_DCI_EVENT | DCI_PKT_TYPE);
1780 if (data_type) {
1781 diag_process_apps_dci_read_data(data_type, buf_copy,
1782 payload_size);
1783 if (pkt_type & DATA_TYPE_DCI_LOG)
1784 pkt_type ^= DATA_TYPE_DCI_LOG;
1785 else if (pkt_type & DATA_TYPE_DCI_EVENT) {
1786 pkt_type ^= DATA_TYPE_DCI_EVENT;
1787 } else {
1788 pkt_type ^= DCI_PKT_TYPE;
1789 diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
1790 return 0;
1791 }
1792
1793 /*
1794 * If the data is not headed for normal processing or the usb
1795 * is unplugged and we are in usb mode
1796 */
1797 if ((pkt_type != DATA_TYPE_LOG && pkt_type != DATA_TYPE_EVENT)
1798 || ((driver->logging_mode == USB_MODE) &&
1799 (!driver->usb_connected))) {
1800 diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
1801 return 0;
1802 }
1803 }
1804
Dixon Peterson15a6ecb2013-06-25 12:36:33 -07001805 if (driver->stm_state[APPS_DATA] &&
1806 (pkt_type >= DATA_TYPE_EVENT && pkt_type <= DATA_TYPE_LOG)) {
1807 int stm_size = 0;
1808
1809 stm_size = stm_log_inv_ts(OST_ENTITY_DIAG, 0, buf_copy,
1810 payload_size);
1811
1812 if (stm_size == 0)
1813 pr_debug("diag: In %s, stm_log_inv_ts returned size of 0\n",
1814 __func__);
1815
1816 diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
1817 return 0;
1818 }
1819
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001820#ifdef DIAG_DEBUG
1821 printk(KERN_DEBUG "data is -->\n");
1822 for (i = 0; i < payload_size; i++)
1823 printk(KERN_DEBUG "\t %x \t", *(((unsigned char *)buf_copy)+i));
1824#endif
1825 send.state = DIAG_STATE_START;
1826 send.pkt = buf_copy;
1827 send.last = (void *)(buf_copy + payload_size - 1);
1828 send.terminate = 1;
1829#ifdef DIAG_DEBUG
1830 pr_debug("diag: Already used bytes in buffer %d, and"
1831 " incoming payload size is %d\n", driver->used, payload_size);
1832 printk(KERN_DEBUG "hdlc encoded data is -->\n");
1833 for (i = 0; i < payload_size + 8; i++) {
1834 printk(KERN_DEBUG "\t %x \t", *(((unsigned char *)buf_hdlc)+i));
1835 if (*(((unsigned char *)buf_hdlc)+i) != 0x7e)
1836 length++;
1837 }
1838#endif
Katish Paran244514d2013-08-01 18:39:31 -07001839 mutex_lock(&driver->diagchar_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001840 if (!buf_hdlc)
1841 buf_hdlc = diagmem_alloc(driver, HDLC_OUT_BUF_SIZE,
1842 POOL_TYPE_HDLC);
1843 if (!buf_hdlc) {
1844 ret = -ENOMEM;
Ravi Aravamudhan4207b652013-06-07 17:37:37 -07001845 driver->used = 0;
1846 goto fail_free_copy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001847 }
Ravi Aravamudhan7867f292012-12-18 17:18:46 -08001848 if (HDLC_OUT_BUF_SIZE < (2*payload_size) + 3) {
1849 pr_err("diag: Dropping packet, HDLC encoded packet payload size crosses buffer limit. Current payload size %d\n",
1850 ((2*payload_size) + 3));
1851 driver->dropped_count++;
1852 ret = -EBADMSG;
1853 goto fail_free_hdlc;
1854 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001855 if (HDLC_OUT_BUF_SIZE - driver->used <= (2*payload_size) + 3) {
1856 err = diag_device_write(buf_hdlc, APPS_DATA, NULL);
1857 if (err) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001858 ret = -EIO;
1859 goto fail_free_hdlc;
1860 }
1861 buf_hdlc = NULL;
1862 driver->used = 0;
1863 buf_hdlc = diagmem_alloc(driver, HDLC_OUT_BUF_SIZE,
1864 POOL_TYPE_HDLC);
1865 if (!buf_hdlc) {
1866 ret = -ENOMEM;
Ravi Aravamudhan4207b652013-06-07 17:37:37 -07001867 goto fail_free_copy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001868 }
1869 }
1870
1871 enc.dest = buf_hdlc + driver->used;
1872 enc.dest_last = (void *)(buf_hdlc + driver->used + 2*payload_size + 3);
1873 diag_hdlc_encode(&send, &enc);
1874
1875 /* This is to check if after HDLC encoding, we are still within the
1876 limits of aggregation buffer. If not, we write out the current buffer
1877 and start aggregation in a newly allocated buffer */
1878 if ((unsigned int) enc.dest >=
1879 (unsigned int)(buf_hdlc + HDLC_OUT_BUF_SIZE)) {
1880 err = diag_device_write(buf_hdlc, APPS_DATA, NULL);
1881 if (err) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001882 ret = -EIO;
1883 goto fail_free_hdlc;
1884 }
1885 buf_hdlc = NULL;
1886 driver->used = 0;
1887 buf_hdlc = diagmem_alloc(driver, HDLC_OUT_BUF_SIZE,
1888 POOL_TYPE_HDLC);
1889 if (!buf_hdlc) {
1890 ret = -ENOMEM;
Ravi Aravamudhan4207b652013-06-07 17:37:37 -07001891 goto fail_free_copy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001892 }
1893 enc.dest = buf_hdlc + driver->used;
1894 enc.dest_last = (void *)(buf_hdlc + driver->used +
1895 (2*payload_size) + 3);
1896 diag_hdlc_encode(&send, &enc);
1897 }
1898
1899 driver->used = (uint32_t) enc.dest - (uint32_t) buf_hdlc;
1900 if (pkt_type == DATA_TYPE_RESPONSE) {
1901 err = diag_device_write(buf_hdlc, APPS_DATA, NULL);
1902 if (err) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001903 ret = -EIO;
1904 goto fail_free_hdlc;
1905 }
1906 buf_hdlc = NULL;
1907 driver->used = 0;
1908 }
1909
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001910 diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
Ravi Aravamudhan4207b652013-06-07 17:37:37 -07001911 buf_copy = NULL;
Ravi Aravamudhan7867f292012-12-18 17:18:46 -08001912 mutex_unlock(&driver->diagchar_mutex);
Katish Paran244514d2013-08-01 18:39:31 -07001913
1914 check_drain_timer();
1915
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001916 return 0;
1917
1918fail_free_hdlc:
Ravi Aravamudhan4207b652013-06-07 17:37:37 -07001919 diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001920 buf_hdlc = NULL;
1921 driver->used = 0;
1922 diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
Ravi Aravamudhan4207b652013-06-07 17:37:37 -07001923 buf_copy = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001924 mutex_unlock(&driver->diagchar_mutex);
1925 return ret;
1926
1927fail_free_copy:
1928 diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
Ravi Aravamudhan4207b652013-06-07 17:37:37 -07001929 buf_copy = NULL;
1930 mutex_unlock(&driver->diagchar_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001931 return ret;
1932}
1933
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07001934static void diag_real_time_info_init(void)
1935{
1936 if (!driver)
1937 return;
1938 driver->real_time_mode = 1;
1939 driver->real_time_update_busy = 0;
1940 driver->proc_active_mask = 0;
1941 driver->proc_rt_vote_mask |= DIAG_PROC_DCI;
1942 driver->proc_rt_vote_mask |= DIAG_PROC_MEMORY_DEVICE;
1943 driver->diag_real_time_wq = create_singlethread_workqueue(
1944 "diag_real_time_wq");
1945 INIT_WORK(&(driver->diag_real_time_work), diag_real_time_work_fn);
1946 mutex_init(&driver->real_time_mutex);
1947}
1948
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001949int mask_request_validate(unsigned char mask_buf[])
1950{
1951 uint8_t packet_id;
1952 uint8_t subsys_id;
1953 uint16_t ss_cmd;
1954
Shalabh Jain482bf122011-12-06 03:54:47 -08001955 packet_id = mask_buf[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001956
1957 if (packet_id == 0x4B) {
Shalabh Jain482bf122011-12-06 03:54:47 -08001958 subsys_id = mask_buf[1];
1959 ss_cmd = *(uint16_t *)(mask_buf + 2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001960 /* Packets with SSID which are allowed */
1961 switch (subsys_id) {
1962 case 0x04: /* DIAG_SUBSYS_WCDMA */
1963 if ((ss_cmd == 0) || (ss_cmd == 0xF))
1964 return 1;
1965 break;
1966 case 0x08: /* DIAG_SUBSYS_GSM */
1967 if ((ss_cmd == 0) || (ss_cmd == 0x1))
1968 return 1;
1969 break;
1970 case 0x09: /* DIAG_SUBSYS_UMTS */
1971 case 0x0F: /* DIAG_SUBSYS_CM */
1972 if (ss_cmd == 0)
1973 return 1;
1974 break;
1975 case 0x0C: /* DIAG_SUBSYS_OS */
1976 if ((ss_cmd == 2) || (ss_cmd == 0x100))
1977 return 1; /* MPU and APU */
1978 break;
1979 case 0x12: /* DIAG_SUBSYS_DIAG_SERV */
1980 if ((ss_cmd == 0) || (ss_cmd == 0x6) || (ss_cmd == 0x7))
1981 return 1;
1982 break;
1983 case 0x13: /* DIAG_SUBSYS_FS */
1984 if ((ss_cmd == 0) || (ss_cmd == 0x1))
1985 return 1;
1986 break;
1987 default:
1988 return 0;
1989 break;
1990 }
1991 } else {
1992 switch (packet_id) {
1993 case 0x00: /* Version Number */
1994 case 0x0C: /* CDMA status packet */
1995 case 0x1C: /* Diag Version */
1996 case 0x1D: /* Time Stamp */
1997 case 0x60: /* Event Report Control */
1998 case 0x63: /* Status snapshot */
1999 case 0x73: /* Logging Configuration */
2000 case 0x7C: /* Extended build ID */
2001 case 0x7D: /* Extended Message configuration */
2002 case 0x81: /* Event get mask */
2003 case 0x82: /* Set the event mask */
2004 return 1;
2005 break;
2006 default:
2007 return 0;
2008 break;
2009 }
2010 }
2011 return 0;
2012}
2013
2014static const struct file_operations diagcharfops = {
2015 .owner = THIS_MODULE,
2016 .read = diagchar_read,
2017 .write = diagchar_write,
2018 .unlocked_ioctl = diagchar_ioctl,
2019 .open = diagchar_open,
2020 .release = diagchar_close
2021};
2022
2023static int diagchar_setup_cdev(dev_t devno)
2024{
2025
2026 int err;
2027
2028 cdev_init(driver->cdev, &diagcharfops);
2029
2030 driver->cdev->owner = THIS_MODULE;
2031 driver->cdev->ops = &diagcharfops;
2032
2033 err = cdev_add(driver->cdev, devno, 1);
2034
2035 if (err) {
2036 printk(KERN_INFO "diagchar cdev registration failed !\n\n");
2037 return -1;
2038 }
2039
2040 driver->diagchar_class = class_create(THIS_MODULE, "diag");
2041
2042 if (IS_ERR(driver->diagchar_class)) {
2043 printk(KERN_ERR "Error creating diagchar class.\n");
2044 return -1;
2045 }
2046
Katish Paran244514d2013-08-01 18:39:31 -07002047 driver->diag_dev = device_create(driver->diagchar_class, NULL, devno,
2048 (void *)driver, "diag");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002049
Katish Paran244514d2013-08-01 18:39:31 -07002050 if (!driver->diag_dev)
2051 return -EIO;
2052
2053 driver->diag_dev->power.wakeup = wakeup_source_register("DIAG_WS");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002054 return 0;
2055
2056}
2057
2058static int diagchar_cleanup(void)
2059{
2060 if (driver) {
2061 if (driver->cdev) {
2062 /* TODO - Check if device exists before deleting */
2063 device_destroy(driver->diagchar_class,
2064 MKDEV(driver->major,
2065 driver->minor_start));
2066 cdev_del(driver->cdev);
2067 }
2068 if (!IS_ERR(driver->diagchar_class))
2069 class_destroy(driver->diagchar_class);
2070 kfree(driver);
2071 }
2072 return 0;
2073}
2074
Shalabh Jain737fca72012-11-14 21:53:43 -08002075#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
Mohit Aggarwalb4465772013-04-18 13:08:07 +05302076static void diag_connect_work_fn(struct work_struct *w)
2077{
2078 diagfwd_connect_bridge(1);
2079}
2080
Shalabh Jain737fca72012-11-14 21:53:43 -08002081static void diag_disconnect_work_fn(struct work_struct *w)
2082{
2083 diagfwd_disconnect_bridge(1);
2084}
2085#endif
2086
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002087#ifdef CONFIG_DIAG_SDIO_PIPE
2088void diag_sdio_fn(int type)
2089{
2090 if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
2091 if (type == INIT)
2092 diagfwd_sdio_init();
2093 else if (type == EXIT)
2094 diagfwd_sdio_exit();
2095 }
2096}
2097#else
2098inline void diag_sdio_fn(int type) {}
2099#endif
2100
Shalabh Jain737fca72012-11-14 21:53:43 -08002101#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
2102void diagfwd_bridge_fn(int type)
Dixon Peterson32e70bb2011-12-16 13:26:45 -08002103{
Shalabh Jain737fca72012-11-14 21:53:43 -08002104 if (type == EXIT)
Shalabh Jainf7228dc2012-05-23 17:32:05 -07002105 diagfwd_bridge_exit();
Dixon Peterson32e70bb2011-12-16 13:26:45 -08002106}
2107#else
Shalabh Jain737fca72012-11-14 21:53:43 -08002108inline void diagfwd_bridge_fn(int type) { }
Dixon Peterson32e70bb2011-12-16 13:26:45 -08002109#endif
2110
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002111static int __init diagchar_init(void)
2112{
2113 dev_t dev;
Shalabh Jainb0037c02013-01-18 12:47:40 -08002114 int error, ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002115
2116 pr_debug("diagfwd initializing ..\n");
Shalabh Jainb0037c02013-01-18 12:47:40 -08002117 ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002118 driver = kzalloc(sizeof(struct diagchar_dev) + 5, GFP_KERNEL);
Shalabh Jain737fca72012-11-14 21:53:43 -08002119#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
2120 diag_bridge = kzalloc(MAX_BRIDGES * sizeof(struct diag_bridge_dev),
Shalabh Jainb0037c02013-01-18 12:47:40 -08002121 GFP_KERNEL);
Shalabh Jain737fca72012-11-14 21:53:43 -08002122 if (!diag_bridge)
Shalabh Jainb0037c02013-01-18 12:47:40 -08002123 pr_warn("diag: could not allocate memory for bridges\n");
2124 diag_hsic = kzalloc(MAX_HSIC_CH * sizeof(struct diag_hsic_dev),
2125 GFP_KERNEL);
2126 if (!diag_hsic)
2127 pr_warn("diag: could not allocate memory for hsic ch\n");
Shalabh Jain737fca72012-11-14 21:53:43 -08002128#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002129
2130 if (driver) {
2131 driver->used = 0;
2132 timer_in_progress = 0;
2133 driver->debug_flag = 1;
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07002134 driver->dci_state = DIAG_DCI_NO_ERROR;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002135 setup_timer(&drain_timer, drain_timer_func, 1234);
2136 driver->itemsize = itemsize;
2137 driver->poolsize = poolsize;
2138 driver->itemsize_hdlc = itemsize_hdlc;
2139 driver->poolsize_hdlc = poolsize_hdlc;
Dixon Peterson6dba7572013-04-12 18:45:16 -07002140 driver->itemsize_user = itemsize_user;
2141 driver->poolsize_user = poolsize_user;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002142 driver->itemsize_write_struct = itemsize_write_struct;
2143 driver->poolsize_write_struct = poolsize_write_struct;
Katish Paran244514d2013-08-01 18:39:31 -07002144 driver->itemsize_dci = itemsize_dci;
2145 driver->poolsize_dci = poolsize_dci;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002146 driver->num_clients = max_clients;
2147 driver->logging_mode = USB_MODE;
Dixon Peterson625ee652012-06-21 22:03:49 -07002148 driver->socket_process = NULL;
Shalabh Jain84e30342012-10-16 16:16:08 -07002149 driver->callback_process = NULL;
Shalabh Jainc236f982011-12-15 22:55:20 -08002150 driver->mask_check = 0;
Ravi Aravamudhan72c55282013-03-20 19:29:01 -07002151 driver->in_busy_pktdata = 0;
Katish Paran244514d2013-08-01 18:39:31 -07002152 driver->in_busy_dcipktdata = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002153 mutex_init(&driver->diagchar_mutex);
2154 init_waitqueue_head(&driver->wait_q);
Shalabh Jainc70b3b62012-08-31 19:11:20 -07002155 init_waitqueue_head(&driver->smd_wait_q);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002156 INIT_WORK(&(driver->diag_drain_work), diag_drain_work_fn);
Ravi Aravamudhan6a2da562013-06-17 16:01:34 -07002157 diag_real_time_info_init();
Dixon Peterson29aebee2012-04-06 12:44:08 -07002158 diag_debugfs_init();
Shalabh Jain9c50ddf2012-10-05 16:26:08 -07002159 diag_masks_init();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002160 diagfwd_init();
Shalabh Jain737fca72012-11-14 21:53:43 -08002161#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
2162 diagfwd_bridge_init(HSIC);
Shalabh Jainb0037c02013-01-18 12:47:40 -08002163 diagfwd_bridge_init(HSIC_2);
2164 /* register HSIC device */
2165 ret = platform_driver_register(&msm_hsic_ch_driver);
2166 if (ret)
2167 pr_err("diag: could not register HSIC device, ret: %d\n",
2168 ret);
Shalabh Jain737fca72012-11-14 21:53:43 -08002169 diagfwd_bridge_init(SMUX);
Mohit Aggarwalb4465772013-04-18 13:08:07 +05302170 INIT_WORK(&(driver->diag_connect_work),
2171 diag_connect_work_fn);
Shalabh Jain737fca72012-11-14 21:53:43 -08002172 INIT_WORK(&(driver->diag_disconnect_work),
2173 diag_disconnect_work_fn);
2174#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002175 diagfwd_cntl_init();
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07002176 driver->dci_state = diag_dci_init();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002177 diag_sdio_fn(INIT);
Shalabh Jain737fca72012-11-14 21:53:43 -08002178
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002179 pr_debug("diagchar initializing ..\n");
2180 driver->num = 1;
2181 driver->name = ((void *)driver) + sizeof(struct diagchar_dev);
2182 strlcpy(driver->name, "diag", 4);
2183
2184 /* Get major number from kernel and initialize */
2185 error = alloc_chrdev_region(&dev, driver->minor_start,
2186 driver->num, driver->name);
2187 if (!error) {
2188 driver->major = MAJOR(dev);
2189 driver->minor_start = MINOR(dev);
2190 } else {
2191 printk(KERN_INFO "Major number not allocated\n");
2192 goto fail;
2193 }
2194 driver->cdev = cdev_alloc();
2195 error = diagchar_setup_cdev(dev);
2196 if (error)
2197 goto fail;
2198 } else {
2199 printk(KERN_INFO "kzalloc failed\n");
2200 goto fail;
2201 }
2202
2203 pr_info("diagchar initialized now");
2204 return 0;
2205
2206fail:
Dixon Peterson29aebee2012-04-06 12:44:08 -07002207 diag_debugfs_cleanup();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002208 diagchar_cleanup();
2209 diagfwd_exit();
2210 diagfwd_cntl_exit();
Dixon Peterson2a49ad22013-04-24 17:10:39 -07002211 diag_dci_exit();
Dixon Petersond6a20a92012-09-27 15:58:50 -07002212 diag_masks_exit();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002213 diag_sdio_fn(EXIT);
Shalabh Jain737fca72012-11-14 21:53:43 -08002214 diagfwd_bridge_fn(EXIT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002215 return -1;
2216}
2217
Steve Mucklef132c6c2012-06-06 18:30:57 -07002218static void diagchar_exit(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002219{
2220 printk(KERN_INFO "diagchar exiting ..\n");
2221 /* On Driver exit, send special pool type to
2222 ensure no memory leaks */
2223 diagmem_exit(driver, POOL_TYPE_ALL);
2224 diagfwd_exit();
2225 diagfwd_cntl_exit();
Dixon Peterson2a49ad22013-04-24 17:10:39 -07002226 diag_dci_exit();
Dixon Petersond6a20a92012-09-27 15:58:50 -07002227 diag_masks_exit();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002228 diag_sdio_fn(EXIT);
Shalabh Jain737fca72012-11-14 21:53:43 -08002229 diagfwd_bridge_fn(EXIT);
Dixon Peterson29aebee2012-04-06 12:44:08 -07002230 diag_debugfs_cleanup();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002231 diagchar_cleanup();
2232 printk(KERN_INFO "done diagchar exit\n");
2233}
2234
2235module_init(diagchar_init);
2236module_exit(diagchar_exit);