blob: 95abd219592f2a38aa891196edb7c2bf6b279648 [file] [log] [blame]
Shalabh Jain10f5f432012-01-11 11:45:44 +05301/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/slab.h>
14#include <linux/diagchar.h>
15#include <linux/platform_device.h>
Dixon Petersoncc0bea772012-04-11 20:45:37 -070016#include <linux/kmemleak.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070017#include "diagchar.h"
18#include "diagfwd.h"
19#include "diagfwd_cntl.h"
Dixon Peterson29aebee2012-04-06 12:44:08 -070020#ifdef CONFIG_DEBUG_FS
21#include <linux/debugfs.h>
22#endif
Shalabh Jain7b20eab2012-06-19 17:50:58 -070023/* tracks which peripheral is undergoing SSR */
24static uint16_t reg_dirty;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#define HDR_SIZ 8
26
Shalabh Jain7b20eab2012-06-19 17:50:58 -070027void diag_clean_modem_reg_fn(struct work_struct *work)
28{
29 pr_debug("diag: clean modem registration\n");
30 reg_dirty |= DIAG_CON_MPSS;
31 diag_clear_reg(MODEM_PROC);
32 reg_dirty ^= DIAG_CON_MPSS;
33}
34
35void diag_clean_lpass_reg_fn(struct work_struct *work)
36{
37 pr_debug("diag: clean lpass registration\n");
38 reg_dirty |= DIAG_CON_LPASS;
39 diag_clear_reg(QDSP_PROC);
40 reg_dirty ^= DIAG_CON_LPASS;
41}
42
43void diag_clean_wcnss_reg_fn(struct work_struct *work)
44{
45 pr_debug("diag: clean wcnss registration\n");
46 reg_dirty |= DIAG_CON_WCNSS;
47 diag_clear_reg(WCNSS_PROC);
48 reg_dirty ^= DIAG_CON_WCNSS;
49}
50
Shalabh Jain4e1bd312012-02-16 19:33:05 -080051void diag_smd_cntl_notify(void *ctxt, unsigned event)
52{
53 int r1, r2;
54
55 if (!(driver->ch_cntl))
56 return;
57
58 switch (event) {
59 case SMD_EVENT_DATA:
60 r1 = smd_read_avail(driver->ch_cntl);
61 r2 = smd_cur_packet_size(driver->ch_cntl);
62 if (r1 > 0 && r1 == r2)
63 queue_work(driver->diag_wq,
64 &(driver->diag_read_smd_cntl_work));
65 else
66 pr_debug("diag: incomplete pkt on Modem CNTL ch\n");
67 break;
Shalabh Jain321c8b52012-02-22 12:37:06 -080068 case SMD_EVENT_OPEN:
69 queue_work(driver->diag_cntl_wq,
70 &(driver->diag_modem_mask_update_work));
71 break;
Shalabh Jain4e1bd312012-02-16 19:33:05 -080072 }
73}
74
75void diag_smd_qdsp_cntl_notify(void *ctxt, unsigned event)
76{
77 int r1, r2;
78
79 if (!(driver->chqdsp_cntl))
80 return;
81
82 switch (event) {
83 case SMD_EVENT_DATA:
84 r1 = smd_read_avail(driver->chqdsp_cntl);
85 r2 = smd_cur_packet_size(driver->chqdsp_cntl);
86 if (r1 > 0 && r1 == r2)
87 queue_work(driver->diag_wq,
88 &(driver->diag_read_smd_qdsp_cntl_work));
89 else
90 pr_debug("diag: incomplete pkt on LPASS CNTL ch\n");
91 break;
Shalabh Jain321c8b52012-02-22 12:37:06 -080092 case SMD_EVENT_OPEN:
93 queue_work(driver->diag_cntl_wq,
94 &(driver->diag_qdsp_mask_update_work));
95 break;
Shalabh Jain4e1bd312012-02-16 19:33:05 -080096 }
97}
98
99void diag_smd_wcnss_cntl_notify(void *ctxt, unsigned event)
100{
101 int r1, r2;
102
103 if (!(driver->ch_wcnss_cntl))
104 return;
105
106 switch (event) {
107 case SMD_EVENT_DATA:
108 r1 = smd_read_avail(driver->ch_wcnss_cntl);
109 r2 = smd_cur_packet_size(driver->ch_wcnss_cntl);
110 if (r1 > 0 && r1 == r2)
111 queue_work(driver->diag_wq,
112 &(driver->diag_read_smd_wcnss_cntl_work));
113 else
114 pr_debug("diag: incomplete pkt on WCNSS CNTL ch\n");
115 break;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800116 case SMD_EVENT_OPEN:
117 queue_work(driver->diag_cntl_wq,
118 &(driver->diag_wcnss_mask_update_work));
119 break;
Shalabh Jain4e1bd312012-02-16 19:33:05 -0800120 }
121}
122
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123static void diag_smd_cntl_send_req(int proc_num)
124{
Shalabh Jaincf5f20e2011-08-22 12:29:52 -0700125 int data_len = 0, type = -1, count_bytes = 0, j, r, flag = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700126 struct bindpkt_params_per_process *pkt_params =
127 kzalloc(sizeof(struct bindpkt_params_per_process), GFP_KERNEL);
128 struct diag_ctrl_msg *msg;
129 struct cmd_code_range *range;
130 struct bindpkt_params *temp;
131 void *buf = NULL;
132 smd_channel_t *smd_ch = NULL;
Shalabh Jain7b20eab2012-06-19 17:50:58 -0700133 /* tracks which peripheral is sending registration */
134 uint16_t reg_mask = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135
Shalabh Jain4e1bd312012-02-16 19:33:05 -0800136 if (pkt_params == NULL) {
137 pr_alert("diag: Memory allocation failure\n");
138 return;
139 }
140
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141 if (proc_num == MODEM_PROC) {
142 buf = driver->buf_in_cntl;
143 smd_ch = driver->ch_cntl;
Shalabh Jain7b20eab2012-06-19 17:50:58 -0700144 reg_mask = DIAG_CON_MPSS;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145 } else if (proc_num == QDSP_PROC) {
146 buf = driver->buf_in_qdsp_cntl;
147 smd_ch = driver->chqdsp_cntl;
Shalabh Jain7b20eab2012-06-19 17:50:58 -0700148 reg_mask = DIAG_CON_LPASS;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149 } else if (proc_num == WCNSS_PROC) {
150 buf = driver->buf_in_wcnss_cntl;
151 smd_ch = driver->ch_wcnss_cntl;
Shalabh Jain7b20eab2012-06-19 17:50:58 -0700152 reg_mask = DIAG_CON_WCNSS;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153 }
154
Shalabh Jainf89c5462011-08-23 18:46:03 -0700155 if (!smd_ch || !buf) {
156 kfree(pkt_params);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157 return;
Shalabh Jainf89c5462011-08-23 18:46:03 -0700158 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159
160 r = smd_read_avail(smd_ch);
161 if (r > IN_BUF_SIZE) {
162 if (r < MAX_IN_BUF_SIZE) {
163 pr_err("diag: SMD CNTL sending pkt upto %d bytes", r);
164 buf = krealloc(buf, r, GFP_KERNEL);
165 } else {
166 pr_err("diag: CNTL pkt > %d bytes", MAX_IN_BUF_SIZE);
167 kfree(pkt_params);
168 return;
169 }
170 }
171 if (buf && r > 0) {
172 smd_read(smd_ch, buf, r);
173 while (count_bytes + HDR_SIZ <= r) {
174 type = *(uint32_t *)(buf);
175 data_len = *(uint32_t *)(buf + 4);
Shalabh Jainf50076b2012-02-15 19:27:01 -0800176 if (type < DIAG_CTRL_MSG_REG ||
177 type > DIAG_CTRL_MSG_F3_MASK_V2) {
Shalabh Jain4e1bd312012-02-16 19:33:05 -0800178 pr_alert("diag: Invalid Msg type %d proc %d",
179 type, proc_num);
Shalabh Jainf50076b2012-02-15 19:27:01 -0800180 break;
181 }
182 if (data_len < 0 || data_len > r) {
Shalabh Jain4e1bd312012-02-16 19:33:05 -0800183 pr_alert("diag: Invalid data len %d proc %d",
184 data_len, proc_num);
Shalabh Jainf50076b2012-02-15 19:27:01 -0800185 break;
186 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187 count_bytes = count_bytes+HDR_SIZ+data_len;
188 if (type == DIAG_CTRL_MSG_REG && r >= count_bytes) {
189 msg = buf+HDR_SIZ;
190 range = buf+HDR_SIZ+
191 sizeof(struct diag_ctrl_msg);
192 pkt_params->count = msg->count_entries;
193 temp = kzalloc(pkt_params->count * sizeof(struct
194 bindpkt_params), GFP_KERNEL);
Shalabh Jain4e1bd312012-02-16 19:33:05 -0800195 if (temp == NULL) {
196 pr_alert("diag: Memory alloc fail\n");
Dixon Petersonee6fb2b2012-03-16 20:26:02 -0700197 kfree(pkt_params);
Shalabh Jain4e1bd312012-02-16 19:33:05 -0800198 return;
199 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200 for (j = 0; j < pkt_params->count; j++) {
201 temp->cmd_code = msg->cmd_code;
202 temp->subsys_id = msg->subsysid;
203 temp->client_id = proc_num;
204 temp->proc_id = proc_num;
205 temp->cmd_code_lo = range->cmd_code_lo;
206 temp->cmd_code_hi = range->cmd_code_hi;
207 range++;
208 temp++;
209 }
210 temp -= pkt_params->count;
211 pkt_params->params = temp;
Shalabh Jaincf5f20e2011-08-22 12:29:52 -0700212 flag = 1;
Shalabh Jain7b20eab2012-06-19 17:50:58 -0700213 /* peripheral undergoing SSR should not
214 * record new registration
215 */
216 if (!(reg_dirty & reg_mask))
217 diagchar_ioctl(NULL,
218 DIAG_IOCTL_COMMAND_REG, (unsigned long)
219 pkt_params);
220 else
221 pr_err("diag: drop reg proc %d\n",
222 proc_num);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700223 kfree(temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700224 }
Dixon Petersone8054f02012-02-06 11:46:49 -0800225 buf = buf + HDR_SIZ + data_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700226 }
227 }
228 kfree(pkt_params);
Shalabh Jaincf5f20e2011-08-22 12:29:52 -0700229 if (flag) {
230 /* Poll SMD CNTL channels to check for data */
Shalabh Jain4e1bd312012-02-16 19:33:05 -0800231 if (proc_num == MODEM_PROC)
232 diag_smd_cntl_notify(NULL, SMD_EVENT_DATA);
233 else if (proc_num == QDSP_PROC)
234 diag_smd_qdsp_cntl_notify(NULL, SMD_EVENT_DATA);
235 else if (proc_num == WCNSS_PROC)
236 diag_smd_wcnss_cntl_notify(NULL, SMD_EVENT_DATA);
Shalabh Jaincf5f20e2011-08-22 12:29:52 -0700237 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700238}
239
240void diag_read_smd_cntl_work_fn(struct work_struct *work)
241{
242 diag_smd_cntl_send_req(MODEM_PROC);
243}
244
245void diag_read_smd_qdsp_cntl_work_fn(struct work_struct *work)
246{
247 diag_smd_cntl_send_req(QDSP_PROC);
248}
249
250void diag_read_smd_wcnss_cntl_work_fn(struct work_struct *work)
251{
252 diag_smd_cntl_send_req(WCNSS_PROC);
253}
254
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700255static int diag_smd_cntl_probe(struct platform_device *pdev)
256{
257 int r = 0;
258
Shalabh Jain10f5f432012-01-11 11:45:44 +0530259 /* open control ports only on 8960 & newer targets */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700260 if (chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261 if (pdev->id == SMD_APPS_MODEM)
262 r = smd_open("DIAG_CNTL", &driver->ch_cntl, driver,
263 diag_smd_cntl_notify);
264 if (pdev->id == SMD_APPS_QDSP)
265 r = smd_named_open_on_edge("DIAG_CNTL", SMD_APPS_QDSP
266 , &driver->chqdsp_cntl, driver,
267 diag_smd_qdsp_cntl_notify);
268 if (pdev->id == SMD_APPS_WCNSS)
269 r = smd_named_open_on_edge("APPS_RIVA_CTRL",
270 SMD_APPS_WCNSS, &driver->ch_wcnss_cntl,
271 driver, diag_smd_wcnss_cntl_notify);
272 pr_debug("diag: open CNTL port, ID = %d,r = %d\n", pdev->id, r);
273 }
274 return 0;
275}
276
277static int diagfwd_cntl_runtime_suspend(struct device *dev)
278{
279 dev_dbg(dev, "pm_runtime: suspending...\n");
280 return 0;
281}
282
283static int diagfwd_cntl_runtime_resume(struct device *dev)
284{
285 dev_dbg(dev, "pm_runtime: resuming...\n");
286 return 0;
287}
288
289static const struct dev_pm_ops diagfwd_cntl_dev_pm_ops = {
290 .runtime_suspend = diagfwd_cntl_runtime_suspend,
291 .runtime_resume = diagfwd_cntl_runtime_resume,
292};
293
294static struct platform_driver msm_smd_ch1_cntl_driver = {
295
296 .probe = diag_smd_cntl_probe,
297 .driver = {
298 .name = "DIAG_CNTL",
299 .owner = THIS_MODULE,
300 .pm = &diagfwd_cntl_dev_pm_ops,
301 },
302};
303
304static struct platform_driver diag_smd_lite_cntl_driver = {
305
306 .probe = diag_smd_cntl_probe,
307 .driver = {
308 .name = "APPS_RIVA_CTRL",
309 .owner = THIS_MODULE,
310 .pm = &diagfwd_cntl_dev_pm_ops,
311 },
312};
313
314void diagfwd_cntl_init(void)
315{
Shalabh Jain7b20eab2012-06-19 17:50:58 -0700316 reg_dirty = 0;
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800317 driver->polling_reg_flag = 0;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800318 driver->diag_cntl_wq = create_singlethread_workqueue("diag_cntl_wq");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 if (driver->buf_in_cntl == NULL) {
320 driver->buf_in_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
321 if (driver->buf_in_cntl == NULL)
322 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -0700323 kmemleak_not_leak(driver->buf_in_cntl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324 }
325 if (driver->buf_in_qdsp_cntl == NULL) {
326 driver->buf_in_qdsp_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
327 if (driver->buf_in_qdsp_cntl == NULL)
328 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -0700329 kmemleak_not_leak(driver->buf_in_qdsp_cntl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 }
331 if (driver->buf_in_wcnss_cntl == NULL) {
332 driver->buf_in_wcnss_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
333 if (driver->buf_in_wcnss_cntl == NULL)
334 goto err;
Dixon Petersoncc0bea772012-04-11 20:45:37 -0700335 kmemleak_not_leak(driver->buf_in_wcnss_cntl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700336 }
337 platform_driver_register(&msm_smd_ch1_cntl_driver);
338 platform_driver_register(&diag_smd_lite_cntl_driver);
339
340 return;
341err:
342 pr_err("diag: Could not initialize diag buffers");
343 kfree(driver->buf_in_cntl);
344 kfree(driver->buf_in_qdsp_cntl);
345 kfree(driver->buf_in_wcnss_cntl);
Shalabh Jain321c8b52012-02-22 12:37:06 -0800346 if (driver->diag_cntl_wq)
347 destroy_workqueue(driver->diag_cntl_wq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700348}
349
350void diagfwd_cntl_exit(void)
351{
352 smd_close(driver->ch_cntl);
353 smd_close(driver->chqdsp_cntl);
354 smd_close(driver->ch_wcnss_cntl);
355 driver->ch_cntl = 0;
356 driver->chqdsp_cntl = 0;
357 driver->ch_wcnss_cntl = 0;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800358 destroy_workqueue(driver->diag_cntl_wq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700359 platform_driver_unregister(&msm_smd_ch1_cntl_driver);
360 platform_driver_unregister(&diag_smd_lite_cntl_driver);
361
362 kfree(driver->buf_in_cntl);
363 kfree(driver->buf_in_qdsp_cntl);
364 kfree(driver->buf_in_wcnss_cntl);
365}
Dixon Peterson29aebee2012-04-06 12:44:08 -0700366
367#ifdef CONFIG_DEBUG_FS
368#define DEBUG_BUF_SIZE 4096
369static struct dentry *diag_dbgfs_dent;
370static int diag_dbgfs_table_index;
371
372static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf,
373 size_t count, loff_t *ppos)
374{
375 char *buf;
376 int ret;
377
378 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
379 if (!buf) {
380 pr_err("diag: %s, Error allocating memory\n", __func__);
381 return -ENOMEM;
382 }
383
384 ret = scnprintf(buf, DEBUG_BUF_SIZE,
385 "modem ch: 0x%x\n"
386 "lpass ch: 0x%x\n"
387 "riva ch: 0x%x\n"
388 "dci ch: 0x%x\n"
389 "modem cntl_ch: 0x%x\n"
390 "lpass cntl_ch: 0x%x\n"
391 "riva cntl_ch: 0x%x\n"
392 "CPU Tools id: %d\n"
393 "Apps only: %d\n"
394 "Apps master: %d\n"
395 "Check Polling Response: %d\n"
396 "polling_reg_flag: %d\n"
397 "uses device tree: %d\n"
398 "in_busy_1: %d\n"
399 "in_busy_2: %d\n"
400 "in_busy_qdsp_1: %d\n"
401 "in_busy_qdsp_2: %d\n"
402 "in_busy_wcnss_1: %d\n"
403 "in_busy_wcnss_2: %d\n"
404 "in_busy_dci: %d\n",
405 (unsigned int)driver->ch,
406 (unsigned int)driver->chqdsp,
407 (unsigned int)driver->ch_wcnss,
408 (unsigned int)driver->ch_dci,
409 (unsigned int)driver->ch_cntl,
410 (unsigned int)driver->chqdsp_cntl,
411 (unsigned int)driver->ch_wcnss_cntl,
412 chk_config_get_id(),
413 chk_apps_only(),
414 chk_apps_master(),
415 chk_polling_response(),
416 driver->polling_reg_flag,
417 driver->use_device_tree,
418 driver->in_busy_1,
419 driver->in_busy_2,
420 driver->in_busy_qdsp_1,
421 driver->in_busy_qdsp_2,
422 driver->in_busy_wcnss_1,
423 driver->in_busy_wcnss_2,
424 driver->in_busy_dci);
425
426#ifdef CONFIG_DIAG_OVER_USB
427 ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
428 "usb_connected: %d\n",
429 driver->usb_connected);
430#endif
431 ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
432
433 kfree(buf);
434 return ret;
435}
436
437static ssize_t diag_dbgfs_read_workpending(struct file *file,
438 char __user *ubuf, size_t count, loff_t *ppos)
439{
440 char *buf;
441 int ret;
442
443 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
444 if (!buf) {
445 pr_err("diag: %s, Error allocating memory\n", __func__);
446 return -ENOMEM;
447 }
448
449 ret = scnprintf(buf, DEBUG_BUF_SIZE,
450 "Pending status for work_stucts:\n"
451 "diag_drain_work: %d\n"
452 "diag_read_smd_work: %d\n"
453 "diag_read_smd_cntl_work: %d\n"
454 "diag_read_smd_qdsp_work: %d\n"
455 "diag_read_smd_qdsp_cntl_work: %d\n"
456 "diag_read_smd_wcnss_work: %d\n"
457 "diag_read_smd_wcnss_cntl_work: %d\n"
458 "diag_modem_mask_update_work: %d\n"
459 "diag_qdsp_mask_update_work: %d\n"
460 "diag_wcnss_mask_update_work: %d\n"
461 "diag_read_smd_dci_work: %d\n",
462 work_pending(&(driver->diag_drain_work)),
463 work_pending(&(driver->diag_read_smd_work)),
464 work_pending(&(driver->diag_read_smd_cntl_work)),
465 work_pending(&(driver->diag_read_smd_qdsp_work)),
466 work_pending(&(driver->diag_read_smd_qdsp_cntl_work)),
467 work_pending(&(driver->diag_read_smd_wcnss_work)),
468 work_pending(&(driver->diag_read_smd_wcnss_cntl_work)),
469 work_pending(&(driver->diag_modem_mask_update_work)),
470 work_pending(&(driver->diag_qdsp_mask_update_work)),
471 work_pending(&(driver->diag_wcnss_mask_update_work)),
472 work_pending(&(driver->diag_read_smd_dci_work)));
473
474#ifdef CONFIG_DIAG_OVER_USB
475 ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
476 "diag_proc_hdlc_work: %d\n"
477 "diag_read_work: %d\n",
478 work_pending(&(driver->diag_proc_hdlc_work)),
479 work_pending(&(driver->diag_read_work)));
480#endif
481 ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
482
483 kfree(buf);
484 return ret;
485}
486
487static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf,
488 size_t count, loff_t *ppos)
489{
490 char *buf;
491 int ret = 0;
492 int i;
493 int bytes_remaining;
494 int bytes_in_buffer = 0;
495 int bytes_written;
496 int buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count;
497
498 if (diag_dbgfs_table_index >= diag_max_reg) {
499 /* Done. Reset to prepare for future requests */
500 diag_dbgfs_table_index = 0;
501 return 0;
502 }
503
504 buf = kzalloc(sizeof(char) * buf_size, GFP_KERNEL);
505 if (!buf) {
506 pr_err("diag: %s, Error allocating memory\n", __func__);
507 return -ENOMEM;
508 }
509
510 bytes_remaining = buf_size;
511 for (i = diag_dbgfs_table_index; i < diag_max_reg; i++) {
512 /* Do not process empty entries in the table */
513 if (driver->table[i].process_id == 0)
514 continue;
515
516 bytes_written = scnprintf(buf+bytes_in_buffer, bytes_remaining,
517 "i: %3d, cmd_code: %4x, subsys_id: %4x, "
518 "client: %2d, cmd_code_lo: %4x, "
519 "cmd_code_hi: %4x, process_id: %5d\n",
520 i,
521 driver->table[i].cmd_code,
522 driver->table[i].subsys_id,
523 driver->table[i].client_id,
524 driver->table[i].cmd_code_lo,
525 driver->table[i].cmd_code_hi,
526 driver->table[i].process_id);
527
528 bytes_in_buffer += bytes_written;
529
530 /* Check if there is room to add another table entry */
531 bytes_remaining = buf_size - bytes_in_buffer;
532 if (bytes_remaining < bytes_written)
533 break;
534 }
535 diag_dbgfs_table_index = i;
536
537 *ppos = 0;
538 ret = simple_read_from_buffer(ubuf, count, ppos, buf, bytes_in_buffer);
539
540 kfree(buf);
541 return ret;
542}
543
544#ifdef CONFIG_DIAG_HSIC_PIPE
545static ssize_t diag_dbgfs_read_hsic(struct file *file, char __user *ubuf,
546 size_t count, loff_t *ppos)
547{
548 char *buf;
549 int ret;
550
551 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
552 if (!buf) {
553 pr_err("diag: %s, Error allocating memory\n", __func__);
554 return -ENOMEM;
555 }
556
557 ret = scnprintf(buf, DEBUG_BUF_SIZE,
558 "hsic initialized: %d\n"
559 "hsic ch: %d\n"
560 "hsic enabled: %d\n"
561 "hsic_opened: %d\n"
562 "hisc_suspend: %d\n"
563 "in_busy_hsic_read_on_mdm: %d\n"
564 "in_busy_hsic_write_on_mdm: %d\n"
565 "in_busy_hsic_write: %d\n"
566 "in_busy_hsic_read: %d\n"
567 "usb_mdm_connected: %d\n"
568 "diag_read_mdm_work: %d\n"
569 "diag_read_hsic_work: %d\n"
570 "diag_disconnect_work: %d\n"
571 "diag_usb_read_complete_work: %d\n",
572 driver->hsic_initialized,
573 driver->hsic_ch,
574 driver->hsic_device_enabled,
575 driver->hsic_device_opened,
576 driver->hsic_suspend,
577 driver->in_busy_hsic_read_on_device,
578 driver->in_busy_hsic_write_on_device,
579 driver->in_busy_hsic_write,
580 driver->in_busy_hsic_read,
581 driver->usb_mdm_connected,
582 work_pending(&(driver->diag_read_mdm_work)),
583 work_pending(&(driver->diag_read_hsic_work)),
584 work_pending(&(driver->diag_disconnect_work)),
585 work_pending(&(driver->diag_usb_read_complete_work)));
586
587 ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
588
589 kfree(buf);
590 return ret;
591}
592
593const struct file_operations diag_dbgfs_hsic_ops = {
594 .read = diag_dbgfs_read_hsic,
595};
596#endif
597
598const struct file_operations diag_dbgfs_status_ops = {
599 .read = diag_dbgfs_read_status,
600};
601
602const struct file_operations diag_dbgfs_table_ops = {
603 .read = diag_dbgfs_read_table,
604};
605
606const struct file_operations diag_dbgfs_workpending_ops = {
607 .read = diag_dbgfs_read_workpending,
608};
609
610void diag_debugfs_init(void)
611{
612 diag_dbgfs_dent = debugfs_create_dir("diag", 0);
613 if (IS_ERR(diag_dbgfs_dent))
614 return;
615
616 debugfs_create_file("status", 0444, diag_dbgfs_dent, 0,
617 &diag_dbgfs_status_ops);
618
619 debugfs_create_file("table", 0444, diag_dbgfs_dent, 0,
620 &diag_dbgfs_table_ops);
621
622 debugfs_create_file("work_pending", 0444, diag_dbgfs_dent, 0,
623 &diag_dbgfs_workpending_ops);
624
625#ifdef CONFIG_DIAG_HSIC_PIPE
626 debugfs_create_file("hsic", 0444, diag_dbgfs_dent, 0,
627 &diag_dbgfs_hsic_ops);
628#endif
629
630 diag_dbgfs_table_index = 0;
631}
632
633void diag_debugfs_cleanup(void)
634{
635 if (diag_dbgfs_dent) {
636 debugfs_remove_recursive(diag_dbgfs_dent);
637 diag_dbgfs_dent = NULL;
638 }
639}
640#else
641void diag_debugfs_init(void) { }
642void diag_debugfs_cleanup(void) { }
643#endif