blob: 41279d3ae106864722e6b0afeb809f03deda89f2 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
2 *
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>
16#include "diagchar.h"
17#include "diagfwd.h"
18#include "diagfwd_cntl.h"
19
20#define HDR_SIZ 8
21
22static void diag_smd_cntl_send_req(int proc_num)
23{
Shalabh Jaincf5f20e2011-08-22 12:29:52 -070024 int data_len = 0, type = -1, count_bytes = 0, j, r, flag = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025 struct bindpkt_params_per_process *pkt_params =
26 kzalloc(sizeof(struct bindpkt_params_per_process), GFP_KERNEL);
27 struct diag_ctrl_msg *msg;
28 struct cmd_code_range *range;
29 struct bindpkt_params *temp;
30 void *buf = NULL;
31 smd_channel_t *smd_ch = NULL;
32
33 if (proc_num == MODEM_PROC) {
34 buf = driver->buf_in_cntl;
35 smd_ch = driver->ch_cntl;
36 } else if (proc_num == QDSP_PROC) {
37 buf = driver->buf_in_qdsp_cntl;
38 smd_ch = driver->chqdsp_cntl;
39 } else if (proc_num == WCNSS_PROC) {
40 buf = driver->buf_in_wcnss_cntl;
41 smd_ch = driver->ch_wcnss_cntl;
42 }
43
44 if (!smd_ch || !buf)
45 return;
46
47 r = smd_read_avail(smd_ch);
48 if (r > IN_BUF_SIZE) {
49 if (r < MAX_IN_BUF_SIZE) {
50 pr_err("diag: SMD CNTL sending pkt upto %d bytes", r);
51 buf = krealloc(buf, r, GFP_KERNEL);
52 } else {
53 pr_err("diag: CNTL pkt > %d bytes", MAX_IN_BUF_SIZE);
54 kfree(pkt_params);
55 return;
56 }
57 }
58 if (buf && r > 0) {
59 smd_read(smd_ch, buf, r);
60 while (count_bytes + HDR_SIZ <= r) {
61 type = *(uint32_t *)(buf);
62 data_len = *(uint32_t *)(buf + 4);
63 count_bytes = count_bytes+HDR_SIZ+data_len;
64 if (type == DIAG_CTRL_MSG_REG && r >= count_bytes) {
65 msg = buf+HDR_SIZ;
66 range = buf+HDR_SIZ+
67 sizeof(struct diag_ctrl_msg);
68 pkt_params->count = msg->count_entries;
69 temp = kzalloc(pkt_params->count * sizeof(struct
70 bindpkt_params), GFP_KERNEL);
71 for (j = 0; j < pkt_params->count; j++) {
72 temp->cmd_code = msg->cmd_code;
73 temp->subsys_id = msg->subsysid;
74 temp->client_id = proc_num;
75 temp->proc_id = proc_num;
76 temp->cmd_code_lo = range->cmd_code_lo;
77 temp->cmd_code_hi = range->cmd_code_hi;
78 range++;
79 temp++;
80 }
81 temp -= pkt_params->count;
82 pkt_params->params = temp;
Shalabh Jaincf5f20e2011-08-22 12:29:52 -070083 flag = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070084 diagchar_ioctl(NULL, DIAG_IOCTL_COMMAND_REG,
85 (unsigned long)pkt_params);
86 kfree(temp);
87 buf = buf + HDR_SIZ + data_len;
88 }
89 }
90 }
91 kfree(pkt_params);
Shalabh Jaincf5f20e2011-08-22 12:29:52 -070092 if (flag) {
93 /* Poll SMD CNTL channels to check for data */
94 queue_work(driver->diag_wq, &(driver->diag_read_smd_cntl_work));
95 queue_work(driver->diag_wq,
96 &(driver->diag_read_smd_qdsp_cntl_work));
97 queue_work(driver->diag_wq,
98 &(driver->diag_read_smd_wcnss_cntl_work));
99 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700100}
101
102void diag_read_smd_cntl_work_fn(struct work_struct *work)
103{
104 diag_smd_cntl_send_req(MODEM_PROC);
105}
106
107void diag_read_smd_qdsp_cntl_work_fn(struct work_struct *work)
108{
109 diag_smd_cntl_send_req(QDSP_PROC);
110}
111
112void diag_read_smd_wcnss_cntl_work_fn(struct work_struct *work)
113{
114 diag_smd_cntl_send_req(WCNSS_PROC);
115}
116
117static void diag_smd_cntl_notify(void *ctxt, unsigned event)
118{
119 queue_work(driver->diag_wq, &(driver->diag_read_smd_cntl_work));
120}
121
122#if defined(CONFIG_MSM_N_WAY_SMD)
123static void diag_smd_qdsp_cntl_notify(void *ctxt, unsigned event)
124{
125 queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_cntl_work));
126}
127#endif
128
129static void diag_smd_wcnss_cntl_notify(void *ctxt, unsigned event)
130{
131 queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_cntl_work));
132}
133
134static int diag_smd_cntl_probe(struct platform_device *pdev)
135{
136 int r = 0;
137
138 /* open control ports only on 8960 */
139 if (chk_config_get_id() == AO8960_TOOLS_ID) {
140 if (pdev->id == SMD_APPS_MODEM)
141 r = smd_open("DIAG_CNTL", &driver->ch_cntl, driver,
142 diag_smd_cntl_notify);
143 if (pdev->id == SMD_APPS_QDSP)
144 r = smd_named_open_on_edge("DIAG_CNTL", SMD_APPS_QDSP
145 , &driver->chqdsp_cntl, driver,
146 diag_smd_qdsp_cntl_notify);
147 if (pdev->id == SMD_APPS_WCNSS)
148 r = smd_named_open_on_edge("APPS_RIVA_CTRL",
149 SMD_APPS_WCNSS, &driver->ch_wcnss_cntl,
150 driver, diag_smd_wcnss_cntl_notify);
151 pr_debug("diag: open CNTL port, ID = %d,r = %d\n", pdev->id, r);
152 }
153 return 0;
154}
155
156static int diagfwd_cntl_runtime_suspend(struct device *dev)
157{
158 dev_dbg(dev, "pm_runtime: suspending...\n");
159 return 0;
160}
161
162static int diagfwd_cntl_runtime_resume(struct device *dev)
163{
164 dev_dbg(dev, "pm_runtime: resuming...\n");
165 return 0;
166}
167
168static const struct dev_pm_ops diagfwd_cntl_dev_pm_ops = {
169 .runtime_suspend = diagfwd_cntl_runtime_suspend,
170 .runtime_resume = diagfwd_cntl_runtime_resume,
171};
172
173static struct platform_driver msm_smd_ch1_cntl_driver = {
174
175 .probe = diag_smd_cntl_probe,
176 .driver = {
177 .name = "DIAG_CNTL",
178 .owner = THIS_MODULE,
179 .pm = &diagfwd_cntl_dev_pm_ops,
180 },
181};
182
183static struct platform_driver diag_smd_lite_cntl_driver = {
184
185 .probe = diag_smd_cntl_probe,
186 .driver = {
187 .name = "APPS_RIVA_CTRL",
188 .owner = THIS_MODULE,
189 .pm = &diagfwd_cntl_dev_pm_ops,
190 },
191};
192
193void diagfwd_cntl_init(void)
194{
195 if (driver->buf_in_cntl == NULL) {
196 driver->buf_in_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
197 if (driver->buf_in_cntl == NULL)
198 goto err;
199 }
200 if (driver->buf_in_qdsp_cntl == NULL) {
201 driver->buf_in_qdsp_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
202 if (driver->buf_in_qdsp_cntl == NULL)
203 goto err;
204 }
205 if (driver->buf_in_wcnss_cntl == NULL) {
206 driver->buf_in_wcnss_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
207 if (driver->buf_in_wcnss_cntl == NULL)
208 goto err;
209 }
210 platform_driver_register(&msm_smd_ch1_cntl_driver);
211 platform_driver_register(&diag_smd_lite_cntl_driver);
212
213 return;
214err:
215 pr_err("diag: Could not initialize diag buffers");
216 kfree(driver->buf_in_cntl);
217 kfree(driver->buf_in_qdsp_cntl);
218 kfree(driver->buf_in_wcnss_cntl);
219}
220
221void diagfwd_cntl_exit(void)
222{
223 smd_close(driver->ch_cntl);
224 smd_close(driver->chqdsp_cntl);
225 smd_close(driver->ch_wcnss_cntl);
226 driver->ch_cntl = 0;
227 driver->chqdsp_cntl = 0;
228 driver->ch_wcnss_cntl = 0;
229 platform_driver_unregister(&msm_smd_ch1_cntl_driver);
230 platform_driver_unregister(&diag_smd_lite_cntl_driver);
231
232 kfree(driver->buf_in_cntl);
233 kfree(driver->buf_in_qdsp_cntl);
234 kfree(driver->buf_in_wcnss_cntl);
235}