blob: 22a2ccbe4a58a149d2af26af14874d696d846b40 [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
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);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070089 }
Dixon Petersone8054f02012-02-06 11:46:49 -080090 buf = buf + HDR_SIZ + data_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091 }
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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700124static void diag_smd_qdsp_cntl_notify(void *ctxt, unsigned event)
125{
126 queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_cntl_work));
127}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128
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
Shalabh Jain10f5f432012-01-11 11:45:44 +0530138 /* open control ports only on 8960 & newer targets */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700139 if (chk_apps_only()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140 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{
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800195 driver->polling_reg_flag = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196 if (driver->buf_in_cntl == NULL) {
197 driver->buf_in_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
198 if (driver->buf_in_cntl == NULL)
199 goto err;
200 }
201 if (driver->buf_in_qdsp_cntl == NULL) {
202 driver->buf_in_qdsp_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
203 if (driver->buf_in_qdsp_cntl == NULL)
204 goto err;
205 }
206 if (driver->buf_in_wcnss_cntl == NULL) {
207 driver->buf_in_wcnss_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
208 if (driver->buf_in_wcnss_cntl == NULL)
209 goto err;
210 }
211 platform_driver_register(&msm_smd_ch1_cntl_driver);
212 platform_driver_register(&diag_smd_lite_cntl_driver);
213
214 return;
215err:
216 pr_err("diag: Could not initialize diag buffers");
217 kfree(driver->buf_in_cntl);
218 kfree(driver->buf_in_qdsp_cntl);
219 kfree(driver->buf_in_wcnss_cntl);
220}
221
222void diagfwd_cntl_exit(void)
223{
224 smd_close(driver->ch_cntl);
225 smd_close(driver->chqdsp_cntl);
226 smd_close(driver->ch_wcnss_cntl);
227 driver->ch_cntl = 0;
228 driver->chqdsp_cntl = 0;
229 driver->ch_wcnss_cntl = 0;
230 platform_driver_unregister(&msm_smd_ch1_cntl_driver);
231 platform_driver_unregister(&diag_smd_lite_cntl_driver);
232
233 kfree(driver->buf_in_cntl);
234 kfree(driver->buf_in_qdsp_cntl);
235 kfree(driver->buf_in_wcnss_cntl);
236}