blob: 694b483c5033378f428783fd000f92724d9e0524 [file] [log] [blame]
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -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>
19#include <linux/delay.h>
20#include <linux/uaccess.h>
21#include <linux/diagchar.h>
22#include <linux/sched.h>
23#include <linux/ratelimit.h>
24#include <linux/timer.h>
25#ifdef CONFIG_DIAG_OVER_USB
26#include <linux/usb/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"
34#include "diag_dci.h"
35#include "diag_debugfs.h"
36#include "diag_masks.h"
37#include "diagfwd_bridge.h"
38#include "diag_usb.h"
39#include "diag_memorydevice.h"
40#include "diag_mux.h"
41#include "diag_ipc_logging.h"
42#include "diagfwd_peripheral.h"
43
44#include <linux/coresight-stm.h>
45#include <linux/kernel.h>
46#ifdef CONFIG_COMPAT
47#include <linux/compat.h>
48#endif
49
50MODULE_DESCRIPTION("Diag Char Driver");
51MODULE_LICENSE("GPL v2");
52
53#define MIN_SIZ_ALLOW 4
54#define INIT 1
55#define EXIT -1
56struct diagchar_dev *driver;
57struct diagchar_priv {
58 int pid;
59};
60
61#define USER_SPACE_RAW_DATA 0
62#define USER_SPACE_HDLC_DATA 1
63
64/* Memory pool variables */
65/* Used for copying any incoming packet from user space clients. */
66static unsigned int poolsize = 12;
67module_param(poolsize, uint, 0000);
68
69/*
70 * Used for HDLC encoding packets coming from the user
71 * space.
72 */
73static unsigned int poolsize_hdlc = 10;
74module_param(poolsize_hdlc, uint, 0000);
75
76/*
77 * This is used for incoming DCI requests from the user space clients.
78 * Don't expose itemsize as it is internal.
79 */
80static unsigned int poolsize_user = 8;
81module_param(poolsize_user, uint, 0000);
82
83/*
84 * USB structures allocated for writing Diag data generated on the Apps to USB.
85 * Don't expose itemsize as it is constant.
86 */
87static unsigned int itemsize_usb_apps = sizeof(struct diag_request);
88static unsigned int poolsize_usb_apps = 10;
89module_param(poolsize_usb_apps, uint, 0000);
90
91/* Used for DCI client buffers. Don't expose itemsize as it is constant. */
92static unsigned int poolsize_dci = 10;
93module_param(poolsize_dci, uint, 0000);
94
95#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
96/* Used for reading data from the remote device. */
97static unsigned int itemsize_mdm = DIAG_MDM_BUF_SIZE;
98static unsigned int poolsize_mdm = 18;
99module_param(itemsize_mdm, uint, 0000);
100module_param(poolsize_mdm, uint, 0000);
101
102/*
103 * Used for reading DCI data from the remote device.
104 * Don't expose poolsize for DCI data. There is only one read buffer
105 */
106static unsigned int itemsize_mdm_dci = DIAG_MDM_BUF_SIZE;
107static unsigned int poolsize_mdm_dci = 1;
108module_param(itemsize_mdm_dci, uint, 0000);
109
110/*
111 * Used for USB structues associated with a remote device.
112 * Don't expose the itemsize since it is constant.
113 */
114static unsigned int itemsize_mdm_usb = sizeof(struct diag_request);
115static unsigned int poolsize_mdm_usb = 18;
116module_param(poolsize_mdm_usb, uint, 0000);
117
118/*
119 * Used for writing read DCI data to remote peripherals. Don't
120 * expose poolsize for DCI data. There is only one read
121 * buffer. Add 6 bytes for DCI header information: Start (1),
122 * Version (1), Length (2), Tag (2)
123 */
124static unsigned int itemsize_mdm_dci_write = DIAG_MDM_DCI_BUF_SIZE;
125static unsigned int poolsize_mdm_dci_write = 1;
126module_param(itemsize_mdm_dci_write, uint, 0000);
127
128/*
129 * Used for USB structures associated with a remote SMUX
130 * device Don't expose the itemsize since it is constant
131 */
132static unsigned int itemsize_qsc_usb = sizeof(struct diag_request);
133static unsigned int poolsize_qsc_usb = 8;
134module_param(poolsize_qsc_usb, uint, 0000);
135#endif
136
137/* This is the max number of user-space clients supported at initialization*/
138static unsigned int max_clients = 15;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700139module_param(max_clients, uint, 0000);
140
141/* Timer variables */
142static struct timer_list drain_timer;
143static int timer_in_progress;
144
Manoj Prabhu B95427a22016-11-04 11:58:11 +0530145/*
146 * Diag Mask clear variable
147 * Used for clearing masks upon
148 * USB disconnection and stopping ODL
149 */
150static int diag_mask_clear_param = 1;
151module_param(diag_mask_clear_param, int, 0644);
152
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700153struct diag_apps_data_t {
154 void *buf;
155 uint32_t len;
156 int ctxt;
157};
158
159static struct diag_apps_data_t hdlc_data;
160static struct diag_apps_data_t non_hdlc_data;
161static struct mutex apps_data_mutex;
162
163#define DIAGPKT_MAX_DELAYED_RSP 0xFFFF
164
165#ifdef DIAG_DEBUG
166uint16_t diag_debug_mask;
167void *diag_ipc_log;
168#endif
169
Hardik Aryadbb1c2a2017-11-10 16:29:16 +0530170static void diag_md_session_close(int pid);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700171
172/*
173 * Returns the next delayed rsp id. If wrapping is enabled,
174 * wraps the delayed rsp id to DIAGPKT_MAX_DELAYED_RSP.
175 */
176static uint16_t diag_get_next_delayed_rsp_id(void)
177{
178 uint16_t rsp_id = 0;
179
180 mutex_lock(&driver->delayed_rsp_mutex);
181 rsp_id = driver->delayed_rsp_id;
182 if (rsp_id < DIAGPKT_MAX_DELAYED_RSP)
183 rsp_id++;
184 else {
185 if (wrap_enabled) {
186 rsp_id = 1;
187 wrap_count++;
188 } else
189 rsp_id = DIAGPKT_MAX_DELAYED_RSP;
190 }
191 driver->delayed_rsp_id = rsp_id;
192 mutex_unlock(&driver->delayed_rsp_mutex);
193
194 return rsp_id;
195}
196
197static int diag_switch_logging(struct diag_logging_mode_param_t *param);
198
199#define COPY_USER_SPACE_OR_ERR(buf, data, length) \
200do { \
201 if ((count < ret+length) || (copy_to_user(buf, \
202 (void *)&data, length))) { \
203 ret = -EFAULT; \
204 } \
205 ret += length; \
206} while (0)
207
208static void drain_timer_func(unsigned long data)
209{
210 queue_work(driver->diag_wq, &(driver->diag_drain_work));
211}
212
213static void diag_drain_apps_data(struct diag_apps_data_t *data)
214{
215 int err = 0;
216
217 if (!data || !data->buf)
218 return;
219
220 err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len,
221 data->ctxt);
222 if (err)
223 diagmem_free(driver, data->buf, POOL_TYPE_HDLC);
224
225 data->buf = NULL;
226 data->len = 0;
227}
228
229void diag_update_user_client_work_fn(struct work_struct *work)
230{
231 diag_update_userspace_clients(HDLC_SUPPORT_TYPE);
232}
233
234static void diag_update_md_client_work_fn(struct work_struct *work)
235{
236 diag_update_md_clients(HDLC_SUPPORT_TYPE);
237}
238
239void diag_drain_work_fn(struct work_struct *work)
240{
241 struct diag_md_session_t *session_info = NULL;
242 uint8_t hdlc_disabled = 0;
243
244 timer_in_progress = 0;
245 mutex_lock(&apps_data_mutex);
Hardik Aryadbb1c2a2017-11-10 16:29:16 +0530246 mutex_lock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700247 session_info = diag_md_session_get_peripheral(APPS_DATA);
248 if (session_info)
249 hdlc_disabled = session_info->hdlc_disabled;
250 else
251 hdlc_disabled = driver->hdlc_disabled;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +0530252 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700253 if (!hdlc_disabled)
254 diag_drain_apps_data(&hdlc_data);
255 else
256 diag_drain_apps_data(&non_hdlc_data);
257 mutex_unlock(&apps_data_mutex);
258}
259
260void check_drain_timer(void)
261{
262 int ret = 0;
263
264 if (!timer_in_progress) {
265 timer_in_progress = 1;
266 ret = mod_timer(&drain_timer, jiffies + msecs_to_jiffies(200));
267 }
268}
269
270void diag_add_client(int i, struct file *file)
271{
272 struct diagchar_priv *diagpriv_data;
273
274 driver->client_map[i].pid = current->tgid;
275 diagpriv_data = kmalloc(sizeof(struct diagchar_priv),
276 GFP_KERNEL);
277 if (diagpriv_data)
278 diagpriv_data->pid = current->tgid;
279 file->private_data = diagpriv_data;
280 strlcpy(driver->client_map[i].name, current->comm, 20);
281 driver->client_map[i].name[19] = '\0';
282}
283
284static void diag_mempool_init(void)
285{
286 uint32_t itemsize = DIAG_MAX_REQ_SIZE;
287 uint32_t itemsize_hdlc = DIAG_MAX_HDLC_BUF_SIZE + APF_DIAG_PADDING;
288 uint32_t itemsize_dci = IN_BUF_SIZE;
289 uint32_t itemsize_user = DCI_REQ_BUF_SIZE;
290
291 itemsize += ((DCI_HDR_SIZE > CALLBACK_HDR_SIZE) ? DCI_HDR_SIZE :
292 CALLBACK_HDR_SIZE);
293 diagmem_setsize(POOL_TYPE_COPY, itemsize, poolsize);
294 diagmem_setsize(POOL_TYPE_HDLC, itemsize_hdlc, poolsize_hdlc);
295 diagmem_setsize(POOL_TYPE_DCI, itemsize_dci, poolsize_dci);
296 diagmem_setsize(POOL_TYPE_USER, itemsize_user, poolsize_user);
297
298 diagmem_init(driver, POOL_TYPE_COPY);
299 diagmem_init(driver, POOL_TYPE_HDLC);
300 diagmem_init(driver, POOL_TYPE_USER);
301 diagmem_init(driver, POOL_TYPE_DCI);
302}
303
304static void diag_mempool_exit(void)
305{
306 diagmem_exit(driver, POOL_TYPE_COPY);
307 diagmem_exit(driver, POOL_TYPE_HDLC);
308 diagmem_exit(driver, POOL_TYPE_USER);
309 diagmem_exit(driver, POOL_TYPE_DCI);
310}
311
312static int diagchar_open(struct inode *inode, struct file *file)
313{
314 int i = 0;
315 void *temp;
316
317 if (driver) {
318 mutex_lock(&driver->diagchar_mutex);
319
320 for (i = 0; i < driver->num_clients; i++)
321 if (driver->client_map[i].pid == 0)
322 break;
323
324 if (i < driver->num_clients) {
325 diag_add_client(i, file);
326 } else {
Mohit Aggarwalb8474a42017-10-12 14:22:05 +0530327 if (i < THRESHOLD_CLIENT_LIMIT) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700328 driver->num_clients++;
329 temp = krealloc(driver->client_map
330 , (driver->num_clients) * sizeof(struct
331 diag_client_map), GFP_KERNEL);
332 if (!temp)
333 goto fail;
334 else
335 driver->client_map = temp;
336 temp = krealloc(driver->data_ready
337 , (driver->num_clients) * sizeof(int),
338 GFP_KERNEL);
339 if (!temp)
340 goto fail;
341 else
342 driver->data_ready = temp;
343 diag_add_client(i, file);
344 } else {
345 mutex_unlock(&driver->diagchar_mutex);
346 pr_err_ratelimited("diag: Max client limit for DIAG reached\n");
347 pr_err_ratelimited("diag: Cannot open handle %s %d",
348 current->comm, current->tgid);
349 for (i = 0; i < driver->num_clients; i++)
350 pr_debug("%d) %s PID=%d", i, driver->
351 client_map[i].name,
352 driver->client_map[i].pid);
353 return -ENOMEM;
354 }
355 }
356 driver->data_ready[i] = 0x0;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +0530357 atomic_set(&driver->data_ready_notif[i], 0);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700358 driver->data_ready[i] |= MSG_MASKS_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +0530359 atomic_inc(&driver->data_ready_notif[i]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700360 driver->data_ready[i] |= EVENT_MASKS_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +0530361 atomic_inc(&driver->data_ready_notif[i]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700362 driver->data_ready[i] |= LOG_MASKS_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +0530363 atomic_inc(&driver->data_ready_notif[i]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700364 driver->data_ready[i] |= DCI_LOG_MASKS_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +0530365 atomic_inc(&driver->data_ready_notif[i]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700366 driver->data_ready[i] |= DCI_EVENT_MASKS_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +0530367 atomic_inc(&driver->data_ready_notif[i]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700368
369 if (driver->ref_count == 0)
370 diag_mempool_init();
371 driver->ref_count++;
372 mutex_unlock(&driver->diagchar_mutex);
373 return 0;
374 }
375 return -ENOMEM;
376
377fail:
378 mutex_unlock(&driver->diagchar_mutex);
379 driver->num_clients--;
380 pr_err_ratelimited("diag: Insufficient memory for new client");
381 return -ENOMEM;
382}
383
384static uint32_t diag_translate_kernel_to_user_mask(uint32_t peripheral_mask)
385{
386 uint32_t ret = 0;
387
388 if (peripheral_mask & MD_PERIPHERAL_MASK(APPS_DATA))
389 ret |= DIAG_CON_APSS;
390 if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_MODEM))
391 ret |= DIAG_CON_MPSS;
392 if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_LPASS))
393 ret |= DIAG_CON_LPASS;
394 if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_WCNSS))
395 ret |= DIAG_CON_WCNSS;
396 if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_SENSORS))
397 ret |= DIAG_CON_SENSORS;
398 if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_WDSP))
399 ret |= DIAG_CON_WDSP;
Sreelakshmi Gownipalli588a31d2016-11-02 13:33:43 -0700400 if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_CDSP))
401 ret |= DIAG_CON_CDSP;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530402 if (peripheral_mask & MD_PERIPHERAL_MASK(UPD_WLAN))
403 ret |= DIAG_CON_UPD_WLAN;
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530404 if (peripheral_mask & MD_PERIPHERAL_MASK(UPD_AUDIO))
405 ret |= DIAG_CON_UPD_AUDIO;
406 if (peripheral_mask & MD_PERIPHERAL_MASK(UPD_SENSORS))
407 ret |= DIAG_CON_UPD_SENSORS;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700408 return ret;
409}
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530410
411uint8_t diag_mask_to_pd_value(uint32_t peripheral_mask)
412{
413 uint8_t upd = 0;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530414
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530415 for (upd = UPD_WLAN; upd < NUM_MD_SESSIONS; upd++) {
416 if (peripheral_mask & (1 << upd))
417 return upd;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530418 }
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530419 return 0;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530420}
421
Manoj Prabhu B95427a22016-11-04 11:58:11 +0530422int diag_mask_param(void)
423{
424 return diag_mask_clear_param;
425}
Hardik Aryadbb1c2a2017-11-10 16:29:16 +0530426void diag_clear_masks(int pid)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700427{
428 int ret;
429 char cmd_disable_log_mask[] = { 0x73, 0, 0, 0, 0, 0, 0, 0};
430 char cmd_disable_msg_mask[] = { 0x7D, 0x05, 0, 0, 0, 0, 0, 0};
431 char cmd_disable_event_mask[] = { 0x60, 0};
432
433 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
434 "diag: %s: masks clear request upon %s\n", __func__,
Hardik Aryadbb1c2a2017-11-10 16:29:16 +0530435 ((pid) ? "ODL exit" : "USB Disconnection"));
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700436
437 ret = diag_process_apps_masks(cmd_disable_log_mask,
Hardik Aryadbb1c2a2017-11-10 16:29:16 +0530438 sizeof(cmd_disable_log_mask), pid);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700439 ret = diag_process_apps_masks(cmd_disable_msg_mask,
Hardik Aryadbb1c2a2017-11-10 16:29:16 +0530440 sizeof(cmd_disable_msg_mask), pid);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700441 ret = diag_process_apps_masks(cmd_disable_event_mask,
Hardik Aryadbb1c2a2017-11-10 16:29:16 +0530442 sizeof(cmd_disable_event_mask), pid);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700443 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
444 "diag:%s: masks cleared successfully\n", __func__);
445}
446
447static void diag_close_logging_process(const int pid)
448{
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530449 int i, j;
450 int session_mask;
451 uint32_t p_mask;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700452 struct diag_md_session_t *session_info = NULL;
453 struct diag_logging_mode_param_t params;
454
Hardik Aryadbb1c2a2017-11-10 16:29:16 +0530455 mutex_lock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700456 session_info = diag_md_session_get_pid(pid);
Hardik Aryadbb1c2a2017-11-10 16:29:16 +0530457 if (!session_info) {
458 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700459 return;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +0530460 }
461 session_mask = session_info->peripheral_mask;
462 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700463
Manoj Prabhu B95427a22016-11-04 11:58:11 +0530464 if (diag_mask_clear_param)
Hardik Aryadbb1c2a2017-11-10 16:29:16 +0530465 diag_clear_masks(pid);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700466
467 mutex_lock(&driver->diag_maskclear_mutex);
468 driver->mask_clear = 1;
469 mutex_unlock(&driver->diag_maskclear_mutex);
470
Sreelakshmi Gownipalli078824f2017-01-17 14:03:54 -0800471 mutex_lock(&driver->diagchar_mutex);
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530472 p_mask =
473 diag_translate_kernel_to_user_mask(session_mask);
474
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700475 for (i = 0; i < NUM_MD_SESSIONS; i++)
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530476 if (MD_PERIPHERAL_MASK(i) & session_mask)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700477 diag_mux_close_peripheral(DIAG_LOCAL_PROC, i);
478
479 params.req_mode = USB_MODE;
480 params.mode_param = 0;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530481 params.pd_mask = 0;
482 params.peripheral_mask = p_mask;
483
484 if (driver->num_pd_session > 0) {
485 for (i = UPD_WLAN; (i < NUM_MD_SESSIONS); i++) {
486 if (session_mask & MD_PERIPHERAL_MASK(i)) {
487 j = i - UPD_WLAN;
488 driver->pd_session_clear[j] = 1;
489 driver->pd_logging_mode[j] = 0;
490 driver->num_pd_session -= 1;
491 params.pd_mask = p_mask;
492 }
493 }
494 }
Hardik Aryadbb1c2a2017-11-10 16:29:16 +0530495 mutex_lock(&driver->md_session_lock);
496 diag_md_session_close(pid);
497 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700498 diag_switch_logging(&params);
499 mutex_unlock(&driver->diagchar_mutex);
500}
501
502static int diag_remove_client_entry(struct file *file)
503{
504 int i = -1;
505 struct diagchar_priv *diagpriv_data = NULL;
506 struct diag_dci_client_tbl *dci_entry = NULL;
507
508 if (!driver)
509 return -ENOMEM;
510
511 mutex_lock(&driver->diag_file_mutex);
512 if (!file) {
513 DIAG_LOG(DIAG_DEBUG_USERSPACE, "Invalid file pointer\n");
514 mutex_unlock(&driver->diag_file_mutex);
515 return -ENOENT;
516 }
517 if (!(file->private_data)) {
518 DIAG_LOG(DIAG_DEBUG_USERSPACE, "Invalid private data\n");
519 mutex_unlock(&driver->diag_file_mutex);
520 return -EINVAL;
521 }
522
523 diagpriv_data = file->private_data;
524
525 /*
526 * clean up any DCI registrations, if this is a DCI client
527 * This will specially help in case of ungraceful exit of any DCI client
528 * This call will remove any pending registrations of such client
529 */
530 mutex_lock(&driver->dci_mutex);
531 dci_entry = dci_lookup_client_entry_pid(current->tgid);
532 if (dci_entry)
533 diag_dci_deinit_client(dci_entry);
534 mutex_unlock(&driver->dci_mutex);
535
536 diag_close_logging_process(current->tgid);
537
538 /* Delete the pkt response table entry for the exiting process */
539 diag_cmd_remove_reg_by_pid(current->tgid);
540
541 mutex_lock(&driver->diagchar_mutex);
542 driver->ref_count--;
543 if (driver->ref_count == 0)
544 diag_mempool_exit();
545
546 for (i = 0; i < driver->num_clients; i++) {
547 if (diagpriv_data && diagpriv_data->pid ==
548 driver->client_map[i].pid) {
549 driver->client_map[i].pid = 0;
550 kfree(diagpriv_data);
551 diagpriv_data = NULL;
552 file->private_data = 0;
553 break;
554 }
555 }
556 mutex_unlock(&driver->diagchar_mutex);
557 mutex_unlock(&driver->diag_file_mutex);
558 return 0;
559}
560static int diagchar_close(struct inode *inode, struct file *file)
561{
562 int ret;
563
564 DIAG_LOG(DIAG_DEBUG_USERSPACE, "diag: process exit %s\n",
565 current->comm);
566 ret = diag_remove_client_entry(file);
567 mutex_lock(&driver->diag_maskclear_mutex);
568 driver->mask_clear = 0;
569 mutex_unlock(&driver->diag_maskclear_mutex);
570 return ret;
571}
572
573void diag_record_stats(int type, int flag)
574{
575 struct diag_pkt_stats_t *pkt_stats = NULL;
576
577 switch (type) {
578 case DATA_TYPE_EVENT:
579 pkt_stats = &driver->event_stats;
580 break;
581 case DATA_TYPE_F3:
582 pkt_stats = &driver->msg_stats;
583 break;
584 case DATA_TYPE_LOG:
585 pkt_stats = &driver->log_stats;
586 break;
587 case DATA_TYPE_RESPONSE:
588 if (flag != PKT_DROP)
589 return;
590 pr_err_ratelimited("diag: In %s, dropping response. This shouldn't happen\n",
591 __func__);
592 return;
593 case DATA_TYPE_DELAYED_RESPONSE:
594 /* No counters to increase for Delayed responses */
595 return;
596 default:
597 pr_err_ratelimited("diag: In %s, invalid pkt_type: %d\n",
598 __func__, type);
599 return;
600 }
601
602 switch (flag) {
603 case PKT_ALLOC:
604 atomic_add(1, (atomic_t *)&pkt_stats->alloc_count);
605 break;
606 case PKT_DROP:
607 atomic_add(1, (atomic_t *)&pkt_stats->drop_count);
608 break;
609 case PKT_RESET:
610 atomic_set((atomic_t *)&pkt_stats->alloc_count, 0);
611 atomic_set((atomic_t *)&pkt_stats->drop_count, 0);
612 break;
613 default:
614 pr_err_ratelimited("diag: In %s, invalid flag: %d\n",
615 __func__, flag);
616 return;
617 }
618}
619
620void diag_get_timestamp(char *time_str)
621{
622 struct timeval t;
623 struct tm broken_tm;
624
625 do_gettimeofday(&t);
626 if (!time_str)
627 return;
628 time_to_tm(t.tv_sec, 0, &broken_tm);
629 scnprintf(time_str, DIAG_TS_SIZE, "%d:%d:%d:%ld", broken_tm.tm_hour,
630 broken_tm.tm_min, broken_tm.tm_sec, t.tv_usec);
631}
632
633int diag_get_remote(int remote_info)
634{
635 int val = (remote_info < 0) ? -remote_info : remote_info;
636 int remote_val;
637
638 switch (val) {
639 case MDM:
640 case MDM2:
641 case QSC:
642 remote_val = -remote_info;
643 break;
644 default:
645 remote_val = 0;
646 break;
647 }
648
649 return remote_val;
650}
651
652int diag_cmd_chk_polling(struct diag_cmd_reg_entry_t *entry)
653{
654 int polling = DIAG_CMD_NOT_POLLING;
655
656 if (!entry)
657 return -EIO;
658
659 if (entry->cmd_code == DIAG_CMD_NO_SUBSYS) {
660 if (entry->subsys_id == DIAG_CMD_NO_SUBSYS &&
661 entry->cmd_code_hi >= DIAG_CMD_STATUS &&
662 entry->cmd_code_lo <= DIAG_CMD_STATUS)
663 polling = DIAG_CMD_POLLING;
664 else if (entry->subsys_id == DIAG_SS_WCDMA &&
665 entry->cmd_code_hi >= DIAG_CMD_QUERY_CALL &&
666 entry->cmd_code_lo <= DIAG_CMD_QUERY_CALL)
667 polling = DIAG_CMD_POLLING;
668 else if (entry->subsys_id == DIAG_SS_GSM &&
669 entry->cmd_code_hi >= DIAG_CMD_QUERY_TMC &&
670 entry->cmd_code_lo <= DIAG_CMD_QUERY_TMC)
671 polling = DIAG_CMD_POLLING;
672 else if (entry->subsys_id == DIAG_SS_PARAMS &&
673 entry->cmd_code_hi >= DIAG_DIAG_POLL &&
674 entry->cmd_code_lo <= DIAG_DIAG_POLL)
675 polling = DIAG_CMD_POLLING;
676 else if (entry->subsys_id == DIAG_SS_TDSCDMA &&
677 entry->cmd_code_hi >= DIAG_CMD_TDSCDMA_STATUS &&
678 entry->cmd_code_lo <= DIAG_CMD_TDSCDMA_STATUS)
679 polling = DIAG_CMD_POLLING;
680 }
681
682 return polling;
683}
684
685static void diag_cmd_invalidate_polling(int change_flag)
686{
687 int polling = DIAG_CMD_NOT_POLLING;
688 struct list_head *start;
689 struct list_head *temp;
690 struct diag_cmd_reg_t *item = NULL;
691
692 if (change_flag == DIAG_CMD_ADD) {
693 if (driver->polling_reg_flag)
694 return;
695 }
696
697 driver->polling_reg_flag = 0;
698 list_for_each_safe(start, temp, &driver->cmd_reg_list) {
699 item = list_entry(start, struct diag_cmd_reg_t, link);
Hardik Aryaf76d6602017-07-18 13:38:26 +0530700 if (&item->entry == NULL) {
701 pr_err("diag: In %s, unable to search command\n",
702 __func__);
703 return;
704 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700705 polling = diag_cmd_chk_polling(&item->entry);
706 if (polling == DIAG_CMD_POLLING) {
707 driver->polling_reg_flag = 1;
708 break;
709 }
710 }
711}
712
713int diag_cmd_add_reg(struct diag_cmd_reg_entry_t *new_entry, uint8_t proc,
714 int pid)
715{
716 struct diag_cmd_reg_t *new_item = NULL;
717
718 if (!new_entry) {
719 pr_err("diag: In %s, invalid new entry\n", __func__);
720 return -EINVAL;
721 }
722
723 if (proc > APPS_DATA) {
724 pr_err("diag: In %s, invalid peripheral %d\n", __func__, proc);
725 return -EINVAL;
726 }
727
728 if (proc != APPS_DATA)
729 pid = INVALID_PID;
730
731 new_item = kzalloc(sizeof(struct diag_cmd_reg_t), GFP_KERNEL);
732 if (!new_item)
733 return -ENOMEM;
734 kmemleak_not_leak(new_item);
735
736 new_item->pid = pid;
737 new_item->proc = proc;
738 memcpy(&new_item->entry, new_entry,
739 sizeof(struct diag_cmd_reg_entry_t));
740 INIT_LIST_HEAD(&new_item->link);
741
742 mutex_lock(&driver->cmd_reg_mutex);
743 list_add_tail(&new_item->link, &driver->cmd_reg_list);
744 driver->cmd_reg_count++;
745 diag_cmd_invalidate_polling(DIAG_CMD_ADD);
746 mutex_unlock(&driver->cmd_reg_mutex);
747
748 return 0;
749}
750
751struct diag_cmd_reg_entry_t *diag_cmd_search(
752 struct diag_cmd_reg_entry_t *entry, int proc)
753{
754 struct list_head *start;
755 struct list_head *temp;
756 struct diag_cmd_reg_t *item = NULL;
757 struct diag_cmd_reg_entry_t *temp_entry = NULL;
758
759 if (!entry) {
760 pr_err("diag: In %s, invalid entry\n", __func__);
761 return NULL;
762 }
763
764 list_for_each_safe(start, temp, &driver->cmd_reg_list) {
765 item = list_entry(start, struct diag_cmd_reg_t, link);
Manoj Prabhu Bd9b3b622017-01-17 10:15:53 +0530766 if (&item->entry == NULL) {
Gopikrishna Mogasati9b332372016-11-10 20:03:46 +0530767 pr_err("diag: In %s, unable to search command\n",
768 __func__);
769 return NULL;
770 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700771 temp_entry = &item->entry;
772 if (temp_entry->cmd_code == entry->cmd_code &&
773 temp_entry->subsys_id == entry->subsys_id &&
774 temp_entry->cmd_code_hi >= entry->cmd_code_hi &&
775 temp_entry->cmd_code_lo <= entry->cmd_code_lo &&
776 (proc == item->proc || proc == ALL_PROC)) {
777 return &item->entry;
778 } else if (temp_entry->cmd_code == DIAG_CMD_NO_SUBSYS &&
779 entry->cmd_code == DIAG_CMD_DIAG_SUBSYS) {
780 if (temp_entry->subsys_id == entry->subsys_id &&
781 temp_entry->cmd_code_hi >= entry->cmd_code_hi &&
782 temp_entry->cmd_code_lo <= entry->cmd_code_lo &&
783 (proc == item->proc || proc == ALL_PROC)) {
784 return &item->entry;
785 }
786 } else if (temp_entry->cmd_code == DIAG_CMD_NO_SUBSYS &&
787 temp_entry->subsys_id == DIAG_CMD_NO_SUBSYS) {
788 if ((temp_entry->cmd_code_hi >= entry->cmd_code) &&
789 (temp_entry->cmd_code_lo <= entry->cmd_code) &&
790 (proc == item->proc || proc == ALL_PROC)) {
791 if (entry->cmd_code == MODE_CMD) {
792 if (entry->subsys_id == RESET_ID &&
793 item->proc != APPS_DATA) {
794 continue;
795 }
796 if (entry->subsys_id != RESET_ID &&
797 item->proc == APPS_DATA) {
798 continue;
799 }
800 }
801 return &item->entry;
802 }
803 }
804 }
805
806 return NULL;
807}
808
809void diag_cmd_remove_reg(struct diag_cmd_reg_entry_t *entry, uint8_t proc)
810{
811 struct diag_cmd_reg_t *item = NULL;
812 struct diag_cmd_reg_entry_t *temp_entry;
813
814 if (!entry) {
815 pr_err("diag: In %s, invalid entry\n", __func__);
816 return;
817 }
818
819 mutex_lock(&driver->cmd_reg_mutex);
820 temp_entry = diag_cmd_search(entry, proc);
821 if (temp_entry) {
822 item = container_of(temp_entry, struct diag_cmd_reg_t, entry);
823 if (!item) {
824 mutex_unlock(&driver->cmd_reg_mutex);
825 return;
826 }
827 list_del(&item->link);
828 kfree(item);
829 driver->cmd_reg_count--;
830 }
831 diag_cmd_invalidate_polling(DIAG_CMD_REMOVE);
832 mutex_unlock(&driver->cmd_reg_mutex);
833}
834
835void diag_cmd_remove_reg_by_pid(int pid)
836{
837 struct list_head *start;
838 struct list_head *temp;
839 struct diag_cmd_reg_t *item = NULL;
840
841 mutex_lock(&driver->cmd_reg_mutex);
842 list_for_each_safe(start, temp, &driver->cmd_reg_list) {
843 item = list_entry(start, struct diag_cmd_reg_t, link);
Hardik Aryaf76d6602017-07-18 13:38:26 +0530844 if (&item->entry == NULL) {
845 pr_err("diag: In %s, unable to search command\n",
846 __func__);
847 mutex_unlock(&driver->cmd_reg_mutex);
848 return;
849 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700850 if (item->pid == pid) {
851 list_del(&item->link);
852 kfree(item);
853 driver->cmd_reg_count--;
854 }
855 }
856 mutex_unlock(&driver->cmd_reg_mutex);
857}
858
859void diag_cmd_remove_reg_by_proc(int proc)
860{
861 struct list_head *start;
862 struct list_head *temp;
863 struct diag_cmd_reg_t *item = NULL;
864
865 mutex_lock(&driver->cmd_reg_mutex);
866 list_for_each_safe(start, temp, &driver->cmd_reg_list) {
867 item = list_entry(start, struct diag_cmd_reg_t, link);
Hardik Aryaf76d6602017-07-18 13:38:26 +0530868 if (&item->entry == NULL) {
869 pr_err("diag: In %s, unable to search command\n",
870 __func__);
871 mutex_unlock(&driver->cmd_reg_mutex);
872 return;
873 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700874 if (item->proc == proc) {
875 list_del(&item->link);
876 kfree(item);
877 driver->cmd_reg_count--;
878 }
879 }
880 diag_cmd_invalidate_polling(DIAG_CMD_REMOVE);
881 mutex_unlock(&driver->cmd_reg_mutex);
882}
883
884static int diag_copy_dci(char __user *buf, size_t count,
885 struct diag_dci_client_tbl *entry, int *pret)
886{
887 int total_data_len = 0;
888 int ret = 0;
889 int exit_stat = 1;
890 uint8_t drain_again = 0;
891 struct diag_dci_buffer_t *buf_entry, *temp;
892
893 if (!buf || !entry || !pret)
894 return exit_stat;
895
896 ret = *pret;
897
898 ret += sizeof(int);
899 if (ret >= count) {
900 pr_err("diag: In %s, invalid value for ret: %d, count: %zu\n",
901 __func__, ret, count);
902 return -EINVAL;
903 }
904
905 mutex_lock(&entry->write_buf_mutex);
906 list_for_each_entry_safe(buf_entry, temp, &entry->list_write_buf,
907 buf_track) {
908
909 if ((ret + buf_entry->data_len) > count) {
910 drain_again = 1;
911 break;
912 }
913
914 list_del(&buf_entry->buf_track);
915 mutex_lock(&buf_entry->data_mutex);
916 if ((buf_entry->data_len > 0) &&
917 (buf_entry->in_busy) &&
918 (buf_entry->data)) {
919 if (copy_to_user(buf+ret, (void *)buf_entry->data,
920 buf_entry->data_len))
921 goto drop;
922 ret += buf_entry->data_len;
923 total_data_len += buf_entry->data_len;
924 diag_ws_on_copy(DIAG_WS_DCI);
925drop:
926 buf_entry->in_busy = 0;
927 buf_entry->data_len = 0;
928 buf_entry->in_list = 0;
929 if (buf_entry->buf_type == DCI_BUF_CMD) {
930 mutex_unlock(&buf_entry->data_mutex);
931 continue;
932 } else if (buf_entry->buf_type == DCI_BUF_SECONDARY) {
933 diagmem_free(driver, buf_entry->data,
934 POOL_TYPE_DCI);
935 buf_entry->data = NULL;
936 mutex_unlock(&buf_entry->data_mutex);
937 kfree(buf_entry);
938 continue;
939 }
940
941 }
942 mutex_unlock(&buf_entry->data_mutex);
943 }
944
945 if (total_data_len > 0) {
946 /* Copy the total data length */
947 COPY_USER_SPACE_OR_ERR(buf+8, total_data_len, 4);
948 if (ret == -EFAULT)
949 goto exit;
950 ret -= 4;
951 } else {
952 pr_debug("diag: In %s, Trying to copy ZERO bytes, total_data_len: %d\n",
953 __func__, total_data_len);
954 }
955
956 exit_stat = 0;
957exit:
958 entry->in_service = 0;
959 mutex_unlock(&entry->write_buf_mutex);
960 *pret = ret;
961 if (drain_again)
962 dci_drain_data(0);
963
964 return exit_stat;
965}
966
967#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
968static int diag_remote_init(void)
969{
970 diagmem_setsize(POOL_TYPE_MDM, itemsize_mdm, poolsize_mdm);
971 diagmem_setsize(POOL_TYPE_MDM2, itemsize_mdm, poolsize_mdm);
972 diagmem_setsize(POOL_TYPE_MDM_DCI, itemsize_mdm_dci, poolsize_mdm_dci);
973 diagmem_setsize(POOL_TYPE_MDM2_DCI, itemsize_mdm_dci,
974 poolsize_mdm_dci);
975 diagmem_setsize(POOL_TYPE_MDM_MUX, itemsize_mdm_usb, poolsize_mdm_usb);
976 diagmem_setsize(POOL_TYPE_MDM2_MUX, itemsize_mdm_usb, poolsize_mdm_usb);
977 diagmem_setsize(POOL_TYPE_MDM_DCI_WRITE, itemsize_mdm_dci_write,
978 poolsize_mdm_dci_write);
979 diagmem_setsize(POOL_TYPE_MDM2_DCI_WRITE, itemsize_mdm_dci_write,
980 poolsize_mdm_dci_write);
981 diagmem_setsize(POOL_TYPE_QSC_MUX, itemsize_qsc_usb,
982 poolsize_qsc_usb);
983 driver->hdlc_encode_buf = kzalloc(DIAG_MAX_HDLC_BUF_SIZE, GFP_KERNEL);
984 if (!driver->hdlc_encode_buf)
985 return -ENOMEM;
986 driver->hdlc_encode_buf_len = 0;
987 return 0;
988}
989
990static void diag_remote_exit(void)
991{
992 kfree(driver->hdlc_encode_buf);
993}
994
995static int diag_send_raw_data_remote(int proc, void *buf, int len,
996 uint8_t hdlc_flag)
997{
998 int err = 0;
999 int max_len = 0;
1000 uint8_t retry_count = 0;
1001 uint8_t max_retries = 3;
1002 uint16_t payload = 0;
1003 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
1004 struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
1005 int bridge_index = proc - 1;
1006 struct diag_md_session_t *session_info = NULL;
1007 uint8_t hdlc_disabled = 0;
1008
1009 if (!buf)
1010 return -EINVAL;
1011
1012 if (len <= 0) {
1013 pr_err("diag: In %s, invalid len: %d", __func__, len);
1014 return -EBADMSG;
1015 }
1016
1017 if (bridge_index < 0 || bridge_index > NUM_REMOTE_DEV) {
1018 pr_err("diag: In %s, invalid bridge index: %d\n", __func__,
1019 bridge_index);
1020 return -EINVAL;
1021 }
1022
1023 do {
1024 if (driver->hdlc_encode_buf_len == 0)
1025 break;
1026 usleep_range(10000, 10100);
1027 retry_count++;
1028 } while (retry_count < max_retries);
1029
1030 if (driver->hdlc_encode_buf_len != 0)
1031 return -EAGAIN;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301032 mutex_lock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001033 session_info = diag_md_session_get_peripheral(APPS_DATA);
1034 if (session_info)
1035 hdlc_disabled = session_info->hdlc_disabled;
1036 else
1037 hdlc_disabled = driver->hdlc_disabled;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301038 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001039 if (hdlc_disabled) {
Hardik Arya5dbb4aa2017-06-12 11:26:05 +05301040 if (len < 4) {
1041 pr_err("diag: In %s, invalid len: %d of non_hdlc pkt",
1042 __func__, len);
1043 return -EBADMSG;
1044 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001045 payload = *(uint16_t *)(buf + 2);
Gopikrishna Mogasati810223f2017-04-20 16:25:20 +05301046 if (payload > DIAG_MAX_HDLC_BUF_SIZE) {
1047 pr_err("diag: Dropping packet, payload size is %d\n",
1048 payload);
1049 return -EBADMSG;
1050 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001051 driver->hdlc_encode_buf_len = payload;
1052 /*
Hardik Arya5dbb4aa2017-06-12 11:26:05 +05301053 * Adding 5 bytes for start (1 byte), version (1 byte),
1054 * payload (2 bytes) and end (1 byte)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001055 */
Hardik Arya5dbb4aa2017-06-12 11:26:05 +05301056 if (len == (payload + 5)) {
1057 /*
1058 * Adding 4 bytes for start (1 byte), version (1 byte)
1059 * and payload (2 bytes)
1060 */
1061 memcpy(driver->hdlc_encode_buf, buf + 4, payload);
1062 goto send_data;
1063 } else {
1064 pr_err("diag: In %s, invalid len: %d of non_hdlc pkt",
1065 __func__, len);
1066 return -EBADMSG;
1067 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001068 }
1069
1070 if (hdlc_flag) {
1071 if (len > DIAG_MAX_HDLC_BUF_SIZE) {
1072 pr_err("diag: Dropping packet, HDLC encoded packet payload size crosses buffer limit. Current payload size %d\n",
1073 len);
1074 return -EBADMSG;
1075 }
1076 driver->hdlc_encode_buf_len = len;
1077 memcpy(driver->hdlc_encode_buf, buf, len);
1078 goto send_data;
1079 }
1080
1081 /*
1082 * The worst case length will be twice as the incoming packet length.
1083 * Add 3 bytes for CRC bytes (2 bytes) and delimiter (1 byte)
1084 */
1085 max_len = (2 * len) + 3;
1086 if (max_len > DIAG_MAX_HDLC_BUF_SIZE) {
1087 pr_err("diag: Dropping packet, HDLC encoded packet payload size crosses buffer limit. Current payload size %d\n",
1088 max_len);
1089 return -EBADMSG;
1090 }
1091
1092 /* Perform HDLC encoding on incoming data */
1093 send.state = DIAG_STATE_START;
1094 send.pkt = (void *)(buf);
1095 send.last = (void *)(buf + len - 1);
1096 send.terminate = 1;
1097
1098 enc.dest = driver->hdlc_encode_buf;
1099 enc.dest_last = (void *)(driver->hdlc_encode_buf + max_len - 1);
1100 diag_hdlc_encode(&send, &enc);
1101 driver->hdlc_encode_buf_len = (int)(enc.dest -
1102 (void *)driver->hdlc_encode_buf);
1103
1104send_data:
1105 err = diagfwd_bridge_write(bridge_index, driver->hdlc_encode_buf,
1106 driver->hdlc_encode_buf_len);
1107 if (err) {
1108 pr_err_ratelimited("diag: Error writing Callback packet to proc: %d, err: %d\n",
1109 proc, err);
1110 driver->hdlc_encode_buf_len = 0;
1111 }
1112
1113 return err;
1114}
1115
1116static int diag_process_userspace_remote(int proc, void *buf, int len)
1117{
1118 int bridge_index = proc - 1;
1119
1120 if (!buf || len < 0) {
1121 pr_err("diag: Invalid input in %s, buf: %pK, len: %d\n",
1122 __func__, buf, len);
1123 return -EINVAL;
1124 }
1125
1126 if (bridge_index < 0 || bridge_index > NUM_REMOTE_DEV) {
1127 pr_err("diag: In %s, invalid bridge index: %d\n", __func__,
1128 bridge_index);
1129 return -EINVAL;
1130 }
1131
1132 driver->user_space_data_busy = 1;
1133 return diagfwd_bridge_write(bridge_index, buf, len);
1134}
1135#else
1136static int diag_remote_init(void)
1137{
1138 return 0;
1139}
1140
1141static void diag_remote_exit(void)
1142{
1143}
1144
1145int diagfwd_bridge_init(void)
1146{
1147 return 0;
1148}
1149
1150void diagfwd_bridge_exit(void)
1151{
1152}
1153
1154uint16_t diag_get_remote_device_mask(void)
1155{
1156 return 0;
1157}
1158
1159static int diag_send_raw_data_remote(int proc, void *buf, int len,
1160 uint8_t hdlc_flag)
1161{
1162 return -EINVAL;
1163}
1164
1165static int diag_process_userspace_remote(int proc, void *buf, int len)
1166{
1167 return 0;
1168}
1169#endif
1170
1171static int mask_request_validate(unsigned char mask_buf[])
1172{
1173 uint8_t packet_id;
1174 uint8_t subsys_id;
1175 uint16_t ss_cmd;
1176
1177 packet_id = mask_buf[0];
1178
1179 if (packet_id == DIAG_CMD_DIAG_SUBSYS_DELAY) {
1180 subsys_id = mask_buf[1];
1181 ss_cmd = *(uint16_t *)(mask_buf + 2);
1182 switch (subsys_id) {
1183 case DIAG_SS_DIAG:
1184 if ((ss_cmd == DIAG_SS_FILE_READ_MODEM) ||
1185 (ss_cmd == DIAG_SS_FILE_READ_ADSP) ||
1186 (ss_cmd == DIAG_SS_FILE_READ_WCNSS) ||
1187 (ss_cmd == DIAG_SS_FILE_READ_SLPI) ||
1188 (ss_cmd == DIAG_SS_FILE_READ_APPS))
1189 return 1;
1190 break;
1191 default:
1192 return 0;
1193 }
1194 } else if (packet_id == 0x4B) {
1195 subsys_id = mask_buf[1];
1196 ss_cmd = *(uint16_t *)(mask_buf + 2);
1197 /* Packets with SSID which are allowed */
1198 switch (subsys_id) {
1199 case 0x04: /* DIAG_SUBSYS_WCDMA */
1200 if ((ss_cmd == 0) || (ss_cmd == 0xF))
1201 return 1;
1202 break;
1203 case 0x08: /* DIAG_SUBSYS_GSM */
1204 if ((ss_cmd == 0) || (ss_cmd == 0x1))
1205 return 1;
1206 break;
1207 case 0x09: /* DIAG_SUBSYS_UMTS */
1208 case 0x0F: /* DIAG_SUBSYS_CM */
1209 if (ss_cmd == 0)
1210 return 1;
1211 break;
1212 case 0x0C: /* DIAG_SUBSYS_OS */
1213 if ((ss_cmd == 2) || (ss_cmd == 0x100))
1214 return 1; /* MPU and APU */
1215 break;
1216 case 0x12: /* DIAG_SUBSYS_DIAG_SERV */
1217 if ((ss_cmd == 0) || (ss_cmd == 0x6) || (ss_cmd == 0x7))
1218 return 1;
1219 else if (ss_cmd == 0x218) /* HDLC Disabled Command*/
1220 return 0;
1221 else if (ss_cmd == DIAG_GET_TIME_API)
1222 return 1;
1223 else if (ss_cmd == DIAG_SET_TIME_API)
1224 return 1;
1225 else if (ss_cmd == DIAG_SWITCH_COMMAND)
1226 return 1;
1227 else if (ss_cmd == DIAG_BUFFERING_MODE)
1228 return 1;
1229 break;
1230 case 0x13: /* DIAG_SUBSYS_FS */
1231 if ((ss_cmd == 0) || (ss_cmd == 0x1))
1232 return 1;
1233 break;
1234 default:
1235 return 0;
1236 }
1237 } else {
1238 switch (packet_id) {
1239 case 0x00: /* Version Number */
1240 case 0x0C: /* CDMA status packet */
1241 case 0x1C: /* Diag Version */
1242 case 0x1D: /* Time Stamp */
1243 case 0x60: /* Event Report Control */
1244 case 0x63: /* Status snapshot */
1245 case 0x73: /* Logging Configuration */
1246 case 0x7C: /* Extended build ID */
1247 case 0x7D: /* Extended Message configuration */
1248 case 0x81: /* Event get mask */
1249 case 0x82: /* Set the event mask */
1250 return 1;
1251 default:
1252 return 0;
1253 }
1254 }
1255 return 0;
1256}
1257
1258static void diag_md_session_init(void)
1259{
1260 int i;
1261
1262 mutex_init(&driver->md_session_lock);
1263 driver->md_session_mask = 0;
1264 driver->md_session_mode = DIAG_MD_NONE;
1265 for (i = 0; i < NUM_MD_SESSIONS; i++)
1266 driver->md_session_map[i] = NULL;
1267}
1268
1269static void diag_md_session_exit(void)
1270{
1271 int i;
1272 struct diag_md_session_t *session_info = NULL;
1273
1274 for (i = 0; i < NUM_MD_SESSIONS; i++) {
1275 if (driver->md_session_map[i]) {
1276 session_info = driver->md_session_map[i];
1277 diag_log_mask_free(session_info->log_mask);
1278 kfree(session_info->log_mask);
1279 session_info->log_mask = NULL;
1280 diag_msg_mask_free(session_info->msg_mask);
1281 kfree(session_info->msg_mask);
1282 session_info->msg_mask = NULL;
1283 diag_event_mask_free(session_info->event_mask);
1284 kfree(session_info->event_mask);
1285 session_info->event_mask = NULL;
1286 kfree(session_info);
1287 session_info = NULL;
1288 driver->md_session_map[i] = NULL;
1289 }
1290 }
1291 mutex_destroy(&driver->md_session_lock);
1292 driver->md_session_mask = 0;
1293 driver->md_session_mode = DIAG_MD_NONE;
1294}
1295
1296int diag_md_session_create(int mode, int peripheral_mask, int proc)
1297{
1298 int i;
1299 int err = 0;
1300 struct diag_md_session_t *new_session = NULL;
1301
1302 /*
1303 * If a session is running with a peripheral mask and a new session
1304 * request comes in with same peripheral mask value then return
1305 * invalid param
1306 */
1307 if (driver->md_session_mode == DIAG_MD_PERIPHERAL &&
1308 (driver->md_session_mask & peripheral_mask) != 0)
1309 return -EINVAL;
1310
1311 mutex_lock(&driver->md_session_lock);
1312 new_session = kzalloc(sizeof(struct diag_md_session_t), GFP_KERNEL);
1313 if (!new_session) {
1314 mutex_unlock(&driver->md_session_lock);
1315 return -ENOMEM;
1316 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001317 new_session->peripheral_mask = 0;
1318 new_session->pid = current->tgid;
1319 new_session->task = current;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001320 new_session->log_mask = kzalloc(sizeof(struct diag_mask_info),
1321 GFP_KERNEL);
1322 if (!new_session->log_mask) {
1323 err = -ENOMEM;
1324 goto fail_peripheral;
1325 }
1326 new_session->event_mask = kzalloc(sizeof(struct diag_mask_info),
1327 GFP_KERNEL);
1328 if (!new_session->event_mask) {
1329 err = -ENOMEM;
1330 goto fail_peripheral;
1331 }
1332 new_session->msg_mask = kzalloc(sizeof(struct diag_mask_info),
1333 GFP_KERNEL);
1334 if (!new_session->msg_mask) {
1335 err = -ENOMEM;
1336 goto fail_peripheral;
1337 }
1338
1339 err = diag_log_mask_copy(new_session->log_mask, &log_mask);
1340 if (err) {
1341 DIAG_LOG(DIAG_DEBUG_USERSPACE,
1342 "return value of log copy. err %d\n", err);
1343 goto fail_peripheral;
1344 }
1345 err = diag_event_mask_copy(new_session->event_mask, &event_mask);
1346 if (err) {
1347 DIAG_LOG(DIAG_DEBUG_USERSPACE,
1348 "return value of event copy. err %d\n", err);
1349 goto fail_peripheral;
1350 }
1351 err = diag_msg_mask_copy(new_session->msg_mask, &msg_mask);
1352 if (err) {
1353 DIAG_LOG(DIAG_DEBUG_USERSPACE,
1354 "return value of msg copy. err %d\n", err);
1355 goto fail_peripheral;
1356 }
1357 for (i = 0; i < NUM_MD_SESSIONS; i++) {
1358 if ((MD_PERIPHERAL_MASK(i) & peripheral_mask) == 0)
1359 continue;
1360 if (driver->md_session_map[i] != NULL) {
1361 DIAG_LOG(DIAG_DEBUG_USERSPACE,
1362 "another instance present for %d\n", i);
1363 err = -EEXIST;
1364 goto fail_peripheral;
1365 }
1366 new_session->peripheral_mask |= MD_PERIPHERAL_MASK(i);
1367 driver->md_session_map[i] = new_session;
1368 driver->md_session_mask |= MD_PERIPHERAL_MASK(i);
1369 }
1370 setup_timer(&new_session->hdlc_reset_timer,
1371 diag_md_hdlc_reset_timer_func,
1372 new_session->pid);
1373
1374 driver->md_session_mode = DIAG_MD_PERIPHERAL;
1375 mutex_unlock(&driver->md_session_lock);
1376 DIAG_LOG(DIAG_DEBUG_USERSPACE,
1377 "created session in peripheral mode\n");
1378 return 0;
1379
1380fail_peripheral:
1381 diag_log_mask_free(new_session->log_mask);
1382 kfree(new_session->log_mask);
1383 new_session->log_mask = NULL;
1384 diag_event_mask_free(new_session->event_mask);
1385 kfree(new_session->event_mask);
1386 new_session->event_mask = NULL;
1387 diag_msg_mask_free(new_session->msg_mask);
1388 kfree(new_session->msg_mask);
1389 new_session->msg_mask = NULL;
1390 kfree(new_session);
1391 new_session = NULL;
1392 mutex_unlock(&driver->md_session_lock);
1393 return err;
1394}
1395
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301396static void diag_md_session_close(int pid)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001397{
1398 int i;
1399 uint8_t found = 0;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301400 struct diag_md_session_t *session_info = NULL;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001401
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301402 session_info = diag_md_session_get_pid(pid);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001403 if (!session_info)
1404 return;
1405
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001406 for (i = 0; i < NUM_MD_SESSIONS; i++) {
1407 if (driver->md_session_map[i] != session_info)
1408 continue;
1409 driver->md_session_map[i] = NULL;
1410 driver->md_session_mask &= ~session_info->peripheral_mask;
1411 }
1412 diag_log_mask_free(session_info->log_mask);
1413 kfree(session_info->log_mask);
1414 session_info->log_mask = NULL;
1415 diag_msg_mask_free(session_info->msg_mask);
1416 kfree(session_info->msg_mask);
1417 session_info->msg_mask = NULL;
1418 diag_event_mask_free(session_info->event_mask);
1419 kfree(session_info->event_mask);
1420 session_info->event_mask = NULL;
1421 del_timer(&session_info->hdlc_reset_timer);
1422
1423 for (i = 0; i < NUM_MD_SESSIONS && !found; i++) {
1424 if (driver->md_session_map[i] != NULL)
1425 found = 1;
1426 }
1427
1428 driver->md_session_mode = (found) ? DIAG_MD_PERIPHERAL : DIAG_MD_NONE;
1429 kfree(session_info);
1430 session_info = NULL;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001431 DIAG_LOG(DIAG_DEBUG_USERSPACE, "cleared up session\n");
1432}
1433
1434struct diag_md_session_t *diag_md_session_get_pid(int pid)
1435{
1436 int i;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301437 if (pid <= 0)
1438 return NULL;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001439 for (i = 0; i < NUM_MD_SESSIONS; i++) {
1440 if (driver->md_session_map[i] &&
1441 driver->md_session_map[i]->pid == pid)
1442 return driver->md_session_map[i];
1443 }
1444 return NULL;
1445}
1446
1447struct diag_md_session_t *diag_md_session_get_peripheral(uint8_t peripheral)
1448{
1449 if (peripheral >= NUM_MD_SESSIONS)
1450 return NULL;
1451 return driver->md_session_map[peripheral];
1452}
1453
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301454static int diag_md_peripheral_switch(int pid,
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001455 int peripheral_mask, int req_mode) {
1456 int i, bit = 0;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301457 struct diag_md_session_t *session_info = NULL;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001458
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301459 session_info = diag_md_session_get_pid(pid);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001460 if (!session_info)
1461 return -EINVAL;
1462 if (req_mode != DIAG_USB_MODE || req_mode != DIAG_MEMORY_DEVICE_MODE)
1463 return -EINVAL;
1464
1465 /*
1466 * check that md_session_map for i == session_info,
1467 * if not then race condition occurred and bail
1468 */
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001469 for (i = 0; i < NUM_MD_SESSIONS; i++) {
1470 bit = MD_PERIPHERAL_MASK(i) & peripheral_mask;
1471 if (!bit)
1472 continue;
1473 if (req_mode == DIAG_USB_MODE) {
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301474 if (driver->md_session_map[i] != session_info)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001475 return -EINVAL;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001476 driver->md_session_map[i] = NULL;
1477 driver->md_session_mask &= ~bit;
1478 session_info->peripheral_mask &= ~bit;
1479
1480 } else {
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301481 if (driver->md_session_map[i] != NULL)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001482 return -EINVAL;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001483 driver->md_session_map[i] = session_info;
1484 driver->md_session_mask |= bit;
1485 session_info->peripheral_mask |= bit;
1486
1487 }
1488 }
1489
1490 driver->md_session_mode = DIAG_MD_PERIPHERAL;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001491 DIAG_LOG(DIAG_DEBUG_USERSPACE, "Changed Peripherals:0x%x to mode:%d\n",
1492 peripheral_mask, req_mode);
1493}
1494
1495static int diag_md_session_check(int curr_mode, int req_mode,
1496 const struct diag_logging_mode_param_t *param,
1497 uint8_t *change_mode)
1498{
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301499 int i, bit = 0, err = 0, peripheral_mask = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001500 int change_mask = 0;
1501 struct diag_md_session_t *session_info = NULL;
1502
1503 if (!param || !change_mode)
1504 return -EIO;
1505
1506 *change_mode = 0;
1507
1508 switch (curr_mode) {
1509 case DIAG_USB_MODE:
1510 case DIAG_MEMORY_DEVICE_MODE:
1511 case DIAG_MULTI_MODE:
1512 break;
1513 default:
1514 return -EINVAL;
1515 }
1516
1517 if (req_mode != DIAG_USB_MODE && req_mode != DIAG_MEMORY_DEVICE_MODE)
1518 return -EINVAL;
1519
1520 if (req_mode == DIAG_USB_MODE) {
1521 if (curr_mode == DIAG_USB_MODE)
1522 return 0;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301523 mutex_lock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001524 if (driver->md_session_mode == DIAG_MD_NONE
1525 && driver->md_session_mask == 0 && driver->logging_mask) {
1526 *change_mode = 1;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301527 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001528 return 0;
1529 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001530 /*
1531 * curr_mode is either DIAG_MULTI_MODE or DIAG_MD_MODE
1532 * Check if requested peripherals are already in usb mode
1533 */
1534 for (i = 0; i < NUM_MD_SESSIONS; i++) {
1535 bit = MD_PERIPHERAL_MASK(i) & param->peripheral_mask;
1536 if (!bit)
1537 continue;
1538 if (bit & driver->logging_mask)
1539 change_mask |= bit;
1540 }
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301541 if (!change_mask) {
1542 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001543 return 0;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301544 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001545
1546 /*
1547 * Change is needed. Check if this md_session has set all the
1548 * requested peripherals. If another md session set a requested
1549 * peripheral then we cannot switch that peripheral to USB.
1550 * If this session owns all the requested peripherals, then
1551 * call function to switch the modes/masks for the md_session
1552 */
1553 session_info = diag_md_session_get_pid(current->tgid);
1554 if (!session_info) {
1555 *change_mode = 1;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301556 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001557 return 0;
1558 }
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301559 peripheral_mask = session_info->peripheral_mask;
1560 if ((change_mask & peripheral_mask)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001561 != change_mask) {
1562 DIAG_LOG(DIAG_DEBUG_USERSPACE,
1563 "Another MD Session owns a requested peripheral\n");
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301564 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001565 return -EINVAL;
1566 }
1567 *change_mode = 1;
1568
1569 /* If all peripherals are being set to USB Mode, call close */
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301570 if (~change_mask & peripheral_mask) {
1571 err = diag_md_peripheral_switch(current->tgid,
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001572 change_mask, DIAG_USB_MODE);
1573 } else
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301574 diag_md_session_close(current->tgid);
1575 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001576 return err;
1577
1578 } else if (req_mode == DIAG_MEMORY_DEVICE_MODE) {
1579 /*
1580 * Get bit mask that represents what peripherals already have
1581 * been set. Check that requested peripherals already set are
1582 * owned by this md session
1583 */
Manoj Prabhu B0130d0e2017-10-12 22:14:24 +05301584 mutex_lock(&driver->md_session_lock);
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301585 change_mask = driver->md_session_mask & param->peripheral_mask;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001586 session_info = diag_md_session_get_pid(current->tgid);
1587
1588 if (session_info) {
1589 if ((session_info->peripheral_mask & change_mask)
1590 != change_mask) {
1591 DIAG_LOG(DIAG_DEBUG_USERSPACE,
1592 "Another MD Session owns a requested peripheral\n");
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301593 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001594 return -EINVAL;
1595 }
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301596 err = diag_md_peripheral_switch(current->tgid,
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001597 change_mask, DIAG_USB_MODE);
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301598 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001599 } else {
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05301600 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001601 if (change_mask) {
1602 DIAG_LOG(DIAG_DEBUG_USERSPACE,
1603 "Another MD Session owns a requested peripheral\n");
1604 return -EINVAL;
1605 }
1606 err = diag_md_session_create(DIAG_MD_PERIPHERAL,
1607 param->peripheral_mask, DIAG_LOCAL_PROC);
1608 }
1609 *change_mode = 1;
1610 return err;
1611 }
1612 return -EINVAL;
1613}
1614
1615static uint32_t diag_translate_mask(uint32_t peripheral_mask)
1616{
1617 uint32_t ret = 0;
1618
1619 if (peripheral_mask & DIAG_CON_APSS)
1620 ret |= (1 << APPS_DATA);
1621 if (peripheral_mask & DIAG_CON_MPSS)
1622 ret |= (1 << PERIPHERAL_MODEM);
1623 if (peripheral_mask & DIAG_CON_LPASS)
1624 ret |= (1 << PERIPHERAL_LPASS);
1625 if (peripheral_mask & DIAG_CON_WCNSS)
1626 ret |= (1 << PERIPHERAL_WCNSS);
1627 if (peripheral_mask & DIAG_CON_SENSORS)
1628 ret |= (1 << PERIPHERAL_SENSORS);
1629 if (peripheral_mask & DIAG_CON_WDSP)
1630 ret |= (1 << PERIPHERAL_WDSP);
Sreelakshmi Gownipalli588a31d2016-11-02 13:33:43 -07001631 if (peripheral_mask & DIAG_CON_CDSP)
1632 ret |= (1 << PERIPHERAL_CDSP);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301633 if (peripheral_mask & DIAG_CON_UPD_WLAN)
1634 ret |= (1 << UPD_WLAN);
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301635 if (peripheral_mask & DIAG_CON_UPD_AUDIO)
1636 ret |= (1 << UPD_AUDIO);
1637 if (peripheral_mask & DIAG_CON_UPD_SENSORS)
1638 ret |= (1 << UPD_SENSORS);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001639 return ret;
1640}
1641
1642static int diag_switch_logging(struct diag_logging_mode_param_t *param)
1643{
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301644 int new_mode, i = 0;
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301645 int curr_mode, err = 0;
1646 uint8_t do_switch = 1, peripheral = 0;
1647 uint32_t peripheral_mask = 0, pd_mask = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001648
1649 if (!param)
1650 return -EINVAL;
1651
1652 if (!param->peripheral_mask) {
1653 DIAG_LOG(DIAG_DEBUG_USERSPACE,
1654 "asking for mode switch with no peripheral mask set\n");
1655 return -EINVAL;
1656 }
1657
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301658 if (param->pd_mask) {
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301659 pd_mask = diag_translate_mask(param->pd_mask);
1660 for (i = UPD_WLAN; i < NUM_MD_SESSIONS; i++) {
1661 if (pd_mask & (1 << i)) {
1662 if (diag_search_diagid_by_pd(i, &param->diag_id,
1663 &param->peripheral)) {
1664 param->pd_val = i;
1665 break;
1666 }
1667 }
1668 }
Manoj Prabhu B85088ba2017-12-06 11:52:02 +05301669 if (!param->diag_id ||
1670 (param->pd_val < UPD_WLAN) ||
1671 (param->pd_val > NUM_MD_SESSIONS)) {
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301672 DIAG_LOG(DIAG_DEBUG_USERSPACE,
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301673 "diag_id support is not present for the pd mask = %d\n",
1674 param->pd_mask);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301675 return -EINVAL;
1676 }
1677
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301678 DIAG_LOG(DIAG_DEBUG_USERSPACE,
1679 "diag: pd_mask = %d, diag_id = %d, peripheral = %d, pd_val = %d\n",
1680 param->pd_mask, param->diag_id,
1681 param->peripheral, param->pd_val);
1682
1683 peripheral = param->peripheral;
Manoj Prabhu B85088ba2017-12-06 11:52:02 +05301684 i = param->pd_val - UPD_WLAN;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301685 if (driver->md_session_map[peripheral] &&
1686 (MD_PERIPHERAL_MASK(peripheral) &
Manoj Prabhu B85088ba2017-12-06 11:52:02 +05301687 diag_mux->mux_mask) &&
1688 !driver->pd_session_clear[i]) {
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301689 DIAG_LOG(DIAG_DEBUG_USERSPACE,
1690 "diag_fr: User PD is already logging onto active peripheral logging\n");
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301691 driver->pd_session_clear[i] = 0;
1692 return -EINVAL;
1693 }
1694 peripheral_mask =
1695 diag_translate_mask(param->pd_mask);
1696 param->peripheral_mask = peripheral_mask;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301697 if (!driver->pd_session_clear[i]) {
1698 driver->pd_logging_mode[i] = 1;
1699 driver->num_pd_session += 1;
1700 }
1701 driver->pd_session_clear[i] = 0;
1702 } else {
1703 peripheral_mask =
1704 diag_translate_mask(param->peripheral_mask);
1705 param->peripheral_mask = peripheral_mask;
1706 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001707
1708 switch (param->req_mode) {
1709 case CALLBACK_MODE:
1710 case UART_MODE:
1711 case SOCKET_MODE:
1712 case MEMORY_DEVICE_MODE:
1713 new_mode = DIAG_MEMORY_DEVICE_MODE;
1714 break;
1715 case USB_MODE:
1716 new_mode = DIAG_USB_MODE;
1717 break;
1718 default:
1719 pr_err("diag: In %s, request to switch to invalid mode: %d\n",
1720 __func__, param->req_mode);
1721 return -EINVAL;
1722 }
1723
1724 curr_mode = driver->logging_mode;
1725 DIAG_LOG(DIAG_DEBUG_USERSPACE,
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301726 "request to switch logging from %d mask:%0x to new_mode %d mask:%0x\n",
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001727 curr_mode, driver->md_session_mask, new_mode, peripheral_mask);
1728
1729 err = diag_md_session_check(curr_mode, new_mode, param, &do_switch);
1730 if (err) {
1731 DIAG_LOG(DIAG_DEBUG_USERSPACE,
1732 "err from diag_md_session_check, err: %d\n", err);
1733 return err;
1734 }
1735
1736 if (do_switch == 0) {
1737 DIAG_LOG(DIAG_DEBUG_USERSPACE,
1738 "not switching modes c: %d n: %d\n",
1739 curr_mode, new_mode);
1740 return 0;
1741 }
1742
1743 diag_ws_reset(DIAG_WS_MUX);
1744 err = diag_mux_switch_logging(&new_mode, &peripheral_mask);
1745 if (err) {
1746 pr_err("diag: In %s, unable to switch mode from %d to %d, err: %d\n",
1747 __func__, curr_mode, new_mode, err);
1748 driver->logging_mode = curr_mode;
1749 goto fail;
1750 }
1751 driver->logging_mode = new_mode;
1752 driver->logging_mask = peripheral_mask;
1753 DIAG_LOG(DIAG_DEBUG_USERSPACE,
1754 "Switch logging to %d mask:%0x\n", new_mode, peripheral_mask);
1755
1756 /* Update to take peripheral_mask */
1757 if (new_mode != DIAG_MEMORY_DEVICE_MODE) {
1758 diag_update_real_time_vote(DIAG_PROC_MEMORY_DEVICE,
1759 MODE_REALTIME, ALL_PROC);
1760 } else {
1761 diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_UP,
1762 ALL_PROC);
1763 }
1764
1765 if (!(new_mode == DIAG_MEMORY_DEVICE_MODE &&
1766 curr_mode == DIAG_USB_MODE)) {
1767 queue_work(driver->diag_real_time_wq,
1768 &driver->diag_real_time_work);
1769 }
1770
1771 return 0;
1772fail:
1773 return err;
1774}
1775
1776static int diag_ioctl_dci_reg(unsigned long ioarg)
1777{
1778 int result = -EINVAL;
1779 struct diag_dci_reg_tbl_t dci_reg_params;
1780
1781 if (copy_from_user(&dci_reg_params, (void __user *)ioarg,
1782 sizeof(struct diag_dci_reg_tbl_t)))
1783 return -EFAULT;
1784
1785 result = diag_dci_register_client(&dci_reg_params);
1786
1787 return result;
1788}
1789
1790static int diag_ioctl_dci_health_stats(unsigned long ioarg)
1791{
1792 int result = -EINVAL;
1793 struct diag_dci_health_stats_proc stats;
1794
1795 if (copy_from_user(&stats, (void __user *)ioarg,
1796 sizeof(struct diag_dci_health_stats_proc)))
1797 return -EFAULT;
1798
1799 result = diag_dci_copy_health_stats(&stats);
1800 if (result == DIAG_DCI_NO_ERROR) {
1801 if (copy_to_user((void __user *)ioarg, &stats,
1802 sizeof(struct diag_dci_health_stats_proc)))
1803 return -EFAULT;
1804 }
1805
1806 return result;
1807}
1808
1809static int diag_ioctl_dci_log_status(unsigned long ioarg)
1810{
1811 struct diag_log_event_stats le_stats;
1812 struct diag_dci_client_tbl *dci_client = NULL;
1813
1814 if (copy_from_user(&le_stats, (void __user *)ioarg,
1815 sizeof(struct diag_log_event_stats)))
1816 return -EFAULT;
1817
1818 dci_client = diag_dci_get_client_entry(le_stats.client_id);
1819 if (!dci_client)
1820 return DIAG_DCI_NOT_SUPPORTED;
1821 le_stats.is_set = diag_dci_query_log_mask(dci_client, le_stats.code);
1822 if (copy_to_user((void __user *)ioarg, &le_stats,
1823 sizeof(struct diag_log_event_stats)))
1824 return -EFAULT;
1825
1826 return DIAG_DCI_NO_ERROR;
1827}
1828
1829static int diag_ioctl_dci_event_status(unsigned long ioarg)
1830{
1831 struct diag_log_event_stats le_stats;
1832 struct diag_dci_client_tbl *dci_client = NULL;
1833
1834 if (copy_from_user(&le_stats, (void __user *)ioarg,
1835 sizeof(struct diag_log_event_stats)))
1836 return -EFAULT;
1837
1838 dci_client = diag_dci_get_client_entry(le_stats.client_id);
1839 if (!dci_client)
1840 return DIAG_DCI_NOT_SUPPORTED;
1841
1842 le_stats.is_set = diag_dci_query_event_mask(dci_client, le_stats.code);
1843 if (copy_to_user((void __user *)ioarg, &le_stats,
1844 sizeof(struct diag_log_event_stats)))
1845 return -EFAULT;
1846
1847 return DIAG_DCI_NO_ERROR;
1848}
1849
1850static int diag_ioctl_lsm_deinit(void)
1851{
1852 int i;
1853
Mohit Aggarwal9f694302017-07-06 10:16:52 +05301854 mutex_lock(&driver->diagchar_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001855 for (i = 0; i < driver->num_clients; i++)
1856 if (driver->client_map[i].pid == current->tgid)
1857 break;
1858
Mohit Aggarwal9f694302017-07-06 10:16:52 +05301859 if (i == driver->num_clients) {
1860 mutex_unlock(&driver->diagchar_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001861 return -EINVAL;
Mohit Aggarwal9f694302017-07-06 10:16:52 +05301862 }
Sreelakshmi Gownipalli018fdc12017-11-22 12:25:39 -08001863 if (!(driver->data_ready[i] & DEINIT_TYPE)) {
1864 driver->data_ready[i] |= DEINIT_TYPE;
1865 atomic_inc(&driver->data_ready_notif[i]);
1866 }
Mohit Aggarwal9f694302017-07-06 10:16:52 +05301867 mutex_unlock(&driver->diagchar_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001868 wake_up_interruptible(&driver->wait_q);
1869
1870 return 1;
1871}
1872
1873static int diag_ioctl_vote_real_time(unsigned long ioarg)
1874{
1875 int real_time = 0;
1876 int temp_proc = ALL_PROC;
1877 struct real_time_vote_t vote;
1878 struct diag_dci_client_tbl *dci_client = NULL;
1879
1880 if (copy_from_user(&vote, (void __user *)ioarg,
1881 sizeof(struct real_time_vote_t)))
1882 return -EFAULT;
1883
1884 if (vote.proc > DIAG_PROC_MEMORY_DEVICE ||
1885 vote.real_time_vote > MODE_UNKNOWN ||
1886 vote.client_id < 0) {
1887 pr_err("diag: %s, invalid params, proc: %d, vote: %d, client_id: %d\n",
1888 __func__, vote.proc, vote.real_time_vote,
1889 vote.client_id);
1890 return -EINVAL;
1891 }
1892
1893 driver->real_time_update_busy++;
1894 if (vote.proc == DIAG_PROC_DCI) {
1895 dci_client = diag_dci_get_client_entry(vote.client_id);
1896 if (!dci_client) {
1897 driver->real_time_update_busy--;
1898 return DIAG_DCI_NOT_SUPPORTED;
1899 }
1900 diag_dci_set_real_time(dci_client, vote.real_time_vote);
1901 real_time = diag_dci_get_cumulative_real_time(
1902 dci_client->client_info.token);
1903 diag_update_real_time_vote(vote.proc, real_time,
1904 dci_client->client_info.token);
1905 } else {
1906 real_time = vote.real_time_vote;
1907 temp_proc = vote.client_id;
1908 diag_update_real_time_vote(vote.proc, real_time,
1909 temp_proc);
1910 }
1911 queue_work(driver->diag_real_time_wq, &driver->diag_real_time_work);
1912 return 0;
1913}
1914
1915static int diag_ioctl_get_real_time(unsigned long ioarg)
1916{
1917 int i;
1918 int retry_count = 0;
1919 int timer = 0;
1920 struct real_time_query_t rt_query;
1921
1922 if (copy_from_user(&rt_query, (void __user *)ioarg,
1923 sizeof(struct real_time_query_t)))
1924 return -EFAULT;
1925 while (retry_count < 3) {
1926 if (driver->real_time_update_busy > 0) {
1927 retry_count++;
1928 /*
1929 * The value 10000 was chosen empirically as an
1930 * optimum value in order to give the work in
1931 * diag_real_time_wq to complete processing.
1932 */
1933 for (timer = 0; timer < 5; timer++)
1934 usleep_range(10000, 10100);
1935 } else {
1936 break;
1937 }
1938 }
1939
1940 if (driver->real_time_update_busy > 0)
1941 return -EAGAIN;
1942
1943 if (rt_query.proc < 0 || rt_query.proc >= DIAG_NUM_PROC) {
1944 pr_err("diag: Invalid proc %d in %s\n", rt_query.proc,
1945 __func__);
1946 return -EINVAL;
1947 }
1948 rt_query.real_time = driver->real_time_mode[rt_query.proc];
1949 /*
1950 * For the local processor, if any of the peripherals is in buffering
1951 * mode, overwrite the value of real time with UNKNOWN_MODE
1952 */
1953 if (rt_query.proc == DIAG_LOCAL_PROC) {
1954 for (i = 0; i < NUM_PERIPHERALS; i++) {
1955 if (!driver->feature[i].peripheral_buffering)
1956 continue;
1957 switch (driver->buffering_mode[i].mode) {
1958 case DIAG_BUFFERING_MODE_CIRCULAR:
1959 case DIAG_BUFFERING_MODE_THRESHOLD:
1960 rt_query.real_time = MODE_UNKNOWN;
1961 break;
1962 }
1963 }
1964 }
1965
1966 if (copy_to_user((void __user *)ioarg, &rt_query,
1967 sizeof(struct real_time_query_t)))
1968 return -EFAULT;
1969
1970 return 0;
1971}
1972
1973static int diag_ioctl_set_buffering_mode(unsigned long ioarg)
1974{
1975 struct diag_buffering_mode_t params;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301976 int peripheral = 0;
1977 uint8_t diag_id = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001978
1979 if (copy_from_user(&params, (void __user *)ioarg, sizeof(params)))
1980 return -EFAULT;
1981
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301982 diag_map_pd_to_diagid(params.peripheral, &diag_id, &peripheral);
1983
1984 if ((peripheral < 0) ||
1985 peripheral >= NUM_PERIPHERALS) {
1986 pr_err("diag: In %s, invalid peripheral = %d\n", __func__,
1987 peripheral);
1988 return -EIO;
1989 }
1990
1991 if (params.peripheral > NUM_PERIPHERALS &&
1992 !driver->feature[peripheral].pd_buffering) {
1993 pr_err("diag: In %s, pd buffering not supported for peripheral:%d\n",
1994 __func__, peripheral);
1995 return -EIO;
1996 }
1997
1998 if (!driver->feature[peripheral].peripheral_buffering) {
1999 pr_err("diag: In %s, peripheral %d doesn't support buffering\n",
2000 __func__, peripheral);
2001 return -EIO;
2002 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002003
2004 mutex_lock(&driver->mode_lock);
2005 driver->buffering_flag[params.peripheral] = 1;
2006 mutex_unlock(&driver->mode_lock);
2007
2008 return diag_send_peripheral_buffering_mode(&params);
2009}
2010
2011static int diag_ioctl_peripheral_drain_immediate(unsigned long ioarg)
2012{
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05302013 uint8_t pd, diag_id = 0;
2014 int peripheral = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002015
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05302016 if (copy_from_user(&pd, (void __user *)ioarg, sizeof(uint8_t)))
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002017 return -EFAULT;
2018
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05302019 diag_map_pd_to_diagid(pd, &diag_id, &peripheral);
2020
2021 if ((peripheral < 0) ||
2022 peripheral >= NUM_PERIPHERALS) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002023 pr_err("diag: In %s, invalid peripheral %d\n", __func__,
2024 peripheral);
2025 return -EINVAL;
2026 }
2027
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05302028 if (pd > NUM_PERIPHERALS &&
2029 !driver->feature[peripheral].pd_buffering) {
2030 pr_err("diag: In %s, pd buffering not supported for peripheral:%d\n",
2031 __func__, peripheral);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002032 return -EIO;
2033 }
2034
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05302035 return diag_send_peripheral_drain_immediate(pd, diag_id, peripheral);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002036}
2037
2038static int diag_ioctl_dci_support(unsigned long ioarg)
2039{
2040 struct diag_dci_peripherals_t dci_support;
2041 int result = -EINVAL;
2042
2043 if (copy_from_user(&dci_support, (void __user *)ioarg,
2044 sizeof(struct diag_dci_peripherals_t)))
2045 return -EFAULT;
2046
2047 result = diag_dci_get_support_list(&dci_support);
2048 if (result == DIAG_DCI_NO_ERROR)
2049 if (copy_to_user((void __user *)ioarg, &dci_support,
2050 sizeof(struct diag_dci_peripherals_t)))
2051 return -EFAULT;
2052
2053 return result;
2054}
2055
2056static int diag_ioctl_hdlc_toggle(unsigned long ioarg)
2057{
2058 uint8_t hdlc_support;
2059 struct diag_md_session_t *session_info = NULL;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002060 if (copy_from_user(&hdlc_support, (void __user *)ioarg,
2061 sizeof(uint8_t)))
2062 return -EFAULT;
2063 mutex_lock(&driver->hdlc_disable_mutex);
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05302064 mutex_lock(&driver->md_session_lock);
2065 session_info = diag_md_session_get_pid(current->tgid);
2066 if (session_info)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002067 session_info->hdlc_disabled = hdlc_support;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05302068 else
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002069 driver->hdlc_disabled = hdlc_support;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05302070 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002071 mutex_unlock(&driver->hdlc_disable_mutex);
2072 diag_update_md_clients(HDLC_SUPPORT_TYPE);
2073
2074 return 0;
2075}
2076
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05302077/*
2078 * diag_search_peripheral_by_pd(uint8_t pd_val)
2079 *
2080 * Function will return peripheral by searching pd in the
2081 * diag_id table.
2082 *
2083 */
2084
2085int diag_search_peripheral_by_pd(uint8_t pd_val)
2086{
2087 struct list_head *start;
2088 struct list_head *temp;
2089 struct diag_id_tbl_t *item = NULL;
2090
2091 mutex_lock(&driver->diag_id_mutex);
2092 list_for_each_safe(start, temp, &driver->diag_id_list) {
2093 item = list_entry(start, struct diag_id_tbl_t, link);
2094 if (pd_val == item->pd_val) {
2095 mutex_unlock(&driver->diag_id_mutex);
2096 return item->peripheral;
2097 }
2098 }
2099 mutex_unlock(&driver->diag_id_mutex);
2100 return -EINVAL;
2101}
2102
2103/*
2104 * diag_search_diagid_by_pd(uint8_t pd_val,
2105 * uint8_t *diag_id, int *peripheral)
2106 *
2107 * Function will update the peripheral and diag_id
2108 * from the pd passed as an argument.
2109 *
2110 */
2111
2112uint8_t diag_search_diagid_by_pd(uint8_t pd_val,
2113 uint8_t *diag_id, int *peripheral)
2114{
2115 struct list_head *start;
2116 struct list_head *temp;
2117 struct diag_id_tbl_t *item = NULL;
2118
2119 mutex_lock(&driver->diag_id_mutex);
2120 list_for_each_safe(start, temp, &driver->diag_id_list) {
2121 item = list_entry(start, struct diag_id_tbl_t, link);
2122 if (pd_val == item->pd_val) {
2123 *peripheral = item->peripheral;
2124 *diag_id = item->diag_id;
2125 mutex_unlock(&driver->diag_id_mutex);
2126 return 1;
2127 }
2128 }
2129 mutex_unlock(&driver->diag_id_mutex);
2130 return 0;
2131}
2132
2133/*
2134 * diag_query_pd_name(char *process_name, char *search_str)
2135 *
2136 * The function searches the pd string in the control packet string
2137 * from the peripheral
2138 *
2139 */
2140
2141static int diag_query_pd_name(char *process_name, char *search_str)
2142{
2143 if (!process_name)
2144 return -EINVAL;
2145
2146 if (strnstr(process_name, search_str, strlen(process_name)))
2147 return 1;
2148
2149 return 0;
2150}
2151
2152/*
2153 * diag_query_pd_name(char *process_name, char *search_str)
2154 *
2155 * The function returns the PD information based on the presence of
2156 * the pd specific string in the control packet's string from peripheral.
2157 *
2158 */
2159
2160int diag_query_pd(char *process_name)
2161{
2162 if (!process_name)
2163 return -EINVAL;
2164
2165 if (diag_query_pd_name(process_name, "modem/root_pd"))
2166 return PERIPHERAL_MODEM;
2167 if (diag_query_pd_name(process_name, "adsp/root_pd"))
2168 return PERIPHERAL_LPASS;
2169 if (diag_query_pd_name(process_name, "slpi/root_pd"))
2170 return PERIPHERAL_SENSORS;
2171 if (diag_query_pd_name(process_name, "cdsp/root_pd"))
2172 return PERIPHERAL_CDSP;
2173 if (diag_query_pd_name(process_name, "wlan_pd"))
2174 return UPD_WLAN;
2175 if (diag_query_pd_name(process_name, "audio_pd"))
2176 return UPD_AUDIO;
2177 if (diag_query_pd_name(process_name, "sensor_pd"))
2178 return UPD_SENSORS;
2179
2180 return -EINVAL;
2181}
2182
2183/*
2184 * diag_ioctl_query_pd_logging(struct diag_logging_mode_param_t *param)
2185 *
2186 * IOCTL handler based on the parameter received will check on which peripheral
2187 * the PD is present and validate if the peripheral supports the diag_id and
2188 * tagging feature.
2189 *
2190 */
2191
Manoj Prabhu B571cf422017-08-08 19:01:41 +05302192static int diag_ioctl_query_pd_logging(struct diag_logging_mode_param_t *param)
2193{
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05302194 int ret = -EINVAL, i = 0;
2195 int peripheral = -EINVAL;
2196 uint32_t pd_mask = 0;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05302197
2198 if (!param)
2199 return -EINVAL;
2200
2201 if (!param->pd_mask) {
2202 DIAG_LOG(DIAG_DEBUG_USERSPACE,
2203 "query with no pd mask set, returning error\n");
2204 return -EINVAL;
2205 }
2206
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05302207 if (param->pd_mask) {
2208 pd_mask = diag_translate_mask(param->pd_mask);
2209 for (i = UPD_WLAN; i < NUM_MD_SESSIONS; i++) {
2210 if (pd_mask & (1 << i)) {
2211 peripheral = diag_search_peripheral_by_pd(i);
2212 break;
2213 }
2214 }
2215 if (peripheral < 0) {
2216 DIAG_LOG(DIAG_DEBUG_USERSPACE,
2217 "diag_id support is not present for the pd mask = %d\n",
2218 param->pd_mask);
2219 return -EINVAL;
2220 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +05302221 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +05302222 mutex_lock(&driver->diag_cntl_mutex);
2223 DIAG_LOG(DIAG_DEBUG_USERSPACE,
2224 "diag: %s: Untagging support on APPS is %s\n", __func__,
2225 ((driver->supports_apps_header_untagging) ?
2226 "present" : "absent"));
2227
2228 DIAG_LOG(DIAG_DEBUG_USERSPACE,
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05302229 "diag: %s: Tagging support on peripheral = %d is %s\n",
2230 __func__, peripheral,
Manoj Prabhu B571cf422017-08-08 19:01:41 +05302231 (driver->feature[peripheral].untag_header ?
2232 "present" : "absent"));
2233
2234 if (driver->supports_apps_header_untagging &&
2235 driver->feature[peripheral].untag_header)
2236 ret = 0;
2237
2238 mutex_unlock(&driver->diag_cntl_mutex);
2239 return ret;
2240}
2241
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002242static int diag_ioctl_register_callback(unsigned long ioarg)
2243{
2244 int err = 0;
2245 struct diag_callback_reg_t reg;
2246
2247 if (copy_from_user(&reg, (void __user *)ioarg,
2248 sizeof(struct diag_callback_reg_t))) {
2249 return -EFAULT;
2250 }
2251
2252 if (reg.proc < 0 || reg.proc >= DIAG_NUM_PROC) {
2253 pr_err("diag: In %s, invalid proc %d for callback registration\n",
2254 __func__, reg.proc);
2255 return -EINVAL;
2256 }
2257
2258 if (driver->md_session_mode == DIAG_MD_PERIPHERAL)
2259 return -EIO;
2260
2261 return err;
2262}
2263
2264static int diag_cmd_register_tbl(struct diag_cmd_reg_tbl_t *reg_tbl)
2265{
2266 int i;
2267 int err = 0;
2268 uint32_t count = 0;
2269 struct diag_cmd_reg_entry_t *entries = NULL;
2270 const uint16_t entry_len = sizeof(struct diag_cmd_reg_entry_t);
2271
2272
2273 if (!reg_tbl) {
2274 pr_err("diag: In %s, invalid registration table\n", __func__);
2275 return -EINVAL;
2276 }
2277
2278 count = reg_tbl->count;
2279 if ((UINT_MAX / entry_len) < count) {
2280 pr_warn("diag: In %s, possbile integer overflow.\n", __func__);
2281 return -EFAULT;
2282 }
2283
2284 entries = kzalloc(count * entry_len, GFP_KERNEL);
2285 if (!entries)
2286 return -ENOMEM;
2287
2288
2289 err = copy_from_user(entries, reg_tbl->entries, count * entry_len);
2290 if (err) {
2291 pr_err("diag: In %s, error copying data from userspace, err: %d\n",
2292 __func__, err);
2293 kfree(entries);
2294 return -EFAULT;
2295 }
2296
2297 for (i = 0; i < count; i++) {
2298 err = diag_cmd_add_reg(&entries[i], APPS_DATA, current->tgid);
2299 if (err) {
2300 pr_err("diag: In %s, unable to register command, err: %d\n",
2301 __func__, err);
2302 break;
2303 }
2304 }
2305
2306 kfree(entries);
2307 return err;
2308}
2309
2310static int diag_ioctl_cmd_reg(unsigned long ioarg)
2311{
2312 struct diag_cmd_reg_tbl_t reg_tbl;
2313
2314 if (copy_from_user(&reg_tbl, (void __user *)ioarg,
2315 sizeof(struct diag_cmd_reg_tbl_t))) {
2316 return -EFAULT;
2317 }
2318
2319 return diag_cmd_register_tbl(&reg_tbl);
2320}
2321
2322static int diag_ioctl_cmd_dereg(void)
2323{
2324 diag_cmd_remove_reg_by_pid(current->tgid);
2325 return 0;
2326}
2327
2328#ifdef CONFIG_COMPAT
2329/*
2330 * @sync_obj_name: name of the synchronization object associated with this proc
2331 * @count: number of entries in the bind
2332 * @params: the actual packet registrations
2333 */
2334struct diag_cmd_reg_tbl_compat_t {
2335 char sync_obj_name[MAX_SYNC_OBJ_NAME_SIZE];
2336 uint32_t count;
2337 compat_uptr_t entries;
2338};
2339
2340static int diag_ioctl_cmd_reg_compat(unsigned long ioarg)
2341{
2342 struct diag_cmd_reg_tbl_compat_t reg_tbl_compat;
2343 struct diag_cmd_reg_tbl_t reg_tbl;
2344
2345 if (copy_from_user(&reg_tbl_compat, (void __user *)ioarg,
2346 sizeof(struct diag_cmd_reg_tbl_compat_t))) {
2347 return -EFAULT;
2348 }
2349
2350 strlcpy(reg_tbl.sync_obj_name, reg_tbl_compat.sync_obj_name,
2351 MAX_SYNC_OBJ_NAME_SIZE);
2352 reg_tbl.count = reg_tbl_compat.count;
2353 reg_tbl.entries = (struct diag_cmd_reg_entry_t *)
2354 (uintptr_t)reg_tbl_compat.entries;
2355
2356 return diag_cmd_register_tbl(&reg_tbl);
2357}
2358
2359long diagchar_compat_ioctl(struct file *filp,
2360 unsigned int iocmd, unsigned long ioarg)
2361{
2362 int result = -EINVAL;
2363 int client_id = 0;
2364 uint16_t delayed_rsp_id = 0;
2365 uint16_t remote_dev;
2366 struct diag_dci_client_tbl *dci_client = NULL;
2367 struct diag_logging_mode_param_t mode_param;
2368
2369 switch (iocmd) {
2370 case DIAG_IOCTL_COMMAND_REG:
2371 result = diag_ioctl_cmd_reg_compat(ioarg);
2372 break;
2373 case DIAG_IOCTL_COMMAND_DEREG:
2374 result = diag_ioctl_cmd_dereg();
2375 break;
2376 case DIAG_IOCTL_GET_DELAYED_RSP_ID:
2377 delayed_rsp_id = diag_get_next_delayed_rsp_id();
2378 if (copy_to_user((void __user *)ioarg, &delayed_rsp_id,
2379 sizeof(uint16_t)))
2380 result = -EFAULT;
2381 else
2382 result = 0;
2383 break;
2384 case DIAG_IOCTL_DCI_REG:
2385 result = diag_ioctl_dci_reg(ioarg);
2386 break;
2387 case DIAG_IOCTL_DCI_DEINIT:
2388 mutex_lock(&driver->dci_mutex);
2389 if (copy_from_user((void *)&client_id, (void __user *)ioarg,
2390 sizeof(int))) {
2391 mutex_unlock(&driver->dci_mutex);
2392 return -EFAULT;
2393 }
2394 dci_client = diag_dci_get_client_entry(client_id);
2395 if (!dci_client) {
2396 mutex_unlock(&driver->dci_mutex);
2397 return DIAG_DCI_NOT_SUPPORTED;
2398 }
2399 result = diag_dci_deinit_client(dci_client);
2400 mutex_unlock(&driver->dci_mutex);
2401 break;
2402 case DIAG_IOCTL_DCI_SUPPORT:
2403 result = diag_ioctl_dci_support(ioarg);
2404 break;
2405 case DIAG_IOCTL_DCI_HEALTH_STATS:
2406 mutex_lock(&driver->dci_mutex);
2407 result = diag_ioctl_dci_health_stats(ioarg);
2408 mutex_unlock(&driver->dci_mutex);
2409 break;
2410 case DIAG_IOCTL_DCI_LOG_STATUS:
2411 mutex_lock(&driver->dci_mutex);
2412 result = diag_ioctl_dci_log_status(ioarg);
2413 mutex_unlock(&driver->dci_mutex);
2414 break;
2415 case DIAG_IOCTL_DCI_EVENT_STATUS:
2416 mutex_lock(&driver->dci_mutex);
2417 result = diag_ioctl_dci_event_status(ioarg);
2418 mutex_unlock(&driver->dci_mutex);
2419 break;
2420 case DIAG_IOCTL_DCI_CLEAR_LOGS:
2421 mutex_lock(&driver->dci_mutex);
2422 if (copy_from_user((void *)&client_id, (void __user *)ioarg,
2423 sizeof(int))) {
2424 mutex_unlock(&driver->dci_mutex);
2425 return -EFAULT;
2426 }
2427 result = diag_dci_clear_log_mask(client_id);
2428 mutex_unlock(&driver->dci_mutex);
2429 break;
2430 case DIAG_IOCTL_DCI_CLEAR_EVENTS:
2431 mutex_lock(&driver->dci_mutex);
2432 if (copy_from_user(&client_id, (void __user *)ioarg,
2433 sizeof(int))) {
2434 mutex_unlock(&driver->dci_mutex);
2435 return -EFAULT;
2436 }
2437 result = diag_dci_clear_event_mask(client_id);
2438 mutex_unlock(&driver->dci_mutex);
2439 break;
2440 case DIAG_IOCTL_LSM_DEINIT:
2441 result = diag_ioctl_lsm_deinit();
2442 break;
2443 case DIAG_IOCTL_SWITCH_LOGGING:
2444 if (copy_from_user((void *)&mode_param, (void __user *)ioarg,
2445 sizeof(mode_param)))
2446 return -EFAULT;
2447 mutex_lock(&driver->diagchar_mutex);
2448 result = diag_switch_logging(&mode_param);
2449 mutex_unlock(&driver->diagchar_mutex);
2450 break;
2451 case DIAG_IOCTL_REMOTE_DEV:
2452 remote_dev = diag_get_remote_device_mask();
2453 if (copy_to_user((void __user *)ioarg, &remote_dev,
2454 sizeof(uint16_t)))
2455 result = -EFAULT;
2456 else
2457 result = 1;
2458 break;
2459 case DIAG_IOCTL_VOTE_REAL_TIME:
2460 mutex_lock(&driver->dci_mutex);
2461 result = diag_ioctl_vote_real_time(ioarg);
2462 mutex_unlock(&driver->dci_mutex);
2463 break;
2464 case DIAG_IOCTL_GET_REAL_TIME:
2465 result = diag_ioctl_get_real_time(ioarg);
2466 break;
2467 case DIAG_IOCTL_PERIPHERAL_BUF_CONFIG:
2468 result = diag_ioctl_set_buffering_mode(ioarg);
2469 break;
2470 case DIAG_IOCTL_PERIPHERAL_BUF_DRAIN:
2471 result = diag_ioctl_peripheral_drain_immediate(ioarg);
2472 break;
2473 case DIAG_IOCTL_REGISTER_CALLBACK:
2474 result = diag_ioctl_register_callback(ioarg);
2475 break;
2476 case DIAG_IOCTL_HDLC_TOGGLE:
2477 result = diag_ioctl_hdlc_toggle(ioarg);
2478 break;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05302479 case DIAG_IOCTL_QUERY_PD_LOGGING:
2480 if (copy_from_user((void *)&mode_param, (void __user *)ioarg,
2481 sizeof(mode_param)))
2482 return -EFAULT;
2483 result = diag_ioctl_query_pd_logging(&mode_param);
2484 break;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002485 }
2486 return result;
2487}
2488#endif
2489
2490long diagchar_ioctl(struct file *filp,
2491 unsigned int iocmd, unsigned long ioarg)
2492{
2493 int result = -EINVAL;
2494 int client_id = 0;
2495 uint16_t delayed_rsp_id;
2496 uint16_t remote_dev;
2497 struct diag_dci_client_tbl *dci_client = NULL;
2498 struct diag_logging_mode_param_t mode_param;
2499
2500 switch (iocmd) {
2501 case DIAG_IOCTL_COMMAND_REG:
2502 result = diag_ioctl_cmd_reg(ioarg);
2503 break;
2504 case DIAG_IOCTL_COMMAND_DEREG:
2505 result = diag_ioctl_cmd_dereg();
2506 break;
2507 case DIAG_IOCTL_GET_DELAYED_RSP_ID:
2508 delayed_rsp_id = diag_get_next_delayed_rsp_id();
2509 if (copy_to_user((void __user *)ioarg, &delayed_rsp_id,
2510 sizeof(uint16_t)))
2511 result = -EFAULT;
2512 else
2513 result = 0;
2514 break;
2515 case DIAG_IOCTL_DCI_REG:
2516 result = diag_ioctl_dci_reg(ioarg);
2517 break;
2518 case DIAG_IOCTL_DCI_DEINIT:
2519 mutex_lock(&driver->dci_mutex);
2520 if (copy_from_user((void *)&client_id, (void __user *)ioarg,
2521 sizeof(int))) {
2522 mutex_unlock(&driver->dci_mutex);
2523 return -EFAULT;
2524 }
2525 dci_client = diag_dci_get_client_entry(client_id);
2526 if (!dci_client) {
2527 mutex_unlock(&driver->dci_mutex);
2528 return DIAG_DCI_NOT_SUPPORTED;
2529 }
2530 result = diag_dci_deinit_client(dci_client);
2531 mutex_unlock(&driver->dci_mutex);
2532 break;
2533 case DIAG_IOCTL_DCI_SUPPORT:
2534 result = diag_ioctl_dci_support(ioarg);
2535 break;
2536 case DIAG_IOCTL_DCI_HEALTH_STATS:
2537 mutex_lock(&driver->dci_mutex);
2538 result = diag_ioctl_dci_health_stats(ioarg);
2539 mutex_unlock(&driver->dci_mutex);
2540 break;
2541 case DIAG_IOCTL_DCI_LOG_STATUS:
2542 mutex_lock(&driver->dci_mutex);
2543 result = diag_ioctl_dci_log_status(ioarg);
2544 mutex_unlock(&driver->dci_mutex);
2545 break;
2546 case DIAG_IOCTL_DCI_EVENT_STATUS:
Mohit Aggarwal91199ae2017-04-22 10:49:18 +05302547 mutex_lock(&driver->dci_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002548 result = diag_ioctl_dci_event_status(ioarg);
Mohit Aggarwal91199ae2017-04-22 10:49:18 +05302549 mutex_unlock(&driver->dci_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002550 break;
2551 case DIAG_IOCTL_DCI_CLEAR_LOGS:
2552 mutex_lock(&driver->dci_mutex);
2553 if (copy_from_user((void *)&client_id, (void __user *)ioarg,
2554 sizeof(int))) {
2555 mutex_unlock(&driver->dci_mutex);
2556 return -EFAULT;
2557 }
2558 result = diag_dci_clear_log_mask(client_id);
2559 mutex_unlock(&driver->dci_mutex);
2560 break;
2561 case DIAG_IOCTL_DCI_CLEAR_EVENTS:
2562 mutex_lock(&driver->dci_mutex);
2563 if (copy_from_user(&client_id, (void __user *)ioarg,
2564 sizeof(int))) {
2565 mutex_unlock(&driver->dci_mutex);
2566 return -EFAULT;
2567 }
2568 result = diag_dci_clear_event_mask(client_id);
2569 mutex_unlock(&driver->dci_mutex);
2570 break;
2571 case DIAG_IOCTL_LSM_DEINIT:
2572 result = diag_ioctl_lsm_deinit();
2573 break;
2574 case DIAG_IOCTL_SWITCH_LOGGING:
2575 if (copy_from_user((void *)&mode_param, (void __user *)ioarg,
2576 sizeof(mode_param)))
2577 return -EFAULT;
2578 mutex_lock(&driver->diagchar_mutex);
2579 result = diag_switch_logging(&mode_param);
2580 mutex_unlock(&driver->diagchar_mutex);
2581 break;
2582 case DIAG_IOCTL_REMOTE_DEV:
2583 remote_dev = diag_get_remote_device_mask();
2584 if (copy_to_user((void __user *)ioarg, &remote_dev,
2585 sizeof(uint16_t)))
2586 result = -EFAULT;
2587 else
2588 result = 1;
2589 break;
2590 case DIAG_IOCTL_VOTE_REAL_TIME:
2591 mutex_lock(&driver->dci_mutex);
2592 result = diag_ioctl_vote_real_time(ioarg);
2593 mutex_unlock(&driver->dci_mutex);
2594 break;
2595 case DIAG_IOCTL_GET_REAL_TIME:
2596 result = diag_ioctl_get_real_time(ioarg);
2597 break;
2598 case DIAG_IOCTL_PERIPHERAL_BUF_CONFIG:
2599 result = diag_ioctl_set_buffering_mode(ioarg);
2600 break;
2601 case DIAG_IOCTL_PERIPHERAL_BUF_DRAIN:
2602 result = diag_ioctl_peripheral_drain_immediate(ioarg);
2603 break;
2604 case DIAG_IOCTL_REGISTER_CALLBACK:
2605 result = diag_ioctl_register_callback(ioarg);
2606 break;
2607 case DIAG_IOCTL_HDLC_TOGGLE:
2608 result = diag_ioctl_hdlc_toggle(ioarg);
2609 break;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05302610 case DIAG_IOCTL_QUERY_PD_LOGGING:
2611 if (copy_from_user((void *)&mode_param, (void __user *)ioarg,
2612 sizeof(mode_param)))
2613 return -EFAULT;
2614 result = diag_ioctl_query_pd_logging(&mode_param);
2615 break;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002616 }
2617 return result;
2618}
2619
2620static int diag_process_apps_data_hdlc(unsigned char *buf, int len,
2621 int pkt_type)
2622{
2623 int err = 0;
2624 int ret = PKT_DROP;
2625 struct diag_apps_data_t *data = &hdlc_data;
2626 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
2627 struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
2628 /*
2629 * The maximum encoded size of the buffer can be atmost twice the length
2630 * of the packet. Add three bytes foe footer - 16 bit CRC (2 bytes) +
2631 * delimiter (1 byte).
2632 */
2633 const uint32_t max_encoded_size = ((2 * len) + 3);
2634
2635 if (!buf || len <= 0) {
2636 pr_err("diag: In %s, invalid buf: %pK len: %d\n",
2637 __func__, buf, len);
2638 return -EIO;
2639 }
2640
2641 if (max_encoded_size > DIAG_MAX_HDLC_BUF_SIZE) {
2642 pr_err_ratelimited("diag: In %s, encoded data is larger %d than the buffer size %d\n",
2643 __func__, max_encoded_size, DIAG_MAX_HDLC_BUF_SIZE);
2644 return -EBADMSG;
2645 }
2646
2647 send.state = DIAG_STATE_START;
2648 send.pkt = buf;
2649 send.last = (void *)(buf + len - 1);
2650 send.terminate = 1;
2651
2652 if (!data->buf)
2653 data->buf = diagmem_alloc(driver, DIAG_MAX_HDLC_BUF_SIZE +
2654 APF_DIAG_PADDING,
2655 POOL_TYPE_HDLC);
2656 if (!data->buf) {
2657 ret = PKT_DROP;
2658 goto fail_ret;
2659 }
2660
2661 if ((DIAG_MAX_HDLC_BUF_SIZE - data->len) <= max_encoded_size) {
2662 err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len,
2663 data->ctxt);
2664 if (err) {
2665 ret = -EIO;
2666 goto fail_free_buf;
2667 }
2668 data->buf = NULL;
2669 data->len = 0;
2670 data->buf = diagmem_alloc(driver, DIAG_MAX_HDLC_BUF_SIZE +
2671 APF_DIAG_PADDING,
2672 POOL_TYPE_HDLC);
2673 if (!data->buf) {
2674 ret = PKT_DROP;
2675 goto fail_ret;
2676 }
2677 }
2678
2679 enc.dest = data->buf + data->len;
2680 enc.dest_last = (void *)(data->buf + data->len + max_encoded_size);
2681 diag_hdlc_encode(&send, &enc);
2682
2683 /*
2684 * This is to check if after HDLC encoding, we are still within
2685 * the limits of aggregation buffer. If not, we write out the
2686 * current buffer and start aggregation in a newly allocated
2687 * buffer.
2688 */
2689 if ((uintptr_t)enc.dest >= (uintptr_t)(data->buf +
2690 DIAG_MAX_HDLC_BUF_SIZE)) {
2691 err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len,
2692 data->ctxt);
2693 if (err) {
2694 ret = -EIO;
2695 goto fail_free_buf;
2696 }
2697 data->buf = NULL;
2698 data->len = 0;
2699 data->buf = diagmem_alloc(driver, DIAG_MAX_HDLC_BUF_SIZE +
2700 APF_DIAG_PADDING,
2701 POOL_TYPE_HDLC);
2702 if (!data->buf) {
2703 ret = PKT_DROP;
2704 goto fail_ret;
2705 }
2706
2707 enc.dest = data->buf + data->len;
2708 enc.dest_last = (void *)(data->buf + data->len +
2709 max_encoded_size);
2710 diag_hdlc_encode(&send, &enc);
2711 }
2712
2713 data->len = (((uintptr_t)enc.dest - (uintptr_t)data->buf) <
2714 DIAG_MAX_HDLC_BUF_SIZE) ?
2715 ((uintptr_t)enc.dest - (uintptr_t)data->buf) :
2716 DIAG_MAX_HDLC_BUF_SIZE;
2717
2718 if (pkt_type == DATA_TYPE_RESPONSE) {
2719 err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len,
2720 data->ctxt);
2721 if (err) {
2722 ret = -EIO;
2723 goto fail_free_buf;
2724 }
2725 data->buf = NULL;
2726 data->len = 0;
2727 }
2728
2729 return PKT_ALLOC;
2730
2731fail_free_buf:
2732 diagmem_free(driver, data->buf, POOL_TYPE_HDLC);
2733 data->buf = NULL;
2734 data->len = 0;
2735
2736fail_ret:
2737 return ret;
2738}
2739
2740static int diag_process_apps_data_non_hdlc(unsigned char *buf, int len,
2741 int pkt_type)
2742{
2743 int err = 0;
2744 int ret = PKT_DROP;
2745 struct diag_pkt_frame_t header;
2746 struct diag_apps_data_t *data = &non_hdlc_data;
2747 /*
2748 * The maximum packet size, when the data is non hdlc encoded is equal
2749 * to the size of the packet frame header and the length. Add 1 for the
2750 * delimiter 0x7E at the end.
2751 */
2752 const uint32_t max_pkt_size = sizeof(header) + len + 1;
2753
2754 if (!buf || len <= 0) {
2755 pr_err("diag: In %s, invalid buf: %pK len: %d\n",
2756 __func__, buf, len);
2757 return -EIO;
2758 }
2759
2760 if (!data->buf) {
2761 data->buf = diagmem_alloc(driver, DIAG_MAX_HDLC_BUF_SIZE +
2762 APF_DIAG_PADDING,
2763 POOL_TYPE_HDLC);
2764 if (!data->buf) {
2765 ret = PKT_DROP;
2766 goto fail_ret;
2767 }
2768 }
2769
2770 if ((DIAG_MAX_HDLC_BUF_SIZE - data->len) <= max_pkt_size) {
2771 err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len,
2772 data->ctxt);
2773 if (err) {
2774 ret = -EIO;
2775 goto fail_free_buf;
2776 }
2777 data->buf = NULL;
2778 data->len = 0;
2779 data->buf = diagmem_alloc(driver, DIAG_MAX_HDLC_BUF_SIZE +
2780 APF_DIAG_PADDING,
2781 POOL_TYPE_HDLC);
2782 if (!data->buf) {
2783 ret = PKT_DROP;
2784 goto fail_ret;
2785 }
2786 }
2787
2788 header.start = CONTROL_CHAR;
2789 header.version = 1;
2790 header.length = len;
2791 memcpy(data->buf + data->len, &header, sizeof(header));
2792 data->len += sizeof(header);
2793 memcpy(data->buf + data->len, buf, len);
2794 data->len += len;
2795 *(uint8_t *)(data->buf + data->len) = CONTROL_CHAR;
2796 data->len += sizeof(uint8_t);
2797 if (pkt_type == DATA_TYPE_RESPONSE) {
2798 err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len,
2799 data->ctxt);
2800 if (err) {
2801 ret = -EIO;
2802 goto fail_free_buf;
2803 }
2804 data->buf = NULL;
2805 data->len = 0;
2806 }
2807
2808 return PKT_ALLOC;
2809
2810fail_free_buf:
2811 diagmem_free(driver, data->buf, POOL_TYPE_HDLC);
2812 data->buf = NULL;
2813 data->len = 0;
2814
2815fail_ret:
2816 return ret;
2817}
2818
2819static int diag_user_process_dci_data(const char __user *buf, int len)
2820{
2821 int err = 0;
2822 const int mempool = POOL_TYPE_USER;
2823 unsigned char *user_space_data = NULL;
2824
2825 if (!buf || len <= 0 || len > diag_mempools[mempool].itemsize) {
2826 pr_err_ratelimited("diag: In %s, invalid buf %pK len: %d\n",
2827 __func__, buf, len);
2828 return -EBADMSG;
2829 }
2830
2831 user_space_data = diagmem_alloc(driver, len, mempool);
2832 if (!user_space_data)
2833 return -ENOMEM;
2834
2835 err = copy_from_user(user_space_data, buf, len);
2836 if (err) {
2837 pr_err_ratelimited("diag: In %s, unable to copy data from userspace, err: %d\n",
2838 __func__, err);
2839 err = DIAG_DCI_SEND_DATA_FAIL;
2840 goto fail;
2841 }
2842
2843 err = diag_process_dci_transaction(user_space_data, len);
2844fail:
2845 diagmem_free(driver, user_space_data, mempool);
2846 user_space_data = NULL;
2847 return err;
2848}
2849
2850static int diag_user_process_dci_apps_data(const char __user *buf, int len,
2851 int pkt_type)
2852{
2853 int err = 0;
2854 const int mempool = POOL_TYPE_COPY;
2855 unsigned char *user_space_data = NULL;
2856
2857 if (!buf || len <= 0 || len > diag_mempools[mempool].itemsize) {
2858 pr_err_ratelimited("diag: In %s, invalid buf %pK len: %d\n",
2859 __func__, buf, len);
2860 return -EBADMSG;
2861 }
2862
2863 pkt_type &= (DCI_PKT_TYPE | DATA_TYPE_DCI_LOG | DATA_TYPE_DCI_EVENT);
2864 if (!pkt_type) {
2865 pr_err_ratelimited("diag: In %s, invalid pkt_type: %d\n",
2866 __func__, pkt_type);
2867 return -EBADMSG;
2868 }
2869
2870 user_space_data = diagmem_alloc(driver, len, mempool);
2871 if (!user_space_data)
2872 return -ENOMEM;
2873
2874 err = copy_from_user(user_space_data, buf, len);
2875 if (err) {
2876 pr_alert("diag: In %s, unable to copy data from userspace, err: %d\n",
2877 __func__, err);
2878 goto fail;
2879 }
2880
2881 diag_process_apps_dci_read_data(pkt_type, user_space_data, len);
2882fail:
2883 diagmem_free(driver, user_space_data, mempool);
2884 user_space_data = NULL;
2885 return err;
2886}
2887
2888static int diag_user_process_raw_data(const char __user *buf, int len)
2889{
2890 int err = 0;
2891 int ret = 0;
2892 int token_offset = 0;
2893 int remote_proc = 0;
2894 const int mempool = POOL_TYPE_COPY;
2895 unsigned char *user_space_data = NULL;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002896
2897 if (!buf || len <= 0 || len > CALLBACK_BUF_SIZE) {
2898 pr_err_ratelimited("diag: In %s, invalid buf %pK len: %d\n",
2899 __func__, buf, len);
2900 return -EBADMSG;
2901 }
2902
2903 user_space_data = diagmem_alloc(driver, len, mempool);
2904 if (!user_space_data)
2905 return -ENOMEM;
2906
2907 err = copy_from_user(user_space_data, buf, len);
2908 if (err) {
2909 pr_err("diag: copy failed for user space data\n");
2910 goto fail;
2911 }
2912
2913 /* Check for proc_type */
2914 remote_proc = diag_get_remote(*(int *)user_space_data);
2915 if (remote_proc) {
2916 token_offset = sizeof(int);
2917 if (len <= MIN_SIZ_ALLOW) {
2918 pr_err("diag: In %s, possible integer underflow, payload size: %d\n",
2919 __func__, len);
2920 diagmem_free(driver, user_space_data, mempool);
2921 user_space_data = NULL;
2922 return -EBADMSG;
2923 }
2924 len -= sizeof(int);
2925 }
2926 if (driver->mask_check) {
2927 if (!mask_request_validate(user_space_data +
2928 token_offset)) {
2929 pr_alert("diag: mask request Invalid\n");
2930 diagmem_free(driver, user_space_data, mempool);
2931 user_space_data = NULL;
2932 return -EFAULT;
2933 }
2934 }
2935 if (remote_proc) {
2936 ret = diag_send_raw_data_remote(remote_proc,
2937 (void *)(user_space_data + token_offset),
2938 len, USER_SPACE_RAW_DATA);
2939 if (ret) {
2940 pr_err("diag: Error sending data to remote proc %d, err: %d\n",
2941 remote_proc, ret);
2942 }
2943 } else {
2944 wait_event_interruptible(driver->wait_q,
2945 (driver->in_busy_pktdata == 0));
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05302946 ret = diag_process_apps_pkt(user_space_data, len,
2947 current->tgid);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002948 if (ret == 1)
Chris Lewc937d692017-10-12 13:13:18 +05302949 diag_send_error_rsp((void *)(user_space_data), len,
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05302950 current->tgid);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07002951 }
2952fail:
2953 diagmem_free(driver, user_space_data, mempool);
2954 user_space_data = NULL;
2955 return ret;
2956}
2957
2958static int diag_user_process_userspace_data(const char __user *buf, int len)
2959{
2960 int err = 0;
2961 int max_retries = 3;
2962 int retry_count = 0;
2963 int remote_proc = 0;
2964 int token_offset = 0;
2965 struct diag_md_session_t *session_info = NULL;
2966 uint8_t hdlc_disabled;
2967
2968 if (!buf || len <= 0 || len > USER_SPACE_DATA) {
2969 pr_err_ratelimited("diag: In %s, invalid buf %pK len: %d\n",
2970 __func__, buf, len);
2971 return -EBADMSG;
2972 }
2973
2974 do {
2975 if (!driver->user_space_data_busy)
2976 break;
2977 retry_count++;
2978 usleep_range(10000, 10100);
2979 } while (retry_count < max_retries);
2980
2981 if (driver->user_space_data_busy)
2982 return -EAGAIN;
2983
2984 err = copy_from_user(driver->user_space_data_buf, buf, len);
2985 if (err) {
2986 pr_err("diag: In %s, failed to copy data from userspace, err: %d\n",
2987 __func__, err);
2988 return -EIO;
2989 }
2990
2991 /* Check for proc_type */
2992 remote_proc = diag_get_remote(*(int *)driver->user_space_data_buf);
2993 if (remote_proc) {
2994 if (len <= MIN_SIZ_ALLOW) {
2995 pr_err("diag: Integer underflow in %s, payload size: %d",
2996 __func__, len);
2997 return -EBADMSG;
2998 }
2999 token_offset = sizeof(int);
3000 len -= sizeof(int);
3001 }
3002
3003 /* Check masks for On-Device logging */
3004 if (driver->mask_check) {
3005 if (!mask_request_validate(driver->user_space_data_buf +
3006 token_offset)) {
3007 pr_alert("diag: mask request Invalid\n");
3008 return -EFAULT;
3009 }
3010 }
3011
3012 /* send masks to local processor now */
3013 if (!remote_proc) {
Manoj Prabhu B0130d0e2017-10-12 22:14:24 +05303014 mutex_lock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003015 session_info = diag_md_session_get_pid(current->tgid);
3016 if (!session_info) {
3017 pr_err("diag:In %s request came from invalid md session pid:%d",
3018 __func__, current->tgid);
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303019 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003020 return -EINVAL;
3021 }
3022 if (session_info)
3023 hdlc_disabled = session_info->hdlc_disabled;
3024 else
3025 hdlc_disabled = driver->hdlc_disabled;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303026 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003027 if (!hdlc_disabled)
3028 diag_process_hdlc_pkt((void *)
3029 (driver->user_space_data_buf),
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303030 len, current->tgid);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003031 else
3032 diag_process_non_hdlc_pkt((char *)
3033 (driver->user_space_data_buf),
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303034 len, current->tgid);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003035 return 0;
3036 }
3037
3038 err = diag_process_userspace_remote(remote_proc,
3039 driver->user_space_data_buf +
3040 token_offset, len);
3041 if (err) {
3042 driver->user_space_data_busy = 0;
3043 pr_err("diag: Error sending mask to remote proc %d, err: %d\n",
3044 remote_proc, err);
3045 }
3046
3047 return err;
3048}
3049
3050static int diag_user_process_apps_data(const char __user *buf, int len,
3051 int pkt_type)
3052{
3053 int ret = 0;
3054 int stm_size = 0;
3055 const int mempool = POOL_TYPE_COPY;
3056 unsigned char *user_space_data = NULL;
3057 struct diag_md_session_t *session_info = NULL;
3058 uint8_t hdlc_disabled;
3059
3060 if (!buf || len <= 0 || len > DIAG_MAX_RSP_SIZE) {
3061 pr_err_ratelimited("diag: In %s, invalid buf %pK len: %d\n",
3062 __func__, buf, len);
3063 return -EBADMSG;
3064 }
3065
3066 switch (pkt_type) {
3067 case DATA_TYPE_EVENT:
3068 case DATA_TYPE_F3:
3069 case DATA_TYPE_LOG:
3070 case DATA_TYPE_RESPONSE:
3071 case DATA_TYPE_DELAYED_RESPONSE:
3072 break;
3073 default:
3074 pr_err_ratelimited("diag: In %s, invalid pkt_type: %d\n",
3075 __func__, pkt_type);
3076 return -EBADMSG;
3077 }
3078
3079 user_space_data = diagmem_alloc(driver, len, mempool);
3080 if (!user_space_data) {
3081 diag_record_stats(pkt_type, PKT_DROP);
3082 return -ENOMEM;
3083 }
3084
3085 ret = copy_from_user(user_space_data, buf, len);
3086 if (ret) {
3087 pr_alert("diag: In %s, unable to copy data from userspace, err: %d\n",
3088 __func__, ret);
3089 diagmem_free(driver, user_space_data, mempool);
3090 user_space_data = NULL;
3091 diag_record_stats(pkt_type, PKT_DROP);
3092 return -EBADMSG;
3093 }
3094
3095 if (driver->stm_state[APPS_DATA] &&
3096 (pkt_type >= DATA_TYPE_EVENT) && (pkt_type <= DATA_TYPE_LOG)) {
3097 stm_size = stm_log_inv_ts(OST_ENTITY_DIAG, 0, user_space_data,
3098 len);
3099 if (stm_size == 0) {
3100 pr_debug("diag: In %s, stm_log_inv_ts returned size of 0\n",
3101 __func__);
3102 }
3103 diagmem_free(driver, user_space_data, mempool);
3104 user_space_data = NULL;
3105
3106 return 0;
3107 }
3108
3109 mutex_lock(&apps_data_mutex);
3110 mutex_lock(&driver->hdlc_disable_mutex);
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303111 mutex_lock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003112 session_info = diag_md_session_get_peripheral(APPS_DATA);
3113 if (session_info)
3114 hdlc_disabled = session_info->hdlc_disabled;
3115 else
3116 hdlc_disabled = driver->hdlc_disabled;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303117 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003118 if (hdlc_disabled)
3119 ret = diag_process_apps_data_non_hdlc(user_space_data, len,
3120 pkt_type);
3121 else
3122 ret = diag_process_apps_data_hdlc(user_space_data, len,
3123 pkt_type);
3124 mutex_unlock(&driver->hdlc_disable_mutex);
3125 mutex_unlock(&apps_data_mutex);
3126
3127 diagmem_free(driver, user_space_data, mempool);
3128 user_space_data = NULL;
3129
3130 check_drain_timer();
3131
3132 if (ret == PKT_DROP)
3133 diag_record_stats(pkt_type, PKT_DROP);
3134 else if (ret == PKT_ALLOC)
3135 diag_record_stats(pkt_type, PKT_ALLOC);
3136 else
3137 return ret;
3138
3139 return 0;
3140}
3141
3142static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count,
3143 loff_t *ppos)
3144{
3145 struct diag_dci_client_tbl *entry;
3146 struct list_head *start, *temp;
3147 int index = -1, i = 0, ret = 0;
3148 int data_type;
3149 int copy_dci_data = 0;
3150 int exit_stat = 0;
3151 int write_len = 0;
3152 struct diag_md_session_t *session_info = NULL;
3153
Mohit Aggarwal99a06732017-07-28 15:40:27 +05303154 mutex_lock(&driver->diagchar_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003155 for (i = 0; i < driver->num_clients; i++)
3156 if (driver->client_map[i].pid == current->tgid)
3157 index = i;
Mohit Aggarwal99a06732017-07-28 15:40:27 +05303158 mutex_unlock(&driver->diagchar_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003159
3160 if (index == -1) {
3161 pr_err("diag: Client PID not found in table");
3162 return -EINVAL;
3163 }
3164 if (!buf) {
3165 pr_err("diag: bad address from user side\n");
3166 return -EFAULT;
3167 }
Mohit Aggarwalb8474a42017-10-12 14:22:05 +05303168 wait_event_interruptible(driver->wait_q,
3169 atomic_read(&driver->data_ready_notif[index]) > 0);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003170
3171 mutex_lock(&driver->diagchar_mutex);
3172
3173 if ((driver->data_ready[index] & USER_SPACE_DATA_TYPE) &&
3174 (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE ||
3175 driver->logging_mode == DIAG_MULTI_MODE)) {
3176 pr_debug("diag: process woken up\n");
3177 /*Copy the type of data being passed*/
3178 data_type = driver->data_ready[index] & USER_SPACE_DATA_TYPE;
3179 driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +05303180 atomic_dec(&driver->data_ready_notif[index]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003181 COPY_USER_SPACE_OR_ERR(buf, data_type, sizeof(int));
3182 if (ret == -EFAULT)
3183 goto exit;
3184 /* place holder for number of data field */
3185 ret += sizeof(int);
Manoj Prabhu B0130d0e2017-10-12 22:14:24 +05303186 mutex_lock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003187 session_info = diag_md_session_get_pid(current->tgid);
3188 exit_stat = diag_md_copy_to_user(buf, &ret, count,
3189 session_info);
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303190 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003191 goto exit;
3192 } else if (driver->data_ready[index] & USER_SPACE_DATA_TYPE) {
3193 /* In case, the thread wakes up and the logging mode is not
3194 * memory device any more, the condition needs to be cleared.
3195 */
3196 driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +05303197 atomic_dec(&driver->data_ready_notif[index]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003198 }
3199
3200 if (driver->data_ready[index] & HDLC_SUPPORT_TYPE) {
3201 data_type = driver->data_ready[index] & HDLC_SUPPORT_TYPE;
3202 driver->data_ready[index] ^= HDLC_SUPPORT_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +05303203 atomic_dec(&driver->data_ready_notif[index]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003204 COPY_USER_SPACE_OR_ERR(buf, data_type, sizeof(int));
3205 if (ret == -EFAULT)
3206 goto exit;
3207
Manoj Prabhu B0130d0e2017-10-12 22:14:24 +05303208 mutex_lock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003209 session_info = diag_md_session_get_pid(current->tgid);
3210 if (session_info) {
3211 COPY_USER_SPACE_OR_ERR(buf+4,
3212 session_info->hdlc_disabled,
3213 sizeof(uint8_t));
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303214 if (ret == -EFAULT) {
3215 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003216 goto exit;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303217 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003218 }
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303219 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003220 goto exit;
3221 }
3222
3223 if (driver->data_ready[index] & DEINIT_TYPE) {
3224 /*Copy the type of data being passed*/
3225 data_type = driver->data_ready[index] & DEINIT_TYPE;
3226 COPY_USER_SPACE_OR_ERR(buf, data_type, 4);
3227 if (ret == -EFAULT)
3228 goto exit;
3229 driver->data_ready[index] ^= DEINIT_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +05303230 atomic_dec(&driver->data_ready_notif[index]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003231 mutex_unlock(&driver->diagchar_mutex);
3232 diag_remove_client_entry(file);
3233 return ret;
3234 }
3235
3236 if (driver->data_ready[index] & MSG_MASKS_TYPE) {
3237 /*Copy the type of data being passed*/
3238 data_type = driver->data_ready[index] & MSG_MASKS_TYPE;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303239 mutex_lock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003240 session_info = diag_md_session_get_peripheral(APPS_DATA);
3241 COPY_USER_SPACE_OR_ERR(buf, data_type, sizeof(int));
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303242 if (ret == -EFAULT) {
3243 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003244 goto exit;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303245 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003246 write_len = diag_copy_to_user_msg_mask(buf + ret, count,
3247 session_info);
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303248 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003249 if (write_len > 0)
3250 ret += write_len;
3251 driver->data_ready[index] ^= MSG_MASKS_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +05303252 atomic_dec(&driver->data_ready_notif[index]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003253 goto exit;
3254 }
3255
3256 if (driver->data_ready[index] & EVENT_MASKS_TYPE) {
3257 /*Copy the type of data being passed*/
3258 data_type = driver->data_ready[index] & EVENT_MASKS_TYPE;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303259 mutex_lock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003260 session_info = diag_md_session_get_peripheral(APPS_DATA);
3261 COPY_USER_SPACE_OR_ERR(buf, data_type, 4);
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303262 if (ret == -EFAULT) {
3263 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003264 goto exit;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303265 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003266 if (session_info && session_info->event_mask &&
3267 session_info->event_mask->ptr) {
3268 COPY_USER_SPACE_OR_ERR(buf + sizeof(int),
3269 *(session_info->event_mask->ptr),
3270 session_info->event_mask->mask_len);
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303271 if (ret == -EFAULT) {
3272 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003273 goto exit;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303274 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003275 } else {
3276 COPY_USER_SPACE_OR_ERR(buf + sizeof(int),
3277 *(event_mask.ptr),
3278 event_mask.mask_len);
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303279 if (ret == -EFAULT) {
3280 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003281 goto exit;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303282 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003283 }
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303284 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003285 driver->data_ready[index] ^= EVENT_MASKS_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +05303286 atomic_dec(&driver->data_ready_notif[index]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003287 goto exit;
3288 }
3289
3290 if (driver->data_ready[index] & LOG_MASKS_TYPE) {
3291 /*Copy the type of data being passed*/
3292 data_type = driver->data_ready[index] & LOG_MASKS_TYPE;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303293 mutex_lock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003294 session_info = diag_md_session_get_peripheral(APPS_DATA);
3295 COPY_USER_SPACE_OR_ERR(buf, data_type, sizeof(int));
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303296 if (ret == -EFAULT) {
3297 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003298 goto exit;
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303299 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003300
3301 write_len = diag_copy_to_user_log_mask(buf + ret, count,
3302 session_info);
Hardik Aryadbb1c2a2017-11-10 16:29:16 +05303303 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003304 if (write_len > 0)
3305 ret += write_len;
3306 driver->data_ready[index] ^= LOG_MASKS_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +05303307 atomic_dec(&driver->data_ready_notif[index]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003308 goto exit;
3309 }
3310
3311 if (driver->data_ready[index] & PKT_TYPE) {
3312 /*Copy the type of data being passed*/
3313 data_type = driver->data_ready[index] & PKT_TYPE;
3314 COPY_USER_SPACE_OR_ERR(buf, data_type, sizeof(data_type));
3315 if (ret == -EFAULT)
3316 goto exit;
3317
3318 COPY_USER_SPACE_OR_ERR(buf + sizeof(data_type),
3319 *(driver->apps_req_buf),
3320 driver->apps_req_buf_len);
3321 if (ret == -EFAULT)
3322 goto exit;
3323 driver->data_ready[index] ^= PKT_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +05303324 atomic_dec(&driver->data_ready_notif[index]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003325 driver->in_busy_pktdata = 0;
3326 goto exit;
3327 }
3328
3329 if (driver->data_ready[index] & DCI_PKT_TYPE) {
3330 /* Copy the type of data being passed */
3331 data_type = driver->data_ready[index] & DCI_PKT_TYPE;
3332 COPY_USER_SPACE_OR_ERR(buf, data_type, 4);
3333 if (ret == -EFAULT)
3334 goto exit;
3335
3336 COPY_USER_SPACE_OR_ERR(buf+4, *(driver->dci_pkt_buf),
3337 driver->dci_pkt_length);
3338 if (ret == -EFAULT)
3339 goto exit;
3340
3341 driver->data_ready[index] ^= DCI_PKT_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +05303342 atomic_dec(&driver->data_ready_notif[index]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003343 driver->in_busy_dcipktdata = 0;
3344 goto exit;
3345 }
3346
3347 if (driver->data_ready[index] & DCI_EVENT_MASKS_TYPE) {
3348 /*Copy the type of data being passed*/
3349 data_type = driver->data_ready[index] & DCI_EVENT_MASKS_TYPE;
3350 COPY_USER_SPACE_OR_ERR(buf, data_type, 4);
3351 if (ret == -EFAULT)
3352 goto exit;
3353
3354 COPY_USER_SPACE_OR_ERR(buf+4, driver->num_dci_client, 4);
3355 if (ret == -EFAULT)
3356 goto exit;
3357
3358 COPY_USER_SPACE_OR_ERR(buf + 8, (dci_ops_tbl[DCI_LOCAL_PROC].
3359 event_mask_composite), DCI_EVENT_MASK_SIZE);
3360 if (ret == -EFAULT)
3361 goto exit;
3362
3363 driver->data_ready[index] ^= DCI_EVENT_MASKS_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +05303364 atomic_dec(&driver->data_ready_notif[index]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003365 goto exit;
3366 }
3367
3368 if (driver->data_ready[index] & DCI_LOG_MASKS_TYPE) {
3369 /*Copy the type of data being passed*/
3370 data_type = driver->data_ready[index] & DCI_LOG_MASKS_TYPE;
3371 COPY_USER_SPACE_OR_ERR(buf, data_type, 4);
3372 if (ret == -EFAULT)
3373 goto exit;
3374
3375 COPY_USER_SPACE_OR_ERR(buf+4, driver->num_dci_client, 4);
3376 if (ret == -EFAULT)
3377 goto exit;
3378
3379 COPY_USER_SPACE_OR_ERR(buf+8, (dci_ops_tbl[DCI_LOCAL_PROC].
3380 log_mask_composite), DCI_LOG_MASK_SIZE);
3381 if (ret == -EFAULT)
3382 goto exit;
3383 driver->data_ready[index] ^= DCI_LOG_MASKS_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +05303384 atomic_dec(&driver->data_ready_notif[index]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003385 goto exit;
3386 }
3387
3388exit:
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003389 if (driver->data_ready[index] & DCI_DATA_TYPE) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003390 data_type = driver->data_ready[index] & DCI_DATA_TYPE;
Mohit Aggarwal99a06732017-07-28 15:40:27 +05303391 mutex_unlock(&driver->diagchar_mutex);
3392 /* Copy the type of data being passed */
3393 mutex_lock(&driver->dci_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003394 list_for_each_safe(start, temp, &driver->dci_client_list) {
3395 entry = list_entry(start, struct diag_dci_client_tbl,
3396 track);
3397 if (entry->client->tgid != current->tgid)
3398 continue;
3399 if (!entry->in_service)
3400 continue;
3401 if (copy_to_user(buf + ret, &data_type, sizeof(int))) {
3402 mutex_unlock(&driver->dci_mutex);
3403 goto end;
3404 }
3405 ret += sizeof(int);
3406 if (copy_to_user(buf + ret, &entry->client_info.token,
3407 sizeof(int))) {
3408 mutex_unlock(&driver->dci_mutex);
3409 goto end;
3410 }
3411 ret += sizeof(int);
3412 copy_dci_data = 1;
3413 exit_stat = diag_copy_dci(buf, count, entry, &ret);
3414 mutex_lock(&driver->diagchar_mutex);
3415 driver->data_ready[index] ^= DCI_DATA_TYPE;
Mohit Aggarwalb8474a42017-10-12 14:22:05 +05303416 atomic_dec(&driver->data_ready_notif[index]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003417 mutex_unlock(&driver->diagchar_mutex);
3418 if (exit_stat == 1) {
3419 mutex_unlock(&driver->dci_mutex);
3420 goto end;
3421 }
3422 }
3423 mutex_unlock(&driver->dci_mutex);
3424 goto end;
3425 }
Mohit Aggarwal99a06732017-07-28 15:40:27 +05303426 mutex_unlock(&driver->diagchar_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003427end:
3428 /*
3429 * Flush any read that is currently pending on DCI data and
3430 * command channnels. This will ensure that the next read is not
3431 * missed.
3432 */
3433 if (copy_dci_data) {
3434 diag_ws_on_copy_complete(DIAG_WS_DCI);
3435 flush_workqueue(driver->diag_dci_wq);
3436 }
3437 return ret;
3438}
3439
3440static ssize_t diagchar_write(struct file *file, const char __user *buf,
3441 size_t count, loff_t *ppos)
3442{
3443 int err = 0;
3444 int pkt_type = 0;
3445 int payload_len = 0;
3446 const char __user *payload_buf = NULL;
3447
3448 /*
3449 * The data coming from the user sapce should at least have the
3450 * packet type heeader.
3451 */
3452 if (count < sizeof(int)) {
3453 pr_err("diag: In %s, client is sending short data, len: %d\n",
3454 __func__, (int)count);
3455 return -EBADMSG;
3456 }
3457
3458 err = copy_from_user((&pkt_type), buf, sizeof(int));
3459 if (err) {
3460 pr_err_ratelimited("diag: In %s, unable to copy pkt_type from userspace, err: %d\n",
3461 __func__, err);
3462 return -EIO;
3463 }
3464
3465 if (driver->logging_mode == DIAG_USB_MODE && !driver->usb_connected) {
3466 if (!((pkt_type == DCI_DATA_TYPE) ||
3467 (pkt_type == DCI_PKT_TYPE) ||
3468 (pkt_type & DATA_TYPE_DCI_LOG) ||
3469 (pkt_type & DATA_TYPE_DCI_EVENT))) {
3470 pr_debug("diag: In %s, Dropping non DCI packet type\n",
3471 __func__);
3472 return -EIO;
3473 }
3474 }
3475
3476 payload_buf = buf + sizeof(int);
3477 payload_len = count - sizeof(int);
3478
3479 if (pkt_type == DCI_PKT_TYPE)
3480 return diag_user_process_dci_apps_data(payload_buf,
3481 payload_len,
3482 pkt_type);
3483 else if (pkt_type == DCI_DATA_TYPE)
3484 return diag_user_process_dci_data(payload_buf, payload_len);
3485 else if (pkt_type == USER_SPACE_RAW_DATA_TYPE)
3486 return diag_user_process_raw_data(payload_buf,
3487 payload_len);
3488 else if (pkt_type == USER_SPACE_DATA_TYPE)
3489 return diag_user_process_userspace_data(payload_buf,
3490 payload_len);
3491 if (pkt_type & (DATA_TYPE_DCI_LOG | DATA_TYPE_DCI_EVENT)) {
3492 err = diag_user_process_dci_apps_data(payload_buf, payload_len,
3493 pkt_type);
3494 if (pkt_type & DATA_TYPE_DCI_LOG)
3495 pkt_type ^= DATA_TYPE_DCI_LOG;
3496 if (pkt_type & DATA_TYPE_DCI_EVENT)
3497 pkt_type ^= DATA_TYPE_DCI_EVENT;
3498 /*
3499 * Check if the log or event is selected even on the regular
3500 * stream. If USB is not connected and we are not in memory
3501 * device mode, we should not process these logs/events.
3502 */
3503 if (pkt_type && driver->logging_mode == DIAG_USB_MODE &&
3504 !driver->usb_connected)
3505 return err;
3506 }
3507
3508 switch (pkt_type) {
3509 case DATA_TYPE_EVENT:
3510 case DATA_TYPE_F3:
3511 case DATA_TYPE_LOG:
3512 case DATA_TYPE_DELAYED_RESPONSE:
3513 case DATA_TYPE_RESPONSE:
3514 return diag_user_process_apps_data(payload_buf, payload_len,
3515 pkt_type);
3516 default:
3517 pr_err_ratelimited("diag: In %s, invalid pkt_type: %d\n",
3518 __func__, pkt_type);
3519 return -EINVAL;
3520 }
3521
3522 return err;
3523}
3524
3525void diag_ws_init(void)
3526{
3527 driver->dci_ws.ref_count = 0;
3528 driver->dci_ws.copy_count = 0;
3529 spin_lock_init(&driver->dci_ws.lock);
3530
3531 driver->md_ws.ref_count = 0;
3532 driver->md_ws.copy_count = 0;
3533 spin_lock_init(&driver->md_ws.lock);
3534}
3535
3536static void diag_stats_init(void)
3537{
3538 if (!driver)
3539 return;
3540
3541 driver->msg_stats.alloc_count = 0;
3542 driver->msg_stats.drop_count = 0;
3543
3544 driver->log_stats.alloc_count = 0;
3545 driver->log_stats.drop_count = 0;
3546
3547 driver->event_stats.alloc_count = 0;
3548 driver->event_stats.drop_count = 0;
3549}
3550
3551void diag_ws_on_notify(void)
3552{
3553 /*
3554 * Do not deal with reference count here as there can be spurious
3555 * interrupts.
3556 */
3557 pm_stay_awake(driver->diag_dev);
3558}
3559
3560void diag_ws_on_read(int type, int pkt_len)
3561{
3562 unsigned long flags;
3563 struct diag_ws_ref_t *ws_ref = NULL;
3564
3565 switch (type) {
3566 case DIAG_WS_DCI:
3567 ws_ref = &driver->dci_ws;
3568 break;
3569 case DIAG_WS_MUX:
3570 ws_ref = &driver->md_ws;
3571 break;
3572 default:
3573 pr_err_ratelimited("diag: In %s, invalid type: %d\n",
3574 __func__, type);
3575 return;
3576 }
3577
3578 spin_lock_irqsave(&ws_ref->lock, flags);
3579 if (pkt_len > 0) {
3580 ws_ref->ref_count++;
3581 } else {
3582 if (ws_ref->ref_count < 1) {
3583 ws_ref->ref_count = 0;
3584 ws_ref->copy_count = 0;
3585 }
3586 diag_ws_release();
3587 }
3588 spin_unlock_irqrestore(&ws_ref->lock, flags);
3589}
3590
3591
3592void diag_ws_on_copy(int type)
3593{
3594 unsigned long flags;
3595 struct diag_ws_ref_t *ws_ref = NULL;
3596
3597 switch (type) {
3598 case DIAG_WS_DCI:
3599 ws_ref = &driver->dci_ws;
3600 break;
3601 case DIAG_WS_MUX:
3602 ws_ref = &driver->md_ws;
3603 break;
3604 default:
3605 pr_err_ratelimited("diag: In %s, invalid type: %d\n",
3606 __func__, type);
3607 return;
3608 }
3609
3610 spin_lock_irqsave(&ws_ref->lock, flags);
3611 ws_ref->copy_count++;
3612 spin_unlock_irqrestore(&ws_ref->lock, flags);
3613}
3614
3615void diag_ws_on_copy_fail(int type)
3616{
3617 unsigned long flags;
3618 struct diag_ws_ref_t *ws_ref = NULL;
3619
3620 switch (type) {
3621 case DIAG_WS_DCI:
3622 ws_ref = &driver->dci_ws;
3623 break;
3624 case DIAG_WS_MUX:
3625 ws_ref = &driver->md_ws;
3626 break;
3627 default:
3628 pr_err_ratelimited("diag: In %s, invalid type: %d\n",
3629 __func__, type);
3630 return;
3631 }
3632
3633 spin_lock_irqsave(&ws_ref->lock, flags);
3634 ws_ref->ref_count--;
3635 spin_unlock_irqrestore(&ws_ref->lock, flags);
3636
3637 diag_ws_release();
3638}
3639
3640void diag_ws_on_copy_complete(int type)
3641{
3642 unsigned long flags;
3643 struct diag_ws_ref_t *ws_ref = NULL;
3644
3645 switch (type) {
3646 case DIAG_WS_DCI:
3647 ws_ref = &driver->dci_ws;
3648 break;
3649 case DIAG_WS_MUX:
3650 ws_ref = &driver->md_ws;
3651 break;
3652 default:
3653 pr_err_ratelimited("diag: In %s, invalid type: %d\n",
3654 __func__, type);
3655 return;
3656 }
3657
3658 spin_lock_irqsave(&ws_ref->lock, flags);
3659 ws_ref->ref_count -= ws_ref->copy_count;
3660 if (ws_ref->ref_count < 1)
3661 ws_ref->ref_count = 0;
3662 ws_ref->copy_count = 0;
3663 spin_unlock_irqrestore(&ws_ref->lock, flags);
3664
3665 diag_ws_release();
3666}
3667
3668void diag_ws_reset(int type)
3669{
3670 unsigned long flags;
3671 struct diag_ws_ref_t *ws_ref = NULL;
3672
3673 switch (type) {
3674 case DIAG_WS_DCI:
3675 ws_ref = &driver->dci_ws;
3676 break;
3677 case DIAG_WS_MUX:
3678 ws_ref = &driver->md_ws;
3679 break;
3680 default:
3681 pr_err_ratelimited("diag: In %s, invalid type: %d\n",
3682 __func__, type);
3683 return;
3684 }
3685
3686 spin_lock_irqsave(&ws_ref->lock, flags);
3687 ws_ref->ref_count = 0;
3688 ws_ref->copy_count = 0;
3689 spin_unlock_irqrestore(&ws_ref->lock, flags);
3690
3691 diag_ws_release();
3692}
3693
3694void diag_ws_release(void)
3695{
3696 if (driver->dci_ws.ref_count == 0 && driver->md_ws.ref_count == 0)
3697 pm_relax(driver->diag_dev);
3698}
3699
3700#ifdef DIAG_DEBUG
3701static void diag_debug_init(void)
3702{
3703 diag_ipc_log = ipc_log_context_create(DIAG_IPC_LOG_PAGES, "diag", 0);
3704 if (!diag_ipc_log)
3705 pr_err("diag: Failed to create IPC logging context\n");
3706 /*
3707 * Set the bit mask here as per diag_ipc_logging.h to enable debug logs
3708 * to be logged to IPC
3709 */
3710 diag_debug_mask = DIAG_DEBUG_PERIPHERALS | DIAG_DEBUG_DCI |
Manoj Prabhu B571cf422017-08-08 19:01:41 +05303711 DIAG_DEBUG_USERSPACE | DIAG_DEBUG_BRIDGE;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003712}
3713#else
3714static void diag_debug_init(void)
3715{
3716
3717}
3718#endif
3719
3720static int diag_real_time_info_init(void)
3721{
3722 int i;
3723
3724 if (!driver)
3725 return -EIO;
3726 for (i = 0; i < DIAG_NUM_PROC; i++) {
3727 driver->real_time_mode[i] = 1;
3728 driver->proc_rt_vote_mask[i] |= DIAG_PROC_DCI;
3729 driver->proc_rt_vote_mask[i] |= DIAG_PROC_MEMORY_DEVICE;
3730 }
3731 driver->real_time_update_busy = 0;
3732 driver->proc_active_mask = 0;
3733 driver->diag_real_time_wq = create_singlethread_workqueue(
3734 "diag_real_time_wq");
3735 if (!driver->diag_real_time_wq)
3736 return -ENOMEM;
3737 INIT_WORK(&(driver->diag_real_time_work), diag_real_time_work_fn);
3738 mutex_init(&driver->real_time_mutex);
3739 return 0;
3740}
3741
3742static const struct file_operations diagcharfops = {
3743 .owner = THIS_MODULE,
3744 .read = diagchar_read,
3745 .write = diagchar_write,
3746#ifdef CONFIG_COMPAT
3747 .compat_ioctl = diagchar_compat_ioctl,
3748#endif
3749 .unlocked_ioctl = diagchar_ioctl,
3750 .open = diagchar_open,
3751 .release = diagchar_close
3752};
3753
3754static int diagchar_setup_cdev(dev_t devno)
3755{
3756
3757 int err;
3758
3759 cdev_init(driver->cdev, &diagcharfops);
3760
3761 driver->cdev->owner = THIS_MODULE;
3762 driver->cdev->ops = &diagcharfops;
3763
3764 err = cdev_add(driver->cdev, devno, 1);
3765
3766 if (err) {
3767 pr_info("diagchar cdev registration failed !\n");
3768 return err;
3769 }
3770
3771 driver->diagchar_class = class_create(THIS_MODULE, "diag");
3772
3773 if (IS_ERR(driver->diagchar_class)) {
3774 pr_err("Error creating diagchar class.\n");
3775 return PTR_ERR(driver->diagchar_class);
3776 }
3777
3778 driver->diag_dev = device_create(driver->diagchar_class, NULL, devno,
3779 (void *)driver, "diag");
3780
3781 if (!driver->diag_dev)
3782 return -EIO;
3783
3784 driver->diag_dev->power.wakeup = wakeup_source_register("DIAG_WS");
3785 return 0;
3786
3787}
3788
3789static int diagchar_cleanup(void)
3790{
3791 if (driver) {
3792 if (driver->cdev) {
3793 /* TODO - Check if device exists before deleting */
3794 device_destroy(driver->diagchar_class,
3795 MKDEV(driver->major,
3796 driver->minor_start));
3797 cdev_del(driver->cdev);
3798 }
3799 if (!IS_ERR(driver->diagchar_class))
3800 class_destroy(driver->diagchar_class);
3801 kfree(driver);
3802 }
3803 return 0;
3804}
3805
3806static int __init diagchar_init(void)
3807{
3808 dev_t dev;
Manoj Prabhu B98325462017-01-10 20:19:28 +05303809 int ret, i;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003810
3811 pr_debug("diagfwd initializing ..\n");
3812 ret = 0;
3813 driver = kzalloc(sizeof(struct diagchar_dev) + 5, GFP_KERNEL);
3814 if (!driver)
3815 return -ENOMEM;
3816 kmemleak_not_leak(driver);
3817
3818 timer_in_progress = 0;
3819 driver->delayed_rsp_id = 0;
3820 driver->hdlc_disabled = 0;
3821 driver->dci_state = DIAG_DCI_NO_ERROR;
3822 setup_timer(&drain_timer, drain_timer_func, 1234);
3823 driver->supports_sockets = 1;
3824 driver->time_sync_enabled = 0;
3825 driver->uses_time_api = 0;
3826 driver->poolsize = poolsize;
3827 driver->poolsize_hdlc = poolsize_hdlc;
3828 driver->poolsize_dci = poolsize_dci;
3829 driver->poolsize_user = poolsize_user;
3830 /*
3831 * POOL_TYPE_MUX_APPS is for the buffers in the Diag MUX layer.
3832 * The number of buffers encompasses Diag data generated on
3833 * the Apss processor + 1 for the responses generated exclusively on
3834 * the Apps processor + data from data channels (4 channels per
3835 * peripheral) + data from command channels (2)
3836 */
3837 diagmem_setsize(POOL_TYPE_MUX_APPS, itemsize_usb_apps,
3838 poolsize_usb_apps + 1 + (NUM_PERIPHERALS * 6));
3839 driver->num_clients = max_clients;
3840 driver->logging_mode = DIAG_USB_MODE;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05303841 for (i = 0; i < NUM_UPD; i++) {
3842 driver->pd_logging_mode[i] = 0;
3843 driver->pd_session_clear[i] = 0;
3844 }
3845 driver->num_pd_session = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003846 driver->mask_check = 0;
3847 driver->in_busy_pktdata = 0;
3848 driver->in_busy_dcipktdata = 0;
3849 driver->rsp_buf_ctxt = SET_BUF_CTXT(APPS_DATA, TYPE_CMD, 1);
3850 hdlc_data.ctxt = SET_BUF_CTXT(APPS_DATA, TYPE_DATA, 1);
3851 hdlc_data.len = 0;
3852 non_hdlc_data.ctxt = SET_BUF_CTXT(APPS_DATA, TYPE_DATA, 1);
3853 non_hdlc_data.len = 0;
3854 mutex_init(&driver->hdlc_disable_mutex);
3855 mutex_init(&driver->diagchar_mutex);
3856 mutex_init(&driver->diag_maskclear_mutex);
Manoj Prabhu B2a428272016-12-22 15:22:03 +05303857 mutex_init(&driver->diag_notifier_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003858 mutex_init(&driver->diag_file_mutex);
3859 mutex_init(&driver->delayed_rsp_mutex);
3860 mutex_init(&apps_data_mutex);
Gopikrishna Mogasati9a44d8d2017-05-05 16:04:35 +05303861 mutex_init(&driver->msg_mask_lock);
Hardik Arya62dce9f2017-06-15 10:39:34 +05303862 mutex_init(&driver->hdlc_recovery_mutex);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05303863 for (i = 0; i < NUM_PERIPHERALS; i++) {
Manoj Prabhu B98325462017-01-10 20:19:28 +05303864 mutex_init(&driver->diagfwd_channel_mutex[i]);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05303865 driver->diag_id_sent[i] = 0;
3866 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003867 init_waitqueue_head(&driver->wait_q);
3868 INIT_WORK(&(driver->diag_drain_work), diag_drain_work_fn);
3869 INIT_WORK(&(driver->update_user_clients),
3870 diag_update_user_client_work_fn);
3871 INIT_WORK(&(driver->update_md_clients),
3872 diag_update_md_client_work_fn);
3873 diag_ws_init();
3874 diag_stats_init();
3875 diag_debug_init();
3876 diag_md_session_init();
3877
3878 driver->incoming_pkt.capacity = DIAG_MAX_REQ_SIZE;
3879 driver->incoming_pkt.data = kzalloc(DIAG_MAX_REQ_SIZE, GFP_KERNEL);
3880 if (!driver->incoming_pkt.data) {
3881 ret = -ENOMEM;
3882 goto fail;
3883 }
3884 kmemleak_not_leak(driver->incoming_pkt.data);
3885 driver->incoming_pkt.processing = 0;
3886 driver->incoming_pkt.read_len = 0;
3887 driver->incoming_pkt.remaining = 0;
3888 driver->incoming_pkt.total_len = 0;
3889
3890 ret = diag_real_time_info_init();
3891 if (ret)
3892 goto fail;
3893 ret = diag_debugfs_init();
3894 if (ret)
3895 goto fail;
3896 ret = diag_masks_init();
3897 if (ret)
3898 goto fail;
3899 ret = diag_remote_init();
3900 if (ret)
3901 goto fail;
3902 ret = diag_mux_init();
3903 if (ret)
3904 goto fail;
3905 ret = diagfwd_init();
3906 if (ret)
3907 goto fail;
3908 ret = diagfwd_cntl_init();
3909 if (ret)
3910 goto fail;
3911 driver->dci_state = diag_dci_init();
3912 ret = diagfwd_peripheral_init();
3913 if (ret)
3914 goto fail;
3915 diagfwd_cntl_channel_init();
3916 if (driver->dci_state == DIAG_DCI_NO_ERROR)
3917 diag_dci_channel_init();
3918 pr_debug("diagchar initializing ..\n");
3919 driver->num = 1;
3920 driver->name = ((void *)driver) + sizeof(struct diagchar_dev);
3921 strlcpy(driver->name, "diag", 4);
3922 /* Get major number from kernel and initialize */
3923 ret = alloc_chrdev_region(&dev, driver->minor_start,
3924 driver->num, driver->name);
3925 if (!ret) {
3926 driver->major = MAJOR(dev);
3927 driver->minor_start = MINOR(dev);
3928 } else {
3929 pr_err("diag: Major number not allocated\n");
3930 goto fail;
3931 }
3932 driver->cdev = cdev_alloc();
3933 ret = diagchar_setup_cdev(dev);
3934 if (ret)
3935 goto fail;
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -08003936 mutex_init(&driver->diag_id_mutex);
3937 INIT_LIST_HEAD(&driver->diag_id_list);
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05303938 diag_add_diag_id_to_list(DIAG_ID_APPS, "APPS", APPS_DATA, APPS_DATA);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07003939 pr_debug("diagchar initialized now");
3940 ret = diagfwd_bridge_init();
3941 if (ret)
3942 diagfwd_bridge_exit();
3943 return 0;
3944
3945fail:
3946 pr_err("diagchar is not initialized, ret: %d\n", ret);
3947 diag_debugfs_cleanup();
3948 diagchar_cleanup();
3949 diag_mux_exit();
3950 diagfwd_peripheral_exit();
3951 diagfwd_bridge_exit();
3952 diagfwd_exit();
3953 diagfwd_cntl_exit();
3954 diag_dci_exit();
3955 diag_masks_exit();
3956 diag_remote_exit();
3957 return ret;
3958
3959}
3960
3961static void diagchar_exit(void)
3962{
3963 pr_info("diagchar exiting...\n");
3964 diag_mempool_exit();
3965 diag_mux_exit();
3966 diagfwd_peripheral_exit();
3967 diagfwd_exit();
3968 diagfwd_cntl_exit();
3969 diag_dci_exit();
3970 diag_masks_exit();
3971 diag_md_session_exit();
3972 diag_remote_exit();
3973 diag_debugfs_cleanup();
3974 diagchar_cleanup();
3975 pr_info("done diagchar exit\n");
3976}
3977
3978module_init(diagchar_init);
3979module_exit(diagchar_exit);