/trunk/kernel/generic/include/ipc/ipc.h |
---|
61,15 → 61,17 |
/** Interrupt notification */ |
#define IPC_CALL_NOTIF (1 << 5) |
/* Flags of callid (the addresses are aligned at least to 4, |
* that is why we can use bottom 2 bits of the call address |
/* |
* Bits used in call hashes. |
* The addresses are aligned at least to 4 that is why we can use the 2 least |
* significant bits of the call address. |
*/ |
/** Type of this msg is 'answer' */ |
/** Type of this call is 'answer' */ |
#define IPC_CALLID_ANSWERED 1 |
/** Type of this msg is 'notification' */ |
/** Type of this call is 'notification' */ |
#define IPC_CALLID_NOTIFICATION 2 |
/* Return values from IPC_ASYNC */ |
/* Return values from sys_ipc_call_async(). */ |
#define IPC_CALLRET_FATAL -1 |
#define IPC_CALLRET_TEMPORARY -2 |
203,17 → 205,17 |
waitq_t wq; |
/** Phones connected to this answerbox */ |
/** Phones connected to this answerbox. */ |
link_t connected_phones; |
/** Received calls */ |
/** Received calls. */ |
link_t calls; |
link_t dispatched_calls; /* Should be hash table in the future */ |
/** Answered calls */ |
/** Answered calls. */ |
link_t answers; |
SPINLOCK_DECLARE(irq_lock); |
/** Notifications from IRQ handlers */ |
/** Notifications from IRQ handlers. */ |
link_t irq_notifs; |
/** IRQs with notifications to this answerbox. */ |
link_t irq_head; |
229,17 → 231,16 |
int flags; |
/* Identification of the caller */ |
/** Identification of the caller. */ |
struct task *sender; |
/* The caller box is different from sender->answerbox |
* for synchronous calls |
*/ |
/** The caller box is different from sender->answerbox for synchronous |
* calls. */ |
answerbox_t *callerbox; |
/** Private data to internal IPC */ |
/** Private data to internal IPC. */ |
unative_t priv; |
/** Data passed from/to userspace */ |
/** Data passed from/to userspace. */ |
ipc_data_t data; |
} call_t; |
/trunk/kernel/generic/include/ipc/irq.h |
---|
46,7 → 46,8 |
extern int ipc_irq_register(answerbox_t *box, inr_t inr, devno_t devno, |
unative_t method, irq_code_t *ucode); |
extern void ipc_irq_send_notif(irq_t *irq); |
extern void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2, unative_t a3); |
extern void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2, |
unative_t a3); |
extern void ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno); |
extern void ipc_irq_cleanup(answerbox_t *box); |
/trunk/kernel/generic/include/ipc/ipcrsc.h |
---|
35,10 → 35,10 |
#ifndef KERN_IPCRSC_H_ |
#define KERN_IPCRSC_H_ |
call_t * get_call(unative_t callid); |
int phone_alloc(void); |
void phone_connect(int phoneid, answerbox_t *box); |
void phone_dealloc(int phoneid); |
extern call_t * get_call(unative_t callid); |
extern int phone_alloc(void); |
extern void phone_connect(int phoneid, answerbox_t *box); |
extern void phone_dealloc(int phoneid); |
#endif |
/trunk/kernel/generic/src/ipc/ipcrsc.c |
---|
132,10 → 132,15 |
#include <ipc/ipcrsc.h> |
#include <debug.h> |
/** Find call_t * in call table according to callid |
/** Find call_t * in call table according to callid. |
* |
* TODO: Some speedup (hash table?) |
* @return NULL on not found, otherwise pointer to call structure |
* @todo Some speedup (hash table?) |
* |
* @param callid Userspace hash of the call. Currently it is the call |
* structure kernel address. |
* |
* @return NULL on not found, otherwise pointer to the call |
* structure. |
*/ |
call_t * get_call(unative_t callid) |
{ |
155,7 → 160,11 |
return result; |
} |
/** Allocate new phone slot in current TASK structure */ |
/** Allocate new phone slot in the current TASK structure. |
* |
* @return New phone handle or -1 if the phone handle limit is |
* exceeded. |
*/ |
int phone_alloc(void) |
{ |
int i; |
163,7 → 172,7 |
spinlock_lock(&TASK->lock); |
for (i=0; i < IPC_MAX_PHONES; i++) { |
if (TASK->phones[i].state == IPC_PHONE_HUNGUP && \ |
if (TASK->phones[i].state == IPC_PHONE_HUNGUP && |
atomic_get(&TASK->phones[i].active_calls) == 0) |
TASK->phones[i].state = IPC_PHONE_FREE; |
179,6 → 188,10 |
return i; |
} |
/** Mark a phone structure free. |
* |
* @param phone Phone structure to be marked free. |
*/ |
static void phone_deallocp(phone_t *phone) |
{ |
ASSERT(phone->state == IPC_PHONE_CONNECTING); |
187,9 → 200,11 |
phone->state = IPC_PHONE_FREE; |
} |
/** Free slot from a disconnected phone |
/** Free slot from a disconnected phone. |
* |
* All already sent messages will be correctly processed |
* All already sent messages will be correctly processed. |
* |
* @param phoneid Phone handle of the phone to be freed. |
*/ |
void phone_dealloc(int phoneid) |
{ |
196,9 → 211,10 |
phone_deallocp(&TASK->phones[phoneid]); |
} |
/** Connect phone to a given answerbox |
/** Connect phone to a given answerbox. |
* |
* @param phoneid The slot that will be connected |
* @param phoneid Phone handle to be connected. |
* @param box Answerbox to which to connect the phone handle. |
* |
* The procedure _enforces_ that the user first marks the phone |
* busy (e.g. via phone_alloc) and then connects the phone, otherwise |
/trunk/kernel/generic/src/ipc/sysipc.c |
---|
49,14 → 49,23 |
#include <mm/as.h> |
#include <print.h> |
#define GET_CHECK_PHONE(phone, phoneid, err) { \ |
if (phoneid > IPC_MAX_PHONES) { err; } \ |
#define GET_CHECK_PHONE(phone, phoneid, err) \ |
{ \ |
if (phoneid > IPC_MAX_PHONES) { \ |
err; \ |
} \ |
phone = &TASK->phones[phoneid]; \ |
} |
#define STRUCT_TO_USPACE(dst, src) copy_to_uspace(dst, src, sizeof(*(src))) |
/** Return true if the method is a system method */ |
/** Decide if the method is a system method. |
* |
* @param method Method to be decided. |
* |
* @return Return 1 if the method is a system method. |
* Otherwise return 0. |
*/ |
static inline int is_system_method(unative_t method) |
{ |
if (method <= IPC_M_LAST_SYSTEM) |
64,10 → 73,15 |
return 0; |
} |
/** Return true if the message with this method is forwardable |
/** Decide if the message with this method is forwardable. |
* |
* - some system messages may be forwarded, for some of them |
* it is useless |
* |
* @param method Method to be decided. |
* |
* @return Return 1 if the method is forwardable. |
* Otherwise return 0. |
*/ |
static inline int is_forwardable(unative_t method) |
{ |
77,13 → 91,18 |
return 1; |
} |
/****************************************************/ |
/* Functions that preprocess answer before sending |
* it to the recepient |
*/ |
/** Return true if the caller (ipc_answer) should save |
* the old call contents for answer_preprocess |
/*********************************************************************** |
* Functions that preprocess answer before sending it to the recepient. |
***********************************************************************/ |
/** Decide if the caller (e.g. ipc_answer()) should save the old call contents |
* for answer_preprocess(). |
* |
* @param call Call structure to be decided. |
* |
* @return Return 1 if the old call contents should be saved. |
* Return 0 otherwise. |
*/ |
static inline int answer_need_old(call_t *call) |
{ |
98,9 → 117,14 |
return 0; |
} |
/** Interpret process answer as control information |
/** Interpret process answer as control information. |
* |
* This function is called directly after sys_ipc_answer |
* This function is called directly after sys_ipc_answer(). |
* |
* @param answer Call structure with the answer. |
* @param olddata Saved data of the request. |
* |
* @return Return 0 on success or an error code. |
*/ |
static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata) |
{ |
131,7 → 155,7 |
} else { |
/* The connection was accepted */ |
phone_connect(phoneid, &answer->sender->answerbox); |
/* Set 'phone identification' as arg3 of response */ |
/* Set 'phone hash' as arg3 of response */ |
IPC_SET_ARG3(answer->data, |
(unative_t) &TASK->phones[phoneid]); |
} |
181,9 → 205,11 |
return 0; |
} |
/** Called before the request is sent |
/** Called before the request is sent. |
* |
* @return 0 - no error, -1 - report error to user |
* @param call Call structure with the request. |
* |
* @return Return 0 on success, ELIMIT or EPERM on error. |
*/ |
static int request_preprocess(call_t *call) |
{ |
202,9 → 228,8 |
break; |
case IPC_M_AS_AREA_SEND: |
size = as_get_size(IPC_GET_ARG1(call->data)); |
if (!size) { |
if (!size) |
return EPERM; |
} |
IPC_SET_ARG2(call->data, size); |
break; |
default: |
213,12 → 238,14 |
return 0; |
} |
/****************************************************/ |
/* Functions called to process received call/answer |
* before passing to uspace |
/******************************************************************************* |
* Functions called to process received call/answer before passing it to uspace. |
*******************************************************************************/ |
/** Do basic kernel processing of received call answer. |
* |
* @param call Call structure with the answer. |
*/ |
/** Do basic kernel processing of received call answer */ |
static void process_answer(call_t *call) |
{ |
if (IPC_GET_RETVAL(call->data) == EHANGUP && |
233,9 → 260,13 |
} |
} |
/** Do basic kernel processing of received call request |
/** Do basic kernel processing of received call request. |
* |
* @return 0 - the call should be passed to userspace, 1 - ignore call |
* @param box Destination answerbox structure. |
* @param call Call structure with the request. |
* |
* @return Return 0 if the call should be passed to userspace. |
* Return -1 if the call should be ignored. |
*/ |
static int process_request(answerbox_t *box, call_t *call) |
{ |
253,10 → 284,19 |
return 0; |
} |
/** Send a call over IPC, wait for reply, return to user |
/** Make a fast call over IPC, wait for reply and return to user. |
* |
* @return Call identification, returns -1 on fatal error, |
-2 on 'Too many async request, handle answers first |
* This function can handle only one argument of payload, but is faster than |
* the generic function (i.e. sys_ipc_call_sync()). |
* |
* @param phoneid Phone handle for the call. |
* @param method Method of the call. |
* @param arg1 Service-defined payload argument. |
* @param data Address of userspace structure where the reply call will |
* be stored. |
* |
* @return Returns 0 on success. |
* Return ENOENT if there is no such phone handle. |
*/ |
unative_t sys_ipc_call_sync_fast(unative_t phoneid, unative_t method, |
unative_t arg1, ipc_data_t *data) |
274,14 → 314,22 |
if (!(res=request_preprocess(&call))) { |
ipc_call_sync(phone, &call); |
process_answer(&call); |
} else |
} else { |
IPC_SET_RETVAL(call.data, res); |
} |
STRUCT_TO_USPACE(&data->args, &call.data.args); |
return 0; |
} |
/** Synchronous IPC call allowing to send whole message */ |
/** Make a synchronous IPC call allowing to transmit the entire payload. |
* |
* @param phoneid Phone handle for the call. |
* @param question Userspace address of call data with the request. |
* @param reply Userspace address of call data where to store the answer. |
* |
* @return Zero on success or an error code. |
*/ |
unative_t sys_ipc_call_sync(unative_t phoneid, ipc_data_t *question, |
ipc_data_t *reply) |
{ |
311,9 → 359,9 |
return 0; |
} |
/** Check that the task did not exceed allowed limit |
/** Check that the task did not exceed the allowed limit of asynchronous calls. |
* |
* @return 0 - Limit OK, -1 - limit exceeded |
* @return Return 0 if limit not reached or -1 if limit exceeded. |
*/ |
static int check_call_limit(void) |
{ |
324,10 → 372,20 |
return 0; |
} |
/** Send an asynchronous call over ipc |
/** Make a fast asynchronous call over IPC. |
* |
* @return Call identification, returns -1 on fatal error, |
-2 on 'Too many async request, handle answers first |
* This function can only handle two arguments of payload, but is faster than |
* the generic function sys_ipc_call_async(). |
* |
* @param phoneid Phone handle for the call. |
* @param method Method of the call. |
* @param arg1 Service-defined payload argument. |
* @param arg2 Service-defined payload argument. |
* |
* @return Return call hash on success. |
* Return IPC_CALLRET_FATAL in case of a fatal error and |
* IPC_CALLRET_TEMPORARY if there are too many pending |
* asynchronous requests; answers should be handled first. |
*/ |
unative_t sys_ipc_call_async_fast(unative_t phoneid, unative_t method, |
unative_t arg1, unative_t arg2) |
355,9 → 413,12 |
return (unative_t) call; |
} |
/** Synchronous IPC call allowing to send whole message |
/** Make an asynchronous IPC call allowing to transmit the entire payload. |
* |
* @return The same as sys_ipc_call_async |
* @param phoneid Phone handle for the call. |
* @param data Userspace address of call data with the request. |
* |
* @return See sys_ipc_call_async_fast(). |
*/ |
unative_t sys_ipc_call_async(unative_t phoneid, ipc_data_t *data) |
{ |
386,12 → 447,22 |
return (unative_t) call; |
} |
/** Forward received call to another destination |
/** Forward a received call to another destination. |
* |
* The arg1 and arg2 are changed in the forwarded message |
* @param callid Hash of the call to forward. |
* @param phoneid Phone handle to use for forwarding. |
* @param method New method to use for the forwarded call. |
* @param arg1 New value of the first argument for the forwarded call. |
* |
* @return Return 0 on succes, otherwise return an error code. |
* |
* In case the original method is a system method, ARG1 and ARG2 are overwritten |
* in the forwarded message with the new method and the new arg1, respectively. |
* Otherwise the METHOD and ARG1 are rewritten with the new method and arg1, |
* respectively. |
* |
* Warning: If implementing non-fast version, make sure that |
* arg3 is not rewritten for certain system IPC |
* ARG3 is not rewritten for certain system IPC |
*/ |
unative_t sys_ipc_forward_fast(unative_t callid, unative_t phoneid, |
unative_t method, unative_t arg1) |
434,7 → 505,18 |
return ipc_forward(call, phone, &TASK->answerbox); |
} |
/** Send IPC answer */ |
/** Answer an IPC call - fast version. |
* |
* This function can handle only two return arguments of payload, but is faster |
* than the generic sys_ipc_answer(). |
* |
* @param callid Hash of the call to be answered. |
* @param retval Return value of the answer. |
* @param arg1 Service-defined return value. |
* @param arg2 Service-defined return value. |
* |
* @return Return 0 on success, otherwise return an error code. |
*/ |
unative_t sys_ipc_answer_fast(unative_t callid, unative_t retval, |
unative_t arg1, unative_t arg2) |
{ |
465,7 → 547,13 |
return rc; |
} |
/** Send IPC answer */ |
/** Answer an IPC call. |
* |
* @param callid Hash of the call to be answered. |
* @param data Userspace address of call data with the answer. |
* |
* @return Return 0 on success, otherwise return an error code. |
*/ |
unative_t sys_ipc_answer(unative_t callid, ipc_data_t *data) |
{ |
call_t *call; |
497,8 → 585,11 |
return rc; |
} |
/** Hang up the phone |
/** Hang up a phone. |
* |
* @param Phone handle of the phone to be hung up. |
* |
* @return Return 0 on success or an error code. |
*/ |
unative_t sys_ipc_hangup(int phoneid) |
{ |
512,7 → 603,7 |
return 0; |
} |
/** Wait for incoming ipc call or answer |
/** Wait for an incoming IPC call or an answer. |
* |
* @param calldata Pointer to buffer where the call/answer data is stored. |
* @param usec Timeout. See waitq_sleep_timeout() for explanation. |
519,7 → 610,10 |
* @param flags Select mode of sleep operation. See waitq_sleep_timeout() |
* for explanation. |
* |
* @return Callid, if callid & 1, then the call is answer |
* @return Hash of the call. |
* If IPC_CALLID_NOTIFICATION bit is set in the hash, the |
* call is a notification. IPC_CALLID_ANSWERED denotes an |
* answer. |
*/ |
unative_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec, int flags) |
{ |
573,7 → 667,7 |
return (unative_t)call; |
} |
/** Connect irq handler to task. |
/** Connect an IRQ handler to a task. |
* |
* @param inr IRQ number. |
* @param devno Device number. |
591,10 → 685,12 |
return ipc_irq_register(&TASK->answerbox, inr, devno, method, ucode); |
} |
/** Disconnect irq handler from task. |
/** Disconnect an IRQ handler from a task. |
* |
* @param inr IRQ number. |
* @param devno Device number. |
* |
* @return Zero on success or EPERM on error.. |
*/ |
unative_t sys_ipc_unregister_irq(inr_t inr, devno_t devno) |
{ |
/trunk/kernel/generic/src/ipc/ipc.c |
---|
34,7 → 34,7 |
/* Lock ordering |
* |
* First the answerbox, then the phone |
* First the answerbox, then the phone. |
*/ |
#include <synch/spinlock.h> |
53,12 → 53,15 |
#include <arch/interrupt.h> |
#include <ipc/irq.h> |
/* Open channel that is assigned automatically to new tasks */ |
/** Open channel that is assigned automatically to new tasks */ |
answerbox_t *ipc_phone_0 = NULL; |
static slab_cache_t *ipc_call_slab; |
/* Initialize new call */ |
/** Initialize a call structure. |
* |
* @param call Call structure to be initialized. |
*/ |
static void _ipc_call_init(call_t *call) |
{ |
memsetb((uintptr_t)call, sizeof(*call), 0); |
66,12 → 69,15 |
call->sender = TASK; |
} |
/** Allocate & initialize call structure |
/** Allocate and initialize a call structure. |
* |
* The call is initialized, so that the reply will be directed |
* to TASK->answerbox |
* The call is initialized, so that the reply will be directed to |
* TASK->answerbox. |
* |
* @param flags Parameters for slab_alloc (ATOMIC, etc.) |
* @param flags Parameters for slab_alloc (e.g FRAME_ATOMIC). |
* |
* @return If flags permit it, return NULL, or initialized kernel |
* call structure. |
*/ |
call_t * ipc_call_alloc(int flags) |
{ |
83,7 → 89,11 |
return call; |
} |
/** Initialize allocated call */ |
/** Initialize a statically allocated call structure. |
* |
* @param call Statically allocated kernel call structure to be |
* initialized. |
*/ |
void ipc_call_static_init(call_t *call) |
{ |
_ipc_call_init(call); |
90,13 → 100,19 |
call->flags |= IPC_CALL_STATIC_ALLOC; |
} |
/** Deallocate call stracuture */ |
/** Deallocate a call stracuture. |
* |
* @param call Call structure to be freed. |
*/ |
void ipc_call_free(call_t *call) |
{ |
ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC)); |
slab_free(ipc_call_slab, call); |
} |
/** Initialize answerbox structure |
/** Initialize an answerbox structure. |
* |
* @param box Answerbox structure to be initialized. |
*/ |
void ipc_answerbox_init(answerbox_t *box) |
{ |
112,7 → 128,11 |
box->task = TASK; |
} |
/** Connect phone to answerbox */ |
/** Connect a phone to an answerbox. |
* |
* @param phone Initialized phone structure. |
* @param box Initialized answerbox structure. |
*/ |
void ipc_phone_connect(phone_t *phone, answerbox_t *box) |
{ |
spinlock_lock(&phone->lock); |
127,7 → 147,9 |
spinlock_unlock(&phone->lock); |
} |
/** Initialize phone structure and connect phone to answerbox |
/** Initialize a phone structure. |
* |
* @param phone Phone structure to be initialized. |
*/ |
void ipc_phone_init(phone_t *phone) |
{ |
137,7 → 159,11 |
atomic_set(&phone->active_calls, 0); |
} |
/** Helper function to facilitate synchronous calls */ |
/** Helper function to facilitate synchronous calls. |
* |
* @param phone Destination kernel phone structure. |
* @param request Call structure with request. |
*/ |
void ipc_call_sync(phone_t *phone, call_t *request) |
{ |
answerbox_t sync_box; |
144,7 → 170,7 |
ipc_answerbox_init(&sync_box); |
/* We will receive data on special box */ |
/* We will receive data in a special box. */ |
request->callerbox = &sync_box; |
ipc_call(phone, request); |
151,8 → 177,9 |
ipc_wait_for_call(&sync_box, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE); |
} |
/** Answer message that was not dispatched and is not entered in |
* any queue |
/** Answer a message which was not dispatched and is not listed in any queue. |
* |
* @param call Call structure to be answered. |
*/ |
static void _ipc_answer_free_call(call_t *call) |
{ |
166,10 → 193,10 |
waitq_wakeup(&callerbox->wq, WAKEUP_FIRST); |
} |
/** Answer message, that is in callee queue |
/** Answer a message which is in a callee queue. |
* |
* @param box Answerbox that is answering the message |
* @param call Modified request that is being sent back |
* @param box Answerbox that is answering the message. |
* @param call Modified request that is being sent back. |
*/ |
void ipc_answer(answerbox_t *box, call_t *call) |
{ |
181,10 → 208,14 |
_ipc_answer_free_call(call); |
} |
/** Simulate sending back a message |
/** Simulate sending back a message. |
* |
* Most errors are better handled by forming a normal backward |
* message and sending it as a normal answer. |
* |
* @param phone Phone structure the call should appear to come from. |
* @param call Call structure to be answered. |
* @param err Return value to be used for the answer. |
*/ |
void ipc_backsend_err(phone_t *phone, call_t *call, unative_t err) |
{ |
194,7 → 225,11 |
_ipc_answer_free_call(call); |
} |
/* Unsafe unchecking ipc_call */ |
/** Unsafe unchecking version of ipc_call. |
* |
* @param phone Phone structure the call comes from. |
* @param box Destination answerbox structure. |
*/ |
static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call) |
{ |
if (! (call->flags & IPC_CALL_FORWARDED)) { |
208,10 → 243,13 |
waitq_wakeup(&box->wq, WAKEUP_FIRST); |
} |
/** Send a asynchronous request using phone to answerbox |
/** Send an asynchronous request using a phone to an answerbox. |
* |
* @param phone Phone connected to answerbox. |
* @param call Structure representing the call. |
* @param phone Phone structure the call comes from and which is |
* connected to the destination answerbox. |
* @param call Call structure with request. |
* |
* @return Return 0 on success, ENOENT on error. |
*/ |
int ipc_call(phone_t *phone, call_t *call) |
{ |
238,14 → 276,15 |
return 0; |
} |
/** Disconnect phone from answerbox |
/** Disconnect phone from answerbox. |
* |
* This call leaves the phone in HUNGUP state. The change to 'free' is done |
* This call leaves the phone in the HUNGUP state. The change to 'free' is done |
* lazily later. |
* |
* @param phone Phone to be hung up |
* @param phone Phone structure to be hung up. |
* |
* @return 0 - phone disconnected, -1 - the phone was already disconnected |
* @return Return 0 if the phone is disconnected. |
* Return -1 if the phone was already disconnected. |
*/ |
int ipc_phone_hangup(phone_t *phone) |
{ |
253,8 → 292,8 |
call_t *call; |
spinlock_lock(&phone->lock); |
if (phone->state == IPC_PHONE_FREE || phone->state ==IPC_PHONE_HUNGUP \ |
|| phone->state == IPC_PHONE_CONNECTING) { |
if (phone->state == IPC_PHONE_FREE || phone->state == IPC_PHONE_HUNGUP || |
phone->state == IPC_PHONE_CONNECTING) { |
spinlock_unlock(&phone->lock); |
return -1; |
} |
279,15 → 318,17 |
return 0; |
} |
/** Forwards call from one answerbox to a new one |
/** Forwards call from one answerbox to another one. |
* |
* @param call Call to be redirected. |
* @param newphone Phone to target answerbox. |
* @param oldbox Old answerbox |
* @return 0 on forward ok, error code, if there was error |
* @param call Call structure to be redirected. |
* @param newphone Phone structure to target answerbox. |
* @param oldbox Old answerbox structure. |
* |
* - the return value serves only as an information for the forwarder, |
* the original caller is notified automatically with EFORWARD |
* @return Return 0 if forwarding succeeded or an error code if |
* there was error. |
* |
* The return value serves only as an information for the forwarder, |
* the original caller is notified automatically with EFORWARD. |
*/ |
int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox) |
{ |
299,15 → 340,18 |
} |
/** Wait for phone call |
/** Wait for a phone call. |
* |
* @param box Answerbox expecting the call. |
* @param usec Timeout in microseconds. See documentation for waitq_sleep_timeout() for |
* decription of its special meaning. |
* @param flags Select mode of sleep operation. See documentation for waitq_sleep_timeout()i |
* for description of its special meaning. |
* @return Recived message address |
* - to distinguish between call and answer, look at call->flags |
* @param usec Timeout in microseconds. See documentation for |
* waitq_sleep_timeout() for decription of its special |
* meaning. |
* @param flags Select mode of sleep operation. See documentation for |
* waitq_sleep_timeout() for description of its special |
* meaning. |
* @return Recived call structure or NULL. |
* |
* To distinguish between a call and an answer, have a look at call->flags. |
*/ |
call_t * ipc_wait_for_call(answerbox_t *box, uint32_t usec, int flags) |
{ |
350,7 → 394,10 |
return request; |
} |
/** Answer all calls from list with EHANGUP msg */ |
/** Answer all calls from list with EHANGUP answer. |
* |
* @param lst Head of the list to be cleaned up. |
*/ |
static void ipc_cleanup_call_list(link_t *lst) |
{ |
call_t *call; |
364,10 → 411,10 |
} |
} |
/** Cleans up all IPC communication of the current task |
/** Cleans up all IPC communication of the current task. |
* |
* Note: ipc_hangup sets returning answerbox to TASK->answerbox, you |
* have to change it as well if you want to cleanup other current then current. |
* have to change it as well if you want to cleanup other tasks than TASK. |
*/ |
void ipc_cleanup(void) |
{ |
414,7 → 461,7 |
/* Locking not needed, no one else should modify |
* it, when we are in cleanup */ |
for (i=0;i < IPC_MAX_PHONES; i++) { |
if (TASK->phones[i].state == IPC_PHONE_HUNGUP && \ |
if (TASK->phones[i].state == IPC_PHONE_HUNGUP && |
atomic_get(&TASK->phones[i].active_calls) == 0) |
TASK->phones[i].state = IPC_PHONE_FREE; |
433,8 → 480,10 |
if (i == IPC_MAX_PHONES) |
break; |
call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE); |
ASSERT((call->flags & IPC_CALL_ANSWERED) || (call->flags & IPC_CALL_NOTIF)); |
call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT, |
SYNCH_FLAGS_NONE); |
ASSERT((call->flags & IPC_CALL_ANSWERED) || |
(call->flags & IPC_CALL_NOTIF)); |
ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC)); |
atomic_dec(&TASK->active_calls); |
446,11 → 495,15 |
/** Initilize IPC subsystem */ |
void ipc_init(void) |
{ |
ipc_call_slab = slab_cache_create("ipc_call", sizeof(call_t), 0, NULL, NULL, 0); |
ipc_call_slab = slab_cache_create("ipc_call", sizeof(call_t), 0, NULL, |
NULL, 0); |
} |
/** Kconsole - list answerbox contents */ |
/** List answerbox contents. |
* |
* @param taskid Task ID. |
*/ |
void ipc_print_task(task_id_t taskid) |
{ |
task_t *task; |
/trunk/kernel/generic/src/ipc/irq.c |
---|
124,6 → 124,10 |
} |
} |
/** Free top-half pseudocode. |
* |
* @param code Pointer to the top-half pseudocode. |
*/ |
static void code_free(irq_code_t *code) |
{ |
if (code) { |
132,6 → 136,12 |
} |
} |
/** Copy top-half pseudocode from userspace into the kernel. |
* |
* @param ucode Userspace address of the top-half pseudocode. |
* |
* @return Kernel address of the copied pseudocode. |
*/ |
static irq_code_t * code_from_uspace(irq_code_t *ucode) |
{ |
irq_code_t *code; |
150,8 → 160,9 |
return NULL; |
} |
ucmds = code->cmds; |
code->cmds = malloc(sizeof(code->cmds[0]) * (code->cmdcount), 0); |
rc = copy_from_uspace(code->cmds, ucmds, sizeof(code->cmds[0]) * (code->cmdcount)); |
code->cmds = malloc(sizeof(code->cmds[0]) * code->cmdcount, 0); |
rc = copy_from_uspace(code->cmds, ucmds, |
sizeof(code->cmds[0]) * code->cmdcount); |
if (rc != 0) { |
free(code->cmds); |
free(code); |
164,7 → 175,7 |
/** Unregister task from IRQ notification. |
* |
* @param box Answerbox associated with the notification. |
* @param inr IRQ numbe. |
* @param inr IRQ number. |
* @param devno Device number. |
*/ |
void ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno) |
203,7 → 214,8 |
* |
* @return EBADMEM, ENOENT or EEXISTS on failure or 0 on success. |
*/ |
int ipc_irq_register(answerbox_t *box, inr_t inr, devno_t devno, unative_t method, irq_code_t *ucode) |
int ipc_irq_register(answerbox_t *box, inr_t inr, devno_t devno, |
unative_t method, irq_code_t *ucode) |
{ |
ipl_t ipl; |
irq_code_t *code; |
213,8 → 225,9 |
code = code_from_uspace(ucode); |
if (!code) |
return EBADMEM; |
} else |
} else { |
code = NULL; |
} |
ipl = interrupts_disable(); |
irq = irq_find_and_lock(inr, devno); |
247,10 → 260,12 |
return 0; |
} |
/** Add call to proper answerbox queue. |
/** Add a call to the proper answerbox queue. |
* |
* Assume irq->lock is locked. |
* |
* @param irq IRQ structure referencing the target answerbox. |
* @param call IRQ notification call. |
*/ |
static void send_call(irq_t *irq, call_t *call) |
{ |
261,8 → 276,12 |
waitq_wakeup(&irq->notif_cfg.answerbox->wq, WAKEUP_FIRST); |
} |
/** Send notification message |
/** Send notification message. |
* |
* @param irq IRQ structure. |
* @param a1 Driver-specific payload argument. |
* @param a2 Driver-specific payload argument. |
* @param a3 Driver-specific payload argument. |
*/ |
void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2, unative_t a3) |
{ |
289,9 → 308,11 |
spinlock_unlock(&irq->lock); |
} |
/** Notify task that an irq had occurred. |
/** Notify a task that an IRQ had occurred. |
* |
* We expect interrupts to be disabled and the irq->lock already held. |
* |
* @param irq IRQ structure. |
*/ |
void ipc_irq_send_notif(irq_t *irq) |
{ |