Subversion Repositories HelenOS

Rev

Rev 4404 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2006 Ondrej Palkovsky
  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.
  27.  */
  28.  
  29. /** @addtogroup libc
  30.  * @{
  31.  * @}
  32.  */
  33.  
  34. /** @addtogroup libcipc IPC
  35.  * @brief HelenOS uspace IPC
  36.  * @{
  37.  * @ingroup libc
  38.  */
  39. /** @file
  40.  */
  41.  
  42. #include <ipc/ipc.h>
  43. #include <libc.h>
  44. #include <malloc.h>
  45. #include <errno.h>
  46. #include <libadt/list.h>
  47. #include <stdio.h>
  48. #include <unistd.h>
  49. #include <futex.h>
  50. #include <kernel/synch/synch.h>
  51. #include <async.h>
  52. #include <fibril.h>
  53. #include <assert.h>
  54.  
  55. /**
  56.  * Structures of this type are used for keeping track of sent asynchronous calls
  57.  * and queing unsent calls.
  58.  */
  59. typedef struct {
  60.     link_t list;
  61.  
  62.     ipc_async_callback_t callback;
  63.     void *private;
  64.     union {
  65.         ipc_callid_t callid;
  66.         struct {
  67.             ipc_call_t data;
  68.             int phoneid;
  69.         } msg;
  70.     } u;
  71.     fid_t fid;  /**< Fibril waiting for sending this call. */
  72. } async_call_t;
  73.  
  74. LIST_INITIALIZE(dispatched_calls);
  75.  
  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.
  80.  */
  81. LIST_INITIALIZE(queued_calls);
  82.  
  83. static atomic_t ipc_futex = FUTEX_INITIALIZER;
  84.  
  85. /** Make a fast synchronous call.
  86.  *
  87.  * Only three payload arguments can be passed using this function. However, this
  88.  * function is faster than the generic ipc_call_sync_slow() because the payload
  89.  * is passed directly in registers.
  90.  *
  91.  * @param phoneid   Phone handle for the call.
  92.  * @param method    Requested method.
  93.  * @param arg1      Service-defined payload argument.
  94.  * @param arg2      Service-defined payload argument.
  95.  * @param arg3      Service-defined payload argument.
  96.  * @param result1   If non-NULL, the return ARG1 will be stored there.
  97.  * @param result2   If non-NULL, the return ARG2 will be stored there.
  98.  * @param result3   If non-NULL, the return ARG3 will be stored there.
  99.  * @param result4   If non-NULL, the return ARG4 will be stored there.
  100.  * @param result5   If non-NULL, the return ARG5 will be stored there.
  101.  *
  102.  * @return      Negative values represent errors returned by IPC.
  103.  *          Otherwise the RETVAL of the answer is returned.
  104.  */
  105. int
  106. ipc_call_sync_fast(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
  107.     ipcarg_t arg3, ipcarg_t *result1, ipcarg_t *result2, ipcarg_t *result3,
  108.     ipcarg_t *result4, ipcarg_t *result5)
  109. {
  110.     ipc_call_t resdata;
  111.     int callres;
  112.    
  113.     callres = __SYSCALL6(SYS_IPC_CALL_SYNC_FAST, phoneid, method, arg1,
  114.         arg2, arg3, (sysarg_t) &resdata);
  115.     if (callres)
  116.         return callres;
  117.     if (result1)
  118.         *result1 = IPC_GET_ARG1(resdata);
  119.     if (result2)
  120.         *result2 = IPC_GET_ARG2(resdata);
  121.     if (result3)
  122.         *result3 = IPC_GET_ARG3(resdata);
  123.     if (result4)
  124.         *result4 = IPC_GET_ARG4(resdata);
  125.     if (result5)
  126.         *result5 = IPC_GET_ARG5(resdata);
  127.  
  128.     return IPC_GET_RETVAL(resdata);
  129. }
  130.  
  131. /** Make a synchronous call transmitting 5 arguments of payload.
  132.  *
  133.  * @param phoneid   Phone handle for the call.
  134.  * @param method    Requested method.
  135.  * @param arg1      Service-defined payload argument.
  136.  * @param arg2      Service-defined payload argument.
  137.  * @param arg3      Service-defined payload argument.
  138.  * @param arg4      Service-defined payload argument.
  139.  * @param arg5      Service-defined payload argument.
  140.  * @param result1   If non-NULL, storage for the first return argument.
  141.  * @param result2   If non-NULL, storage for the second return argument.
  142.  * @param result3   If non-NULL, storage for the third return argument.
  143.  * @param result4   If non-NULL, storage for the fourth return argument.
  144.  * @param result5   If non-NULL, storage for the fifth return argument.
  145.  *
  146.  * @return      Negative value means IPC error.
  147.  *          Otherwise the RETVAL of the answer.
  148.  */
  149. int
  150. ipc_call_sync_slow(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
  151.     ipcarg_t arg3, ipcarg_t arg4, ipcarg_t arg5, ipcarg_t *result1,
  152.     ipcarg_t *result2, ipcarg_t *result3, ipcarg_t *result4, ipcarg_t *result5)
  153. {
  154.     ipc_call_t data;
  155.     int callres;
  156.  
  157.     IPC_SET_METHOD(data, method);
  158.     IPC_SET_ARG1(data, arg1);
  159.     IPC_SET_ARG2(data, arg2);
  160.     IPC_SET_ARG3(data, arg3);
  161.     IPC_SET_ARG4(data, arg4);
  162.     IPC_SET_ARG5(data, arg5);
  163.  
  164.     callres = __SYSCALL3(SYS_IPC_CALL_SYNC_SLOW, phoneid, (sysarg_t) &data,
  165.         (sysarg_t) &data);
  166.     if (callres)
  167.         return callres;
  168.  
  169.     if (result1)
  170.         *result1 = IPC_GET_ARG1(data);
  171.     if (result2)
  172.         *result2 = IPC_GET_ARG2(data);
  173.     if (result3)
  174.         *result3 = IPC_GET_ARG3(data);
  175.     if (result4)
  176.         *result4 = IPC_GET_ARG4(data);
  177.     if (result5)
  178.         *result5 = IPC_GET_ARG5(data);
  179.  
  180.     return IPC_GET_RETVAL(data);
  181. }
  182.  
  183. /** Syscall to send asynchronous message.
  184.  *
  185.  * @param phoneid   Phone handle for the call.
  186.  * @param data      Call data with the request.
  187.  *
  188.  * @return      Hash of the call or an error code.
  189.  */
  190. static ipc_callid_t _ipc_call_async(int phoneid, ipc_call_t *data)
  191. {
  192.     return __SYSCALL2(SYS_IPC_CALL_ASYNC_SLOW, phoneid, (sysarg_t) data);
  193. }
  194.  
  195. /** Prolog to ipc_call_async_*() functions.
  196.  *
  197.  * @param private   Argument for the answer/error callback.
  198.  * @param callback  Answer/error callback.
  199.  *
  200.  * @return      New, partially initialized async_call structure or NULL.
  201.  */
  202. static inline async_call_t *ipc_prepare_async(void *private,
  203.     ipc_async_callback_t callback)
  204. {
  205.     async_call_t *call;
  206.  
  207.     call = malloc(sizeof(*call));
  208.     if (!call) {
  209.         if (callback)
  210.             callback(private, ENOMEM, NULL);
  211.         return NULL;
  212.     }
  213.     call->callback = callback;
  214.     call->private = private;
  215.  
  216.     return call;
  217. }
  218.  
  219. /** Epilogue of ipc_call_async_*() functions.
  220.  *
  221.  * @param callid    Value returned by the SYS_IPC_CALL_ASYNC_* syscall.
  222.  * @param phoneid   Phone handle through which the call was made.
  223.  * @param call      async_call structure returned by ipc_prepare_async().
  224.  * @param can_preempt   If non-zero, the current fibril can be preempted in this
  225.  *          call.
  226.  */
  227. static inline void ipc_finish_async(ipc_callid_t callid, int phoneid,
  228.     async_call_t *call, int can_preempt)
  229. {
  230.     if (!call) { /* Nothing to do regardless if failed or not */
  231.         futex_up(&ipc_futex);
  232.         return;
  233.     }
  234.  
  235.     if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
  236.         futex_up(&ipc_futex);
  237.         /* Call asynchronous handler with error code */
  238.         if (call->callback)
  239.             call->callback(call->private, ENOENT, NULL);
  240.         free(call);
  241.         return;
  242.     }
  243.  
  244.     if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) {
  245.         futex_up(&ipc_futex);
  246.  
  247.         call->u.msg.phoneid = phoneid;
  248.        
  249.         futex_down(&async_futex);
  250.         list_append(&call->list, &queued_calls);
  251.  
  252.         if (can_preempt) {
  253.             call->fid = fibril_get_id();
  254.             fibril_switch(FIBRIL_TO_MANAGER);
  255.             /* Async futex unlocked by previous call */
  256.         } else {
  257.             call->fid = 0;
  258.             futex_up(&async_futex);
  259.         }
  260.         return;
  261.     }
  262.     call->u.callid = callid;
  263.     /* Add call to the list of dispatched calls */
  264.     list_append(&call->list, &dispatched_calls);
  265.     futex_up(&ipc_futex);
  266.    
  267. }
  268.  
  269. /** Make a fast asynchronous call.
  270.  *
  271.  * This function can only handle four arguments of payload. It is, however,
  272.  * faster than the more generic ipc_call_async_slow().
  273.  *
  274.  * Note that this function is a void function.
  275.  * During normal opertation, answering this call will trigger the callback.
  276.  * In case of fatal error, call the callback handler with the proper error code.
  277.  * If the call cannot be temporarily made, queue it.
  278.  *
  279.  * @param phoneid   Phone handle for the call.
  280.  * @param method    Requested method.
  281.  * @param arg1      Service-defined payload argument.
  282.  * @param arg2      Service-defined payload argument.
  283.  * @param arg3      Service-defined payload argument.
  284.  * @param arg4      Service-defined payload argument.
  285.  * @param private   Argument to be passed to the answer/error callback.
  286.  * @param callback  Answer or error callback.
  287.  * @param can_preempt   If non-zero, the current fibril will be preempted in
  288.  *          case the kernel temporarily refuses to accept more
  289.  *          asynchronous calls.
  290.  */
  291. void ipc_call_async_fast(int phoneid, ipcarg_t method, ipcarg_t arg1,
  292.     ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, void *private,
  293.     ipc_async_callback_t callback, int can_preempt)
  294. {
  295.     async_call_t *call = NULL;
  296.     ipc_callid_t callid;
  297.  
  298.     if (callback) {
  299.         call = ipc_prepare_async(private, callback);
  300.         if (!call)
  301.             return;
  302.     }
  303.  
  304.     /*
  305.      * We need to make sure that we get callid before another thread
  306.      * accesses the queue again.
  307.      */
  308.     futex_down(&ipc_futex);
  309.     callid = __SYSCALL6(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1,
  310.         arg2, arg3, arg4);
  311.  
  312.     if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) {
  313.         if (!call) {
  314.             call = ipc_prepare_async(private, callback);
  315.             if (!call)
  316.                 return;
  317.         }
  318.         IPC_SET_METHOD(call->u.msg.data, method);
  319.         IPC_SET_ARG1(call->u.msg.data, arg1);
  320.         IPC_SET_ARG2(call->u.msg.data, arg2);
  321.         IPC_SET_ARG3(call->u.msg.data, arg3);
  322.         IPC_SET_ARG4(call->u.msg.data, arg4);
  323.         /*
  324.          * To achieve deterministic behavior, we always zero out the
  325.          * arguments that are beyond the limits of the fast version.
  326.          */
  327.         IPC_SET_ARG5(call->u.msg.data, 0);
  328.     }
  329.     ipc_finish_async(callid, phoneid, call, can_preempt);
  330. }
  331.  
  332. /** Make an asynchronous call transmitting the entire payload.
  333.  *
  334.  * Note that this function is a void function.
  335.  * During normal opertation, answering this call will trigger the callback.
  336.  * In case of fatal error, call the callback handler with the proper error code.
  337.  * If the call cannot be temporarily made, queue it.
  338.  *
  339.  * @param phoneid   Phone handle for the call.
  340.  * @param method    Requested method.
  341.  * @param arg1      Service-defined payload argument.
  342.  * @param arg2      Service-defined payload argument.
  343.  * @param arg3      Service-defined payload argument.
  344.  * @param arg4      Service-defined payload argument.
  345.  * @param arg5      Service-defined payload argument.
  346.  * @param private   Argument to be passed to the answer/error callback.
  347.  * @param callback  Answer or error callback.
  348.  * @param can_preempt   If non-zero, the current fibril will be preempted in
  349.  *          case the kernel temporarily refuses to accept more
  350.  *          asynchronous calls.
  351.  *
  352.  */
  353. void ipc_call_async_slow(int phoneid, ipcarg_t method, ipcarg_t arg1,
  354.     ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipcarg_t arg5, void *private,
  355.     ipc_async_callback_t callback, int can_preempt)
  356. {
  357.     async_call_t *call;
  358.     ipc_callid_t callid;
  359.  
  360.     call = ipc_prepare_async(private, callback);
  361.     if (!call)
  362.         return;
  363.  
  364.     IPC_SET_METHOD(call->u.msg.data, method);
  365.     IPC_SET_ARG1(call->u.msg.data, arg1);
  366.     IPC_SET_ARG2(call->u.msg.data, arg2);
  367.     IPC_SET_ARG3(call->u.msg.data, arg3);
  368.     IPC_SET_ARG4(call->u.msg.data, arg4);
  369.     IPC_SET_ARG5(call->u.msg.data, arg5);
  370.     /*
  371.      * We need to make sure that we get callid before another thread
  372.      * accesses the queue again.
  373.      */
  374.     futex_down(&ipc_futex);
  375.     callid = _ipc_call_async(phoneid, &call->u.msg.data);
  376.  
  377.     ipc_finish_async(callid, phoneid, call, can_preempt);
  378. }
  379.  
  380.  
  381. /** Answer a received call - fast version.
  382.  *
  383.  * The fast answer makes use of passing retval and first four arguments in
  384.  * registers. If you need to return more, use the ipc_answer_slow() instead.
  385.  *
  386.  * @param callid    Hash of the call being answered.
  387.  * @param retval    Return value.
  388.  * @param arg1      First return argument.
  389.  * @param arg2      Second return argument.
  390.  * @param arg3      Third return argument.
  391.  * @param arg4      Fourth return argument.
  392.  *
  393.  * @return      Zero on success or a value from @ref errno.h on failure.
  394.  */
  395. ipcarg_t ipc_answer_fast(ipc_callid_t callid, ipcarg_t retval, ipcarg_t arg1,
  396.     ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4)
  397. {
  398.     return __SYSCALL6(SYS_IPC_ANSWER_FAST, callid, retval, arg1, arg2, arg3,
  399.         arg4);
  400. }
  401.  
  402. /** Answer a received call - slow full version.
  403.  *
  404.  * @param callid    Hash of the call being answered.
  405.  * @param retval    Return value.
  406.  * @param arg1      First return argument.
  407.  * @param arg2      Second return argument.
  408.  * @param arg3      Third return argument.
  409.  * @param arg4      Fourth return argument.
  410.  * @param arg5      Fifth return argument.
  411.  *
  412.  * @return      Zero on success or a value from @ref errno.h on failure.
  413.  */
  414. ipcarg_t ipc_answer_slow(ipc_callid_t callid, ipcarg_t retval, ipcarg_t arg1,
  415.     ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipcarg_t arg5)
  416. {
  417.     ipc_call_t data;
  418.  
  419.     IPC_SET_RETVAL(data, retval);
  420.     IPC_SET_ARG1(data, arg1);
  421.     IPC_SET_ARG2(data, arg2);
  422.     IPC_SET_ARG3(data, arg3);
  423.     IPC_SET_ARG4(data, arg4);
  424.     IPC_SET_ARG5(data, arg5);
  425.  
  426.     return __SYSCALL2(SYS_IPC_ANSWER_SLOW, callid, (sysarg_t) &data);
  427. }
  428.  
  429.  
  430. /** Try to dispatch queued calls from the async queue. */
  431. static void try_dispatch_queued_calls(void)
  432. {
  433.     async_call_t *call;
  434.     ipc_callid_t callid;
  435.  
  436.     /** @todo
  437.      * Integrate intelligently ipc_futex, so that it is locked during
  438.      * ipc_call_async_*(), until it is added to dispatched_calls.
  439.      */
  440.     futex_down(&async_futex);
  441.     while (!list_empty(&queued_calls)) {
  442.         call = list_get_instance(queued_calls.next, async_call_t, list);
  443.         callid = _ipc_call_async(call->u.msg.phoneid,
  444.             &call->u.msg.data);
  445.         if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) {
  446.             break;
  447.         }
  448.         list_remove(&call->list);
  449.  
  450.         futex_up(&async_futex);
  451.         if (call->fid)
  452.             fibril_add_ready(call->fid);
  453.        
  454.         if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
  455.             if (call->callback)
  456.                 call->callback(call->private, ENOENT, NULL);
  457.             free(call);
  458.         } else {
  459.             call->u.callid = callid;
  460.             futex_down(&ipc_futex);
  461.             list_append(&call->list, &dispatched_calls);
  462.             futex_up(&ipc_futex);
  463.         }
  464.         futex_down(&async_futex);
  465.     }
  466.     futex_up(&async_futex);
  467. }
  468.  
  469. /** Handle a received answer.
  470.  *
  471.  * Find the hash of the answer and call the answer callback.
  472.  *
  473.  * @todo Make it use hash table.
  474.  *
  475.  * @param callid    Hash of the received answer.
  476.  *          The answer has the same hash as the request OR'ed with
  477.  *          the IPC_CALLID_ANSWERED bit.
  478.  * @param data      Call data of the answer.
  479.  */
  480. static void handle_answer(ipc_callid_t callid, ipc_call_t *data)
  481. {
  482.     link_t *item;
  483.     async_call_t *call;
  484.  
  485.     callid &= ~IPC_CALLID_ANSWERED;
  486.    
  487.     futex_down(&ipc_futex);
  488.     for (item = dispatched_calls.next; item != &dispatched_calls;
  489.         item = item->next) {
  490.         call = list_get_instance(item, async_call_t, list);
  491.         if (call->u.callid == callid) {
  492.             list_remove(&call->list);
  493.             futex_up(&ipc_futex);
  494.             if (call->callback)
  495.                 call->callback(call->private,
  496.                     IPC_GET_RETVAL(*data), data);
  497.             free(call);
  498.             return;
  499.         }
  500.     }
  501.     futex_up(&ipc_futex);
  502. }
  503.  
  504.  
  505. /** Wait for a first call to come.
  506.  *
  507.  * @param call      Storage where the incoming call data will be stored.
  508.  * @param usec      Timeout in microseconds
  509.  * @param flags     Flags passed to SYS_IPC_WAIT (blocking, nonblocking).
  510.  *
  511.  * @return      Hash of the call. Note that certain bits have special
  512.  *          meaning. IPC_CALLID_ANSWERED will be set in an answer
  513.  *          and IPC_CALLID_NOTIFICATION is used for notifications.
  514.  *         
  515.  */
  516. ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags)
  517. {
  518.     ipc_callid_t callid;
  519.  
  520.     callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags);
  521.     /* Handle received answers */
  522.     if (callid & IPC_CALLID_ANSWERED) {
  523.         handle_answer(callid, call);
  524.         try_dispatch_queued_calls();
  525.     }
  526.  
  527.     return callid;
  528. }
  529.  
  530. /** Wait some time for an IPC call.
  531.  *
  532.  * The call will return after an answer is received.
  533.  *
  534.  * @param call      Storage where the incoming call data will be stored.
  535.  * @param usec      Timeout in microseconds.
  536.  *
  537.  * @return      Hash of the answer.
  538.  */
  539. ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *call, uint32_t usec)
  540. {
  541.     ipc_callid_t callid;
  542.  
  543.     do {
  544.         callid = ipc_wait_cycle(call, usec, SYNCH_FLAGS_NONE);
  545.     } while (callid & IPC_CALLID_ANSWERED);
  546.  
  547.     return callid;
  548. }
  549.  
  550. /** Check if there is an IPC call waiting to be picked up.
  551.  *
  552.  * @param call      Storage where the incoming call will be stored.
  553.  * @return      Hash of the answer.
  554.  */
  555. ipc_callid_t ipc_trywait_for_call(ipc_call_t *call)
  556. {
  557.     ipc_callid_t callid;
  558.  
  559.     do {
  560.         callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT,
  561.             SYNCH_FLAGS_NON_BLOCKING);
  562.     } while (callid & IPC_CALLID_ANSWERED);
  563.  
  564.     return callid;
  565. }
  566.  
  567. /** Ask destination to do a callback connection.
  568.  *
  569.  * @param phoneid   Phone handle used for contacting the other side.
  570.  * @param arg1      Service-defined argument.
  571.  * @param arg2      Service-defined argument.
  572.  * @param arg3      Service-defined argument.
  573.  * @param phonehash Storage where the library will store an opaque
  574.  *          identifier of the phone that will be used for incoming
  575.  *          calls. This identifier can be used for connection
  576.  *          tracking.
  577.  *
  578.  * @return      Zero on success or a negative error code.
  579.  */
  580. int ipc_connect_to_me(int phoneid, int arg1, int arg2, int arg3,
  581.     ipcarg_t *phonehash)
  582. {
  583.     return ipc_call_sync_3_5(phoneid, IPC_M_CONNECT_TO_ME, arg1, arg2,
  584.         arg3, NULL, NULL, NULL, NULL, phonehash);
  585. }
  586.  
  587. /** Ask through phone for a new connection to some service.
  588.  *
  589.  * @param phoneid   Phone handle used for contacting the other side.
  590.  * @param arg1      User defined argument.
  591.  * @param arg2      User defined argument.
  592.  * @param arg3      User defined argument.
  593.  *
  594.  * @return      New phone handle on success or a negative error code.
  595.  */
  596. int ipc_connect_me_to(int phoneid, int arg1, int arg2, int arg3)
  597. {
  598.     ipcarg_t newphid;
  599.     int res;
  600.  
  601.     res = ipc_call_sync_3_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
  602.         NULL, NULL, NULL, NULL, &newphid);
  603.     if (res)
  604.         return res;
  605.     return newphid;
  606. }
  607.  
  608. /** Ask through phone for a new connection to some service.
  609.  *
  610.  * If the connection is not available at the moment, the
  611.  * call will block.
  612.  *
  613.  * @param phoneid   Phone handle used for contacting the other side.
  614.  * @param arg1      User defined argument.
  615.  * @param arg2      User defined argument.
  616.  * @param arg3      User defined argument.
  617.  *
  618.  * @return      New phone handle on success or a negative error code.
  619.  */
  620. int ipc_connect_me_to_blocking(int phoneid, int arg1, int arg2, int arg3)
  621. {
  622.     ipcarg_t newphid;
  623.     int res;
  624.  
  625.     res = ipc_call_sync_4_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
  626.         IPC_FLAG_BLOCKING, NULL, NULL, NULL, NULL, &newphid);
  627.     if (res)
  628.         return res;
  629.     return newphid;
  630. }
  631.  
  632. /** Hang up a phone.
  633.  *
  634.  * @param phoneid   Handle of the phone to be hung up.
  635.  *
  636.  * @return      Zero on success or a negative error code.
  637.  */
  638. int ipc_hangup(int phoneid)
  639. {
  640.     return __SYSCALL1(SYS_IPC_HANGUP, phoneid);
  641. }
  642.  
  643. /** Register IRQ notification.
  644.  *
  645.  * @param inr       IRQ number.
  646.  * @param devno     Device number of the device generating inr.
  647.  * @param method    Use this method for notifying me.
  648.  * @param ucode     Top-half pseudocode handler.
  649.  *
  650.  * @return      Value returned by the kernel.
  651.  */
  652. int ipc_register_irq(int inr, int devno, int method, irq_code_t *ucode)
  653. {
  654.     return __SYSCALL4(SYS_IPC_REGISTER_IRQ, inr, devno, method,
  655.         (sysarg_t) ucode);
  656. }
  657.  
  658. /** Unregister IRQ notification.
  659.  *
  660.  * @param inr       IRQ number.
  661.  * @param devno     Device number of the device generating inr.
  662.  *
  663.  * @return      Value returned by the kernel.
  664.  */
  665. int ipc_unregister_irq(int inr, int devno)
  666. {
  667.     return __SYSCALL2(SYS_IPC_UNREGISTER_IRQ, inr, devno);
  668. }
  669.  
  670. /** Forward a received call to another destination.
  671.  *
  672.  * @param callid    Hash of the call to forward.
  673.  * @param phoneid   Phone handle to use for forwarding.
  674.  * @param method    New method for the forwarded call.
  675.  * @param arg1      New value of the first argument for the forwarded call.
  676.  * @param arg2      New value of the second argument for the forwarded call.
  677.  * @param mode      Flags specifying mode of the forward operation.
  678.  *
  679.  * @return      Zero on success or an error code.
  680.  *
  681.  * For non-system methods, the old method, arg1 and arg2 are rewritten by the
  682.  * new values. For system methods, the new method, arg1 and arg2 are written
  683.  * to the old arg1, arg2 and arg3, respectivelly. Calls with immutable
  684.  * methods are forwarded verbatim.
  685.  */
  686. int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method,
  687.     ipcarg_t arg1, ipcarg_t arg2, int mode)
  688. {
  689.     return __SYSCALL6(SYS_IPC_FORWARD_FAST, callid, phoneid, method, arg1,
  690.         arg2, mode);
  691. }
  692.  
  693.  
  694. int ipc_forward_slow(ipc_callid_t callid, int phoneid, int method,
  695.     ipcarg_t arg1, ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipcarg_t arg5,
  696.     int mode)
  697. {
  698.     ipc_call_t data;
  699.  
  700.     IPC_SET_METHOD(data, method);
  701.     IPC_SET_ARG1(data, arg1);
  702.     IPC_SET_ARG2(data, arg2);
  703.     IPC_SET_ARG3(data, arg3);
  704.     IPC_SET_ARG4(data, arg4);
  705.     IPC_SET_ARG5(data, arg5);
  706.  
  707.     return __SYSCALL4(SYS_IPC_FORWARD_SLOW, callid, phoneid, (sysarg_t) &data, mode);
  708. }
  709.  
  710. /** Wrapper for making IPC_M_SHARE_IN calls.
  711.  *
  712.  * @param phoneid   Phone that will be used to contact the receiving side.
  713.  * @param dst       Destination address space area base.
  714.  * @param size      Size of the destination address space area.
  715.  * @param arg       User defined argument.
  716.  * @param flags     Storage where the received flags will be stored. Can be
  717.  *          NULL.
  718.  *
  719.  * @return      Zero on success or a negative error code from errno.h.
  720.  */
  721. int ipc_share_in_start(int phoneid, void *dst, size_t size, ipcarg_t arg,
  722.     int *flags)
  723. {
  724.     int res;
  725.     sysarg_t tmp_flags;
  726.     res = async_req_3_2(phoneid, IPC_M_SHARE_IN, (ipcarg_t) dst,
  727.         (ipcarg_t) size, arg, NULL, &tmp_flags);
  728.     if (flags)
  729.         *flags = tmp_flags;
  730.     return res;
  731. }
  732.  
  733. /** Wrapper for receiving the IPC_M_SHARE_IN calls.
  734.  *
  735.  * This wrapper only makes it more comfortable to receive IPC_M_SHARE_IN calls
  736.  * so that the user doesn't have to remember the meaning of each IPC argument.
  737.  *
  738.  * So far, this wrapper is to be used from within a connection fibril.
  739.  *
  740.  * @param callid    Storage where the hash of the IPC_M_SHARE_IN call will
  741.  *          be stored.
  742.  * @param size      Destination address space area size.   
  743.  *
  744.  * @return      Non-zero on success, zero on failure.
  745.  */
  746. int ipc_share_in_receive(ipc_callid_t *callid, size_t *size)
  747. {
  748.     ipc_call_t data;
  749.    
  750.     assert(callid);
  751.     assert(size);
  752.  
  753.     *callid = async_get_call(&data);
  754.     if (IPC_GET_METHOD(data) != IPC_M_SHARE_IN)
  755.         return 0;
  756.     *size = (size_t) IPC_GET_ARG2(data);
  757.     return 1;
  758. }
  759.  
  760. /** Wrapper for answering the IPC_M_SHARE_IN calls.
  761.  *
  762.  * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ calls
  763.  * so that the user doesn't have to remember the meaning of each IPC argument.
  764.  *
  765.  * @param callid    Hash of the IPC_M_DATA_READ call to answer.
  766.  * @param src       Source address space base.
  767.  * @param flags     Flags to be used for sharing. Bits can be only cleared.
  768.  *
  769.  * @return      Zero on success or a value from @ref errno.h on failure.
  770.  */
  771. int ipc_share_in_finalize(ipc_callid_t callid, void *src, int flags)
  772. {
  773.     return ipc_answer_2(callid, EOK, (ipcarg_t) src, (ipcarg_t) flags);
  774. }
  775.  
  776. /** Wrapper for making IPC_M_SHARE_OUT calls.
  777.  *
  778.  * @param phoneid   Phone that will be used to contact the receiving side.
  779.  * @param src       Source address space area base address.
  780.  * @param flags     Flags to be used for sharing. Bits can be only cleared.
  781.  *
  782.  * @return      Zero on success or a negative error code from errno.h.
  783.  */
  784. int ipc_share_out_start(int phoneid, void *src, int flags)
  785. {
  786.     return async_req_3_0(phoneid, IPC_M_SHARE_OUT, (ipcarg_t) src, 0,
  787.         (ipcarg_t) flags);
  788. }
  789.  
  790. /** Wrapper for receiving the IPC_M_SHARE_OUT calls.
  791.  *
  792.  * This wrapper only makes it more comfortable to receive IPC_M_SHARE_OUT calls
  793.  * so that the user doesn't have to remember the meaning of each IPC argument.
  794.  *
  795.  * So far, this wrapper is to be used from within a connection fibril.
  796.  *
  797.  * @param callid    Storage where the hash of the IPC_M_SHARE_OUT call will
  798.  *          be stored.
  799.  * @param size      Storage where the source address space area size will be
  800.  *          stored.
  801.  * @param flags     Storage where the sharing flags will be stored.
  802.  *
  803.  * @return      Non-zero on success, zero on failure.
  804.  */
  805. int ipc_share_out_receive(ipc_callid_t *callid, size_t *size, int *flags)
  806. {
  807.     ipc_call_t data;
  808.    
  809.     assert(callid);
  810.     assert(size);
  811.     assert(flags);
  812.  
  813.     *callid = async_get_call(&data);
  814.     if (IPC_GET_METHOD(data) != IPC_M_SHARE_OUT)
  815.         return 0;
  816.     *size = (size_t) IPC_GET_ARG2(data);
  817.     *flags = (int) IPC_GET_ARG3(data);
  818.     return 1;
  819. }
  820.  
  821. /** Wrapper for answering the IPC_M_SHARE_OUT calls.
  822.  *
  823.  * This wrapper only makes it more comfortable to answer IPC_M_SHARE_OUT calls
  824.  * so that the user doesn't have to remember the meaning of each IPC argument.
  825.  *
  826.  * @param callid    Hash of the IPC_M_DATA_WRITE call to answer.
  827.  * @param dst       Destination address space area base address.   
  828.  *
  829.  * @return      Zero on success or a value from @ref errno.h on failure.
  830.  */
  831. int ipc_share_out_finalize(ipc_callid_t callid, void *dst)
  832. {
  833.     return ipc_answer_1(callid, EOK, (ipcarg_t) dst);
  834. }
  835.  
  836.  
  837. /** Wrapper for making IPC_M_DATA_READ calls.
  838.  *
  839.  * @param phoneid   Phone that will be used to contact the receiving side.
  840.  * @param dst       Address of the beginning of the destination buffer.
  841.  * @param size      Size of the destination buffer.
  842.  *
  843.  * @return      Zero on success or a negative error code from errno.h.
  844.  */
  845. int ipc_data_read_start(int phoneid, void *dst, size_t size)
  846. {
  847.     return async_req_2_0(phoneid, IPC_M_DATA_READ, (ipcarg_t) dst,
  848.         (ipcarg_t) size);
  849. }
  850.  
  851. /** Wrapper for receiving the IPC_M_DATA_READ calls.
  852.  *
  853.  * This wrapper only makes it more comfortable to receive IPC_M_DATA_READ calls
  854.  * so that the user doesn't have to remember the meaning of each IPC argument.
  855.  *
  856.  * So far, this wrapper is to be used from within a connection fibril.
  857.  *
  858.  * @param callid    Storage where the hash of the IPC_M_DATA_READ call will
  859.  *          be stored.
  860.  * @param size      Storage where the maximum size will be stored. Can be
  861.  *          NULL.
  862.  *
  863.  * @return      Non-zero on success, zero on failure.
  864.  */
  865. int ipc_data_read_receive(ipc_callid_t *callid, size_t *size)
  866. {
  867.     ipc_call_t data;
  868.    
  869.     assert(callid);
  870.  
  871.     *callid = async_get_call(&data);
  872.     if (IPC_GET_METHOD(data) != IPC_M_DATA_READ)
  873.         return 0;
  874.     if (size)
  875.         *size = (size_t) IPC_GET_ARG2(data);
  876.     return 1;
  877. }
  878.  
  879. /** Wrapper for answering the IPC_M_DATA_READ calls.
  880.  *
  881.  * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ calls
  882.  * so that the user doesn't have to remember the meaning of each IPC argument.
  883.  *
  884.  * @param callid    Hash of the IPC_M_DATA_READ call to answer.
  885.  * @param src       Source address for the IPC_M_DATA_READ call.
  886.  * @param size      Size for the IPC_M_DATA_READ call. Can be smaller than
  887.  *          the maximum size announced by the sender.
  888.  *
  889.  * @return      Zero on success or a value from @ref errno.h on failure.
  890.  */
  891. int ipc_data_read_finalize(ipc_callid_t callid, const void *src, size_t size)
  892. {
  893.     return ipc_answer_2(callid, EOK, (ipcarg_t) src, (ipcarg_t) size);
  894. }
  895.  
  896. /** Wrapper for making IPC_M_DATA_WRITE calls.
  897.  *
  898.  * @param phoneid   Phone that will be used to contact the receiving side.
  899.  * @param src       Address of the beginning of the source buffer.
  900.  * @param size      Size of the source buffer.
  901.  *
  902.  * @return      Zero on success or a negative error code from errno.h.
  903.  */
  904. int ipc_data_write_start(int phoneid, const void *src, size_t size)
  905. {
  906.     return async_req_2_0(phoneid, IPC_M_DATA_WRITE, (ipcarg_t) src,
  907.         (ipcarg_t) size);
  908. }
  909.  
  910. /** Wrapper for receiving the IPC_M_DATA_WRITE calls.
  911.  *
  912.  * This wrapper only makes it more comfortable to receive IPC_M_DATA_WRITE calls
  913.  * so that the user doesn't have to remember the meaning of each IPC argument.
  914.  *
  915.  * So far, this wrapper is to be used from within a connection fibril.
  916.  *
  917.  * @param callid    Storage where the hash of the IPC_M_DATA_WRITE call will
  918.  *          be stored.
  919.  * @param size      Storage where the suggested size will be stored. May be
  920.  *          NULL
  921.  *
  922.  * @return      Non-zero on success, zero on failure.
  923.  */
  924. int ipc_data_write_receive(ipc_callid_t *callid, size_t *size)
  925. {
  926.     ipc_call_t data;
  927.    
  928.     assert(callid);
  929.  
  930.     *callid = async_get_call(&data);
  931.     if (IPC_GET_METHOD(data) != IPC_M_DATA_WRITE)
  932.         return 0;
  933.     if (size)
  934.         *size = (size_t) IPC_GET_ARG2(data);
  935.     return 1;
  936. }
  937.  
  938. /** Wrapper for answering the IPC_M_DATA_WRITE calls.
  939.  *
  940.  * This wrapper only makes it more comfortable to answer IPC_M_DATA_WRITE calls
  941.  * so that the user doesn't have to remember the meaning of each IPC argument.
  942.  *
  943.  * @param callid    Hash of the IPC_M_DATA_WRITE call to answer.
  944.  * @param dst       Final destination address for the IPC_M_DATA_WRITE call.
  945.  * @param size      Final size for the IPC_M_DATA_WRITE call.
  946.  *
  947.  * @return      Zero on success or a value from @ref errno.h on failure.
  948.  */
  949. int ipc_data_write_finalize(ipc_callid_t callid, void *dst, size_t size)
  950. {
  951.     return ipc_answer_2(callid, EOK, (ipcarg_t) dst, (ipcarg_t) size);
  952. }
  953.  
  954. #include <kernel/syscall/sysarg64.h>
  955. /** Connect to a task specified by id.
  956.  */
  957. int ipc_connect_kbox(task_id_t id)
  958. {
  959.     sysarg64_t arg;
  960.  
  961.     arg.value = (unsigned long long) id;
  962.  
  963.     return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) &arg);
  964. }
  965.  
  966. /** @}
  967.  */
  968.