/arch/arm/mach-fsm/smd_rpcrouter_xdr.c
C | 419 lines | 308 code | 87 blank | 24 comment | 41 complexity | 92fd812bac62b5f38017c5ce008f0ad3 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
1/* Copyright (c) 2010, 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 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 *
17 */
18
19/*
20 * SMD RPCROUTER XDR module.
21 */
22
23#include <linux/types.h>
24#include <linux/string.h>
25#include <linux/kernel.h>
26#include <linux/delay.h>
27#include <linux/sched.h>
28
29#include <mach/msm_rpcrouter.h>
30
31int xdr_send_uint32(struct msm_rpc_xdr *xdr, const uint32_t *value)
32{
33 if ((xdr->out_index + sizeof(uint32_t)) > xdr->out_size) {
34 pr_err("%s: xdr out buffer full\n", __func__);
35 return -1;
36 }
37
38 *(uint32_t *)(xdr->out_buf + xdr->out_index) = cpu_to_be32(*value);
39 xdr->out_index += sizeof(uint32_t);
40 return 0;
41}
42
43int xdr_send_int8(struct msm_rpc_xdr *xdr, const int8_t *value)
44{
45 return xdr_send_uint32(xdr, (uint32_t *)value);
46}
47
48int xdr_send_uint8(struct msm_rpc_xdr *xdr, const uint8_t *value)
49{
50 return xdr_send_uint32(xdr, (uint32_t *)value);
51}
52
53int xdr_send_int16(struct msm_rpc_xdr *xdr, const int16_t *value)
54{
55 return xdr_send_uint32(xdr, (uint32_t *)value);
56}
57
58int xdr_send_uint16(struct msm_rpc_xdr *xdr, const uint16_t *value)
59{
60 return xdr_send_uint32(xdr, (uint32_t *)value);
61}
62
63int xdr_send_int32(struct msm_rpc_xdr *xdr, const int32_t *value)
64{
65 return xdr_send_uint32(xdr, (uint32_t *)value);
66}
67
68int xdr_send_bytes(struct msm_rpc_xdr *xdr, const void **data,
69 uint32_t *size)
70{
71 void *buf = xdr->out_buf + xdr->out_index;
72 uint32_t temp;
73
74 if (!size || !data || !*data)
75 return -1;
76
77 temp = *size;
78 if (temp & 0x3)
79 temp += 4 - (temp & 0x3);
80
81 temp += sizeof(uint32_t);
82 if ((xdr->out_index + temp) > xdr->out_size) {
83 pr_err("%s: xdr out buffer full\n", __func__);
84 return -1;
85 }
86
87 *((uint32_t *)buf) = cpu_to_be32(*size);
88 buf += sizeof(uint32_t);
89 memcpy(buf, *data, *size);
90 buf += *size;
91 if (*size & 0x3) {
92 memset(buf, 0, 4 - (*size & 0x3));
93 buf += 4 - (*size & 0x3);
94 }
95
96 xdr->out_index = buf - xdr->out_buf;
97 return 0;
98}
99
100int xdr_recv_uint32(struct msm_rpc_xdr *xdr, uint32_t *value)
101{
102 if ((xdr->in_index + sizeof(uint32_t)) > xdr->in_size) {
103 pr_err("%s: xdr in buffer full\n", __func__);
104 return -1;
105 }
106
107 *value = be32_to_cpu(*(uint32_t *)(xdr->in_buf + xdr->in_index));
108 xdr->in_index += sizeof(uint32_t);
109 return 0;
110}
111
112int xdr_recv_int8(struct msm_rpc_xdr *xdr, int8_t *value)
113{
114 return xdr_recv_uint32(xdr, (uint32_t *)value);
115}
116
117int xdr_recv_uint8(struct msm_rpc_xdr *xdr, uint8_t *value)
118{
119 return xdr_recv_uint32(xdr, (uint32_t *)value);
120}
121
122int xdr_recv_int16(struct msm_rpc_xdr *xdr, int16_t *value)
123{
124 return xdr_recv_uint32(xdr, (uint32_t *)value);
125}
126
127int xdr_recv_uint16(struct msm_rpc_xdr *xdr, uint16_t *value)
128{
129 return xdr_recv_uint32(xdr, (uint32_t *)value);
130}
131
132int xdr_recv_int32(struct msm_rpc_xdr *xdr, int32_t *value)
133{
134 return xdr_recv_uint32(xdr, (uint32_t *)value);
135}
136
137int xdr_recv_bytes(struct msm_rpc_xdr *xdr, void **data,
138 uint32_t *size)
139{
140 void *buf = xdr->in_buf + xdr->in_index;
141 uint32_t temp;
142
143 if (!size || !data)
144 return -1;
145
146 *size = be32_to_cpu(*(uint32_t *)buf);
147 buf += sizeof(uint32_t);
148
149 temp = *size;
150 if (temp & 0x3)
151 temp += 4 - (temp & 0x3);
152
153 temp += sizeof(uint32_t);
154 if ((xdr->in_index + temp) > xdr->in_size) {
155 pr_err("%s: xdr in buffer full\n", __func__);
156 return -1;
157 }
158
159 if (*size) {
160 *data = kmalloc(*size, GFP_KERNEL);
161 if (!*data)
162 return -1;
163
164 memcpy(*data, buf, *size);
165
166 buf += *size;
167 if (*size & 0x3)
168 buf += 4 - (*size & 0x3);
169 } else
170 *data = NULL;
171
172 xdr->in_index = buf - xdr->in_buf;
173 return 0;
174}
175
176int xdr_send_pointer(struct msm_rpc_xdr *xdr, void **obj,
177 uint32_t obj_size, void *xdr_op)
178{
179 uint32_t ptr_valid, rc;
180
181 ptr_valid = (*obj != NULL);
182
183 rc = xdr_send_uint32(xdr, &ptr_valid);
184 if (rc)
185 return rc;
186
187 if (!ptr_valid)
188 return 0;
189
190 return ((int (*) (struct msm_rpc_xdr *, void *))xdr_op)(xdr, *obj);
191}
192
193int xdr_recv_pointer(struct msm_rpc_xdr *xdr, void **obj,
194 uint32_t obj_size, void *xdr_op)
195{
196 uint32_t rc, ptr_valid = 0;
197
198 rc = xdr_recv_uint32(xdr, &ptr_valid);
199 if (rc)
200 return rc;
201
202 if (!ptr_valid) {
203 *obj = NULL;
204 return 0;
205 }
206
207 *obj = kmalloc(obj_size, GFP_KERNEL);
208 if (!*obj)
209 return -1;
210
211 rc = ((int (*) (struct msm_rpc_xdr *, void *))xdr_op)(xdr, *obj);
212 if (rc)
213 kfree(*obj);
214
215 return rc;
216}
217
218int xdr_send_array(struct msm_rpc_xdr *xdr, void **addr, uint32_t *size,
219 uint32_t maxsize, uint32_t elm_size, void *xdr_op)
220{
221 int i, rc;
222 void *tmp_addr = *addr;
223
224 if (!size || !tmp_addr || (*size > maxsize) || !xdr_op)
225 return -1;
226
227 rc = xdr_send_uint32(xdr, size);
228 if (rc)
229 return rc;
230
231 for (i = 0; i < *size; i++) {
232 rc = ((int (*) (struct msm_rpc_xdr *, void *))xdr_op)
233 (xdr, tmp_addr);
234 if (rc)
235 return rc;
236
237 tmp_addr += elm_size;
238 }
239
240 return 0;
241}
242
243int xdr_recv_array(struct msm_rpc_xdr *xdr, void **addr, uint32_t *size,
244 uint32_t maxsize, uint32_t elm_size, void *xdr_op)
245{
246 int i, rc;
247 void *tmp_addr;
248
249 if (!size || !xdr_op)
250 return -1;
251
252 rc = xdr_recv_uint32(xdr, size);
253 if (rc)
254 return rc;
255
256 if (*size > maxsize)
257 return -1;
258
259 tmp_addr = kmalloc((*size * elm_size), GFP_KERNEL);
260 if (!tmp_addr)
261 return -1;
262
263 *addr = tmp_addr;
264 for (i = 0; i < *size; i++) {
265 rc = ((int (*) (struct msm_rpc_xdr *, void *))xdr_op)
266 (xdr, tmp_addr);
267 if (rc) {
268 kfree(*addr);
269 *addr = NULL;
270 return rc;
271 }
272
273 tmp_addr += elm_size;
274 }
275
276 return 0;
277}
278
279int xdr_recv_req(struct msm_rpc_xdr *xdr, struct rpc_request_hdr *req)
280{
281 int rc = 0;
282 if (!req)
283 return -1;
284
285 rc |= xdr_recv_uint32(xdr, &req->xid); /* xid */
286 rc |= xdr_recv_uint32(xdr, &req->type); /* type */
287 rc |= xdr_recv_uint32(xdr, &req->rpc_vers); /* rpc_vers */
288 rc |= xdr_recv_uint32(xdr, &req->prog); /* prog */
289 rc |= xdr_recv_uint32(xdr, &req->vers); /* vers */
290 rc |= xdr_recv_uint32(xdr, &req->procedure); /* procedure */
291 rc |= xdr_recv_uint32(xdr, &req->cred_flavor); /* cred_flavor */
292 rc |= xdr_recv_uint32(xdr, &req->cred_length); /* cred_length */
293 rc |= xdr_recv_uint32(xdr, &req->verf_flavor); /* verf_flavor */
294 rc |= xdr_recv_uint32(xdr, &req->verf_length); /* verf_length */
295
296 return rc;
297}
298
299int xdr_recv_reply(struct msm_rpc_xdr *xdr, struct rpc_reply_hdr *reply)
300{
301 int rc = 0;
302
303 if (!reply)
304 return -1;
305
306 rc |= xdr_recv_uint32(xdr, &reply->xid); /* xid */
307 rc |= xdr_recv_uint32(xdr, &reply->type); /* type */
308 rc |= xdr_recv_uint32(xdr, &reply->reply_stat); /* reply_stat */
309
310 /* acc_hdr */
311 if (reply->reply_stat == RPCMSG_REPLYSTAT_ACCEPTED) {
312 rc |= xdr_recv_uint32(xdr, &reply->data.acc_hdr.verf_flavor);
313 rc |= xdr_recv_uint32(xdr, &reply->data.acc_hdr.verf_length);
314 rc |= xdr_recv_uint32(xdr, &reply->data.acc_hdr.accept_stat);
315 }
316
317 return rc;
318}
319
320int xdr_start_request(struct msm_rpc_xdr *xdr, uint32_t prog,
321 uint32_t ver, uint32_t proc)
322{
323 mutex_lock(&xdr->out_lock);
324
325 /* TODO: replace below function with its implementation */
326 msm_rpc_setup_req((struct rpc_request_hdr *)xdr->out_buf,
327 prog, ver, proc);
328
329 xdr->out_index = sizeof(struct rpc_request_hdr);
330 return 0;
331}
332
333int xdr_start_accepted_reply(struct msm_rpc_xdr *xdr, uint32_t accept_status)
334{
335 struct rpc_reply_hdr *reply;
336
337 mutex_lock(&xdr->out_lock);
338
339 /* TODO: err if xdr is not cb xdr */
340 reply = (struct rpc_reply_hdr *)xdr->out_buf;
341
342 /* TODO: use xdr functions instead */
343 reply->xid = ((struct rpc_request_hdr *)(xdr->in_buf))->xid;
344 reply->type = cpu_to_be32(1); /* reply */
345 reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
346
347 reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
348 reply->data.acc_hdr.verf_flavor = 0;
349 reply->data.acc_hdr.verf_length = 0;
350
351 xdr->out_index = sizeof(*reply);
352 return 0;
353}
354
355int xdr_send_msg(struct msm_rpc_xdr *xdr)
356{
357 int rc = 0;
358
359 rc = msm_rpc_write(xdr->ept, xdr->out_buf,
360 xdr->out_index);
361 if (rc > 0)
362 rc = 0;
363
364 mutex_unlock(&xdr->out_lock);
365 return rc;
366}
367
368void xdr_init(struct msm_rpc_xdr *xdr)
369{
370 mutex_init(&xdr->out_lock);
371 init_waitqueue_head(&xdr->in_buf_wait_q);
372
373 xdr->in_buf = NULL;
374 xdr->in_size = 0;
375 xdr->in_index = 0;
376
377 xdr->out_buf = NULL;
378 xdr->out_size = 0;
379 xdr->out_index = 0;
380}
381
382void xdr_init_input(struct msm_rpc_xdr *xdr, void *buf, uint32_t size)
383{
384 wait_event(xdr->in_buf_wait_q, !(xdr->in_buf));
385
386 xdr->in_buf = buf;
387 xdr->in_size = size;
388 xdr->in_index = 0;
389}
390
391void xdr_init_output(struct msm_rpc_xdr *xdr, void *buf, uint32_t size)
392{
393 xdr->out_buf = buf;
394 xdr->out_size = size;
395 xdr->out_index = 0;
396}
397
398void xdr_clean_input(struct msm_rpc_xdr *xdr)
399{
400 kfree(xdr->in_buf);
401 xdr->in_size = 0;
402 xdr->in_index = 0;
403 xdr->in_buf = NULL;
404
405 wake_up(&xdr->in_buf_wait_q);
406}
407
408void xdr_clean_output(struct msm_rpc_xdr *xdr)
409{
410 kfree(xdr->out_buf);
411 xdr->out_buf = NULL;
412 xdr->out_size = 0;
413 xdr->out_index = 0;
414}
415
416uint32_t xdr_read_avail(struct msm_rpc_xdr *xdr)
417{
418 return xdr->in_size;
419}