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