source: mainline/uspace/lib/libc/generic/ipc.c@ 5d4e90f0

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5d4e90f0 was 26f2af0, checked in by Jakub Jermar <jakub@…>, 18 years ago

VFS work.
Implement VFS_REGISTER part of the protocol in the FAT file system.

IPC work.
Rename ipc_data_send_accept() to ipc_data_receive() and ipc_data_send_answer()
to ipc_data_deliver(). Introduce ipc_data_send().

  • Property mode set to 100644
File size: 19.0 KB
RevLine 
[b419162]1/*
[df4ed85]2 * Copyright (c) 2006 Ondrej Palkovsky
[b419162]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[b2951e2]27 */
28
29/** @addtogroup libc
30 * @{
31 * @}
32 */
33
[fadd381]34/** @addtogroup libcipc IPC
[b2951e2]35 * @brief HelenOS uspace IPC
36 * @{
37 * @ingroup libc
38 */
39/** @file
[b419162]40 */
41
[7ee6aff]42#include <ipc/ipc.h>
[b419162]43#include <libc.h>
[936351c1]44#include <malloc.h>
45#include <errno.h>
[7ee6aff]46#include <libadt/list.h>
[936351c1]47#include <stdio.h>
48#include <unistd.h>
[35509652]49#include <futex.h>
[04a73cdf]50#include <kernel/synch/synch.h>
[fc42b28]51#include <async.h>
[bc1f1c2]52#include <fibril.h>
[183b4a0]53#include <assert.h>
[b419162]54
[36c9234]55/**
56 * Structures of this type are used for keeping track of sent asynchronous calls
57 * and queing unsent calls.
[936351c1]58 */
59typedef struct {
60 link_t list;
61
62 ipc_async_callback_t callback;
63 void *private;
64 union {
65 ipc_callid_t callid;
66 struct {
[4c61e60]67 ipc_call_t data;
[936351c1]68 int phoneid;
69 } msg;
[8b243f2]70 } u;
[bc1f1c2]71 fid_t fid; /**< Fibril waiting for sending this call. */
[936351c1]72} async_call_t;
73
74LIST_INITIALIZE(dispatched_calls);
[fc42b28]75
[8b243f2]76/** List of asynchronous calls that were not accepted by kernel.
77 *
78 * It is protected by async_futex, because if the call cannot be sent into the
79 * kernel, the async framework is used automatically.
[fc42b28]80 */
[8b243f2]81LIST_INITIALIZE(queued_calls);
[936351c1]82
[80649a91]83static atomic_t ipc_futex = FUTEX_INITIALIZER;
[35509652]84
[8b243f2]85/** Make a fast synchronous call.
86 *
87 * Only one payload argument can be passed using this function. However, this
88 * function is faster than the generic ipc_call_sync_3().
89 *
90 * @param phoneid Phone handle for the call.
91 * @param method Requested method.
92 * @param arg1 Service-defined payload argument.
93 * @param result If non-NULL, the return ARG1 will be stored there.
94 *
95 * @return Negative values represent errors returned by IPC.
96 * Otherwise the RETVAL of the answer is returned.
97 */
98int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t *result)
[b419162]99{
[4c61e60]100 ipc_call_t resdata;
[06502f7d]101 int callres;
102
[936351c1]103 callres = __SYSCALL4(SYS_IPC_CALL_SYNC_FAST, phoneid, method, arg1,
[8b243f2]104 (sysarg_t) &resdata);
[06502f7d]105 if (callres)
106 return callres;
107 if (result)
108 *result = IPC_GET_ARG1(resdata);
109 return IPC_GET_RETVAL(resdata);
[b419162]110}
111
[8b243f2]112/** Make a synchronous call transmitting 3 arguments of payload.
113 *
114 * @param phoneid Phone handle for the call.
115 * @param method Requested method.
116 * @param arg1 Service-defined payload argument.
117 * @param arg2 Service-defined payload argument.
118 * @param arg3 Service-defined payload argument.
119 * @param result1 If non-NULL, storage for the first return argument.
120 * @param result2 If non-NULL, storage for the second return argument.
121 * @param result3 If non-NULL, storage for the third return argument.
122 *
123 * @return Negative value means IPC error.
124 * Otherwise the RETVAL of the answer.
125 */
126int ipc_call_sync_3(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
127 ipcarg_t arg3, ipcarg_t *result1, ipcarg_t *result2, ipcarg_t *result3)
[06502f7d]128{
[4c61e60]129 ipc_call_t data;
[06502f7d]130 int callres;
131
132 IPC_SET_METHOD(data, method);
133 IPC_SET_ARG1(data, arg1);
134 IPC_SET_ARG2(data, arg2);
135 IPC_SET_ARG3(data, arg3);
136
[8b243f2]137 callres = __SYSCALL3(SYS_IPC_CALL_SYNC, phoneid, (sysarg_t) &data,
138 (sysarg_t) &data);
[06502f7d]139 if (callres)
140 return callres;
141
142 if (result1)
143 *result1 = IPC_GET_ARG1(data);
144 if (result2)
145 *result2 = IPC_GET_ARG2(data);
146 if (result3)
147 *result3 = IPC_GET_ARG3(data);
148 return IPC_GET_RETVAL(data);
149}
150
[8b243f2]151/** Syscall to send asynchronous message.
152 *
153 * @param phoneid Phone handle for the call.
154 * @param data Call data with the request.
155 *
156 * @return Hash of the call or an error code.
157 */
158static ipc_callid_t _ipc_call_async(int phoneid, ipc_call_t *data)
[936351c1]159{
[8b243f2]160 return __SYSCALL2(SYS_IPC_CALL_ASYNC, phoneid, (sysarg_t) data);
[936351c1]161}
162
[8b243f2]163/** Prolog to ipc_call_async_*() functions.
164 *
165 * @param private Argument for the answer/error callback.
166 * @param callback Answer/error callback.
167 *
168 * @return New, partially initialized async_call structure or NULL.
169 */
170static inline async_call_t *ipc_prepare_async(void *private,
171 ipc_async_callback_t callback)
[b419162]172{
[936351c1]173 async_call_t *call;
[06502f7d]174
[936351c1]175 call = malloc(sizeof(*call));
176 if (!call) {
[a784a96]177 if (callback)
178 callback(private, ENOMEM, NULL);
[c1d2c9d]179 return NULL;
[936351c1]180 }
[fc42b28]181 call->callback = callback;
182 call->private = private;
183
[c1d2c9d]184 return call;
185}
186
[8b243f2]187/** Epilogue of ipc_call_async_*() functions.
188 *
189 * @param callid Value returned by the SYS_IPC_CALL_ASYNC_* syscall.
190 * @param phoneid Phone handle through which the call was made.
191 * @param call async_call structure returned by ipc_prepare_async().
[c3b25510]192 * @param can_preempt If non-zero, the current fibril can be preempted in this
193 * call.
[8b243f2]194 */
195static inline void ipc_finish_async(ipc_callid_t callid, int phoneid,
196 async_call_t *call, int can_preempt)
[c1d2c9d]197{
[d8b42fb2]198 if (!call) { /* Nothing to do regardless if failed or not */
199 futex_up(&ipc_futex);
200 return;
201 }
202
[06502f7d]203 if (callid == IPC_CALLRET_FATAL) {
[fc42b28]204 futex_up(&ipc_futex);
[06502f7d]205 /* Call asynchronous handler with error code */
[c1d2c9d]206 if (call->callback)
207 call->callback(call->private, ENOENT, NULL);
[936351c1]208 free(call);
[06502f7d]209 return;
210 }
[936351c1]211
[06502f7d]212 if (callid == IPC_CALLRET_TEMPORARY) {
[fc42b28]213 futex_up(&ipc_futex);
214
[936351c1]215 call->u.msg.phoneid = phoneid;
[b1f51f0]216
[fc42b28]217 futex_down(&async_futex);
[936351c1]218 list_append(&call->list, &queued_calls);
[fc42b28]219
[b1f51f0]220 if (can_preempt) {
[bc1f1c2]221 call->fid = fibril_get_id();
222 fibril_schedule_next_adv(FIBRIL_TO_MANAGER);
[b1f51f0]223 /* Async futex unlocked by previous call */
224 } else {
[bc1f1c2]225 call->fid = 0;
[b1f51f0]226 futex_up(&async_futex);
227 }
[06502f7d]228 return;
229 }
[936351c1]230 call->u.callid = callid;
[8b243f2]231 /* Add call to the list of dispatched calls */
[936351c1]232 list_append(&call->list, &dispatched_calls);
[35509652]233 futex_up(&ipc_futex);
[c1d2c9d]234
235}
236
[8b243f2]237/** Make a fast asynchronous call.
238 *
239 * This function can only handle two arguments of payload. It is, however,
240 * faster than the more generic ipc_call_async_3().
241 *
242 * Note that this function is a void function.
243 * During normal opertation, answering this call will trigger the callback.
244 * In case of fatal error, call the callback handler with the proper error code.
245 * If the call cannot be temporarily made, queue it.
[c1d2c9d]246 *
[8b243f2]247 * @param phoneid Phone handle for the call.
248 * @param method Requested method.
249 * @param arg1 Service-defined payload argument.
250 * @param arg2 Service-defined payload argument.
251 * @param private Argument to be passed to the answer/error callback.
252 * @param callback Answer or error callback.
[c3b25510]253 * @param can_preempt If non-zero, the current fibril will be preempted in
254 * case the kernel temporarily refuses to accept more
[8b243f2]255 * asynchronous calls.
[c1d2c9d]256 */
257void ipc_call_async_2(int phoneid, ipcarg_t method, ipcarg_t arg1,
[8b243f2]258 ipcarg_t arg2, void *private, ipc_async_callback_t callback,
259 int can_preempt)
[c1d2c9d]260{
[d8b42fb2]261 async_call_t *call = NULL;
[c1d2c9d]262 ipc_callid_t callid;
263
[d8b42fb2]264 if (callback) {
265 call = ipc_prepare_async(private, callback);
266 if (!call)
267 return;
268 }
[c1d2c9d]269
[8b243f2]270 /*
271 * We need to make sure that we get callid before another thread
272 * accesses the queue again.
273 */
[c1d2c9d]274 futex_down(&ipc_futex);
[8b243f2]275 callid = __SYSCALL4(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1,
276 arg2);
[c1d2c9d]277
278 if (callid == IPC_CALLRET_TEMPORARY) {
[d8b42fb2]279 if (!call) {
280 call = ipc_prepare_async(private, callback);
281 if (!call)
282 return;
283 }
[c1d2c9d]284 IPC_SET_METHOD(call->u.msg.data, method);
285 IPC_SET_ARG1(call->u.msg.data, arg1);
286 IPC_SET_ARG2(call->u.msg.data, arg2);
287 }
[b1f51f0]288 ipc_finish_async(callid, phoneid, call, can_preempt);
[c1d2c9d]289}
290
[8b243f2]291/** Make an asynchronous call transmitting the entire payload.
292 *
293 * Note that this function is a void function.
294 * During normal opertation, answering this call will trigger the callback.
295 * In case of fatal error, call the callback handler with the proper error code.
296 * If the call cannot be temporarily made, queue it.
297 *
298 * @param phoneid Phone handle for the call.
299 * @param method Requested method.
300 * @param arg1 Service-defined payload argument.
301 * @param arg2 Service-defined payload argument.
302 * @param arg3 Service-defined payload argument.
303 * @param private Argument to be passed to the answer/error callback.
304 * @param callback Answer or error callback.
[c3b25510]305 * @param can_preempt If non-zero, the current fibril will be preempted in
306 * case the kernel temporarily refuses to accept more
[8b243f2]307 * asynchronous calls.
[c1d2c9d]308 *
309 */
310void ipc_call_async_3(int phoneid, ipcarg_t method, ipcarg_t arg1,
[8b243f2]311 ipcarg_t arg2, ipcarg_t arg3, void *private, ipc_async_callback_t callback,
312 int can_preempt)
[c1d2c9d]313{
314 async_call_t *call;
315 ipc_callid_t callid;
316
317 call = ipc_prepare_async(private, callback);
318 if (!call)
319 return;
320
321 IPC_SET_METHOD(call->u.msg.data, method);
322 IPC_SET_ARG1(call->u.msg.data, arg1);
323 IPC_SET_ARG2(call->u.msg.data, arg2);
324 IPC_SET_ARG3(call->u.msg.data, arg3);
[8b243f2]325 /*
326 * We need to make sure that we get callid before another thread accesses
327 * the queue again.
328 */
[c1d2c9d]329 futex_down(&ipc_futex);
330 callid = _ipc_call_async(phoneid, &call->u.msg.data);
331
[b1f51f0]332 ipc_finish_async(callid, phoneid, call, can_preempt);
[b419162]333}
334
[06502f7d]335
[8b243f2]336/** Answer a received call - fast version.
[250717cc]337 *
[8b243f2]338 * The fast answer makes use of passing retval and first two arguments in
339 * registers. If you need to return more, use the ipc_answer() instead.
[250717cc]340 *
[8b243f2]341 * @param callid Hash of the call being answered.
342 * @param retval Return value.
343 * @param arg1 First return argument.
344 * @param arg2 Second return argument.
[250717cc]345 *
[8b243f2]346 * @return Zero on success or a value from @ref errno.h on failure.
[250717cc]347 */
348ipcarg_t ipc_answer_fast(ipc_callid_t callid, ipcarg_t retval, ipcarg_t arg1,
[8b243f2]349 ipcarg_t arg2)
[b419162]350{
[8a568e3]351 return __SYSCALL4(SYS_IPC_ANSWER_FAST, callid, retval, arg1, arg2);
[b419162]352}
[06502f7d]353
[8b243f2]354/** Answer a received call - full version.
[250717cc]355 *
[8b243f2]356 * @param callid Hash of the call being answered.
357 * @param call Call structure with the answer.
358 * Must be already initialized by the responder.
[250717cc]359 *
[8b243f2]360 * @return Zero on success or a value from @ref errno.h on failure.
[250717cc]361 */
362ipcarg_t ipc_answer(ipc_callid_t callid, ipc_call_t *call)
363{
364 return __SYSCALL2(SYS_IPC_ANSWER, callid, (sysarg_t) call);
365}
366
367
[8b243f2]368/** Try to dispatch queued calls from the async queue. */
[936351c1]369static void try_dispatch_queued_calls(void)
370{
371 async_call_t *call;
372 ipc_callid_t callid;
373
[8b243f2]374 /** @todo
375 * Integrate intelligently ipc_futex, so that it is locked during
376 * ipc_call_async_*(), until it is added to dispatched_calls.
[fc42b28]377 */
378 futex_down(&async_futex);
[936351c1]379 while (!list_empty(&queued_calls)) {
[8b243f2]380 call = list_get_instance(queued_calls.next, async_call_t, list);
381 callid = _ipc_call_async(call->u.msg.phoneid, &call->u.msg.data);
[fc42b28]382 if (callid == IPC_CALLRET_TEMPORARY) {
[936351c1]383 break;
[fc42b28]384 }
[936351c1]385 list_remove(&call->list);
[35509652]386
[fc42b28]387 futex_up(&async_futex);
[bc1f1c2]388 if (call->fid)
389 fibril_add_ready(call->fid);
[fc42b28]390
[936351c1]391 if (callid == IPC_CALLRET_FATAL) {
[a784a96]392 if (call->callback)
393 call->callback(call->private, ENOENT, NULL);
[936351c1]394 free(call);
395 } else {
396 call->u.callid = callid;
[fc42b28]397 futex_down(&ipc_futex);
[936351c1]398 list_append(&call->list, &dispatched_calls);
[fc42b28]399 futex_up(&ipc_futex);
[936351c1]400 }
[fc42b28]401 futex_down(&async_futex);
[936351c1]402 }
[fc42b28]403 futex_up(&async_futex);
[936351c1]404}
405
[8b243f2]406/** Handle a received answer.
[936351c1]407 *
[8b243f2]408 * Find the hash of the answer and call the answer callback.
[936351c1]409 *
[8b243f2]410 * @todo Make it use hash table.
411 *
412 * @param callid Hash of the received answer.
413 * The answer has the same hash as the request OR'ed with
414 * the IPC_CALLID_ANSWERED bit.
415 * @param data Call data of the answer.
[936351c1]416 */
[4c61e60]417static void handle_answer(ipc_callid_t callid, ipc_call_t *data)
[936351c1]418{
419 link_t *item;
420 async_call_t *call;
421
422 callid &= ~IPC_CALLID_ANSWERED;
423
[35509652]424 futex_down(&ipc_futex);
[936351c1]425 for (item = dispatched_calls.next; item != &dispatched_calls;
[8b243f2]426 item = item->next) {
[936351c1]427 call = list_get_instance(item, async_call_t, list);
428 if (call->u.callid == callid) {
429 list_remove(&call->list);
[35509652]430 futex_up(&ipc_futex);
[a784a96]431 if (call->callback)
432 call->callback(call->private,
[8b243f2]433 IPC_GET_RETVAL(*data), data);
[a784a96]434 free(call);
[936351c1]435 return;
436 }
437 }
[35509652]438 futex_up(&ipc_futex);
[936351c1]439}
440
441
[8b243f2]442/** Wait for a first call to come.
443 *
444 * @param call Storage where the incoming call data will be stored.
445 * @param usec Timeout in microseconds
446 * @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking).
[b419162]447 *
[8b243f2]448 * @return Hash of the call. Note that certain bits have special
449 * meaning. IPC_CALLID_ANSWERED will be set in an answer
450 * and IPC_CALLID_NOTIFICATION is used for notifications.
451 *
[b419162]452 */
[80649a91]453ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags)
[b419162]454{
455 ipc_callid_t callid;
456
[80649a91]457 callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags);
458 /* Handle received answers */
[fc42b28]459 if (callid & IPC_CALLID_ANSWERED) {
[80649a91]460 handle_answer(callid, call);
[fc42b28]461 try_dispatch_queued_calls();
462 }
[04a73cdf]463
464 return callid;
465}
466
467/** Wait some time for an IPC call.
468 *
[8b243f2]469 * The call will return after an answer is received.
470 *
471 * @param call Storage where the incoming call data will be stored.
472 * @param usec Timeout in microseconds.
[096ba7a]473 *
[8b243f2]474 * @return Hash of the answer.
[04a73cdf]475 */
476ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *call, uint32_t usec)
477{
478 ipc_callid_t callid;
479
480 do {
[2d22049]481 callid = ipc_wait_cycle(call, usec, SYNCH_FLAGS_NONE);
[04a73cdf]482 } while (callid & IPC_CALLID_ANSWERED);
483
484 return callid;
485}
486
487/** Check if there is an IPC call waiting to be picked up.
488 *
[8b243f2]489 * @param call Storage where the incoming call will be stored.
490 * @return Hash of the answer.
[04a73cdf]491 */
492ipc_callid_t ipc_trywait_for_call(ipc_call_t *call)
493{
494 ipc_callid_t callid;
495
496 do {
[8b243f2]497 callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT,
498 SYNCH_FLAGS_NON_BLOCKING);
[06502f7d]499 } while (callid & IPC_CALLID_ANSWERED);
[936351c1]500
[b419162]501 return callid;
502}
[5106e98]503
[51ec40f]504/** Ask destination to do a callback connection.
[4c61e60]505 *
[8b243f2]506 * @param phoneid Phone handle used for contacting the other side.
507 * @param arg1 Service-defined argument.
508 * @param arg2 Service-defined argument.
509 * @param phonehash Storage where the library will store an opaque
[51ec40f]510 * identifier of the phone that will be used for incoming
[8b243f2]511 * calls. This identifier can be used for connection
512 * tracking.
513 *
514 * @return Zero on success or a negative error code.
[4c61e60]515 */
[51ec40f]516int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phonehash)
[5106e98]517{
[26f2af0]518 return ipc_call_sync_3(phoneid, IPC_M_CONNECT_TO_ME, arg1, arg2, 0, 0,
519 0, phonehash);
[5106e98]520}
[11eae82]521
[51ec40f]522/** Ask through phone for a new connection to some service.
[4c61e60]523 *
[8b243f2]524 * @param phoneid Phone handle used for contacting the other side.
[51ec40f]525 * @param arg1 User defined argument.
526 * @param arg2 User defined argument.
527 *
[8b243f2]528 * @return New phone handle on success or a negative error code.
[4c61e60]529 */
[11eae82]530int ipc_connect_me_to(int phoneid, int arg1, int arg2)
531{
[06b0d112]532 ipcarg_t newphid;
[4c61e60]533 int res;
534
[26f2af0]535 res = ipc_call_sync_3(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, 0, 0, 0,
[51ec40f]536 &newphid);
[4c61e60]537 if (res)
538 return res;
539 return newphid;
[11eae82]540}
541
[8b243f2]542/** Hang up a phone.
543 *
544 * @param phoneid Handle of the phone to be hung up.
545 *
546 * @return Zero on success or a negative error code.
547 */
[7048773]548int ipc_hangup(int phoneid)
549{
550 return __SYSCALL1(SYS_IPC_HANGUP, phoneid);
551}
[6180b57]552
[2b017ba]553/** Register IRQ notification.
554 *
[8b243f2]555 * @param inr IRQ number.
556 * @param devno Device number of the device generating inr.
557 * @param method Use this method for notifying me.
558 * @param ucode Top-half pseudocode handler.
[2b017ba]559 *
[8b243f2]560 * @return Value returned by the kernel.
[2b017ba]561 */
562int ipc_register_irq(int inr, int devno, int method, irq_code_t *ucode)
[6180b57]563{
[8b243f2]564 return __SYSCALL4(SYS_IPC_REGISTER_IRQ, inr, devno, method,
565 (sysarg_t) ucode);
[6180b57]566}
567
[2b017ba]568/** Unregister IRQ notification.
569 *
[8b243f2]570 * @param inr IRQ number.
571 * @param devno Device number of the device generating inr.
[2b017ba]572 *
[8b243f2]573 * @return Value returned by the kernel.
[2b017ba]574 */
575int ipc_unregister_irq(int inr, int devno)
[6180b57]576{
[2b017ba]577 return __SYSCALL2(SYS_IPC_UNREGISTER_IRQ, inr, devno);
[6180b57]578}
[8a568e3]579
[8b243f2]580/** Forward a received call to another destination.
581 *
582 * @param callid Hash of the call to forward.
583 * @param phoneid Phone handle to use for forwarding.
584 * @param method New method for the forwarded call.
585 * @param arg1 New value of the first argument for the forwarded call.
586 *
587 * @return Zero on success or an error code.
588 *
589 * For non-system methods, the old method and arg1 are rewritten by the new
590 * values. For system methods, the new method and arg1 are written to the old
591 * arg1 and arg2, respectivelly.
592 */
[043dcc27]593int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method, ipcarg_t arg1)
594{
595 return __SYSCALL4(SYS_IPC_FORWARD_FAST, callid, phoneid, method, arg1);
596}
597
[26f2af0]598/** Wrapper for making IPC_M_DATA_SEND calls.
[183b4a0]599 *
[26f2af0]600 * @param phoneid Phone that will be used to contact the receiving side.
601 * @param src Address of the beginning of the source buffer.
602 * @param size Size of the source buffer.
603 *
604 * @return Zero on success or a negative error code from errno.h.
605 */
606int ipc_data_send(int phoneid, void *src, size_t size)
607{
608 return ipc_call_sync_3(phoneid, IPC_M_DATA_SEND, 0, (ipcarg_t) src,
609 (ipcarg_t) size, NULL, NULL, NULL);
610}
611
612/** Wrapper for receiving the IPC_M_DATA_SEND calls.
613 *
614 * This wrapper only makes it more comfortable to receive IPC_M_DATA_SEND calls
[183b4a0]615 * so that the user doesn't have to remember the meaning of each IPC argument.
616 *
617 * So far, this wrapper is to be used from within a connection fibril.
618 *
619 * @param callid Storage where the hash of the IPC_M_DATA_SEND call will
620 * be stored.
621 * @param call Storage where the incoming call will be stored.
622 * @param dst Storage where the suggested destination address will
623 * be stored. May be NULL.
624 * @param size Storage where the suggested size will be stored. May be
625 * NULL
626 *
627 * @return Non-zero on success, zero on failure.
628 */
[26f2af0]629int ipc_data_receive(ipc_callid_t *callid, ipc_call_t *call, void **dst,
[183b4a0]630 size_t *size)
631{
632 assert(callid);
633 assert(call);
634
635 *callid = async_get_call(call);
636 if (IPC_GET_METHOD(*call) != IPC_M_DATA_SEND)
637 return 0;
638 if (dst)
639 *dst = (void *) IPC_GET_ARG1(*call);
640 if (size)
641 *size = (size_t) IPC_GET_ARG3(*call);
642 return 1;
643}
644
645/** Wrapper for answering the IPC_M_DATA_SEND calls.
646 *
647 * This wrapper only makes it more comfortable to answer IPC_M_DATA_SEND calls
648 * so that the user doesn't have to remember the meaning of each IPC argument.
649 *
650 * @param callid Hash of the IPC_M_DATA_SEND call to answer.
651 * @param call Call structure with the request.
652 * @param dst Final destination address for the IPC_M_DATA_SEND call.
653 * @param size Final size for the IPC_M_DATA_SEND call.
654 *
655 * @return Zero on success or a value from @ref errno.h on failure.
656 */
[26f2af0]657ipcarg_t ipc_data_deliver(ipc_callid_t callid, ipc_call_t *call, void *dst,
658 size_t size)
[183b4a0]659{
660 IPC_SET_RETVAL(*call, EOK);
661 IPC_SET_ARG1(*call, (ipcarg_t) dst);
662 IPC_SET_ARG3(*call, (ipcarg_t) size);
663 return ipc_answer(callid, call);
664}
665
[fadd381]666/** @}
[b2951e2]667 */
Note: See TracBrowser for help on using the repository browser.