Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2470 → Rev 2471

/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.
*/