blob: 171168f3246a1cc2cf3e7117842bc90843b452ef [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>
16#include "diagchar.h"
17#include "diagfwd.h"
18#include "diagfwd_cntl.h"
19
20#define HDR_SIZ 8
21
Shalabh Jain4e1bd312012-02-16 19:33:05 -080022void diag_smd_cntl_notify(void *ctxt, unsigned event)
23{
24 int r1, r2;
25
26 if (!(driver->ch_cntl))
27 return;
28
29 switch (event) {
30 case SMD_EVENT_DATA:
31 r1 = smd_read_avail(driver->ch_cntl);
32 r2 = smd_cur_packet_size(driver->ch_cntl);
33 if (r1 > 0 && r1 == r2)
34 queue_work(driver->diag_wq,
35 &(driver->diag_read_smd_cntl_work));
36 else
37 pr_debug("diag: incomplete pkt on Modem CNTL ch\n");
38 break;
Shalabh Jain321c8b52012-02-22 12:37:06 -080039 case SMD_EVENT_OPEN:
40 queue_work(driver->diag_cntl_wq,
41 &(driver->diag_modem_mask_update_work));
42 break;
Shalabh Jain4e1bd312012-02-16 19:33:05 -080043 }
44}
45
46void diag_smd_qdsp_cntl_notify(void *ctxt, unsigned event)
47{
48 int r1, r2;
49
50 if (!(driver->chqdsp_cntl))
51 return;
52
53 switch (event) {
54 case SMD_EVENT_DATA:
55 r1 = smd_read_avail(driver->chqdsp_cntl);
56 r2 = smd_cur_packet_size(driver->chqdsp_cntl);
57 if (r1 > 0 && r1 == r2)
58 queue_work(driver->diag_wq,
59 &(driver->diag_read_smd_qdsp_cntl_work));
60 else
61 pr_debug("diag: incomplete pkt on LPASS CNTL ch\n");
62 break;
Shalabh Jain321c8b52012-02-22 12:37:06 -080063 case SMD_EVENT_OPEN:
64 queue_work(driver->diag_cntl_wq,
65 &(driver->diag_qdsp_mask_update_work));
66 break;
Shalabh Jain4e1bd312012-02-16 19:33:05 -080067 }
68}
69
70void diag_smd_wcnss_cntl_notify(void *ctxt, unsigned event)
71{
72 int r1, r2;
73
74 if (!(driver->ch_wcnss_cntl))
75 return;
76
77 switch (event) {
78 case SMD_EVENT_DATA:
79 r1 = smd_read_avail(driver->ch_wcnss_cntl);
80 r2 = smd_cur_packet_size(driver->ch_wcnss_cntl);
81 if (r1 > 0 && r1 == r2)
82 queue_work(driver->diag_wq,
83 &(driver->diag_read_smd_wcnss_cntl_work));
84 else
85 pr_debug("diag: incomplete pkt on WCNSS CNTL ch\n");
86 break;
Shalabh Jain321c8b52012-02-22 12:37:06 -080087 case SMD_EVENT_OPEN:
88 queue_work(driver->diag_cntl_wq,
89 &(driver->diag_wcnss_mask_update_work));
90 break;
Shalabh Jain4e1bd312012-02-16 19:33:05 -080091 }
92}
93
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094static void diag_smd_cntl_send_req(int proc_num)
95{
Shalabh Jaincf5f20e2011-08-22 12:29:52 -070096 int data_len = 0, type = -1, count_bytes = 0, j, r, flag = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070097 struct bindpkt_params_per_process *pkt_params =
98 kzalloc(sizeof(struct bindpkt_params_per_process), GFP_KERNEL);
99 struct diag_ctrl_msg *msg;
100 struct cmd_code_range *range;
101 struct bindpkt_params *temp;
102 void *buf = NULL;
103 smd_channel_t *smd_ch = NULL;
104
Shalabh Jain4e1bd312012-02-16 19:33:05 -0800105 if (pkt_params == NULL) {
106 pr_alert("diag: Memory allocation failure\n");
107 return;
108 }
109
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700110 if (proc_num == MODEM_PROC) {
111 buf = driver->buf_in_cntl;
112 smd_ch = driver->ch_cntl;
113 } else if (proc_num == QDSP_PROC) {
114 buf = driver->buf_in_qdsp_cntl;
115 smd_ch = driver->chqdsp_cntl;
116 } else if (proc_num == WCNSS_PROC) {
117 buf = driver->buf_in_wcnss_cntl;
118 smd_ch = driver->ch_wcnss_cntl;
119 }
120
Shalabh Jainf89c5462011-08-23 18:46:03 -0700121 if (!smd_ch || !buf) {
122 kfree(pkt_params);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123 return;
Shalabh Jainf89c5462011-08-23 18:46:03 -0700124 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700125
126 r = smd_read_avail(smd_ch);
127 if (r > IN_BUF_SIZE) {
128 if (r < MAX_IN_BUF_SIZE) {
129 pr_err("diag: SMD CNTL sending pkt upto %d bytes", r);
130 buf = krealloc(buf, r, GFP_KERNEL);
131 } else {
132 pr_err("diag: CNTL pkt > %d bytes", MAX_IN_BUF_SIZE);
133 kfree(pkt_params);
134 return;
135 }
136 }
137 if (buf && r > 0) {
138 smd_read(smd_ch, buf, r);
139 while (count_bytes + HDR_SIZ <= r) {
140 type = *(uint32_t *)(buf);
141 data_len = *(uint32_t *)(buf + 4);
Shalabh Jainf50076b2012-02-15 19:27:01 -0800142 if (type < DIAG_CTRL_MSG_REG ||
143 type > DIAG_CTRL_MSG_F3_MASK_V2) {
Shalabh Jain4e1bd312012-02-16 19:33:05 -0800144 pr_alert("diag: Invalid Msg type %d proc %d",
145 type, proc_num);
Shalabh Jainf50076b2012-02-15 19:27:01 -0800146 break;
147 }
148 if (data_len < 0 || data_len > r) {
Shalabh Jain4e1bd312012-02-16 19:33:05 -0800149 pr_alert("diag: Invalid data len %d proc %d",
150 data_len, proc_num);
Shalabh Jainf50076b2012-02-15 19:27:01 -0800151 break;
152 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153 count_bytes = count_bytes+HDR_SIZ+data_len;
154 if (type == DIAG_CTRL_MSG_REG && r >= count_bytes) {
155 msg = buf+HDR_SIZ;
156 range = buf+HDR_SIZ+
157 sizeof(struct diag_ctrl_msg);
158 pkt_params->count = msg->count_entries;
159 temp = kzalloc(pkt_params->count * sizeof(struct
160 bindpkt_params), GFP_KERNEL);
Shalabh Jain4e1bd312012-02-16 19:33:05 -0800161 if (temp == NULL) {
162 pr_alert("diag: Memory alloc fail\n");
Dixon Petersonee6fb2b2012-03-16 20:26:02 -0700163 kfree(pkt_params);
Shalabh Jain4e1bd312012-02-16 19:33:05 -0800164 return;
165 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700166 for (j = 0; j < pkt_params->count; j++) {
167 temp->cmd_code = msg->cmd_code;
168 temp->subsys_id = msg->subsysid;
169 temp->client_id = proc_num;
170 temp->proc_id = proc_num;
171 temp->cmd_code_lo = range->cmd_code_lo;
172 temp->cmd_code_hi = range->cmd_code_hi;
173 range++;
174 temp++;
175 }
176 temp -= pkt_params->count;
177 pkt_params->params = temp;
Shalabh Jaincf5f20e2011-08-22 12:29:52 -0700178 flag = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700179 diagchar_ioctl(NULL, DIAG_IOCTL_COMMAND_REG,
180 (unsigned long)pkt_params);
181 kfree(temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700182 }
Dixon Petersone8054f02012-02-06 11:46:49 -0800183 buf = buf + HDR_SIZ + data_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700184 }
185 }
186 kfree(pkt_params);
Shalabh Jaincf5f20e2011-08-22 12:29:52 -0700187 if (flag) {
188 /* Poll SMD CNTL channels to check for data */
Shalabh Jain4e1bd312012-02-16 19:33:05 -0800189 if (proc_num == MODEM_PROC)
190 diag_smd_cntl_notify(NULL, SMD_EVENT_DATA);
191 else if (proc_num == QDSP_PROC)
192 diag_smd_qdsp_cntl_notify(NULL, SMD_EVENT_DATA);
193 else if (proc_num == WCNSS_PROC)
194 diag_smd_wcnss_cntl_notify(NULL, SMD_EVENT_DATA);
Shalabh Jaincf5f20e2011-08-22 12:29:52 -0700195 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196}
197
198void diag_read_smd_cntl_work_fn(struct work_struct *work)
199{
200 diag_smd_cntl_send_req(MODEM_PROC);
201}
202
203void diag_read_smd_qdsp_cntl_work_fn(struct work_struct *work)
204{
205 diag_smd_cntl_send_req(QDSP_PROC);
206}
207
208void diag_read_smd_wcnss_cntl_work_fn(struct work_struct *work)
209{
210 diag_smd_cntl_send_req(WCNSS_PROC);
211}
212
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213static int diag_smd_cntl_probe(struct platform_device *pdev)
214{
215 int r = 0;
216
Shalabh Jain10f5f432012-01-11 11:45:44 +0530217 /* open control ports only on 8960 & newer targets */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700218 if (chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219 if (pdev->id == SMD_APPS_MODEM)
220 r = smd_open("DIAG_CNTL", &driver->ch_cntl, driver,
221 diag_smd_cntl_notify);
222 if (pdev->id == SMD_APPS_QDSP)
223 r = smd_named_open_on_edge("DIAG_CNTL", SMD_APPS_QDSP
224 , &driver->chqdsp_cntl, driver,
225 diag_smd_qdsp_cntl_notify);
226 if (pdev->id == SMD_APPS_WCNSS)
227 r = smd_named_open_on_edge("APPS_RIVA_CTRL",
228 SMD_APPS_WCNSS, &driver->ch_wcnss_cntl,
229 driver, diag_smd_wcnss_cntl_notify);
230 pr_debug("diag: open CNTL port, ID = %d,r = %d\n", pdev->id, r);
231 }
232 return 0;
233}
234
235static int diagfwd_cntl_runtime_suspend(struct device *dev)
236{
237 dev_dbg(dev, "pm_runtime: suspending...\n");
238 return 0;
239}
240
241static int diagfwd_cntl_runtime_resume(struct device *dev)
242{
243 dev_dbg(dev, "pm_runtime: resuming...\n");
244 return 0;
245}
246
247static const struct dev_pm_ops diagfwd_cntl_dev_pm_ops = {
248 .runtime_suspend = diagfwd_cntl_runtime_suspend,
249 .runtime_resume = diagfwd_cntl_runtime_resume,
250};
251
252static struct platform_driver msm_smd_ch1_cntl_driver = {
253
254 .probe = diag_smd_cntl_probe,
255 .driver = {
256 .name = "DIAG_CNTL",
257 .owner = THIS_MODULE,
258 .pm = &diagfwd_cntl_dev_pm_ops,
259 },
260};
261
262static struct platform_driver diag_smd_lite_cntl_driver = {
263
264 .probe = diag_smd_cntl_probe,
265 .driver = {
266 .name = "APPS_RIVA_CTRL",
267 .owner = THIS_MODULE,
268 .pm = &diagfwd_cntl_dev_pm_ops,
269 },
270};
271
272void diagfwd_cntl_init(void)
273{
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800274 driver->polling_reg_flag = 0;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800275 driver->diag_cntl_wq = create_singlethread_workqueue("diag_cntl_wq");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276 if (driver->buf_in_cntl == NULL) {
277 driver->buf_in_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
278 if (driver->buf_in_cntl == NULL)
279 goto err;
280 }
281 if (driver->buf_in_qdsp_cntl == NULL) {
282 driver->buf_in_qdsp_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
283 if (driver->buf_in_qdsp_cntl == NULL)
284 goto err;
285 }
286 if (driver->buf_in_wcnss_cntl == NULL) {
287 driver->buf_in_wcnss_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
288 if (driver->buf_in_wcnss_cntl == NULL)
289 goto err;
290 }
291 platform_driver_register(&msm_smd_ch1_cntl_driver);
292 platform_driver_register(&diag_smd_lite_cntl_driver);
293
294 return;
295err:
296 pr_err("diag: Could not initialize diag buffers");
297 kfree(driver->buf_in_cntl);
298 kfree(driver->buf_in_qdsp_cntl);
299 kfree(driver->buf_in_wcnss_cntl);
Shalabh Jain321c8b52012-02-22 12:37:06 -0800300 if (driver->diag_cntl_wq)
301 destroy_workqueue(driver->diag_cntl_wq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302}
303
304void diagfwd_cntl_exit(void)
305{
306 smd_close(driver->ch_cntl);
307 smd_close(driver->chqdsp_cntl);
308 smd_close(driver->ch_wcnss_cntl);
309 driver->ch_cntl = 0;
310 driver->chqdsp_cntl = 0;
311 driver->ch_wcnss_cntl = 0;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800312 destroy_workqueue(driver->diag_cntl_wq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700313 platform_driver_unregister(&msm_smd_ch1_cntl_driver);
314 platform_driver_unregister(&diag_smd_lite_cntl_driver);
315
316 kfree(driver->buf_in_cntl);
317 kfree(driver->buf_in_qdsp_cntl);
318 kfree(driver->buf_in_wcnss_cntl);
319}