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