blob: 45226ba1cf1c0208f404b6572b5a8694feeb6a33 [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{
24 int data_len = 0, type = -1, count_bytes = 0, j, r;
25 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;
83 diagchar_ioctl(NULL, DIAG_IOCTL_COMMAND_REG,
84 (unsigned long)pkt_params);
85 kfree(temp);
86 buf = buf + HDR_SIZ + data_len;
87 }
88 }
89 }
90 kfree(pkt_params);
91}
92
93void diag_read_smd_cntl_work_fn(struct work_struct *work)
94{
95 diag_smd_cntl_send_req(MODEM_PROC);
96}
97
98void diag_read_smd_qdsp_cntl_work_fn(struct work_struct *work)
99{
100 diag_smd_cntl_send_req(QDSP_PROC);
101}
102
103void diag_read_smd_wcnss_cntl_work_fn(struct work_struct *work)
104{
105 diag_smd_cntl_send_req(WCNSS_PROC);
106}
107
108static void diag_smd_cntl_notify(void *ctxt, unsigned event)
109{
110 queue_work(driver->diag_wq, &(driver->diag_read_smd_cntl_work));
111}
112
113#if defined(CONFIG_MSM_N_WAY_SMD)
114static void diag_smd_qdsp_cntl_notify(void *ctxt, unsigned event)
115{
116 queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_cntl_work));
117}
118#endif
119
120static void diag_smd_wcnss_cntl_notify(void *ctxt, unsigned event)
121{
122 queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_cntl_work));
123}
124
125static int diag_smd_cntl_probe(struct platform_device *pdev)
126{
127 int r = 0;
128
129 /* open control ports only on 8960 */
130 if (chk_config_get_id() == AO8960_TOOLS_ID) {
131 if (pdev->id == SMD_APPS_MODEM)
132 r = smd_open("DIAG_CNTL", &driver->ch_cntl, driver,
133 diag_smd_cntl_notify);
134 if (pdev->id == SMD_APPS_QDSP)
135 r = smd_named_open_on_edge("DIAG_CNTL", SMD_APPS_QDSP
136 , &driver->chqdsp_cntl, driver,
137 diag_smd_qdsp_cntl_notify);
138 if (pdev->id == SMD_APPS_WCNSS)
139 r = smd_named_open_on_edge("APPS_RIVA_CTRL",
140 SMD_APPS_WCNSS, &driver->ch_wcnss_cntl,
141 driver, diag_smd_wcnss_cntl_notify);
142 pr_debug("diag: open CNTL port, ID = %d,r = %d\n", pdev->id, r);
143 }
144 return 0;
145}
146
147static int diagfwd_cntl_runtime_suspend(struct device *dev)
148{
149 dev_dbg(dev, "pm_runtime: suspending...\n");
150 return 0;
151}
152
153static int diagfwd_cntl_runtime_resume(struct device *dev)
154{
155 dev_dbg(dev, "pm_runtime: resuming...\n");
156 return 0;
157}
158
159static const struct dev_pm_ops diagfwd_cntl_dev_pm_ops = {
160 .runtime_suspend = diagfwd_cntl_runtime_suspend,
161 .runtime_resume = diagfwd_cntl_runtime_resume,
162};
163
164static struct platform_driver msm_smd_ch1_cntl_driver = {
165
166 .probe = diag_smd_cntl_probe,
167 .driver = {
168 .name = "DIAG_CNTL",
169 .owner = THIS_MODULE,
170 .pm = &diagfwd_cntl_dev_pm_ops,
171 },
172};
173
174static struct platform_driver diag_smd_lite_cntl_driver = {
175
176 .probe = diag_smd_cntl_probe,
177 .driver = {
178 .name = "APPS_RIVA_CTRL",
179 .owner = THIS_MODULE,
180 .pm = &diagfwd_cntl_dev_pm_ops,
181 },
182};
183
184void diagfwd_cntl_init(void)
185{
186 if (driver->buf_in_cntl == NULL) {
187 driver->buf_in_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
188 if (driver->buf_in_cntl == NULL)
189 goto err;
190 }
191 if (driver->buf_in_qdsp_cntl == NULL) {
192 driver->buf_in_qdsp_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
193 if (driver->buf_in_qdsp_cntl == NULL)
194 goto err;
195 }
196 if (driver->buf_in_wcnss_cntl == NULL) {
197 driver->buf_in_wcnss_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
198 if (driver->buf_in_wcnss_cntl == NULL)
199 goto err;
200 }
201 platform_driver_register(&msm_smd_ch1_cntl_driver);
202 platform_driver_register(&diag_smd_lite_cntl_driver);
203
204 return;
205err:
206 pr_err("diag: Could not initialize diag buffers");
207 kfree(driver->buf_in_cntl);
208 kfree(driver->buf_in_qdsp_cntl);
209 kfree(driver->buf_in_wcnss_cntl);
210}
211
212void diagfwd_cntl_exit(void)
213{
214 smd_close(driver->ch_cntl);
215 smd_close(driver->chqdsp_cntl);
216 smd_close(driver->ch_wcnss_cntl);
217 driver->ch_cntl = 0;
218 driver->chqdsp_cntl = 0;
219 driver->ch_wcnss_cntl = 0;
220 platform_driver_unregister(&msm_smd_ch1_cntl_driver);
221 platform_driver_unregister(&diag_smd_lite_cntl_driver);
222
223 kfree(driver->buf_in_cntl);
224 kfree(driver->buf_in_qdsp_cntl);
225 kfree(driver->buf_in_wcnss_cntl);
226}