source: mainline/kernel/generic/src/ipc/sysipc.c@ 11675207

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 11675207 was 11675207, checked in by jermar <jermar@…>, 17 years ago

Move everything to kernel/.

  • Property mode set to 100644
File size: 14.9 KB
RevLine 
[2d5a54f3]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
[cc73a8a1]29/** @addtogroup genericipc
[b45c443]30 * @{
31 */
32/** @file
33 */
34
[2d5a54f3]35#include <arch.h>
36#include <proc/task.h>
[e3c762cd]37#include <proc/thread.h>
[2d5a54f3]38#include <errno.h>
39#include <memstr.h>
40#include <debug.h>
41#include <ipc/ipc.h>
42#include <ipc/sysipc.h>
[162f919]43#include <ipc/irq.h>
[4e49572]44#include <ipc/ipcrsc.h>
[5626277]45#include <arch/interrupt.h>
[2d5a54f3]46#include <print.h>
[e3c762cd]47#include <syscall/copy.h>
[2bb8648]48#include <security/cap.h>
[7c23af9]49#include <mm/as.h>
[2d5a54f3]50
[ba81cab]51#define GET_CHECK_PHONE(phone,phoneid,err) { \
52 if (phoneid > IPC_MAX_PHONES) { err; } \
53 phone = &TASK->phones[phoneid]; \
54}
55
[7c7aae16]56#define STRUCT_TO_USPACE(dst,src) copy_to_uspace(dst,src,sizeof(*(src)))
[ba81cab]57
[2ba7810]58/** Return true if the method is a system method */
[7f1c620]59static inline int is_system_method(unative_t method)
[2ba7810]60{
61 if (method <= IPC_M_LAST_SYSTEM)
62 return 1;
63 return 0;
64}
65
66/** Return true if the message with this method is forwardable
67 *
68 * - some system messages may be forwarded, for some of them
69 * it is useless
70 */
[7f1c620]71static inline int is_forwardable(unative_t method)
[2ba7810]72{
[46fc2f9]73 if (method == IPC_M_PHONE_HUNGUP || method == IPC_M_AS_AREA_SEND \
74 || method == IPC_M_AS_AREA_RECV)
[fbcfd458]75 return 0; /* This message is meant only for the receiver */
[2ba7810]76 return 1;
77}
78
[2d5a54f3]79/****************************************************/
80/* Functions that preprocess answer before sending
81 * it to the recepient
82 */
83
84/** Return true if the caller (ipc_answer) should save
[9f22213]85 * the old call contents for answer_preprocess
[2d5a54f3]86 */
[9f22213]87static inline int answer_need_old(call_t *call)
[2d5a54f3]88{
[fbcfd458]89 if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME)
[2d5a54f3]90 return 1;
[fbcfd458]91 if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_ME_TO)
[37c57f2]92 return 1;
[8497711]93 if (IPC_GET_METHOD(call->data) == IPC_M_AS_AREA_SEND)
[7c23af9]94 return 1;
[46fc2f9]95 if (IPC_GET_METHOD(call->data) == IPC_M_AS_AREA_RECV)
96 return 1;
[2d5a54f3]97 return 0;
98}
99
[46fc2f9]100/** Interpret process answer as control information
101 *
102 * This function is called directly after sys_ipc_answer
103 */
[7c23af9]104static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
[2d5a54f3]105{
106 int phoneid;
107
[9f22213]108 if (IPC_GET_RETVAL(answer->data) == EHANGUP) {
[ca687ad]109 /* In case of forward, hangup the forwared phone,
110 * not the originator
111 */
112 spinlock_lock(&answer->data.phone->lock);
113 spinlock_lock(&TASK->answerbox.lock);
[eb3d379]114 if (answer->data.phone->state == IPC_PHONE_CONNECTED) {
[c4e4507]115 list_remove(&answer->data.phone->link);
[eb3d379]116 answer->data.phone->state = IPC_PHONE_SLAMMED;
[ca687ad]117 }
118 spinlock_unlock(&TASK->answerbox.lock);
119 spinlock_unlock(&answer->data.phone->lock);
[9f22213]120 }
121
122 if (!olddata)
[7c23af9]123 return 0;
[9f22213]124
[fbcfd458]125 if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
[2ba7810]126 phoneid = IPC_GET_ARG3(*olddata);
[2d5a54f3]127 if (IPC_GET_RETVAL(answer->data)) {
128 /* The connection was not accepted */
129 phone_dealloc(phoneid);
[2ba7810]130 } else {
[7c7aae16]131 /* The connection was accepted */
[2ba7810]132 phone_connect(phoneid,&answer->sender->answerbox);
[7c7aae16]133 /* Set 'phone identification' as arg3 of response */
[7f1c620]134 IPC_SET_ARG3(answer->data, (unative_t)&TASK->phones[phoneid]);
[2d5a54f3]135 }
[fbcfd458]136 } else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
[37c57f2]137 /* If the users accepted call, connect */
138 if (!IPC_GET_RETVAL(answer->data)) {
139 ipc_phone_connect((phone_t *)IPC_GET_ARG3(*olddata),
140 &TASK->answerbox);
141 }
[8497711]142 } else if (IPC_GET_METHOD(*olddata) == IPC_M_AS_AREA_SEND) {
143 if (!IPC_GET_RETVAL(answer->data)) { /* Accepted, handle as_area receipt */
[8d6bc2d5]144 ipl_t ipl;
[76d7305]145 int rc;
[8d6bc2d5]146 as_t *as;
147
148 ipl = interrupts_disable();
149 spinlock_lock(&answer->sender->lock);
150 as = answer->sender->as;
151 spinlock_unlock(&answer->sender->lock);
152 interrupts_restore(ipl);
153
[76d7305]154 rc = as_area_share(as, IPC_GET_ARG1(*olddata), IPC_GET_ARG2(*olddata),
155 AS, IPC_GET_ARG1(answer->data), IPC_GET_ARG3(*olddata));
156 IPC_SET_RETVAL(answer->data, rc);
157 return rc;
[46fc2f9]158 }
159 } else if (IPC_GET_METHOD(*olddata) == IPC_M_AS_AREA_RECV) {
160 if (!IPC_GET_RETVAL(answer->data)) {
161 ipl_t ipl;
162 as_t *as;
[d6e5cbc]163 int rc;
[46fc2f9]164
165 ipl = interrupts_disable();
166 spinlock_lock(&answer->sender->lock);
167 as = answer->sender->as;
168 spinlock_unlock(&answer->sender->lock);
169 interrupts_restore(ipl);
170
[d6e5cbc]171 rc = as_area_share(AS, IPC_GET_ARG1(answer->data), IPC_GET_ARG2(*olddata),
[76d7305]172 as, IPC_GET_ARG1(*olddata), IPC_GET_ARG2(answer->data));
[d6e5cbc]173 IPC_SET_RETVAL(answer->data, rc);
[7c23af9]174 }
[2d5a54f3]175 }
[7c23af9]176 return 0;
[2d5a54f3]177}
178
[7c7aae16]179/** Called before the request is sent
180 *
181 * @return 0 - no error, -1 - report error to user
182 */
183static int request_preprocess(call_t *call)
184{
185 int newphid;
[7c23af9]186 size_t size;
[7c7aae16]187
188 switch (IPC_GET_METHOD(call->data)) {
189 case IPC_M_CONNECT_ME_TO:
190 newphid = phone_alloc();
191 if (newphid < 0)
192 return ELIMIT;
193 /* Set arg3 for server */
[7f1c620]194 IPC_SET_ARG3(call->data, (unative_t)&TASK->phones[newphid]);
[7c7aae16]195 call->flags |= IPC_CALL_CONN_ME_TO;
196 call->private = newphid;
197 break;
[8497711]198 case IPC_M_AS_AREA_SEND:
[fd4d8c0]199 size = as_get_size(IPC_GET_ARG1(call->data));
[7c23af9]200 if (!size) {
201 return EPERM;
202 }
[fd4d8c0]203 IPC_SET_ARG2(call->data, size);
[7c23af9]204 break;
[7c7aae16]205 default:
206 break;
207 }
208 return 0;
209}
210
[2d5a54f3]211/****************************************************/
212/* Functions called to process received call/answer
213 * before passing to uspace
214 */
215
216/** Do basic kernel processing of received call answer */
[7c7aae16]217static void process_answer(call_t *call)
[2d5a54f3]218{
[9f22213]219 if (IPC_GET_RETVAL(call->data) == EHANGUP && \
220 call->flags & IPC_CALL_FORWARDED)
221 IPC_SET_RETVAL(call->data, EFORWARD);
[7c7aae16]222
223 if (call->flags & IPC_CALL_CONN_ME_TO) {
224 if (IPC_GET_RETVAL(call->data))
225 phone_dealloc(call->private);
226 else
227 IPC_SET_ARG3(call->data, call->private);
228 }
[2d5a54f3]229}
230
231/** Do basic kernel processing of received call request
232 *
233 * @return 0 - the call should be passed to userspace, 1 - ignore call
234 */
235static int process_request(answerbox_t *box,call_t *call)
236{
237 int phoneid;
238
[fbcfd458]239 if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME) {
[2ba7810]240 phoneid = phone_alloc();
[2d5a54f3]241 if (phoneid < 0) { /* Failed to allocate phone */
242 IPC_SET_RETVAL(call->data, ELIMIT);
243 ipc_answer(box,call);
244 return -1;
245 }
246 IPC_SET_ARG3(call->data, phoneid);
247 }
248 return 0;
249}
250
251/** Send a call over IPC, wait for reply, return to user
252 *
253 * @return Call identification, returns -1 on fatal error,
254 -2 on 'Too many async request, handle answers first
255 */
[7f1c620]256unative_t sys_ipc_call_sync_fast(unative_t phoneid, unative_t method,
257 unative_t arg1, ipc_data_t *data)
[2d5a54f3]258{
259 call_t call;
260 phone_t *phone;
[7c7aae16]261 int res;
[2d5a54f3]262
[ba81cab]263 GET_CHECK_PHONE(phone, phoneid, return ENOENT);
[4e49572]264
[ba81cab]265 ipc_call_static_init(&call);
[2d5a54f3]266 IPC_SET_METHOD(call.data, method);
267 IPC_SET_ARG1(call.data, arg1);
268
[7c7aae16]269 if (!(res=request_preprocess(&call))) {
270 ipc_call_sync(phone, &call);
271 process_answer(&call);
272 } else
273 IPC_SET_RETVAL(call.data, res);
[fbcfd458]274 STRUCT_TO_USPACE(&data->args, &call.data.args);
[2d5a54f3]275
276 return 0;
277}
278
279/** Synchronous IPC call allowing to send whole message */
[7f1c620]280unative_t sys_ipc_call_sync(unative_t phoneid, ipc_data_t *question,
[fbcfd458]281 ipc_data_t *reply)
[2d5a54f3]282{
283 call_t call;
284 phone_t *phone;
[7c7aae16]285 int res;
[e3c762cd]286 int rc;
[2d5a54f3]287
[ba81cab]288 ipc_call_static_init(&call);
[e3c762cd]289 rc = copy_from_uspace(&call.data.args, &question->args, sizeof(call.data.args));
290 if (rc != 0)
[7f1c620]291 return (unative_t) rc;
[2ba7810]292
[ba81cab]293 GET_CHECK_PHONE(phone, phoneid, return ENOENT);
[4e49572]294
[7c7aae16]295 if (!(res=request_preprocess(&call))) {
296 ipc_call_sync(phone, &call);
297 process_answer(&call);
298 } else
299 IPC_SET_RETVAL(call.data, res);
[2d5a54f3]300
[e3c762cd]301 rc = STRUCT_TO_USPACE(&reply->args, &call.data.args);
302 if (rc != 0)
303 return rc;
[2d5a54f3]304
305 return 0;
306}
307
308/** Check that the task did not exceed allowed limit
309 *
310 * @return 0 - Limit OK, -1 - limit exceeded
311 */
312static int check_call_limit(void)
313{
314 if (atomic_preinc(&TASK->active_calls) > IPC_MAX_ASYNC_CALLS) {
315 atomic_dec(&TASK->active_calls);
316 return -1;
317 }
318 return 0;
319}
320
321/** Send an asynchronous call over ipc
322 *
323 * @return Call identification, returns -1 on fatal error,
324 -2 on 'Too many async request, handle answers first
325 */
[7f1c620]326unative_t sys_ipc_call_async_fast(unative_t phoneid, unative_t method,
327 unative_t arg1, unative_t arg2)
[2d5a54f3]328{
329 call_t *call;
330 phone_t *phone;
[7c7aae16]331 int res;
[2ba7810]332
[2d5a54f3]333 if (check_call_limit())
334 return IPC_CALLRET_TEMPORARY;
335
[7c7aae16]336 GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
[4e49572]337
[5626277]338 call = ipc_call_alloc(0);
[2d5a54f3]339 IPC_SET_METHOD(call->data, method);
340 IPC_SET_ARG1(call->data, arg1);
341 IPC_SET_ARG2(call->data, arg2);
[85d24f61]342 IPC_SET_ARG3(call->data, 0);
[2d5a54f3]343
[7c7aae16]344 if (!(res=request_preprocess(call)))
345 ipc_call(phone, call);
346 else
347 ipc_backsend_err(phone, call, res);
[2d5a54f3]348
[7f1c620]349 return (unative_t) call;
[2d5a54f3]350}
351
352/** Synchronous IPC call allowing to send whole message
353 *
354 * @return The same as sys_ipc_call_async
355 */
[7f1c620]356unative_t sys_ipc_call_async(unative_t phoneid, ipc_data_t *data)
[2d5a54f3]357{
358 call_t *call;
359 phone_t *phone;
[7c7aae16]360 int res;
[e3c762cd]361 int rc;
[2d5a54f3]362
363 if (check_call_limit())
364 return IPC_CALLRET_TEMPORARY;
365
[7c7aae16]366 GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
[4e49572]367
[5626277]368 call = ipc_call_alloc(0);
[e3c762cd]369 rc = copy_from_uspace(&call->data.args, &data->args, sizeof(call->data.args));
[f58af46]370 if (rc != 0) {
371 ipc_call_free(call);
[7f1c620]372 return (unative_t) rc;
[f58af46]373 }
[7c7aae16]374 if (!(res=request_preprocess(call)))
375 ipc_call(phone, call);
376 else
377 ipc_backsend_err(phone, call, res);
[2d5a54f3]378
[7f1c620]379 return (unative_t) call;
[2d5a54f3]380}
381
[2ba7810]382/** Forward received call to another destination
383 *
384 * The arg1 and arg2 are changed in the forwarded message
[37c57f2]385 *
386 * Warning: If implementing non-fast version, make sure that
387 * arg3 is not rewritten for certain system IPC
[2ba7810]388 */
[7f1c620]389unative_t sys_ipc_forward_fast(unative_t callid, unative_t phoneid,
390 unative_t method, unative_t arg1)
[2ba7810]391{
392 call_t *call;
393 phone_t *phone;
394
395 call = get_call(callid);
396 if (!call)
397 return ENOENT;
398
[9f22213]399 call->flags |= IPC_CALL_FORWARDED;
400
[ba81cab]401 GET_CHECK_PHONE(phone, phoneid, {
[2ba7810]402 IPC_SET_RETVAL(call->data, EFORWARD);
403 ipc_answer(&TASK->answerbox, call);
404 return ENOENT;
[ba81cab]405 });
[2ba7810]406
407 if (!is_forwardable(IPC_GET_METHOD(call->data))) {
408 IPC_SET_RETVAL(call->data, EFORWARD);
409 ipc_answer(&TASK->answerbox, call);
410 return EPERM;
411 }
412
413 /* Userspace is not allowed to change method of system methods
414 * on forward, allow changing ARG1 and ARG2 by means of method and arg1
415 */
416 if (is_system_method(IPC_GET_METHOD(call->data))) {
[7c7aae16]417 if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME)
418 phone_dealloc(IPC_GET_ARG3(call->data));
419
[2ba7810]420 IPC_SET_ARG1(call->data, method);
421 IPC_SET_ARG2(call->data, arg1);
422 } else {
423 IPC_SET_METHOD(call->data, method);
424 IPC_SET_ARG1(call->data, arg1);
425 }
426
[9f22213]427 return ipc_forward(call, phone, &TASK->answerbox);
[2ba7810]428}
429
[2d5a54f3]430/** Send IPC answer */
[7f1c620]431unative_t sys_ipc_answer_fast(unative_t callid, unative_t retval,
432 unative_t arg1, unative_t arg2)
[2d5a54f3]433{
434 call_t *call;
[2ba7810]435 ipc_data_t saved_data;
[9f22213]436 int saveddata = 0;
[7c23af9]437 int rc;
[2d5a54f3]438
[897f2e76]439 /* Do not answer notification callids */
440 if (callid & IPC_CALLID_NOTIFICATION)
441 return 0;
442
[2ba7810]443 call = get_call(callid);
444 if (!call)
445 return ENOENT;
[2d5a54f3]446
[9f22213]447 if (answer_need_old(call)) {
[2ba7810]448 memcpy(&saved_data, &call->data, sizeof(call->data));
[9f22213]449 saveddata = 1;
[2d5a54f3]450 }
451
452 IPC_SET_RETVAL(call->data, retval);
453 IPC_SET_ARG1(call->data, arg1);
454 IPC_SET_ARG2(call->data, arg2);
[7c23af9]455 rc = answer_preprocess(call, saveddata ? &saved_data : NULL);
[2d5a54f3]456
457 ipc_answer(&TASK->answerbox, call);
[7c23af9]458 return rc;
[2d5a54f3]459}
460
461/** Send IPC answer */
[7f1c620]462unative_t sys_ipc_answer(unative_t callid, ipc_data_t *data)
[2d5a54f3]463{
464 call_t *call;
[2ba7810]465 ipc_data_t saved_data;
[9f22213]466 int saveddata = 0;
[e3c762cd]467 int rc;
[2d5a54f3]468
[897f2e76]469 /* Do not answer notification callids */
470 if (callid & IPC_CALLID_NOTIFICATION)
471 return 0;
472
[2ba7810]473 call = get_call(callid);
474 if (!call)
475 return ENOENT;
[2d5a54f3]476
[9f22213]477 if (answer_need_old(call)) {
[2ba7810]478 memcpy(&saved_data, &call->data, sizeof(call->data));
[9f22213]479 saveddata = 1;
[2d5a54f3]480 }
[e3c762cd]481 rc = copy_from_uspace(&call->data.args, &data->args,
[fbcfd458]482 sizeof(call->data.args));
[e3c762cd]483 if (rc != 0)
484 return rc;
[2d5a54f3]485
[7c23af9]486 rc = answer_preprocess(call, saveddata ? &saved_data : NULL);
[2d5a54f3]487
488 ipc_answer(&TASK->answerbox, call);
489
[7c23af9]490 return rc;
[2d5a54f3]491}
492
[fbcfd458]493/** Hang up the phone
[2d5a54f3]494 *
[fbcfd458]495 */
[7f1c620]496unative_t sys_ipc_hangup(int phoneid)
[fbcfd458]497{
498 phone_t *phone;
499
500 GET_CHECK_PHONE(phone, phoneid, return ENOENT);
501
[d8f7362]502 if (ipc_phone_hangup(phone))
[fbcfd458]503 return -1;
504
505 return 0;
506}
507
508/** Wait for incoming ipc call or answer
509 *
510 * @param calldata Pointer to buffer where the call/answer data is stored
[bd5a663]511 * @param usec Timeout. See waitq_sleep_timeout() for explanation.
[116d1ef4]512 * @param flags Select mode of sleep operation. See waitq_sleep_timeout() for explanation.
[bd5a663]513 *
[2d5a54f3]514 * @return Callid, if callid & 1, then the call is answer
515 */
[7f1c620]516unative_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec, int flags)
[2d5a54f3]517{
518 call_t *call;
519
520restart:
[116d1ef4]521 call = ipc_wait_for_call(&TASK->answerbox, usec, flags | SYNCH_FLAGS_INTERRUPTIBLE);
[9f22213]522 if (!call)
523 return 0;
[2d5a54f3]524
[5626277]525 if (call->flags & IPC_CALL_NOTIF) {
526 ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
[43752b6]527
528 /* Set in_phone_hash to the interrupt counter */
529 call->data.phone = (void *)call->private;
530
531 STRUCT_TO_USPACE(calldata, &call->data);
532
[5626277]533 ipc_call_free(call);
534
[7f1c620]535 return ((unative_t)call) | IPC_CALLID_NOTIFICATION;
[5626277]536 }
537
[2d5a54f3]538 if (call->flags & IPC_CALL_ANSWERED) {
[7c7aae16]539 process_answer(call);
[2d5a54f3]540
541 ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
[fbcfd458]542
543 atomic_dec(&TASK->active_calls);
544
545 if (call->flags & IPC_CALL_DISCARD_ANSWER) {
546 ipc_call_free(call);
547 goto restart;
548 }
549
550 STRUCT_TO_USPACE(&calldata->args, &call->data.args);
[2d5a54f3]551 ipc_call_free(call);
552
[7f1c620]553 return ((unative_t)call) | IPC_CALLID_ANSWERED;
[2d5a54f3]554 }
[fbcfd458]555
[2d5a54f3]556 if (process_request(&TASK->answerbox, call))
557 goto restart;
[fbcfd458]558
[7c7aae16]559 /* Include phone address('id') of the caller in the request,
560 * copy whole call->data, not only call->data.args */
[bd55bbb]561 if (STRUCT_TO_USPACE(calldata, &call->data)) {
562 return 0;
563 }
[7f1c620]564 return (unative_t)call;
[2d5a54f3]565}
[5626277]566
567/** Connect irq handler to task */
[7f1c620]568unative_t sys_ipc_register_irq(int irq, irq_code_t *ucode)
[5626277]569{
[2bb8648]570 if (!(cap_get(TASK) & CAP_IRQ_REG))
571 return EPERM;
572
[874621f]573 if (irq >= IRQ_COUNT || irq <= -IPC_IRQ_RESERVED_VIRTUAL)
[7f1c620]574 return (unative_t) ELIMIT;
[874621f]575
[5626277]576 irq_ipc_bind_arch(irq);
[162f919]577
578 return ipc_irq_register(&TASK->answerbox, irq, ucode);
[5626277]579}
580
581/* Disconnect irq handler from task */
[7f1c620]582unative_t sys_ipc_unregister_irq(int irq)
[5626277]583{
[2bb8648]584 if (!(cap_get(TASK) & CAP_IRQ_REG))
585 return EPERM;
586
[874621f]587 if (irq >= IRQ_COUNT || irq <= -IPC_IRQ_RESERVED_VIRTUAL)
[7f1c620]588 return (unative_t) ELIMIT;
[5626277]589
590 ipc_irq_unregister(&TASK->answerbox, irq);
591
592 return 0;
593}
[b45c443]594
[cc73a8a1]595/** @}
[b45c443]596 */
Note: See TracBrowser for help on using the repository browser.