Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2470 → Rev 2471

/trunk/kernel/generic/include/ipc/ipc.h
37,13 → 37,13
 
/* Length of data being transfered with IPC call */
/* - the uspace may not be able to utilize full length */
#define IPC_CALL_LEN 4
#define IPC_CALL_LEN 4
 
/** Maximum active async calls per thread */
#ifdef CONFIG_DEBUG
# define IPC_MAX_ASYNC_CALLS 4
#define IPC_MAX_ASYNC_CALLS 4
#else
# define IPC_MAX_ASYNC_CALLS 4000
#define IPC_MAX_ASYNC_CALLS 4000
#endif
 
/* Flags for calls */
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
 
111,7 → 113,7
* (on the receiving sid) as ARG3 of the call.
* - the caller obtains taskid of the called thread
*/
#define IPC_M_CONNECT_TO_ME 1
#define IPC_M_CONNECT_TO_ME 1
/** Protocol for CONNECT - ME - TO
*
* Calling process asks the callee to create for him a new connection.
130,11 → 132,11
* system message
*
*/
#define IPC_M_CONNECT_ME_TO 2
#define IPC_M_CONNECT_ME_TO 2
/** This message is sent to answerbox when the phone
* is hung up
*/
#define IPC_M_PHONE_HUNGUP 3
#define IPC_M_PHONE_HUNGUP 3
 
/** Send as_area over IPC
* - ARG1 - src as_area base address
144,7 → 146,7
* on answer:
* - ARG1 - dst as_area base adress
*/
#define IPC_M_AS_AREA_SEND 5
#define IPC_M_AS_AREA_SEND 5
 
/** Get as_area over IPC
* - ARG1 - dst as_area base address
156,14 → 158,14
* - ARG1 - src as_area base address
* - ARG2 - flags that will be used for sharing
*/
#define IPC_M_AS_AREA_RECV 6
#define IPC_M_AS_AREA_RECV 6
 
 
/* Well-known methods */
#define IPC_M_LAST_SYSTEM 511
#define IPC_M_PING 512
#define IPC_M_LAST_SYSTEM 511
#define IPC_M_PING 512
/* User methods */
#define FIRST_USER_METHOD 1024
#define FIRST_USER_METHOD 1024
 
#ifdef KERNEL
 
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
36,7 → 36,7
#define KERN_IPC_IRQ_H_
 
/** Maximum length of IPC IRQ program */
#define IRQ_MAX_PROG_SIZE 10
#define IRQ_MAX_PROG_SIZE 10
 
#include <ipc/ipc.h>
#include <ddi/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,12 → 132,17
#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)
call_t *get_call(unative_t callid)
{
link_t *lst;
call_t *call, *result = NULL;
144,9 → 149,9
 
spinlock_lock(&TASK->answerbox.lock);
for (lst = TASK->answerbox.dispatched_calls.next;
lst != &TASK->answerbox.dispatched_calls; lst = lst->next) {
lst != &TASK->answerbox.dispatched_calls; lst = lst->next) {
call = list_get_instance(lst, call_t, link);
if ((unative_t)call == callid) {
if ((unative_t) call == callid) {
result = call;
break;
}
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;
162,8 → 171,8
 
spinlock_lock(&TASK->lock);
for (i=0; i < IPC_MAX_PHONES; i++) {
if (TASK->phones[i].state == IPC_PHONE_HUNGUP && \
for (i = 0; i < IPC_MAX_PHONES; i++) {
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; } \
phone = &TASK->phones[phoneid]; \
#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)))
#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)
{
245,7 → 276,7
phoneid = phone_alloc();
if (phoneid < 0) { /* Failed to allocate phone */
IPC_SET_RETVAL(call->data, ELIMIT);
ipc_answer(box,call);
ipc_answer(box, call);
return -1;
}
IPC_SET_ARG3(call->data, phoneid);
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)
271,17 → 311,25
IPC_SET_METHOD(call.data, method);
IPC_SET_ARG1(call.data, arg1);
 
if (!(res=request_preprocess(&call))) {
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)
{
298,7 → 346,7
 
GET_CHECK_PHONE(phone, phoneid, return ENOENT);
 
if (!(res=request_preprocess(&call))) {
if (!(res = request_preprocess(&call))) {
ipc_call_sync(phone, &call);
process_answer(&call);
} else
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)
{
541,7 → 635,7
 
ipc_call_free(call);
return ((unative_t)call) | IPC_CALLID_NOTIFICATION;
return ((unative_t) call) | IPC_CALLID_NOTIFICATION;
}
 
if (call->flags & IPC_CALL_ANSWERED) {
559,7 → 653,7
STRUCT_TO_USPACE(&calldata->args, &call->data.args);
ipc_call_free(call);
 
return ((unative_t)call) | IPC_CALLID_ANSWERED;
return ((unative_t) call) | IPC_CALLID_ANSWERED;
}
 
if (process_request(&TASK->answerbox, call))
573,14 → 667,14
return (unative_t)call;
}
 
/** Connect irq handler to task.
/** Connect an IRQ handler to a task.
*
* @param inr IRQ number.
* @param devno Device number.
* @param method Method to be associated with the notification.
* @param ucode Uspace pointer to the top-half pseudocode.
* @param inr IRQ number.
* @param devno Device number.
* @param method Method to be associated with the notification.
* @param ucode Uspace pointer to the top-half pseudocode.
*
* @return EPERM or a return code returned by ipc_irq_register().
* @return EPERM or a return code returned by ipc_irq_register().
*/
unative_t sys_ipc_register_irq(inr_t inr, devno_t devno, unative_t method,
irq_code_t *ucode)
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.
* @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,27 → 53,33
#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);
memsetb((uintptr_t) call, sizeof(*call), 0);
call->callerbox = &TASK->answerbox;
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)
call_t *ipc_call_alloc(int flags)
{
call_t *call;
 
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,10 → 225,14
_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)) {
if (!(call->flags & IPC_CALL_FORWARDED)) {
atomic_inc(&phone->active_calls);
call->data.phone = phone;
}
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.
*
* @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
* 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,17 → 340,20
}
 
 
/** 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 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() 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)
call_t *ipc_wait_for_call(answerbox_t *box, uint32_t usec, int flags)
{
call_t *request;
ipl_t ipl;
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)
{
377,7 → 424,7
DEADLOCK_PROBE_INIT(p_phonelck);
 
/* Disconnect all our phones ('ipc_phone_hangup') */
for (i=0;i < IPC_MAX_PHONES; i++)
for (i = 0; i < IPC_MAX_PHONES; i++)
ipc_phone_hangup(&TASK->phones[i]);
 
/* Disconnect all connected irqs */
413,8 → 460,8
/* Go through all phones, until all are FREE... */
/* 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 && \
for (i = 0; i < IPC_MAX_PHONES; i++) {
if (TASK->phones[i].state == IPC_PHONE_HUNGUP &&
atomic_get(&TASK->phones[i].active_calls) == 0)
TASK->phones[i].state = IPC_PHONE_FREE;
433,9 → 480,11
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));
ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
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);
ipc_call_free(call);
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;
468,10 → 521,10
 
/* Print opened phones & details */
printf("PHONE:\n");
for (i=0; i < IPC_MAX_PHONES;i++) {
for (i = 0; i < IPC_MAX_PHONES; i++) {
spinlock_lock(&task->phones[i].lock);
if (task->phones[i].state != IPC_PHONE_FREE) {
printf("%d: ",i);
printf("%d: ", i);
switch (task->phones[i].state) {
case IPC_PHONE_CONNECTING:
printf("connecting ");
/trunk/kernel/generic/src/ipc/irq.c
60,8 → 60,8
 
/** Execute code associated with IRQ notification.
*
* @param call Notification call.
* @param code Top-half pseudocode.
* @param call Notification call.
* @param code Top-half pseudocode.
*/
static void code_execute(call_t *call, irq_code_t *code)
{
71,38 → 71,38
if (!code)
return;
for (i=0; i < code->cmdcount;i++) {
for (i = 0; i < code->cmdcount; i++) {
switch (code->cmds[i].cmd) {
case CMD_MEM_READ_1:
dstval = *((uint8_t *)code->cmds[i].addr);
dstval = *((uint8_t *) code->cmds[i].addr);
break;
case CMD_MEM_READ_2:
dstval = *((uint16_t *)code->cmds[i].addr);
dstval = *((uint16_t *) code->cmds[i].addr);
break;
case CMD_MEM_READ_4:
dstval = *((uint32_t *)code->cmds[i].addr);
dstval = *((uint32_t *) code->cmds[i].addr);
break;
case CMD_MEM_READ_8:
dstval = *((uint64_t *)code->cmds[i].addr);
dstval = *((uint64_t *) code->cmds[i].addr);
break;
case CMD_MEM_WRITE_1:
*((uint8_t *)code->cmds[i].addr) = code->cmds[i].value;
*((uint8_t *) code->cmds[i].addr) = code->cmds[i].value;
break;
case CMD_MEM_WRITE_2:
*((uint16_t *)code->cmds[i].addr) = code->cmds[i].value;
*((uint16_t *) code->cmds[i].addr) = code->cmds[i].value;
break;
case CMD_MEM_WRITE_4:
*((uint32_t *)code->cmds[i].addr) = code->cmds[i].value;
*((uint32_t *) code->cmds[i].addr) = code->cmds[i].value;
break;
case CMD_MEM_WRITE_8:
*((uint64_t *)code->cmds[i].addr) = code->cmds[i].value;
*((uint64_t *) code->cmds[i].addr) = code->cmds[i].value;
break;
#if defined(ia32) || defined(amd64)
case CMD_PORT_READ_1:
dstval = inb((long)code->cmds[i].addr);
dstval = inb((long) code->cmds[i].addr);
break;
case CMD_PORT_WRITE_1:
outb((long)code->cmds[i].addr, code->cmds[i].value);
outb((long) code->cmds[i].addr, code->cmds[i].value);
break;
#endif
#if defined(ia64) && defined(SKI)
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,7 → 136,13
}
}
 
static irq_code_t * code_from_uspace(irq_code_t *ucode)
/** 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;
irq_cmd_t *ucmds;
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);
163,9 → 174,9
 
/** Unregister task from IRQ notification.
*
* @param box Answerbox associated with the notification.
* @param inr IRQ numbe.
* @param devno Device number.
* @param box Answerbox associated with the notification.
* @param inr IRQ number.
* @param devno Device number.
*/
void ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno)
{
195,15 → 206,16
 
/** Register an answerbox as a receiving end for IRQ notifications.
*
* @param box Receiving answerbox.
* @param inr IRQ number.
* @param devno Device number.
* @param method Method to be associated with the notification.
* @param ucode Uspace pointer to top-half pseudocode.
* @param box Receiving answerbox.
* @param inr IRQ number.
* @param devno Device number.
* @param method Method to be associated with the notification.
* @param ucode Uspace pointer to top-half pseudocode.
*
* @return EBADMEM, ENOENT or EEXISTS on failure or 0 on success.
* @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)
{
323,7 → 344,7
* list of all irq_t structures that are registered to
* send notifications to it.
*
* @param box Answerbox for which we want to carry out the cleanup.
* @param box Answerbox for which we want to carry out the cleanup.
*/
void ipc_irq_cleanup(answerbox_t *box)
{
/trunk/uspace/ns/ns.c
155,7 → 155,7
/** Register service.
*
* @param service Service to be registered.
* @param phone phone Phone to be used for connections to the service.
* @param phone Phone to be used for connections to the service.
* @param call Pointer to call structure.
*
* @return Zero on success or a value from @ref errno.h.
/trunk/uspace/rd/rd.c
66,22 → 66,22
while (1) {
callid = async_get_call(&call);
switch (IPC_GET_METHOD(call)) {
case IPC_M_PHONE_HUNGUP:
ipc_answer_fast(callid, 0,0,0);
return;
case IPC_M_AS_AREA_SEND:
ipc_answer_fast(callid, 0, (uintptr_t)fs_addr, 0);
continue;
case RD_READ_BLOCK:
offset = IPC_GET_ARG1(call);
memcpy((void *)fs_addr, rd_addr+offset, BLOCK_SIZE);
retval = EOK;
break;
default:
retval = EINVAL;
case IPC_M_PHONE_HUNGUP:
ipc_answer_fast(callid, 0, 0, 0);
return;
case IPC_M_AS_AREA_SEND:
ipc_answer_fast(callid, 0, (uintptr_t) fs_addr, 0);
continue;
case RD_READ_BLOCK:
offset = IPC_GET_ARG1(call);
memcpy((void *) fs_addr, rd_addr + offset, BLOCK_SIZE);
retval = EOK;
break;
default:
retval = EINVAL;
}
ipc_answer_fast(callid, retval, 0, 0);
}
}
}
 
 
90,7 → 90,7
int retval, flags;
 
size_t rd_size = sysinfo_value("rd.size");
void * rd_ph_addr = (void *) sysinfo_value("rd.address.physical");
void *rd_ph_addr = (void *) sysinfo_value("rd.address.physical");
if (rd_size == 0)
return false;
98,7 → 98,8
rd_addr = as_get_mappable_page(rd_size);
flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE;
retval = physmem_map(rd_ph_addr, rd_addr, ALIGN_UP(rd_size, PAGE_SIZE) >> PAGE_WIDTH, flags);
retval = physmem_map(rd_ph_addr, rd_addr,
ALIGN_UP(rd_size, PAGE_SIZE) >> PAGE_WIDTH, flags);
 
if (retval < 0)
return false;
/trunk/uspace/libc/include/ipc/ipc.h
49,17 → 49,18
typedef sysarg_t ipc_callid_t;
 
typedef void (* ipc_async_callback_t)(void *private, int retval,
ipc_call_t *data);
ipc_call_t *data);
 
#define ipc_call_sync_2(phoneid, method, arg1, arg2, res1, res2) ipc_call_sync_3((phoneid), (method), (arg1), (arg2), 0, (res1), (res2), 0)
#define ipc_call_sync_2(phoneid, method, arg1, arg2, res1, res2) \
ipc_call_sync_3((phoneid), (method), (arg1), (arg2), 0, (res1), (res2), \
0)
extern int ipc_call_sync_3(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t arg2, ipcarg_t arg3,
ipcarg_t *result1, ipcarg_t *result2,
ipcarg_t *result3);
ipcarg_t arg2, ipcarg_t arg3, ipcarg_t *result1, ipcarg_t *result2,
ipcarg_t *result3);
 
extern int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t *result);
 
extern int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t *result);
extern ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags);
extern ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *data, uint32_t usec);
static inline ipc_callid_t ipc_wait_for_call(ipc_call_t *data)
68,17 → 69,19
}
extern ipc_callid_t ipc_trywait_for_call(ipc_call_t *data);
 
extern ipcarg_t ipc_answer_fast(ipc_callid_t callid, ipcarg_t retval, ipcarg_t arg1,
ipcarg_t arg2);
extern ipcarg_t ipc_answer_fast(ipc_callid_t callid, ipcarg_t retval,
ipcarg_t arg1, ipcarg_t arg2);
extern ipcarg_t ipc_answer(ipc_callid_t callid, ipc_call_t *call);
 
#define ipc_call_async(phoneid,method,arg1,private, callback,can_preempt) (ipc_call_async_2(phoneid, method, arg1, 0, private, callback, can_preempt))
#define ipc_call_async(phoneid, method, arg1, private, callback, can_preempt) \
(ipc_call_async_2(phoneid, method, arg1, 0, private, callback, \
can_preempt))
extern void ipc_call_async_2(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t arg2, void *private,
ipc_async_callback_t callback, int can_preempt);
ipcarg_t arg2, void *private, ipc_async_callback_t callback,
int can_preempt);
extern void ipc_call_async_3(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t arg2, ipcarg_t arg3, void *private,
ipc_async_callback_t callback, int can_preempt);
ipcarg_t arg2, ipcarg_t arg3, void *private, ipc_async_callback_t callback,
int can_preempt);
 
extern int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phone);
extern int ipc_connect_me_to(int phoneid, int arg1, int arg2);
85,7 → 88,8
extern int ipc_hangup(int phoneid);
extern int ipc_register_irq(int inr, int devno, int method, irq_code_t *code);
extern int ipc_unregister_irq(int inr, int devno);
extern int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method, ipcarg_t arg1);
extern int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method,
ipcarg_t arg1);
 
#endif
 
/trunk/uspace/libc/generic/ipc.c
51,9 → 51,8
#include <async.h>
#include <psthread.h>
 
/** Structure used for keeping track of sent async msgs
* and queing unsent msgs
*
/** Structure used for keeping track of sent asynchronous calls and queing
* unsent calls.
*/
typedef struct {
link_t list;
66,29 → 65,41
ipc_call_t data;
int phoneid;
} msg;
}u;
pstid_t ptid; /**< Thread waiting for sending this msg */
} u;
pstid_t ptid; /**< Pseudothread waiting for sending this call. */
} async_call_t;
 
LIST_INITIALIZE(dispatched_calls);
 
/* queued_calls is protcted by async_futex, because if the
* call cannot be sent into kernel, async framework is used
* automatically
/** List of asynchronous calls that were not accepted by kernel.
*
* It is protected by async_futex, because if the call cannot be sent into the
* kernel, the async framework is used automatically.
*/
LIST_INITIALIZE(queued_calls); /**< List of async calls that were not accepted
* by kernel */
LIST_INITIALIZE(queued_calls);
 
static atomic_t ipc_futex = FUTEX_INITIALIZER;
 
int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t *result)
/** Make a fast synchronous call.
*
* Only one payload argument can be passed using this function. However, this
* function is faster than the generic ipc_call_sync_3().
*
* @param phoneid Phone handle for the call.
* @param method Requested method.
* @param arg1 Service-defined payload argument.
* @param result If non-NULL, the return ARG1 will be stored there.
*
* @return Negative values represent errors returned by IPC.
* Otherwise the RETVAL of the answer is returned.
*/
int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t *result)
{
ipc_call_t resdata;
int callres;
callres = __SYSCALL4(SYS_IPC_CALL_SYNC_FAST, phoneid, method, arg1,
(sysarg_t)&resdata);
(sysarg_t) &resdata);
if (callres)
return callres;
if (result)
96,9 → 107,22
return IPC_GET_RETVAL(resdata);
}
 
int ipc_call_sync_3(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t arg2, ipcarg_t arg3,
ipcarg_t *result1, ipcarg_t *result2, ipcarg_t *result3)
/** Make a synchronous call transmitting 3 arguments of payload.
*
* @param phoneid Phone handle for the call.
* @param method Requested method.
* @param arg1 Service-defined payload argument.
* @param arg2 Service-defined payload argument.
* @param arg3 Service-defined payload argument.
* @param result1 If non-NULL, storage for the first return argument.
* @param result2 If non-NULL, storage for the second return argument.
* @param result3 If non-NULL, storage for the third return argument.
*
* @return Negative value means IPC error.
* Otherwise the RETVAL of the answer.
*/
int ipc_call_sync_3(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
ipcarg_t arg3, ipcarg_t *result1, ipcarg_t *result2, ipcarg_t *result3)
{
ipc_call_t data;
int callres;
108,8 → 132,8
IPC_SET_ARG2(data, arg2);
IPC_SET_ARG3(data, arg3);
 
callres = __SYSCALL3(SYS_IPC_CALL_SYNC, phoneid, (sysarg_t)&data,
(sysarg_t)&data);
callres = __SYSCALL3(SYS_IPC_CALL_SYNC, phoneid, (sysarg_t) &data,
(sysarg_t) &data);
if (callres)
return callres;
 
122,14 → 146,27
return IPC_GET_RETVAL(data);
}
 
/** Syscall to send asynchronous message */
static ipc_callid_t _ipc_call_async(int phoneid, ipc_call_t *data)
/** Syscall to send asynchronous message.
*
* @param phoneid Phone handle for the call.
* @param data Call data with the request.
*
* @return Hash of the call or an error code.
*/
static ipc_callid_t _ipc_call_async(int phoneid, ipc_call_t *data)
{
return __SYSCALL2(SYS_IPC_CALL_ASYNC, phoneid, (sysarg_t)data);
return __SYSCALL2(SYS_IPC_CALL_ASYNC, phoneid, (sysarg_t) data);
}
 
/** Prolog to ipc_async_send functions */
static inline async_call_t *ipc_prepare_async(void *private, ipc_async_callback_t callback)
/** Prolog to ipc_call_async_*() functions.
*
* @param private Argument for the answer/error callback.
* @param callback Answer/error callback.
*
* @return New, partially initialized async_call structure or NULL.
*/
static inline async_call_t *ipc_prepare_async(void *private,
ipc_async_callback_t callback)
{
async_call_t *call;
 
145,9 → 182,16
return call;
}
 
/** Epilogue of ipc_async_send functions */
static inline void ipc_finish_async(ipc_callid_t callid, int phoneid,
async_call_t *call, int can_preempt)
/** Epilogue of ipc_call_async_*() functions.
*
* @param callid Value returned by the SYS_IPC_CALL_ASYNC_* syscall.
* @param phoneid Phone handle through which the call was made.
* @param call async_call structure returned by ipc_prepare_async().
* @param can_preempt If non-zero, the current pseudo thread can be preempted
* in this call.
*/
static inline void ipc_finish_async(ipc_callid_t callid, int phoneid,
async_call_t *call, int can_preempt)
{
if (!call) { /* Nothing to do regardless if failed or not */
futex_up(&ipc_futex);
182,20 → 226,35
return;
}
call->u.callid = callid;
/* Add call to list of dispatched calls */
/* Add call to the list of dispatched calls */
list_append(&call->list, &dispatched_calls);
futex_up(&ipc_futex);
}
 
/** Send asynchronous message
/** Make a fast asynchronous call.
*
* - if fatal error, call callback handler with proper error code
* - if message cannot be temporarily sent, add to queue
* This function can only handle two arguments of payload. It is, however,
* faster than the more generic ipc_call_async_3().
*
* Note that this function is a void function.
* During normal opertation, answering this call will trigger the callback.
* In case of fatal error, call the callback handler with the proper error code.
* If the call cannot be temporarily made, queue it.
*
* @param phoneid Phone handle for the call.
* @param method Requested method.
* @param arg1 Service-defined payload argument.
* @param arg2 Service-defined payload argument.
* @param private Argument to be passed to the answer/error callback.
* @param callback Answer or error callback.
* @param can_preempt If non-zero, the current pseudo thread will be preempted
* in case the kernel temporarily refuses to accept more
* asynchronous calls.
*/
void ipc_call_async_2(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t arg2, void *private,
ipc_async_callback_t callback, int can_preempt)
ipcarg_t arg2, void *private, ipc_async_callback_t callback,
int can_preempt)
{
async_call_t *call = NULL;
ipc_callid_t callid;
206,10 → 265,13
return;
}
 
/* We need to make sure that we get callid before
* another thread accesses the queue again */
/*
* We need to make sure that we get callid before another thread
* accesses the queue again.
*/
futex_down(&ipc_futex);
callid = __SYSCALL4(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1, arg2);
callid = __SYSCALL4(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1,
arg2);
 
if (callid == IPC_CALLRET_TEMPORARY) {
if (!call) {
224,14 → 286,28
ipc_finish_async(callid, phoneid, call, can_preempt);
}
 
/** Send asynchronous message
/** Make an asynchronous call transmitting the entire payload.
*
* - if fatal error, call callback handler with proper error code
* - if message cannot be temporarily sent, add to queue
* Note that this function is a void function.
* During normal opertation, answering this call will trigger the callback.
* In case of fatal error, call the callback handler with the proper error code.
* If the call cannot be temporarily made, queue it.
*
* @param phoneid Phone handle for the call.
* @param method Requested method.
* @param arg1 Service-defined payload argument.
* @param arg2 Service-defined payload argument.
* @param arg3 Service-defined payload argument.
* @param private Argument to be passed to the answer/error callback.
* @param callback Answer or error callback.
* @param can_preempt If non-zero, the current pseudo thread will be preempted
* in case the kernel temporarily refuses to accept more
* asynchronous calls.
*
*/
void ipc_call_async_3(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t arg2, ipcarg_t arg3, void *private,
ipc_async_callback_t callback, int can_preempt)
ipcarg_t arg2, ipcarg_t arg3, void *private, ipc_async_callback_t callback,
int can_preempt)
{
async_call_t *call;
ipc_callid_t callid;
244,8 → 320,10
IPC_SET_ARG1(call->u.msg.data, arg1);
IPC_SET_ARG2(call->u.msg.data, arg2);
IPC_SET_ARG3(call->u.msg.data, arg3);
/* We need to make sure that we get callid before
* another thread accesses the queue again */
/*
* We need to make sure that we get callid before another thread accesses
* the queue again.
*/
futex_down(&ipc_futex);
callid = _ipc_call_async(phoneid, &call->u.msg.data);
 
253,30 → 331,31
}
 
 
/** Send a fast answer to a received call.
/** Answer a received call - fast version.
*
* The fast answer makes use of passing retval and first two arguments in registers.
* If you need to return more, use the ipc_answer() instead.
* The fast answer makes use of passing retval and first two arguments in
* registers. If you need to return more, use the ipc_answer() instead.
*
* @param callid ID of the call being answered.
* @param retval Return value.
* @param arg1 First return argument.
* @param arg2 Second return argument.
* @param callid Hash of the call being answered.
* @param retval Return value.
* @param arg1 First return argument.
* @param arg2 Second return argument.
*
* @return Zero on success or a value from @ref errno.h on failure.
* @return Zero on success or a value from @ref errno.h on failure.
*/
ipcarg_t ipc_answer_fast(ipc_callid_t callid, ipcarg_t retval, ipcarg_t arg1,
ipcarg_t arg2)
ipcarg_t arg2)
{
return __SYSCALL4(SYS_IPC_ANSWER_FAST, callid, retval, arg1, arg2);
}
 
/** Send a full answer to a received call.
/** Answer a received call - full version.
*
* @param callid ID of the call being answered.
* @param call Call data. Must be already initialized by the responder.
* @param callid Hash of the call being answered.
* @param call Call structure with the answer.
* Must be already initialized by the responder.
*
* @return Zero on success or a value from @ref errno.h on failure.
* @return Zero on success or a value from @ref errno.h on failure.
*/
ipcarg_t ipc_answer(ipc_callid_t callid, ipc_call_t *call)
{
284,23 → 363,20
}
 
 
/** Try to dispatch queed calls from async queue */
/** Try to dispatch queued calls from the async queue. */
static void try_dispatch_queued_calls(void)
{
async_call_t *call;
ipc_callid_t callid;
 
/* TODO: integrate intelligently ipc_futex, so that it
* is locked during ipc_call_async, until it is added
* to dispatched_calls
/** @todo
* Integrate intelligently ipc_futex, so that it is locked during
* ipc_call_async_*(), until it is added to dispatched_calls.
*/
futex_down(&async_futex);
while (!list_empty(&queued_calls)) {
call = list_get_instance(queued_calls.next, async_call_t,
list);
 
callid = _ipc_call_async(call->u.msg.phoneid,
&call->u.msg.data);
call = list_get_instance(queued_calls.next, async_call_t, list);
callid = _ipc_call_async(call->u.msg.phoneid, &call->u.msg.data);
if (callid == IPC_CALLRET_TEMPORARY) {
break;
}
325,11 → 401,16
futex_up(&async_futex);
}
 
/** Handle received answer
/** Handle a received answer.
*
* TODO: Make it use hash table
* Find the hash of the answer and call the answer callback.
*
* @param callid Callid (with first bit set) of the answered call
* @todo Make it use hash table.
*
* @param callid Hash of the received answer.
* The answer has the same hash as the request OR'ed with
* the IPC_CALLID_ANSWERED bit.
* @param data Call data of the answer.
*/
static void handle_answer(ipc_callid_t callid, ipc_call_t *data)
{
340,7 → 421,7
futex_down(&ipc_futex);
for (item = dispatched_calls.next; item != &dispatched_calls;
item = item->next) {
item = item->next) {
call = list_get_instance(item, async_call_t, list);
if (call->u.callid == callid) {
list_remove(&call->list);
347,24 → 428,25
futex_up(&ipc_futex);
if (call->callback)
call->callback(call->private,
IPC_GET_RETVAL(*data),
data);
IPC_GET_RETVAL(*data), data);
free(call);
return;
}
}
futex_up(&ipc_futex);
/* We may get here after async_msg, which doesn't register any callback */
}
 
 
/** One cycle of ipc wait for call call
/** Wait for a first call to come.
*
* - dispatch ASYNC reoutines in the background
* @param call Space where the message is stored
* @param usec Timeout in microseconds
* @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking)
* @return Callid of the answer.
* @param call Storage where the incoming call data will be stored.
* @param usec Timeout in microseconds
* @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking).
*
* @return Hash of the call. Note that certain bits have special
* meaning. IPC_CALLID_ANSWERED will be set in an answer
* and IPC_CALLID_NOTIFICATION is used for notifications.
*
*/
ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags)
{
382,11 → 464,12
 
/** Wait some time for an IPC call.
*
* - dispatch ASYNC reoutines in the background
* The call will return after an answer is received.
*
* @param call Space where the message is stored
* @param usec Timeout in microseconds.
* @return Callid of the answer.
* @param call Storage where the incoming call data will be stored.
* @param usec Timeout in microseconds.
*
* @return Hash of the answer.
*/
ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *call, uint32_t usec)
{
401,10 → 484,8
 
/** Check if there is an IPC call waiting to be picked up.
*
* - dispatch ASYNC reoutines in the background
*
* @param call Space where the message is stored
* @return Callid of the answer.
* @param call Storage where the incoming call will be stored.
* @return Hash of the answer.
*/
ipc_callid_t ipc_trywait_for_call(ipc_call_t *call)
{
411,7 → 492,8
ipc_callid_t callid;
 
do {
callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NON_BLOCKING);
callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT,
SYNCH_FLAGS_NON_BLOCKING);
} while (callid & IPC_CALLID_ANSWERED);
 
return callid;
419,13 → 501,15
 
/** Ask destination to do a callback connection.
*
* @param phoneid Phone ID used for contacting the other side.
* @param arg1 User defined argument.
* @param arg2 User defined argument.
* @param phonehash Pointer to a place where the library will store an opaque
* @param phoneid Phone handle used for contacting the other side.
* @param arg1 Service-defined argument.
* @param arg2 Service-defined argument.
* @param phonehash Storage where the library will store an opaque
* identifier of the phone that will be used for incoming
* calls.
* @return Zero on success or a negative error code.
* calls. This identifier can be used for connection
* tracking.
*
* @return Zero on success or a negative error code.
*/
int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phonehash)
{
435,11 → 519,11
 
/** Ask through phone for a new connection to some service.
*
* @param phoneid Phone ID used for contacting the other side.
* @param phoneid Phone handle used for contacting the other side.
* @param arg1 User defined argument.
* @param arg2 User defined argument.
*
* @return New phone ID on success or a negative error code.
* @return New phone handle on success or a negative error code.
*/
int ipc_connect_me_to(int phoneid, int arg1, int arg2)
{
453,7 → 537,12
return newphid;
}
 
/* Hang up specified phone */
/** Hang up a phone.
*
* @param phoneid Handle of the phone to be hung up.
*
* @return Zero on success or a negative error code.
*/
int ipc_hangup(int phoneid)
{
return __SYSCALL1(SYS_IPC_HANGUP, phoneid);
461,24 → 550,25
 
/** Register IRQ notification.
*
* @param inr IRQ number.
* @param devno Device number of the device generating inr.
* @param method Use this method for notifying me.
* @param ucode Top-half pseudocode handler.
* @param inr IRQ number.
* @param devno Device number of the device generating inr.
* @param method Use this method for notifying me.
* @param ucode Top-half pseudocode handler.
*
* @return Value returned by the kernel.
* @return Value returned by the kernel.
*/
int ipc_register_irq(int inr, int devno, int method, irq_code_t *ucode)
{
return __SYSCALL4(SYS_IPC_REGISTER_IRQ, inr, devno, method, (sysarg_t) ucode);
return __SYSCALL4(SYS_IPC_REGISTER_IRQ, inr, devno, method,
(sysarg_t) ucode);
}
 
/** Unregister IRQ notification.
*
* @param inr IRQ number.
* @param devno Device number of the device generating inr.
* @param inr IRQ number.
* @param devno Device number of the device generating inr.
*
* @return Value returned by the kernel.
* @return Value returned by the kernel.
*/
int ipc_unregister_irq(int inr, int devno)
{
485,6 → 575,19
return __SYSCALL2(SYS_IPC_UNREGISTER_IRQ, inr, devno);
}
 
/** Forward a received call to another destination.
*
* @param callid Hash of the call to forward.
* @param phoneid Phone handle to use for forwarding.
* @param method New method for the forwarded call.
* @param arg1 New value of the first argument for the forwarded call.
*
* @return Zero on success or an error code.
*
* For non-system methods, the old method and arg1 are rewritten by the new
* values. For system methods, the new method and arg1 are written to the old
* arg1 and arg2, respectivelly.
*/
int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method, ipcarg_t arg1)
{
return __SYSCALL4(SYS_IPC_FORWARD_FAST, callid, phoneid, method, arg1);
/trunk/uspace/pci/pci.c
1,11 → 1,9
/*
* HelenOS PCI driver.
*
* Copyright (c) 1997-2003 Martin Mares
* (Based on public domain libpci example.c written by Martin Mares.)
* Copyright (c) 2006 Jakub Jermar
*
* (Based on libpci example.c written by Martin Mares.)
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/