Subversion Repositories HelenOS

Rev

Rev 2359 | Rev 2494 | 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 genericipc
  30.  * @{
  31.  */
  32. /** @file
  33.  */
  34.  
  35. #include <arch.h>
  36. #include <proc/task.h>
  37. #include <proc/thread.h>
  38. #include <errno.h>
  39. #include <memstr.h>
  40. #include <debug.h>
  41. #include <ipc/ipc.h>
  42. #include <ipc/sysipc.h>
  43. #include <ipc/irq.h>
  44. #include <ipc/ipcrsc.h>
  45. #include <arch/interrupt.h>
  46. #include <print.h>
  47. #include <syscall/copy.h>
  48. #include <security/cap.h>
  49. #include <mm/as.h>
  50. #include <print.h>
  51.  
  52. #define GET_CHECK_PHONE(phone, phoneid, err) \
  53. { \
  54.     if (phoneid > IPC_MAX_PHONES) { \
  55.         err; \
  56.     } \
  57.     phone = &TASK->phones[phoneid]; \
  58. }
  59.  
  60. #define STRUCT_TO_USPACE(dst, src)  copy_to_uspace(dst, src, sizeof(*(src)))
  61.  
  62. /** Decide if the method is a system method.
  63.  *
  64.  * @param method    Method to be decided.
  65.  *
  66.  * @return      Return 1 if the method is a system method.
  67.  *          Otherwise return 0.
  68.  */
  69. static inline int is_system_method(unative_t method)
  70. {
  71.     if (method <= IPC_M_LAST_SYSTEM)
  72.         return 1;
  73.     return 0;
  74. }
  75.  
  76. /** Decide if the message with this method is forwardable.
  77.  *
  78.  * - some system messages may be forwarded, for some of them
  79.  *   it is useless
  80.  *
  81.  * @param method    Method to be decided.
  82.  *
  83.  * @return      Return 1 if the method is forwardable.
  84.  *          Otherwise return 0.
  85.  */
  86. static inline int is_forwardable(unative_t method)
  87. {
  88.     if (method == IPC_M_PHONE_HUNGUP || method == IPC_M_AS_AREA_SEND ||
  89.         method == IPC_M_AS_AREA_RECV)
  90.         return 0; /* This message is meant only for the receiver */
  91.     return 1;
  92. }
  93.  
  94.  
  95. /***********************************************************************
  96.  * Functions that preprocess answer before sending it to the recepient.
  97.  ***********************************************************************/
  98.  
  99. /** Decide if the caller (e.g. ipc_answer()) should save the old call contents
  100.  * for answer_preprocess().
  101.  *
  102.  * @param call      Call structure to be decided.
  103.  *
  104.  * @return      Return 1 if the old call contents should be saved.
  105.  *          Return 0 otherwise.
  106.  */
  107. static inline int answer_need_old(call_t *call)
  108. {
  109.     if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME)
  110.         return 1;
  111.     if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_ME_TO)
  112.         return 1;
  113.     if (IPC_GET_METHOD(call->data) == IPC_M_AS_AREA_SEND)
  114.         return 1;
  115.     if (IPC_GET_METHOD(call->data) == IPC_M_AS_AREA_RECV)
  116.         return 1;
  117.     return 0;
  118. }
  119.  
  120. /** Interpret process answer as control information.
  121.  *
  122.  * This function is called directly after sys_ipc_answer().
  123.  *
  124.  * @param answer    Call structure with the answer.
  125.  * @param olddata   Saved data of the request.
  126.  *
  127.  * @return      Return 0 on success or an error code.
  128.  */
  129. static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
  130. {
  131.     int phoneid;
  132.  
  133.     if (IPC_GET_RETVAL(answer->data) == EHANGUP) {
  134.         /* In case of forward, hangup the forwared phone,
  135.          * not the originator
  136.          */
  137.         spinlock_lock(&answer->data.phone->lock);
  138.         spinlock_lock(&TASK->answerbox.lock);
  139.         if (answer->data.phone->state == IPC_PHONE_CONNECTED) {
  140.             list_remove(&answer->data.phone->link);
  141.             answer->data.phone->state = IPC_PHONE_SLAMMED;
  142.         }
  143.         spinlock_unlock(&TASK->answerbox.lock);
  144.         spinlock_unlock(&answer->data.phone->lock);
  145.     }
  146.  
  147.     if (!olddata)
  148.         return 0;
  149.  
  150.     if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
  151.         phoneid = IPC_GET_ARG3(*olddata);
  152.         if (IPC_GET_RETVAL(answer->data)) {
  153.             /* The connection was not accepted */
  154.             phone_dealloc(phoneid);
  155.         } else {
  156.             /* The connection was accepted */
  157.             phone_connect(phoneid, &answer->sender->answerbox);
  158.             /* Set 'phone hash' as arg3 of response */
  159.             IPC_SET_ARG3(answer->data,
  160.                 (unative_t) &TASK->phones[phoneid]);
  161.         }
  162.     } else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
  163.         /* If the users accepted call, connect */
  164.         if (!IPC_GET_RETVAL(answer->data)) {
  165.             ipc_phone_connect((phone_t *) IPC_GET_ARG3(*olddata),
  166.                 &TASK->answerbox);
  167.         }
  168.     } else if (IPC_GET_METHOD(*olddata) == IPC_M_AS_AREA_SEND) {
  169.         if (!IPC_GET_RETVAL(answer->data)) {
  170.             /* Accepted, handle as_area receipt */
  171.             ipl_t ipl;
  172.             int rc;
  173.             as_t *as;
  174.            
  175.             ipl = interrupts_disable();
  176.             spinlock_lock(&answer->sender->lock);
  177.             as = answer->sender->as;
  178.             spinlock_unlock(&answer->sender->lock);
  179.             interrupts_restore(ipl);
  180.            
  181.             rc = as_area_share(as, IPC_GET_ARG1(*olddata),
  182.                 IPC_GET_ARG2(*olddata), AS,
  183.                 IPC_GET_ARG1(answer->data), IPC_GET_ARG3(*olddata));
  184.             IPC_SET_RETVAL(answer->data, rc);
  185.             return rc;
  186.         }
  187.     } else if (IPC_GET_METHOD(*olddata) == IPC_M_AS_AREA_RECV) {
  188.         if (!IPC_GET_RETVAL(answer->data)) {
  189.             ipl_t ipl;
  190.             as_t *as;
  191.             int rc;
  192.            
  193.             ipl = interrupts_disable();
  194.             spinlock_lock(&answer->sender->lock);
  195.             as = answer->sender->as;
  196.             spinlock_unlock(&answer->sender->lock);
  197.             interrupts_restore(ipl);
  198.            
  199.             rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
  200.                 IPC_GET_ARG2(*olddata), as, IPC_GET_ARG1(*olddata),
  201.                 IPC_GET_ARG2(answer->data));
  202.             IPC_SET_RETVAL(answer->data, rc);
  203.         }
  204.     }
  205.     return 0;
  206. }
  207.  
  208. /** Called before the request is sent.
  209.  *
  210.  * @param call      Call structure with the request.
  211.  *
  212.  * @return      Return 0 on success, ELIMIT or EPERM on error.
  213.  */
  214. static int request_preprocess(call_t *call)
  215. {
  216.     int newphid;
  217.     size_t size;
  218.  
  219.     switch (IPC_GET_METHOD(call->data)) {
  220.     case IPC_M_CONNECT_ME_TO:
  221.         newphid = phone_alloc();
  222.         if (newphid < 0)
  223.             return ELIMIT;
  224.         /* Set arg3 for server */
  225.         IPC_SET_ARG3(call->data, (unative_t) &TASK->phones[newphid]);
  226.         call->flags |= IPC_CALL_CONN_ME_TO;
  227.         call->priv = newphid;
  228.         break;
  229.     case IPC_M_AS_AREA_SEND:
  230.         size = as_get_size(IPC_GET_ARG1(call->data));
  231.         if (!size)
  232.             return EPERM;
  233.         IPC_SET_ARG2(call->data, size);
  234.         break;
  235.     default:
  236.         break;
  237.     }
  238.     return 0;
  239. }
  240.  
  241. /*******************************************************************************
  242.  * Functions called to process received call/answer before passing it to uspace.
  243.  *******************************************************************************/
  244.  
  245. /** Do basic kernel processing of received call answer.
  246.  *
  247.  * @param call      Call structure with the answer.
  248.  */
  249. static void process_answer(call_t *call)
  250. {
  251.     if (IPC_GET_RETVAL(call->data) == EHANGUP &&
  252.         (call->flags & IPC_CALL_FORWARDED))
  253.         IPC_SET_RETVAL(call->data, EFORWARD);
  254.  
  255.     if (call->flags & IPC_CALL_CONN_ME_TO) {
  256.         if (IPC_GET_RETVAL(call->data))
  257.             phone_dealloc(call->priv);
  258.         else
  259.             IPC_SET_ARG3(call->data, call->priv);
  260.     }
  261. }
  262.  
  263. /** Do basic kernel processing of received call request.
  264.  *
  265.  * @param box       Destination answerbox structure.
  266.  * @param call      Call structure with the request.
  267.  *
  268.  * @return      Return 0 if the call should be passed to userspace.
  269.  *          Return -1 if the call should be ignored.
  270.  */
  271. static int process_request(answerbox_t *box, call_t *call)
  272. {
  273.     int phoneid;
  274.  
  275.     if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME) {
  276.         phoneid = phone_alloc();
  277.         if (phoneid < 0) { /* Failed to allocate phone */
  278.             IPC_SET_RETVAL(call->data, ELIMIT);
  279.             ipc_answer(box, call);
  280.             return -1;
  281.         }
  282.         IPC_SET_ARG3(call->data, phoneid);
  283.     }
  284.     return 0;
  285. }
  286.  
  287. /** Make a fast call over IPC, wait for reply and return to user.
  288.  *
  289.  * This function can handle only one argument of payload, but is faster than
  290.  * the generic function (i.e. sys_ipc_call_sync()).
  291.  *
  292.  * @param phoneid   Phone handle for the call.
  293.  * @param method    Method of the call.
  294.  * @param arg1      Service-defined payload argument.
  295.  * @param data      Address of userspace structure where the reply call will
  296.  *          be stored.
  297.  *
  298.  * @return      Returns 0 on success.
  299.  *          Return ENOENT if there is no such phone handle.
  300.  */
  301. unative_t sys_ipc_call_sync_fast(unative_t phoneid, unative_t method,
  302.     unative_t arg1, ipc_data_t *data)
  303. {
  304.     call_t call;
  305.     phone_t *phone;
  306.     int res;
  307.  
  308.     GET_CHECK_PHONE(phone, phoneid, return ENOENT);
  309.  
  310.     ipc_call_static_init(&call);
  311.     IPC_SET_METHOD(call.data, method);
  312.     IPC_SET_ARG1(call.data, arg1);
  313.  
  314.     if (!(res = request_preprocess(&call))) {
  315.         ipc_call_sync(phone, &call);
  316.         process_answer(&call);
  317.     } else {
  318.         IPC_SET_RETVAL(call.data, res);
  319.     }
  320.     STRUCT_TO_USPACE(&data->args, &call.data.args);
  321.  
  322.     return 0;
  323. }
  324.  
  325. /** Make a synchronous IPC call allowing to transmit the entire payload.
  326.  *
  327.  * @param phoneid   Phone handle for the call.
  328.  * @param question  Userspace address of call data with the request.
  329.  * @param reply     Userspace address of call data where to store the answer.
  330.  *
  331.  * @return      Zero on success or an error code.
  332.  */
  333. unative_t sys_ipc_call_sync(unative_t phoneid, ipc_data_t *question,
  334.     ipc_data_t *reply)
  335. {
  336.     call_t call;
  337.     phone_t *phone;
  338.     int res;
  339.     int rc;
  340.  
  341.     ipc_call_static_init(&call);
  342.     rc = copy_from_uspace(&call.data.args, &question->args,
  343.         sizeof(call.data.args));
  344.     if (rc != 0)
  345.         return (unative_t) rc;
  346.  
  347.     GET_CHECK_PHONE(phone, phoneid, return ENOENT);
  348.  
  349.     if (!(res = request_preprocess(&call))) {
  350.         ipc_call_sync(phone, &call);
  351.         process_answer(&call);
  352.     } else
  353.         IPC_SET_RETVAL(call.data, res);
  354.  
  355.     rc = STRUCT_TO_USPACE(&reply->args, &call.data.args);
  356.     if (rc != 0)
  357.         return rc;
  358.  
  359.     return 0;
  360. }
  361.  
  362. /** Check that the task did not exceed the allowed limit of asynchronous calls.
  363.  *
  364.  * @return      Return 0 if limit not reached or -1 if limit exceeded.
  365.  */
  366. static int check_call_limit(void)
  367. {
  368.     if (atomic_preinc(&TASK->active_calls) > IPC_MAX_ASYNC_CALLS) {
  369.         atomic_dec(&TASK->active_calls);
  370.         return -1;
  371.     }
  372.     return 0;
  373. }
  374.  
  375. /** Make a fast asynchronous call over IPC.
  376.  *
  377.  * This function can only handle two arguments of payload, but is faster than
  378.  * the generic function sys_ipc_call_async().
  379.  *
  380.  * @param phoneid   Phone handle for the call.
  381.  * @param method    Method of the call.
  382.  * @param arg1      Service-defined payload argument.
  383.  * @param arg2      Service-defined payload argument.
  384.  *
  385.  * @return      Return call hash on success.
  386.  *          Return IPC_CALLRET_FATAL in case of a fatal error and
  387.  *          IPC_CALLRET_TEMPORARY if there are too many pending
  388.  *          asynchronous requests; answers should be handled first.
  389.  */
  390. unative_t sys_ipc_call_async_fast(unative_t phoneid, unative_t method,
  391.     unative_t arg1, unative_t arg2)
  392. {
  393.     call_t *call;
  394.     phone_t *phone;
  395.     int res;
  396.  
  397.     if (check_call_limit())
  398.         return IPC_CALLRET_TEMPORARY;
  399.  
  400.     GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
  401.  
  402.     call = ipc_call_alloc(0);
  403.     IPC_SET_METHOD(call->data, method);
  404.     IPC_SET_ARG1(call->data, arg1);
  405.     IPC_SET_ARG2(call->data, arg2);
  406.     IPC_SET_ARG3(call->data, 0);
  407.  
  408.     if (!(res = request_preprocess(call)))
  409.         ipc_call(phone, call);
  410.     else
  411.         ipc_backsend_err(phone, call, res);
  412.  
  413.     return (unative_t) call;
  414. }
  415.  
  416. /** Make an asynchronous IPC call allowing to transmit the entire payload.
  417.  *
  418.  * @param phoneid   Phone handle for the call.
  419.  * @param data      Userspace address of call data with the request.
  420.  *
  421.  * @return      See sys_ipc_call_async_fast().
  422.  */
  423. unative_t sys_ipc_call_async(unative_t phoneid, ipc_data_t *data)
  424. {
  425.     call_t *call;
  426.     phone_t *phone;
  427.     int res;
  428.     int rc;
  429.  
  430.     if (check_call_limit())
  431.         return IPC_CALLRET_TEMPORARY;
  432.  
  433.     GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
  434.  
  435.     call = ipc_call_alloc(0);
  436.     rc = copy_from_uspace(&call->data.args, &data->args,
  437.         sizeof(call->data.args));
  438.     if (rc != 0) {
  439.         ipc_call_free(call);
  440.         return (unative_t) rc;
  441.     }
  442.     if (!(res = request_preprocess(call)))
  443.         ipc_call(phone, call);
  444.     else
  445.         ipc_backsend_err(phone, call, res);
  446.  
  447.     return (unative_t) call;
  448. }
  449.  
  450. /** Forward a received call to another destination.
  451.  *
  452.  * @param callid    Hash of the call to forward.
  453.  * @param phoneid   Phone handle to use for forwarding.
  454.  * @param method    New method to use for the forwarded call.
  455.  * @param arg1      New value of the first argument for the forwarded call.
  456.  *
  457.  * @return      Return 0 on succes, otherwise return an error code.
  458.  *
  459.  * In case the original method is a system method, ARG1 and ARG2 are overwritten
  460.  * in the forwarded message with the new method and the new arg1, respectively.
  461.  * Otherwise the METHOD and ARG1 are rewritten with the new method and arg1,
  462.  * respectively.
  463.  *
  464.  * Warning: If implementing non-fast version, make sure that
  465.  *          ARG3 is not rewritten for certain system IPC
  466.  */
  467. unative_t sys_ipc_forward_fast(unative_t callid, unative_t phoneid,
  468.     unative_t method, unative_t arg1)
  469. {
  470.     call_t *call;
  471.     phone_t *phone;
  472.  
  473.     call = get_call(callid);
  474.     if (!call)
  475.         return ENOENT;
  476.  
  477.     call->flags |= IPC_CALL_FORWARDED;
  478.  
  479.     GET_CHECK_PHONE(phone, phoneid, {
  480.         IPC_SET_RETVAL(call->data, EFORWARD);
  481.         ipc_answer(&TASK->answerbox, call);
  482.         return ENOENT;
  483.     });    
  484.  
  485.     if (!is_forwardable(IPC_GET_METHOD(call->data))) {
  486.         IPC_SET_RETVAL(call->data, EFORWARD);
  487.         ipc_answer(&TASK->answerbox, call);
  488.         return EPERM;
  489.     }
  490.  
  491.     /* Userspace is not allowed to change method of system methods
  492.      * on forward, allow changing ARG1 and ARG2 by means of method and arg1
  493.      */
  494.     if (is_system_method(IPC_GET_METHOD(call->data))) {
  495.         if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME)
  496.             phone_dealloc(IPC_GET_ARG3(call->data));
  497.  
  498.         IPC_SET_ARG1(call->data, method);
  499.         IPC_SET_ARG2(call->data, arg1);
  500.     } else {
  501.         IPC_SET_METHOD(call->data, method);
  502.         IPC_SET_ARG1(call->data, arg1);
  503.     }
  504.  
  505.     return ipc_forward(call, phone, &TASK->answerbox);
  506. }
  507.  
  508. /** Answer an IPC call - fast version.
  509.  *
  510.  * This function can handle only two return arguments of payload, but is faster
  511.  * than the generic sys_ipc_answer().
  512.  *
  513.  * @param callid    Hash of the call to be answered.
  514.  * @param retval    Return value of the answer.
  515.  * @param arg1      Service-defined return value.
  516.  * @param arg2      Service-defined return value.
  517.  *
  518.  * @return      Return 0 on success, otherwise return an error code.   
  519.  */
  520. unative_t sys_ipc_answer_fast(unative_t callid, unative_t retval,
  521.     unative_t arg1, unative_t arg2)
  522. {
  523.     call_t *call;
  524.     ipc_data_t saved_data;
  525.     int saveddata = 0;
  526.     int rc;
  527.  
  528.     /* Do not answer notification callids */
  529.     if (callid & IPC_CALLID_NOTIFICATION)
  530.         return 0;
  531.  
  532.     call = get_call(callid);
  533.     if (!call)
  534.         return ENOENT;
  535.  
  536.     if (answer_need_old(call)) {
  537.         memcpy(&saved_data, &call->data, sizeof(call->data));
  538.         saveddata = 1;
  539.     }
  540.  
  541.     IPC_SET_RETVAL(call->data, retval);
  542.     IPC_SET_ARG1(call->data, arg1);
  543.     IPC_SET_ARG2(call->data, arg2);
  544.     rc = answer_preprocess(call, saveddata ? &saved_data : NULL);
  545.  
  546.     ipc_answer(&TASK->answerbox, call);
  547.     return rc;
  548. }
  549.  
  550. /** Answer an IPC call.
  551.  *
  552.  * @param callid    Hash of the call to be answered.
  553.  * @param data      Userspace address of call data with the answer.
  554.  *
  555.  * @return      Return 0 on success, otherwise return an error code.
  556.  */
  557. unative_t sys_ipc_answer(unative_t callid, ipc_data_t *data)
  558. {
  559.     call_t *call;
  560.     ipc_data_t saved_data;
  561.     int saveddata = 0;
  562.     int rc;
  563.  
  564.     /* Do not answer notification callids */
  565.     if (callid & IPC_CALLID_NOTIFICATION)
  566.         return 0;
  567.  
  568.     call = get_call(callid);
  569.     if (!call)
  570.         return ENOENT;
  571.  
  572.     if (answer_need_old(call)) {
  573.         memcpy(&saved_data, &call->data, sizeof(call->data));
  574.         saveddata = 1;
  575.     }
  576.     rc = copy_from_uspace(&call->data.args, &data->args,
  577.         sizeof(call->data.args));
  578.     if (rc != 0)
  579.         return rc;
  580.  
  581.     rc = answer_preprocess(call, saveddata ? &saved_data : NULL);
  582.    
  583.     ipc_answer(&TASK->answerbox, call);
  584.  
  585.     return rc;
  586. }
  587.  
  588. /** Hang up a phone.
  589.  *
  590.  * @param       Phone handle of the phone to be hung up.
  591.  *
  592.  * @return      Return 0 on success or an error code.
  593.  */
  594. unative_t sys_ipc_hangup(int phoneid)
  595. {
  596.     phone_t *phone;
  597.  
  598.     GET_CHECK_PHONE(phone, phoneid, return ENOENT);
  599.  
  600.     if (ipc_phone_hangup(phone))
  601.         return -1;
  602.  
  603.     return 0;
  604. }
  605.  
  606. /** Wait for an incoming IPC call or an answer.
  607.  *
  608.  * @param calldata  Pointer to buffer where the call/answer data is stored.
  609.  * @param usec      Timeout. See waitq_sleep_timeout() for explanation.
  610.  * @param flags     Select mode of sleep operation. See waitq_sleep_timeout()
  611.  *          for explanation.
  612.  *
  613.  * @return      Hash of the call.
  614.  *          If IPC_CALLID_NOTIFICATION bit is set in the hash, the
  615.  *          call is a notification. IPC_CALLID_ANSWERED denotes an
  616.  *          answer.
  617.  */
  618. unative_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec, int flags)
  619. {
  620.     call_t *call;
  621.  
  622. restart:   
  623.     call = ipc_wait_for_call(&TASK->answerbox, usec,
  624.         flags | SYNCH_FLAGS_INTERRUPTIBLE);
  625.     if (!call)
  626.         return 0;
  627.  
  628.     if (call->flags & IPC_CALL_NOTIF) {
  629.         ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
  630.  
  631.         /* Set in_phone_hash to the interrupt counter */
  632.         call->data.phone = (void *) call->priv;
  633.        
  634.         STRUCT_TO_USPACE(calldata, &call->data);
  635.  
  636.         ipc_call_free(call);
  637.        
  638.         return ((unative_t) call) | IPC_CALLID_NOTIFICATION;
  639.     }
  640.  
  641.     if (call->flags & IPC_CALL_ANSWERED) {
  642.         process_answer(call);
  643.  
  644.         ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
  645.  
  646.         atomic_dec(&TASK->active_calls);
  647.  
  648.         if (call->flags & IPC_CALL_DISCARD_ANSWER) {
  649.             ipc_call_free(call);
  650.             goto restart;
  651.         }
  652.  
  653.         STRUCT_TO_USPACE(&calldata->args, &call->data.args);
  654.         ipc_call_free(call);
  655.  
  656.         return ((unative_t) call) | IPC_CALLID_ANSWERED;
  657.     }
  658.  
  659.     if (process_request(&TASK->answerbox, call))
  660.         goto restart;
  661.  
  662.     /* Include phone address('id') of the caller in the request,
  663.      * copy whole call->data, not only call->data.args */
  664.     if (STRUCT_TO_USPACE(calldata, &call->data)) {
  665.         return 0;
  666.     }
  667.     return (unative_t)call;
  668. }
  669.  
  670. /** Connect an IRQ handler to a task.
  671.  *
  672.  * @param inr       IRQ number.
  673.  * @param devno     Device number.
  674.  * @param method    Method to be associated with the notification.
  675.  * @param ucode     Uspace pointer to the top-half pseudocode.
  676.  *
  677.  * @return      EPERM or a return code returned by ipc_irq_register().
  678.  */
  679. unative_t sys_ipc_register_irq(inr_t inr, devno_t devno, unative_t method,
  680.     irq_code_t *ucode)
  681. {
  682.     if (!(cap_get(TASK) & CAP_IRQ_REG))
  683.         return EPERM;
  684.  
  685.     return ipc_irq_register(&TASK->answerbox, inr, devno, method, ucode);
  686. }
  687.  
  688. /** Disconnect an IRQ handler from a task.
  689.  *
  690.  * @param inr       IRQ number.
  691.  * @param devno     Device number.
  692.  *
  693.  * @return      Zero on success or EPERM on error..
  694.  */
  695. unative_t sys_ipc_unregister_irq(inr_t inr, devno_t devno)
  696. {
  697.     if (!(cap_get(TASK) & CAP_IRQ_REG))
  698.         return EPERM;
  699.  
  700.     ipc_irq_unregister(&TASK->answerbox, inr, devno);
  701.  
  702.     return 0;
  703. }
  704.  
  705. /** @}
  706.  */
  707.