/branches/dd/uspace/srv/fhc/Makefile |
---|
File deleted |
/branches/dd/uspace/srv/fhc/fhc.c |
---|
File deleted |
/branches/dd/uspace/srv/obio/Makefile |
---|
File deleted |
/branches/dd/uspace/srv/obio/obio.c |
---|
File deleted |
/branches/dd/uspace/srv/kbd/ctl/pc.c |
---|
32,12 → 32,12 |
*/ |
/** |
* @file |
* @brief PC keyboard controller driver. |
* @brief PC keyboard controller driver. |
*/ |
#include <kbd.h> |
#include <kbd/kbd.h> |
#include <kbd/keycode.h> |
#include <io/console.h> |
#include <io/keycode.h> |
#include <kbd_ctl.h> |
#include <gsp.h> |
188,7 → 188,7 |
void kbd_ctl_parse_scancode(int scancode) |
{ |
kbd_ev_type_t type; |
console_ev_type_t type; |
unsigned int key; |
int *map; |
size_t map_length; |
213,9 → 213,9 |
if (scancode & 0x80) { |
scancode &= ~0x80; |
type = KE_RELEASE; |
type = KEY_RELEASE; |
} else { |
type = KE_PRESS; |
type = KEY_PRESS; |
} |
if (scancode < 0 || scancode >= map_length) |
/branches/dd/uspace/srv/kbd/ctl/stty.c |
---|
36,8 → 36,7 |
*/ |
#include <kbd.h> |
#include <kbd/kbd.h> |
#include <kbd/keycode.h> |
#include <io/keycode.h> |
#include <kbd_ctl.h> |
#include <gsp.h> |
#include <stroke.h> |
/branches/dd/uspace/srv/kbd/ctl/sun.c |
---|
36,8 → 36,8 |
*/ |
#include <kbd.h> |
#include <kbd/kbd.h> |
#include <kbd/keycode.h> |
#include <io/console.h> |
#include <io/keycode.h> |
#include <kbd_ctl.h> |
#define KBD_KEY_RELEASE 0x80 |
52,7 → 52,7 |
void kbd_ctl_parse_scancode(int scancode) |
{ |
kbd_ev_type_t type; |
console_ev_type_t type; |
unsigned int key; |
if (scancode < 0 || scancode >= 0x100) |
63,9 → 63,9 |
if (scancode & KBD_KEY_RELEASE) { |
scancode &= ~KBD_KEY_RELEASE; |
type = KE_RELEASE; |
type = KEY_RELEASE; |
} else { |
type = KE_PRESS; |
type = KEY_PRESS; |
} |
key = scanmap_simple[scancode]; |
/branches/dd/uspace/srv/kbd/ctl/gxe_fb.c |
---|
36,8 → 36,8 |
*/ |
#include <kbd.h> |
#include <kbd/kbd.h> |
#include <kbd/keycode.h> |
#include <io/console.h> |
#include <io/keycode.h> |
#include <kbd_ctl.h> |
#include <gsp.h> |
#include <stroke.h> |
/branches/dd/uspace/srv/kbd/include/key_buffer.h |
---|
File deleted |
/branches/dd/uspace/srv/kbd/include/gsp.h |
---|
37,7 → 37,7 |
#ifndef KBD_GSP_H_ |
#define KBD_GSP_H_ |
#include <libadt/hash_table.h> |
#include <adt/hash_table.h> |
enum { |
GSP_END = -1, /**< Terminates a sequence. */ |
/branches/dd/uspace/srv/kbd/include/layout.h |
---|
27,10 → 27,10 |
*/ |
/** @addtogroup kbdgen generic |
* @brief HelenOS generic uspace keyboard handler. |
* @ingroup kbd |
* @brief HelenOS generic uspace keyboard handler. |
* @ingroup kbd |
* @{ |
*/ |
*/ |
/** @file |
*/ |
37,12 → 37,12 |
#ifndef KBD_LAYOUT_H_ |
#define KBD_LAYOUT_H_ |
#include <kbd/kbd.h> |
#include <sys/types.h> |
#include <io/console.h> |
typedef struct { |
void (*reset)(void); |
wchar_t (*parse_ev)(kbd_event_t *); |
wchar_t (*parse_ev)(console_event_t *); |
} layout_op_t; |
extern layout_op_t us_qwerty_op; |
53,5 → 53,4 |
/** |
* @} |
*/ |
*/ |
/branches/dd/uspace/srv/kbd/include/kbd.h |
---|
27,10 → 27,10 |
*/ |
/** @addtogroup kbdgen generic |
* @brief HelenOS generic uspace keyboard handler. |
* @ingroup kbd |
* @brief HelenOS generic uspace keyboard handler. |
* @ingroup kbd |
* @{ |
*/ |
*/ |
/** @file |
*/ |
37,17 → 37,17 |
#ifndef KBD_KBD_H_ |
#define KBD_KBD_H_ |
#include <key_buffer.h> |
#include <keybuffer.h> |
#include <ipc/ipc.h> |
#define KBD_EVENT 1024 |
#define KBD_MS_LEFT 1025 |
#define KBD_MS_RIGHT 1026 |
#define KBD_MS_MIDDLE 1027 |
#define KBD_MS_MOVE 1028 |
#define KBD_EVENT 1024 |
#define KBD_MS_LEFT 1025 |
#define KBD_MS_RIGHT 1026 |
#define KBD_MS_MIDDLE 1027 |
#define KBD_MS_MOVE 1028 |
typedef enum { |
KBD_YIELD = IPC_FIRST_USER_METHOD, |
KBD_YIELD = IPC_FIRST_USER_METHOD, |
KBD_RECLAIM |
} kbd_request_t; |
61,5 → 61,4 |
/** |
* @} |
*/ |
*/ |
/branches/dd/uspace/srv/kbd/include/keybuffer.h |
---|
0,0 → 1,65 |
/* |
* Copyright (c) 2006 Josef Cejka |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup kbdgen |
* @brief HelenOS generic uspace keyboard handler. |
* @ingroup kbd |
* @{ |
*/ |
/** @file |
*/ |
#ifndef __KEYBUFFER_H__ |
#define __KEYBUFFER_H__ |
#include <sys/types.h> |
#include <io/console.h> |
#include <bool.h> |
/** Size of buffer for pressed keys */ |
#define KEYBUFFER_SIZE 128 |
typedef struct { |
console_event_t fifo[KEYBUFFER_SIZE]; |
unsigned long head; |
unsigned long tail; |
unsigned long items; |
} keybuffer_t; |
extern void keybuffer_free(keybuffer_t *); |
extern void keybuffer_init(keybuffer_t *); |
extern size_t keybuffer_available(keybuffer_t *); |
extern bool keybuffer_empty(keybuffer_t *); |
extern void keybuffer_push(keybuffer_t *, const console_event_t *); |
extern bool keybuffer_pop(keybuffer_t *, console_event_t *); |
#endif |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/kbd/genarch/stroke.c |
---|
31,17 → 31,18 |
*/ |
/** |
* @file |
* @brief Stroke simulator. |
* @brief Stroke simulator. |
* |
* When simulating a keyboard using a serial TTY we need to convert the |
* recognized strokes (such as Shift-A) to sequences of key presses and |
* releases (such as 'press Shift, press A, release A, release Shift'). |
* |
*/ |
#include <stroke.h> |
#include <kbd.h> |
#include <kbd/kbd.h> |
#include <kbd/keycode.h> |
#include <io/console.h> |
#include <io/keycode.h> |
/** Correspondence between modifers and the modifier keycodes. */ |
static unsigned int mods_keys[][2] = { |
58,7 → 59,7 |
i = 0; |
while (mods_keys[i][0] != 0) { |
if (mod & mods_keys[i][0]) { |
kbd_push_ev(KE_PRESS, mods_keys[i][1]); |
kbd_push_ev(KEY_PRESS, mods_keys[i][1]); |
} |
++i; |
} |
65,8 → 66,8 |
/* Simulate key press and release. */ |
if (key != 0) { |
kbd_push_ev(KE_PRESS, key); |
kbd_push_ev(KE_RELEASE, key); |
kbd_push_ev(KEY_PRESS, key); |
kbd_push_ev(KEY_RELEASE, key); |
} |
/* Simulate modifier releases. */ |
73,7 → 74,7 |
i = 0; |
while (mods_keys[i][0] != 0) { |
if (mod & mods_keys[i][0]) { |
kbd_push_ev(KE_RELEASE, mods_keys[i][1]); |
kbd_push_ev(KEY_RELEASE, mods_keys[i][1]); |
} |
++i; |
} |
81,4 → 82,4 |
/** |
* @} |
*/ |
*/ |
/branches/dd/uspace/srv/kbd/genarch/gsp.c |
---|
49,7 → 49,7 |
*/ |
#include <gsp.h> |
#include <libadt/hash_table.h> |
#include <adt/hash_table.h> |
#include <stdlib.h> |
#include <stdio.h> |
/branches/dd/uspace/srv/kbd/generic/key_buffer.c |
---|
File deleted |
/branches/dd/uspace/srv/kbd/generic/kbd.c |
---|
28,10 → 28,10 |
/** |
* @addtogroup kbdgen generic |
* @brief HelenOS generic uspace keyboard handler. |
* @ingroup kbd |
* @brief HelenOS generic uspace keyboard handler. |
* @ingroup kbd |
* @{ |
*/ |
*/ |
/** @file |
*/ |
45,12 → 45,12 |
#include <ipc/ns.h> |
#include <async.h> |
#include <errno.h> |
#include <libadt/fifo.h> |
#include <kbd/kbd.h> |
#include <kbd/keycode.h> |
#include <adt/fifo.h> |
#include <io/console.h> |
#include <io/keycode.h> |
#include <kbd.h> |
#include <key_buffer.h> |
#include <keybuffer.h> |
#include <kbd_port.h> |
#include <kbd_ctl.h> |
#include <layout.h> |
88,7 → 88,7 |
void kbd_push_ev(int type, unsigned int key) |
{ |
kbd_event_t ev; |
console_event_t ev; |
unsigned mod_mask; |
switch (key) { |
102,7 → 102,7 |
} |
if (mod_mask != 0) { |
if (type == KE_PRESS) |
if (type == KEY_PRESS) |
mods = mods | mod_mask; |
else |
mods = mods & ~mod_mask; |
116,7 → 116,7 |
} |
if (mod_mask != 0) { |
if (type == KE_PRESS) { |
if (type == KEY_PRESS) { |
/* |
* Only change lock state on transition from released |
* to pressed. This prevents autorepeat from messing |
133,7 → 133,7 |
printf("mods: 0x%x\n", mods); |
printf("keycode: %u\n", key); |
*/ |
if (type == KE_PRESS && (mods & KM_LCTRL) && |
if (type == KEY_PRESS && (mods & KM_LCTRL) && |
key == KC_F1) { |
active_layout = 0; |
layout[active_layout]->reset(); |
140,7 → 140,7 |
return; |
} |
if (type == KE_PRESS && (mods & KM_LCTRL) && |
if (type == KEY_PRESS && (mods & KM_LCTRL) && |
key == KC_F2) { |
active_layout = 1; |
layout[active_layout]->reset(); |
147,7 → 147,7 |
return; |
} |
if (type == KE_PRESS && (mods & KM_LCTRL) && |
if (type == KEY_PRESS && (mods & KM_LCTRL) && |
key == KC_F3) { |
active_layout = 2; |
layout[active_layout]->reset(); |
/branches/dd/uspace/srv/kbd/generic/keybuffer.c |
---|
0,0 → 1,132 |
/* |
* Copyright (c) 2006 Josef Cejka |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup kbdgen |
* @brief HelenOS generic uspace keyboard handler. |
* @ingroup kbd |
* @{ |
*/ |
/** @file |
*/ |
#include <keybuffer.h> |
#include <futex.h> |
atomic_t keybuffer_futex = FUTEX_INITIALIZER; |
/** Clear key buffer. |
*/ |
void keybuffer_free(keybuffer_t *keybuffer) |
{ |
futex_down(&keybuffer_futex); |
keybuffer->head = 0; |
keybuffer->tail = 0; |
keybuffer->items = 0; |
futex_up(&keybuffer_futex); |
} |
/** Key buffer initialization. |
* |
*/ |
void keybuffer_init(keybuffer_t *keybuffer) |
{ |
keybuffer_free(keybuffer); |
} |
/** Get free space in buffer. |
* |
* This function is useful for processing some scancodes that are translated |
* to more than one character. |
* |
* @return empty buffer space |
* |
*/ |
size_t keybuffer_available(keybuffer_t *keybuffer) |
{ |
return KEYBUFFER_SIZE - keybuffer->items; |
} |
/** |
* |
* @return nonzero, if buffer is not empty. |
* |
*/ |
bool keybuffer_empty(keybuffer_t *keybuffer) |
{ |
return (keybuffer->items == 0); |
} |
/** Push key event to key buffer. |
* |
* If the buffer is full, the event is ignored. |
* |
* @param keybuffer The keybuffer. |
* @param ev The event to push. |
* |
*/ |
void keybuffer_push(keybuffer_t *keybuffer, const console_event_t *ev) |
{ |
futex_down(&keybuffer_futex); |
if (keybuffer->items < KEYBUFFER_SIZE) { |
keybuffer->fifo[keybuffer->tail] = *ev; |
keybuffer->tail = (keybuffer->tail + 1) % KEYBUFFER_SIZE; |
keybuffer->items++; |
} |
futex_up(&keybuffer_futex); |
} |
/** Pop event from buffer. |
* |
* @param edst Pointer to where the event should be saved. |
* |
* @return True if an event was popped. |
* |
*/ |
bool keybuffer_pop(keybuffer_t *keybuffer, console_event_t *edst) |
{ |
futex_down(&keybuffer_futex); |
if (keybuffer->items > 0) { |
keybuffer->items--; |
*edst = (keybuffer->fifo[keybuffer->head]); |
keybuffer->head = (keybuffer->head + 1) % KEYBUFFER_SIZE; |
futex_up(&keybuffer_futex); |
return true; |
} |
futex_up(&keybuffer_futex); |
return false; |
} |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/kbd/Makefile |
---|
34,7 → 34,7 |
include $(LIBC_PREFIX)/Makefile.toolchain |
CFLAGS += -Iinclude -I../libadt/include |
CFLAGS += -Iinclude |
LIBS = $(LIBC_PREFIX)/libc.a |
46,7 → 46,7 |
generic/kbd.c \ |
genarch/gsp.c \ |
genarch/stroke.c \ |
generic/key_buffer.c |
generic/keybuffer.c |
ARCH_SOURCES = |
GENARCH_SOURCES = \ |
/branches/dd/uspace/srv/kbd/layout/us_qwerty.c |
---|
32,12 → 32,12 |
*/ |
#include <kbd.h> |
#include <kbd/kbd.h> |
#include <kbd/keycode.h> |
#include <io/console.h> |
#include <io/keycode.h> |
#include <layout.h> |
static void layout_reset(void); |
static wchar_t layout_parse_ev(kbd_event_t *ev); |
static wchar_t layout_parse_ev(console_event_t *ev); |
layout_op_t us_qwerty_op = { |
layout_reset, |
203,7 → 203,7 |
{ |
} |
static wchar_t layout_parse_ev(kbd_event_t *ev) |
static wchar_t layout_parse_ev(console_event_t *ev) |
{ |
wchar_t c; |
/branches/dd/uspace/srv/kbd/layout/cz.c |
---|
27,23 → 27,23 |
*/ |
/** @addtogroup kbd |
* @brief US QWERTY leyout. |
* @brief US QWERTY leyout. |
* @{ |
*/ |
*/ |
#include <kbd.h> |
#include <kbd/kbd.h> |
#include <kbd/keycode.h> |
#include <io/console.h> |
#include <io/keycode.h> |
#include <bool.h> |
#include <layout.h> |
static void layout_reset(void); |
static wchar_t layout_parse_ev(kbd_event_t *ev); |
static wchar_t layout_parse_ev(console_event_t *ev); |
enum m_state { |
ms_start, |
ms_hacek, |
ms_carka |
ms_carka |
}; |
static enum m_state mstate; |
272,7 → 272,7 |
return map[key]; |
} |
static wchar_t parse_ms_hacek(kbd_event_t *ev) |
static wchar_t parse_ms_hacek(console_event_t *ev) |
{ |
wchar_t c; |
290,7 → 290,7 |
return c; |
} |
static wchar_t parse_ms_carka(kbd_event_t *ev) |
static wchar_t parse_ms_carka(console_event_t *ev) |
{ |
wchar_t c; |
308,7 → 308,7 |
return c; |
} |
static wchar_t parse_ms_start(kbd_event_t *ev) |
static wchar_t parse_ms_start(console_event_t *ev) |
{ |
wchar_t c; |
383,21 → 383,24 |
mstate = ms_start; |
} |
static wchar_t layout_parse_ev(kbd_event_t *ev) |
static wchar_t layout_parse_ev(console_event_t *ev) |
{ |
if (ev->type != KE_PRESS) |
return '\0'; |
if (ev->type != KEY_PRESS) |
return 0; |
if (key_is_mod(ev->key)) |
return '\0'; |
return 0; |
switch (mstate) { |
case ms_start: return parse_ms_start(ev); |
case ms_hacek: return parse_ms_hacek(ev); |
case ms_carka: return parse_ms_carka(ev); |
case ms_start: |
return parse_ms_start(ev); |
case ms_hacek: |
return parse_ms_hacek(ev); |
case ms_carka: |
return parse_ms_carka(ev); |
} |
} |
/** |
* @} |
*/ |
*/ |
/branches/dd/uspace/srv/kbd/layout/us_dvorak.c |
---|
32,12 → 32,12 |
*/ |
#include <kbd.h> |
#include <kbd/kbd.h> |
#include <kbd/keycode.h> |
#include <io/console.h> |
#include <io/keycode.h> |
#include <layout.h> |
static void layout_reset(void); |
static wchar_t layout_parse_ev(kbd_event_t *ev); |
static wchar_t layout_parse_ev(console_event_t *ev); |
layout_op_t us_dvorak_op = { |
layout_reset, |
209,7 → 209,7 |
{ |
} |
static wchar_t layout_parse_ev(kbd_event_t *ev) |
static wchar_t layout_parse_ev(console_event_t *ev) |
{ |
wchar_t c; |
/branches/dd/uspace/srv/ns/clonable.c |
---|
0,0 → 1,143 |
/* |
* Copyright (c) 2009 Martin Decky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup ns |
* @{ |
*/ |
#include <ipc/ipc.h> |
#include <ipc/services.h> |
#include <adt/list.h> |
#include <bool.h> |
#include <errno.h> |
#include <assert.h> |
#include <stdio.h> |
#include <malloc.h> |
#include <loader/loader.h> |
#include "clonable.h" |
#include "ns.h" |
/** Request for connection to a clonable service. */ |
typedef struct { |
link_t link; |
ipcarg_t service; |
ipc_call_t call; |
ipc_callid_t callid; |
} cs_req_t; |
/** List of clonable-service connection requests. */ |
static link_t cs_req; |
int clonable_init(void) |
{ |
list_initialize(&cs_req); |
return EOK; |
} |
/** Return true if @a service is clonable. */ |
bool service_clonable(int service) |
{ |
return (service == SERVICE_LOAD); |
} |
/** Register clonable service. |
* |
* @param service Service to be registered. |
* @param phone Phone to be used for connections to the service. |
* @param call Pointer to call structure. |
* |
*/ |
void register_clonable(ipcarg_t service, ipcarg_t phone, ipc_call_t *call, |
ipc_callid_t callid) |
{ |
if (list_empty(&cs_req)) { |
/* There was no pending connection request. */ |
printf(NAME ": Unexpected clonable server.\n"); |
ipc_answer_0(callid, EBUSY); |
return; |
} |
cs_req_t *csr = list_get_instance(cs_req.next, cs_req_t, link); |
list_remove(&csr->link); |
/* Currently we can only handle a single type of clonable service. */ |
assert(csr->service == SERVICE_LOAD); |
ipc_answer_0(callid, EOK); |
ipc_forward_fast(csr->callid, phone, IPC_GET_ARG2(csr->call), |
IPC_GET_ARG3(csr->call), 0, IPC_FF_NONE); |
free(csr); |
ipc_hangup(phone); |
} |
/** Connect client to clonable service. |
* |
* @param service Service to be connected to. |
* @param call Pointer to call structure. |
* @param callid Call ID of the request. |
* |
* @return Zero on success or a value from @ref errno.h. |
* |
*/ |
void connect_to_clonable(ipcarg_t service, ipc_call_t *call, |
ipc_callid_t callid) |
{ |
assert(service == SERVICE_LOAD); |
cs_req_t *csr = malloc(sizeof(cs_req_t)); |
if (csr == NULL) { |
ipc_answer_0(callid, ENOMEM); |
return; |
} |
/* Spawn a loader. */ |
int rc = loader_spawn("loader"); |
if (rc < 0) { |
free(csr); |
ipc_answer_0(callid, rc); |
return; |
} |
csr->service = service; |
csr->call = *call; |
csr->callid = callid; |
/* |
* We can forward the call only after the server we spawned connects |
* to us. Meanwhile we might need to service more connection requests. |
* Thus we store the call in a queue. |
*/ |
list_append(&csr->link, &cs_req); |
} |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/ns/ns.c |
---|
35,93 → 35,28 |
* @brief Naming service for HelenOS IPC. |
*/ |
#include <ipc/ipc.h> |
#include <ipc/services.h> |
#include <ipc/ns.h> |
#include <ipc/services.h> |
#include <unistd.h> |
#include <stdio.h> |
#include <bool.h> |
#include <unistd.h> |
#include <stdlib.h> |
#include <errno.h> |
#include <assert.h> |
#include <libadt/list.h> |
#include <libadt/hash_table.h> |
#include <as.h> |
#include <ddi.h> |
#include <event.h> |
#include <macros.h> |
#include <sysinfo.h> |
#include <loader/loader.h> |
#include <ddi.h> |
#include <as.h> |
#include "ns.h" |
#include "service.h" |
#include "clonable.h" |
#include "task.h" |
#define NAME "ns" |
#define NS_HASH_TABLE_CHAINS 20 |
static int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call); |
static void connect_to_service(ipcarg_t service, ipc_call_t *call, |
ipc_callid_t callid); |
void register_clonable(ipcarg_t service, ipcarg_t phone, ipc_call_t *call, |
ipc_callid_t callid); |
void connect_to_clonable(ipcarg_t service, ipc_call_t *call, |
ipc_callid_t callid); |
/* Static functions implementing NS hash table operations. */ |
static hash_index_t ns_hash(unsigned long *key); |
static int ns_compare(unsigned long *key, hash_count_t keys, link_t *item); |
static void ns_remove(link_t *item); |
/** Operations for NS hash table. */ |
static hash_table_operations_t ns_hash_table_ops = { |
.hash = ns_hash, |
.compare = ns_compare, |
.remove_callback = ns_remove |
}; |
/** NS hash table structure. */ |
static hash_table_t ns_hash_table; |
/** NS hash table item. */ |
typedef struct { |
link_t link; |
ipcarg_t service; /**< Number of the service. */ |
ipcarg_t phone; /**< Phone registered with the service. */ |
ipcarg_t in_phone_hash; /**< Incoming phone hash. */ |
} hashed_service_t; |
/** Pending connection structure. */ |
typedef struct { |
link_t link; |
ipcarg_t service; /**< Number of the service. */ |
ipc_callid_t callid; /**< Call ID waiting for the connection */ |
ipcarg_t arg2; /**< Second argument */ |
ipcarg_t arg3; /**< Third argument */ |
} pending_req_t; |
static link_t pending_req; |
/** Request for connection to a clonable service. */ |
typedef struct { |
link_t link; |
ipcarg_t service; |
ipc_call_t call; |
ipc_callid_t callid; |
} cs_req_t; |
/** List of clonable-service connection requests. */ |
static link_t cs_req; |
static void *clockaddr = NULL; |
static void *klogaddr = NULL; |
/** Return true if @a service is clonable. */ |
static bool service_clonable(int service) |
static void get_as_area(ipc_callid_t callid, ipc_call_t *call, void *ph_addr, |
size_t pages, void **addr) |
{ |
return (service == SERVICE_LOAD); |
} |
static void get_as_area(ipc_callid_t callid, ipc_call_t *call, void *ph_addr, count_t pages, void **addr) |
{ |
if (ph_addr == NULL) { |
ipc_answer_0(callid, ENOENT); |
return; |
145,67 → 80,53 |
ipc_answer_2(callid, EOK, (ipcarg_t) *addr, AS_AREA_READ); |
} |
/** Process pending connection requests */ |
static void process_pending_req() |
{ |
link_t *cur; |
loop: |
for (cur = pending_req.next; cur != &pending_req; cur = cur->next) { |
pending_req_t *pr = list_get_instance(cur, pending_req_t, link); |
unsigned long keys[3] = { |
pr->service, |
0, |
0 |
}; |
link_t *link = hash_table_find(&ns_hash_table, keys); |
if (!link) |
continue; |
hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link); |
ipcarg_t retval = ipc_forward_fast(pr->callid, hs->phone, |
pr->arg2, pr->arg3, 0, IPC_FF_NONE); |
if (!(pr->callid & IPC_CALLID_NOTIFICATION)) |
ipc_answer_0(pr->callid, retval); |
list_remove(cur); |
free(pr); |
goto loop; |
} |
} |
int main(int argc, char **argv) |
{ |
printf(NAME ": HelenOS IPC Naming Service\n"); |
if (!hash_table_create(&ns_hash_table, NS_HASH_TABLE_CHAINS, 3, |
&ns_hash_table_ops)) { |
printf(NAME ": No memory available for services\n"); |
return ENOMEM; |
} |
int rc = service_init(); |
if (rc != EOK) |
return rc; |
list_initialize(&pending_req); |
list_initialize(&cs_req); |
rc = clonable_init(); |
if (rc != EOK) |
return rc; |
rc = task_init(); |
if (rc != EOK) |
return rc; |
printf(NAME ": Accepting connections\n"); |
while (true) { |
process_pending_req(); |
process_pending_conn(); |
process_pending_wait(); |
ipc_call_t call; |
ipc_callid_t callid = ipc_wait_for_call(&call); |
task_id_t id; |
ipcarg_t retval; |
if (callid & IPC_CALLID_NOTIFICATION) { |
id = (task_id_t) |
MERGE_LOUP32(IPC_GET_ARG2(call), IPC_GET_ARG3(call)); |
wait_notification((wait_type_t) IPC_GET_ARG1(call), id); |
continue; |
} |
switch (IPC_GET_METHOD(call)) { |
case IPC_M_SHARE_IN: |
switch (IPC_GET_ARG3(call)) { |
case SERVICE_MEM_REALTIME: |
get_as_area(callid, &call, sysinfo_value("clock.faddr"), 1, &clockaddr); |
get_as_area(callid, &call, |
(void *) sysinfo_value("clock.faddr"), |
1, &clockaddr); |
break; |
case SERVICE_MEM_KLOG: |
get_as_area(callid, &call, sysinfo_value("klog.faddr"), sysinfo_value("klog.pages"), &klogaddr); |
get_as_area(callid, &call, |
(void *) sysinfo_value("klog.faddr"), |
sysinfo_value("klog.pages"), &klogaddr); |
break; |
default: |
ipc_answer_0(callid, ENOENT); |
241,6 → 162,14 |
continue; |
} |
break; |
case NS_PING: |
retval = EOK; |
break; |
case NS_TASK_WAIT: |
id = (task_id_t) |
MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call)); |
wait_for_task(id, &call, callid); |
continue; |
default: |
retval = ENOENT; |
break; |
254,213 → 183,6 |
return 0; |
} |
/** Register service. |
* |
* @param service Service to be registered. |
* @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. |
* |
*/ |
int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call) |
{ |
unsigned long keys[3] = { |
service, |
call->in_phone_hash, |
0 |
}; |
if (hash_table_find(&ns_hash_table, keys)) |
return EEXISTS; |
hashed_service_t *hs = (hashed_service_t *) malloc(sizeof(hashed_service_t)); |
if (!hs) |
return ENOMEM; |
link_initialize(&hs->link); |
hs->service = service; |
hs->phone = phone; |
hs->in_phone_hash = call->in_phone_hash; |
hash_table_insert(&ns_hash_table, keys, &hs->link); |
return 0; |
} |
/** Connect client to service. |
* |
* @param service Service to be connected to. |
* @param call Pointer to call structure. |
* @param callid Call ID of the request. |
* |
* @return Zero on success or a value from @ref errno.h. |
* |
*/ |
void connect_to_service(ipcarg_t service, ipc_call_t *call, ipc_callid_t callid) |
{ |
ipcarg_t retval; |
unsigned long keys[3] = { |
service, |
0, |
0 |
}; |
link_t *link = hash_table_find(&ns_hash_table, keys); |
if (!link) { |
if (IPC_GET_ARG4(*call) & IPC_FLAG_BLOCKING) { |
/* Blocking connection, add to pending list */ |
pending_req_t *pr = (pending_req_t *) malloc(sizeof(pending_req_t)); |
if (!pr) { |
retval = ENOMEM; |
goto out; |
} |
pr->service = service; |
pr->callid = callid; |
pr->arg2 = IPC_GET_ARG2(*call); |
pr->arg3 = IPC_GET_ARG3(*call); |
list_append(&pr->link, &pending_req); |
return; |
} |
retval = ENOENT; |
goto out; |
} |
hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link); |
retval = ipc_forward_fast(callid, hs->phone, IPC_GET_ARG2(*call), |
IPC_GET_ARG3(*call), 0, IPC_FF_NONE); |
out: |
if (!(callid & IPC_CALLID_NOTIFICATION)) |
ipc_answer_0(callid, retval); |
} |
/** Register clonable service. |
* |
* @param service Service to be registered. |
* @param phone Phone to be used for connections to the service. |
* @param call Pointer to call structure. |
* |
*/ |
void register_clonable(ipcarg_t service, ipcarg_t phone, ipc_call_t *call, |
ipc_callid_t callid) |
{ |
if (list_empty(&cs_req)) { |
/* There was no pending connection request. */ |
printf(NAME ": Unexpected clonable server.\n"); |
ipc_answer_0(callid, EBUSY); |
return; |
} |
cs_req_t *csr = list_get_instance(cs_req.next, cs_req_t, link); |
list_remove(&csr->link); |
/* Currently we can only handle a single type of clonable service. */ |
assert(csr->service == SERVICE_LOAD); |
ipc_answer_0(callid, EOK); |
int rc = ipc_forward_fast(csr->callid, phone, IPC_GET_ARG2(csr->call), |
IPC_GET_ARG3(csr->call), 0, IPC_FF_NONE); |
free(csr); |
ipc_hangup(phone); |
} |
/** Connect client to clonable service. |
* |
* @param service Service to be connected to. |
* @param call Pointer to call structure. |
* @param callid Call ID of the request. |
* |
* @return Zero on success or a value from @ref errno.h. |
* |
*/ |
void connect_to_clonable(ipcarg_t service, ipc_call_t *call, |
ipc_callid_t callid) |
{ |
assert(service == SERVICE_LOAD); |
cs_req_t *csr = malloc(sizeof(cs_req_t)); |
if (csr == NULL) { |
ipc_answer_0(callid, ENOMEM); |
return; |
} |
/* Spawn a loader. */ |
int rc = loader_spawn("loader"); |
if (rc < 0) { |
free(csr); |
ipc_answer_0(callid, rc); |
return; |
} |
csr->service = service; |
csr->call = *call; |
csr->callid = callid; |
/* |
* We can forward the call only after the server we spawned connects |
* to us. Meanwhile we might need to service more connection requests. |
* Thus we store the call in a queue. |
*/ |
list_append(&csr->link, &cs_req); |
} |
/** Compute hash index into NS hash table. |
* |
* @param key Pointer keys. However, only the first key (i.e. service number) |
* is used to compute the hash index. |
* |
* @return Hash index corresponding to key[0]. |
* |
*/ |
hash_index_t ns_hash(unsigned long *key) |
{ |
assert(key); |
return (*key % NS_HASH_TABLE_CHAINS); |
} |
/** Compare a key with hashed item. |
* |
* This compare function always ignores the third key. |
* It exists only to make it possible to remove records |
* originating from connection with key[1] in_phone_hash |
* value. Note that this is close to being classified |
* as a nasty hack. |
* |
* @param key Array of keys. |
* @param keys Must be lesser or equal to 3. |
* @param item Pointer to a hash table item. |
* |
* @return Non-zero if the key matches the item, zero otherwise. |
* |
*/ |
int ns_compare(unsigned long key[], hash_count_t keys, link_t *item) |
{ |
assert(key); |
assert(keys <= 3); |
assert(item); |
hashed_service_t *hs = hash_table_get_instance(item, hashed_service_t, link); |
if (keys == 2) |
return key[1] == hs->in_phone_hash; |
else |
return key[0] == hs->service; |
} |
/** Perform actions after removal of item from the hash table. |
* |
* @param item Item that was removed from the hash table. |
* |
*/ |
void ns_remove(link_t *item) |
{ |
assert(item); |
free(hash_table_get_instance(item, hashed_service_t, link)); |
} |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/ns/service.c |
---|
0,0 → 1,254 |
/* |
* Copyright (c) 2009 Martin Decky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup ns |
* @{ |
*/ |
#include <ipc/ipc.h> |
#include <adt/hash_table.h> |
#include <assert.h> |
#include <errno.h> |
#include "service.h" |
#include "ns.h" |
#define SERVICE_HASH_TABLE_CHAINS 20 |
/** Service hash table item. */ |
typedef struct { |
link_t link; |
ipcarg_t service; /**< Number of the service. */ |
ipcarg_t phone; /**< Phone registered with the service. */ |
ipcarg_t in_phone_hash; /**< Incoming phone hash. */ |
} hashed_service_t; |
/** Compute hash index into service hash table. |
* |
* @param key Pointer keys. However, only the first key (i.e. service number) |
* is used to compute the hash index. |
* |
* @return Hash index corresponding to key[0]. |
* |
*/ |
static hash_index_t service_hash(unsigned long *key) |
{ |
assert(key); |
return (*key % SERVICE_HASH_TABLE_CHAINS); |
} |
/** Compare a key with hashed item. |
* |
* This compare function always ignores the third key. |
* It exists only to make it possible to remove records |
* originating from connection with key[1] in_phone_hash |
* value. Note that this is close to being classified |
* as a nasty hack. |
* |
* @param key Array of keys. |
* @param keys Must be lesser or equal to 3. |
* @param item Pointer to a hash table item. |
* |
* @return Non-zero if the key matches the item, zero otherwise. |
* |
*/ |
static int service_compare(unsigned long key[], hash_count_t keys, link_t *item) |
{ |
assert(key); |
assert(keys <= 3); |
assert(item); |
hashed_service_t *hs = hash_table_get_instance(item, hashed_service_t, link); |
if (keys == 2) |
return (key[1] == hs->in_phone_hash); |
else |
return (key[0] == hs->service); |
} |
/** Perform actions after removal of item from the hash table. |
* |
* @param item Item that was removed from the hash table. |
* |
*/ |
static void service_remove(link_t *item) |
{ |
assert(item); |
free(hash_table_get_instance(item, hashed_service_t, link)); |
} |
/** Operations for service hash table. */ |
static hash_table_operations_t service_hash_table_ops = { |
.hash = service_hash, |
.compare = service_compare, |
.remove_callback = service_remove |
}; |
/** Service hash table structure. */ |
static hash_table_t service_hash_table; |
/** Pending connection structure. */ |
typedef struct { |
link_t link; |
ipcarg_t service; /**< Number of the service. */ |
ipc_callid_t callid; /**< Call ID waiting for the connection */ |
ipcarg_t arg2; /**< Second argument */ |
ipcarg_t arg3; /**< Third argument */ |
} pending_conn_t; |
static link_t pending_conn; |
int service_init(void) |
{ |
if (!hash_table_create(&service_hash_table, SERVICE_HASH_TABLE_CHAINS, |
3, &service_hash_table_ops)) { |
printf(NAME ": No memory available for services\n"); |
return ENOMEM; |
} |
list_initialize(&pending_conn); |
return EOK; |
} |
/** Process pending connection requests */ |
void process_pending_conn(void) |
{ |
link_t *cur; |
loop: |
for (cur = pending_conn.next; cur != &pending_conn; cur = cur->next) { |
pending_conn_t *pr = list_get_instance(cur, pending_conn_t, link); |
unsigned long keys[3] = { |
pr->service, |
0, |
0 |
}; |
link_t *link = hash_table_find(&service_hash_table, keys); |
if (!link) |
continue; |
hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link); |
ipcarg_t retval = ipc_forward_fast(pr->callid, hs->phone, |
pr->arg2, pr->arg3, 0, IPC_FF_NONE); |
if (!(pr->callid & IPC_CALLID_NOTIFICATION)) |
ipc_answer_0(pr->callid, retval); |
list_remove(cur); |
free(pr); |
goto loop; |
} |
} |
/** Register service. |
* |
* @param service Service to be registered. |
* @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. |
* |
*/ |
int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call) |
{ |
unsigned long keys[3] = { |
service, |
call->in_phone_hash, |
0 |
}; |
if (hash_table_find(&service_hash_table, keys)) |
return EEXISTS; |
hashed_service_t *hs = (hashed_service_t *) malloc(sizeof(hashed_service_t)); |
if (!hs) |
return ENOMEM; |
link_initialize(&hs->link); |
hs->service = service; |
hs->phone = phone; |
hs->in_phone_hash = call->in_phone_hash; |
hash_table_insert(&service_hash_table, keys, &hs->link); |
return 0; |
} |
/** Connect client to service. |
* |
* @param service Service to be connected to. |
* @param call Pointer to call structure. |
* @param callid Call ID of the request. |
* |
* @return Zero on success or a value from @ref errno.h. |
* |
*/ |
void connect_to_service(ipcarg_t service, ipc_call_t *call, ipc_callid_t callid) |
{ |
ipcarg_t retval; |
unsigned long keys[3] = { |
service, |
0, |
0 |
}; |
link_t *link = hash_table_find(&service_hash_table, keys); |
if (!link) { |
if (IPC_GET_ARG4(*call) & IPC_FLAG_BLOCKING) { |
/* Blocking connection, add to pending list */ |
pending_conn_t *pr = |
(pending_conn_t *) malloc(sizeof(pending_conn_t)); |
if (!pr) { |
retval = ENOMEM; |
goto out; |
} |
pr->service = service; |
pr->callid = callid; |
pr->arg2 = IPC_GET_ARG2(*call); |
pr->arg3 = IPC_GET_ARG3(*call); |
list_append(&pr->link, &pending_conn); |
return; |
} |
retval = ENOENT; |
goto out; |
} |
hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link); |
retval = ipc_forward_fast(callid, hs->phone, IPC_GET_ARG2(*call), |
IPC_GET_ARG3(*call), 0, IPC_FF_NONE); |
out: |
if (!(callid & IPC_CALLID_NOTIFICATION)) |
ipc_answer_0(callid, retval); |
} |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/ns/task.c |
---|
0,0 → 1,269 |
/* |
* Copyright (c) 2009 Martin Decky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup ns |
* @{ |
*/ |
#include <ipc/ipc.h> |
#include <adt/hash_table.h> |
#include <bool.h> |
#include <errno.h> |
#include <assert.h> |
#include <stdio.h> |
#include <macros.h> |
#include "task.h" |
#include "ns.h" |
#define TASK_HASH_TABLE_CHAINS 256 |
/* TODO: |
* |
* The current implementation of waiting on a task is not perfect. If somebody |
* wants to wait on a task which has already finished before the NS asked |
* the kernel to receive notifications, it would block indefinitively. |
* |
* A solution to this is to fail immediately on a task for which no creation |
* notification was received yet. However, there is a danger of a race condition |
* in this solution -- the caller has to make sure that it is not trying to wait |
* before the NS has a change to receive the task creation notification. This |
* can be assured by waiting for this event in task_spawn(). |
* |
* Finally, as there is currently no convention that each task has to be waited |
* for, the NS can leak memory because of the zombie tasks. |
* |
*/ |
/** Task hash table item. */ |
typedef struct { |
link_t link; |
task_id_t id; /**< Task ID. */ |
bool destroyed; |
} hashed_task_t; |
/** Compute hash index into task hash table. |
* |
* @param key Pointer keys. However, only the first key (i.e. truncated task |
* number) is used to compute the hash index. |
* |
* @return Hash index corresponding to key[0]. |
* |
*/ |
static hash_index_t task_hash(unsigned long *key) |
{ |
assert(key); |
return (LOWER32(*key) % TASK_HASH_TABLE_CHAINS); |
} |
/** Compare a key with hashed item. |
* |
* @param key Array of keys. |
* @param keys Must be lesser or equal to 2. |
* @param item Pointer to a hash table item. |
* |
* @return Non-zero if the key matches the item, zero otherwise. |
* |
*/ |
static int task_compare(unsigned long key[], hash_count_t keys, link_t *item) |
{ |
assert(key); |
assert(keys <= 2); |
assert(item); |
hashed_task_t *ht = hash_table_get_instance(item, hashed_task_t, link); |
if (keys == 2) |
return ((LOWER32(key[1]) == UPPER32(ht->id)) |
&& (LOWER32(key[0]) == LOWER32(ht->id))); |
else |
return (LOWER32(key[0]) == LOWER32(ht->id)); |
} |
/** Perform actions after removal of item from the hash table. |
* |
* @param item Item that was removed from the hash table. |
* |
*/ |
static void task_remove(link_t *item) |
{ |
assert(item); |
free(hash_table_get_instance(item, hashed_task_t, link)); |
} |
/** Operations for task hash table. */ |
static hash_table_operations_t task_hash_table_ops = { |
.hash = task_hash, |
.compare = task_compare, |
.remove_callback = task_remove |
}; |
/** Task hash table structure. */ |
static hash_table_t task_hash_table; |
/** Pending task wait structure. */ |
typedef struct { |
link_t link; |
task_id_t id; /**< Task ID. */ |
ipc_callid_t callid; /**< Call ID waiting for the connection */ |
} pending_wait_t; |
static link_t pending_wait; |
int task_init(void) |
{ |
if (!hash_table_create(&task_hash_table, TASK_HASH_TABLE_CHAINS, |
2, &task_hash_table_ops)) { |
printf(NAME ": No memory available for tasks\n"); |
return ENOMEM; |
} |
if (event_subscribe(EVENT_WAIT, 0) != EOK) |
printf(NAME ": Error registering wait notifications\n"); |
list_initialize(&pending_wait); |
return EOK; |
} |
/** Process pending wait requests */ |
void process_pending_wait(void) |
{ |
link_t *cur; |
loop: |
for (cur = pending_wait.next; cur != &pending_wait; cur = cur->next) { |
pending_wait_t *pr = list_get_instance(cur, pending_wait_t, link); |
unsigned long keys[2] = { |
LOWER32(pr->id), |
UPPER32(pr->id) |
}; |
link_t *link = hash_table_find(&task_hash_table, keys); |
if (!link) |
continue; |
hashed_task_t *ht = hash_table_get_instance(link, hashed_task_t, link); |
if (!ht->destroyed) |
continue; |
if (!(pr->callid & IPC_CALLID_NOTIFICATION)) |
ipc_answer_0(pr->callid, EOK); |
hash_table_remove(&task_hash_table, keys, 2); |
list_remove(cur); |
free(pr); |
goto loop; |
} |
} |
static void fail_pending_wait(task_id_t id, int rc) |
{ |
link_t *cur; |
loop: |
for (cur = pending_wait.next; cur != &pending_wait; cur = cur->next) { |
pending_wait_t *pr = list_get_instance(cur, pending_wait_t, link); |
if (pr->id == id) { |
if (!(pr->callid & IPC_CALLID_NOTIFICATION)) |
ipc_answer_0(pr->callid, rc); |
list_remove(cur); |
free(pr); |
goto loop; |
} |
} |
} |
void wait_notification(wait_type_t et, task_id_t id) |
{ |
unsigned long keys[2] = { |
LOWER32(id), |
UPPER32(id) |
}; |
link_t *link = hash_table_find(&task_hash_table, keys); |
if (link == NULL) { |
hashed_task_t *ht = |
(hashed_task_t *) malloc(sizeof(hashed_task_t)); |
if (ht == NULL) { |
fail_pending_wait(id, ENOMEM); |
return; |
} |
link_initialize(&ht->link); |
ht->id = id; |
ht->destroyed = (et == TASK_CREATE) ? false : true; |
hash_table_insert(&task_hash_table, keys, &ht->link); |
} else { |
hashed_task_t *ht = |
hash_table_get_instance(link, hashed_task_t, link); |
ht->destroyed = (et == TASK_CREATE) ? false : true; |
} |
} |
void wait_for_task(task_id_t id, ipc_call_t *call, ipc_callid_t callid) |
{ |
ipcarg_t retval; |
unsigned long keys[2] = { |
LOWER32(id), |
UPPER32(id) |
}; |
link_t *link = hash_table_find(&task_hash_table, keys); |
hashed_task_t *ht = (link != NULL) ? |
hash_table_get_instance(link, hashed_task_t, link) : NULL; |
if ((ht == NULL) || (!ht->destroyed)) { |
/* Add to pending list */ |
pending_wait_t *pr = |
(pending_wait_t *) malloc(sizeof(pending_wait_t)); |
if (!pr) { |
retval = ENOMEM; |
goto out; |
} |
pr->id = id; |
pr->callid = callid; |
list_append(&pr->link, &pending_wait); |
return; |
} |
hash_table_remove(&task_hash_table, keys, 2); |
retval = EOK; |
out: |
if (!(callid & IPC_CALLID_NOTIFICATION)) |
ipc_answer_0(callid, retval); |
} |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/ns/clonable.h |
---|
0,0 → 1,51 |
/* |
* Copyright (c) 2009 Martin Decky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup ns |
* @{ |
*/ |
#ifndef NS_CLONABLE_H__ |
#define NS_CLONABLE_H__ |
#include <ipc/ipc.h> |
#include <bool.h> |
extern int clonable_init(void); |
extern bool service_clonable(int service); |
extern void register_clonable(ipcarg_t service, ipcarg_t phone, |
ipc_call_t *call, ipc_callid_t callid); |
extern void connect_to_clonable(ipcarg_t service, ipc_call_t *call, |
ipc_callid_t callid); |
#endif |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/ns/ns.h |
---|
0,0 → 1,42 |
/* |
* Copyright (c) 2009 Martin Decky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup ns |
* @{ |
*/ |
#ifndef NS_NS_H__ |
#define NS_NS_H__ |
#define NAME "ns" |
#endif |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/ns/service.h |
---|
0,0 → 1,49 |
/* |
* Copyright (c) 2009 Martin Decky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup ns |
* @{ |
*/ |
#ifndef NS_SERVICE_H__ |
#define NS_SERVICE_H__ |
#include <ipc/ipc.h> |
extern int service_init(void); |
extern void process_pending_conn(void); |
extern int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call); |
extern void connect_to_service(ipcarg_t service, ipc_call_t *call, |
ipc_callid_t callid); |
#endif |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/ns/task.h |
---|
0,0 → 1,49 |
/* |
* Copyright (c) 2009 Martin Decky |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup ns |
* @{ |
*/ |
#ifndef NS_TASK_H__ |
#define NS_TASK_H__ |
#include <ipc/ipc.h> |
#include <event.h> |
extern int task_init(void); |
extern void process_pending_wait(void); |
extern void wait_notification(wait_type_t et, task_id_t id); |
extern void wait_for_task(task_id_t id, ipc_call_t *call, ipc_callid_t callid); |
#endif |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/ns/Makefile |
---|
41,7 → 41,10 |
OUTPUT = ns |
SOURCES = \ |
ns.c |
ns.c \ |
service.c \ |
clonable.c \ |
task.c |
OBJECTS := $(addsuffix .o,$(basename $(SOURCES))) |
/branches/dd/uspace/srv/console/gcons.h |
---|
32,19 → 32,24 |
/** @file |
*/ |
#ifndef _GCONS_H_ |
#define _GCONS_H_ |
#ifndef GCONS_H_ |
#define GCONS_H_ |
#include <sys/types.h> |
void gcons_init(int phone); |
void gcons_redraw_console(void); |
void gcons_change_console(int consnum); |
void gcons_notify_char(int consnum); |
void gcons_change_console(size_t index); |
void gcons_notify_char(size_t index); |
void gcons_in_kernel(void); |
void gcons_notify_connect(int consnum); |
void gcons_notify_disconnect(int consnum); |
void gcons_mouse_move(int dx, int dy); |
int gcons_mouse_btn(int state); |
void gcons_notify_connect(size_t index); |
void gcons_notify_disconnect(size_t index); |
void gcons_mouse_move(ssize_t dx, ssize_t dy); |
int gcons_mouse_btn(bool state); |
#endif |
/** @} |
/branches/dd/uspace/srv/console/screenbuffer.h |
---|
37,9 → 37,10 |
#include <stdint.h> |
#include <sys/types.h> |
#include <bool.h> |
#define DEFAULT_FOREGROUND 0x0 /**< default console foreground color */ |
#define DEFAULT_BACKGROUND 0xf0f0f0 /**< default console background color */ |
#define DEFAULT_FOREGROUND 0x0 /**< default console foreground color */ |
#define DEFAULT_BACKGROUND 0xf0f0f0 /**< default console background color */ |
typedef struct { |
uint8_t style; |
72,25 → 73,25 |
/** One field on screen. It contain one character and its attributes. */ |
typedef struct { |
wchar_t character; /**< Character itself */ |
attrs_t attrs; /**< Character`s attributes */ |
attrs_t attrs; /**< Character attributes */ |
} keyfield_t; |
/** Structure for buffering state of one virtual console. |
*/ |
typedef struct { |
keyfield_t *buffer; /**< Screen content - characters and |
their attributes (used as a circular buffer) */ |
unsigned int size_x; /**< Number of columns */ |
unsigned int size_y; /**< Number of rows */ |
keyfield_t *buffer; /**< Screen content - characters and |
their attributes (used as a circular buffer) */ |
size_t size_x; /**< Number of columns */ |
size_t size_y; /**< Number of rows */ |
/** Coordinates of last printed character for determining cursor position */ |
unsigned int position_x; |
unsigned int position_y; |
size_t position_x; |
size_t position_y; |
attrs_t attrs; /**< Current attributes. */ |
unsigned int top_line; /**< Points to buffer[][] line that will |
be printed at screen as the first line */ |
unsigned char is_cursor_visible; /**< Cursor state - default is visible */ |
attrs_t attrs; /**< Current attributes. */ |
size_t top_line; /**< Points to buffer[][] line that will |
be printed at screen as the first line */ |
bool is_cursor_visible; /**< Cursor state - default is visible */ |
} screenbuffer_t; |
/** Returns keyfield for position on screen |
105,7 → 106,7 |
* @return Keyfield structure with character and its attributes on x, y |
* |
*/ |
static inline keyfield_t *get_field_at(screenbuffer_t *scr, unsigned int x, unsigned int y) |
static inline keyfield_t *get_field_at(screenbuffer_t *scr, size_t x, size_t y) |
{ |
return scr->buffer + x + ((y + scr->top_line) % scr->size_y) * scr->size_x; |
} |
138,17 → 139,17 |
void screenbuffer_putchar(screenbuffer_t *scr, wchar_t c); |
screenbuffer_t *screenbuffer_init(screenbuffer_t *scr, int size_x, int size_y); |
screenbuffer_t *screenbuffer_init(screenbuffer_t *scr, size_t size_x, size_t size_y); |
void screenbuffer_clear(screenbuffer_t *scr); |
void screenbuffer_clear_line(screenbuffer_t *scr, unsigned int line); |
void screenbuffer_clear_line(screenbuffer_t *scr, size_t line); |
void screenbuffer_copy_buffer(screenbuffer_t *scr, keyfield_t *dest); |
void screenbuffer_goto(screenbuffer_t *scr, unsigned int x, unsigned int y); |
void screenbuffer_set_style(screenbuffer_t *scr, int style); |
void screenbuffer_set_color(screenbuffer_t *scr, unsigned int fg_color, |
unsigned int bg_color, unsigned int attr); |
void screenbuffer_set_rgb_color(screenbuffer_t *scr, unsigned int fg_color, |
unsigned int bg_color); |
void screenbuffer_goto(screenbuffer_t *scr, size_t x, size_t y); |
void screenbuffer_set_style(screenbuffer_t *scr, uint8_t style); |
void screenbuffer_set_color(screenbuffer_t *scr, uint8_t fg_color, |
uint8_t bg_color, uint8_t attr); |
void screenbuffer_set_rgb_color(screenbuffer_t *scr, uint32_t fg_color, |
uint32_t bg_color); |
#endif |
/branches/dd/uspace/srv/console/console.c |
---|
36,37 → 36,30 |
#include <fb.h> |
#include <ipc/ipc.h> |
#include <kbd.h> |
#include <kbd/keycode.h> |
#include <io/keycode.h> |
#include <ipc/fb.h> |
#include <ipc/services.h> |
#include <errno.h> |
#include <key_buffer.h> |
#include <keybuffer.h> |
#include <ipc/console.h> |
#include <unistd.h> |
#include <async.h> |
#include <libadt/fifo.h> |
#include <screenbuffer.h> |
#include <adt/fifo.h> |
#include <sys/mman.h> |
#include <stdio.h> |
#include <string.h> |
#include <sysinfo.h> |
#include <event.h> |
#include <devmap.h> |
#include "console.h" |
#include "gcons.h" |
#include "screenbuffer.h" |
#define NAME "console" |
#define MAX_KEYREQUESTS_BUFFERED 32 |
#define MAX_DEVICE_NAME 32 |
/** Size of cwrite_buf. */ |
#define CWRITE_BUF_SIZE 256 |
/** Index of currently used virtual console. |
*/ |
int active_console = 0; |
int prev_console = 0; |
/** Phone to the keyboard driver. */ |
static int kbd_phone; |
73,28 → 66,26 |
/** Information about framebuffer */ |
struct { |
int phone; /**< Framebuffer phone */ |
ipcarg_t cols; /**< Framebuffer columns */ |
ipcarg_t rows; /**< Framebuffer rows */ |
ipcarg_t cols; /**< Framebuffer columns */ |
} fb_info; |
typedef struct { |
keybuffer_t keybuffer; /**< Buffer for incoming keys. */ |
/** Buffer for unsatisfied request for keys. */ |
FIFO_CREATE_STATIC(keyrequests, ipc_callid_t, |
MAX_KEYREQUESTS_BUFFERED); |
int keyrequest_counter; /**< Number of requests in buffer. */ |
int client_phone; /**< Phone to connected client. */ |
int used; /**< 1 if this virtual console is |
connected to some client. */ |
screenbuffer_t screenbuffer; /**< Screenbuffer for saving screen |
contents and related settings. */ |
} connection_t; |
size_t index; /**< Console index */ |
size_t refcount; /**< Connection reference count */ |
dev_handle_t dev_handle; /**< Device handle */ |
keybuffer_t keybuffer; /**< Buffer for incoming keys. */ |
screenbuffer_t scr; /**< Screenbuffer for saving screen |
contents and related settings. */ |
} console_t; |
/** Array of data for virtual consoles */ |
static connection_t connections[CONSOLE_COUNT]; |
static console_t consoles[CONSOLE_COUNT]; |
static console_t *active_console = &consoles[0]; |
static console_t *prev_console = &consoles[0]; |
static console_t *kernel_console = &consoles[KERNEL_CONSOLE]; |
/** Pointer to memory shared with framebufer used for |
faster virtual console switching */ |
static keyfield_t *interbuffer = NULL; |
101,34 → 92,69 |
/** Information on row-span yet unsent to FB driver. */ |
struct { |
int row; /**< Row where the span lies. */ |
int col; /**< Leftmost column of the span. */ |
int cnt; /**< Width of the span. */ |
size_t col; /**< Leftmost column of the span. */ |
size_t row; /**< Row where the span lies. */ |
size_t cnt; /**< Width of the span. */ |
} fb_pending; |
/** Buffer for receiving data via the CONSOLE_WRITE call from the client. */ |
static char cwrite_buf[CWRITE_BUF_SIZE]; |
/** Pending input structure. */ |
typedef struct { |
link_t link; |
console_t *cons; /**< Console waiting for input */ |
ipc_callid_t rid; /**< Call ID waiting for input */ |
ipc_callid_t callid; /**< Call ID waiting for IPC_DATA_READ */ |
size_t pos; /**< Position of the last stored data */ |
size_t size; /**< Size of ther buffer */ |
char *data; /**< Already stored data */ |
} pending_input_t; |
/** Find unused virtual console. |
* |
*/ |
static int find_free_connection(void) |
LIST_INITIALIZE(pending_input); |
/** Process pending input requests */ |
static void process_pending_input(void) |
{ |
int i; |
async_serialize_start(); |
for (i = 0; i < CONSOLE_COUNT; i++) { |
if (!connections[i].used) |
return i; |
link_t *cur; |
loop: |
for (cur = pending_input.next; cur != &pending_input; cur = cur->next) { |
pending_input_t *pr = list_get_instance(cur, pending_input_t, link); |
console_event_t ev; |
if (keybuffer_pop(&pr->cons->keybuffer, &ev)) { |
if (pr->data != NULL) { |
if (ev.type == KEY_PRESS) { |
pr->data[pr->pos] = ev.c; |
pr->pos++; |
} |
} else { |
ipc_answer_4(pr->rid, EOK, ev.type, ev.key, ev.mods, ev.c); |
list_remove(cur); |
free(pr); |
goto loop; |
} |
} |
if ((pr->data != NULL) && (pr->pos == pr->size)) { |
(void) ipc_data_read_finalize(pr->callid, pr->data, pr->size); |
ipc_answer_1(pr->rid, EOK, pr->size); |
free(pr->data); |
list_remove(cur); |
free(pr); |
goto loop; |
} |
} |
return -1; |
async_serialize_end(); |
} |
static void clrscr(void) |
{ |
async_msg_0(fb_info.phone, FB_CLEAR); |
} |
static void curs_visibility(bool visible) |
{ |
async_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible); |
139,11 → 165,16 |
ipc_call_sync_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false); |
} |
static void curs_goto(int row, int col) |
static void curs_goto(size_t x, size_t y) |
{ |
async_msg_2(fb_info.phone, FB_CURSOR_GOTO, row, col); |
async_msg_2(fb_info.phone, FB_CURSOR_GOTO, x, y); |
} |
static void screen_clear(void) |
{ |
async_msg_0(fb_info.phone, FB_CLEAR); |
} |
static void screen_yield(void) |
{ |
ipc_call_sync_0_0(fb_info.phone, FB_SCREEN_YIELD); |
166,7 → 197,7 |
static void set_style(int style) |
{ |
async_msg_1(fb_info.phone, FB_SET_STYLE, style); |
async_msg_1(fb_info.phone, FB_SET_STYLE, style); |
} |
static void set_color(int fgcolor, int bgcolor, int flags) |
196,23 → 227,21 |
} |
/** Send an area of screenbuffer to the FB driver. */ |
static void fb_update_area(connection_t *conn, int x, int y, int w, int h) |
static void fb_update_area(console_t *cons, ipcarg_t x0, ipcarg_t y0, ipcarg_t width, ipcarg_t height) |
{ |
int i; |
int j; |
attrs_t *attrs; |
keyfield_t *field; |
if (interbuffer) { |
for (j = 0; j < h; j++) { |
for (i = 0; i < w; i++) { |
interbuffer[i + j * w] = |
*get_field_at(&conn->screenbuffer, x + i, y + j); |
ipcarg_t x; |
ipcarg_t y; |
for (y = 0; y < height; y++) { |
for (x = 0; x < width; x++) { |
interbuffer[y * width + x] = |
*get_field_at(&cons->scr, x0 + x, y0 + y); |
} |
} |
async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA, |
x, y, w, h); |
x0, y0, width, height); |
} |
} |
219,11 → 248,8 |
/** Flush pending cells to FB. */ |
static void fb_pending_flush(void) |
{ |
screenbuffer_t *scr |
= &(connections[active_console].screenbuffer); |
if (fb_pending.cnt > 0) { |
fb_update_area(&connections[active_console], fb_pending.col, |
fb_update_area(active_console, fb_pending.col, |
fb_pending.row, fb_pending.cnt, 1); |
fb_pending.cnt = 0; |
} |
235,18 → 261,18 |
* the old span is flushed first. |
* |
*/ |
static void cell_mark_changed(int row, int col) |
static void cell_mark_changed(size_t col, size_t row) |
{ |
if (fb_pending.cnt != 0) { |
if ((row != fb_pending.row) |
|| (col != fb_pending.col + fb_pending.cnt)) { |
if ((col != fb_pending.col + fb_pending.cnt) |
|| (row != fb_pending.row)) { |
fb_pending_flush(); |
} |
} |
if (fb_pending.cnt == 0) { |
fb_pending.col = col; |
fb_pending.row = row; |
fb_pending.col = col; |
} |
fb_pending.cnt++; |
253,82 → 279,67 |
} |
/** Print a character to the active VC with buffering. */ |
static void fb_putchar(wchar_t c, int row, int col) |
static void fb_putchar(wchar_t c, ipcarg_t col, ipcarg_t row) |
{ |
async_msg_3(fb_info.phone, FB_PUTCHAR, c, row, col); |
async_msg_3(fb_info.phone, FB_PUTCHAR, c, col, row); |
} |
/** Process a character from the client (TTY emulation). */ |
static void write_char(int console, wchar_t ch) |
static void write_char(console_t *cons, wchar_t ch) |
{ |
bool flush_cursor = false; |
screenbuffer_t *scr = &(connections[console].screenbuffer); |
switch (ch) { |
case '\n': |
fb_pending_flush(); |
flush_cursor = true; |
scr->position_y++; |
scr->position_x = 0; |
cons->scr.position_y++; |
cons->scr.position_x = 0; |
break; |
case '\r': |
break; |
case '\t': |
scr->position_x += 8; |
scr->position_x -= scr->position_x % 8; |
cons->scr.position_x += 8; |
cons->scr.position_x -= cons->scr.position_x % 8; |
break; |
case '\b': |
if (scr->position_x == 0) |
if (cons->scr.position_x == 0) |
break; |
scr->position_x--; |
if (console == active_console) |
cell_mark_changed(scr->position_y, scr->position_x); |
screenbuffer_putchar(scr, ' '); |
cons->scr.position_x--; |
if (cons == active_console) |
cell_mark_changed(cons->scr.position_x, cons->scr.position_y); |
screenbuffer_putchar(&cons->scr, ' '); |
break; |
default: |
if (console == active_console) |
cell_mark_changed(scr->position_y, scr->position_x); |
if (cons == active_console) |
cell_mark_changed(cons->scr.position_x, cons->scr.position_y); |
screenbuffer_putchar(scr, ch); |
scr->position_x++; |
screenbuffer_putchar(&cons->scr, ch); |
cons->scr.position_x++; |
} |
if (scr->position_x >= scr->size_x) { |
flush_cursor = true; |
scr->position_y++; |
} |
if (cons->scr.position_x >= cons->scr.size_x) |
cons->scr.position_y++; |
if (scr->position_y >= scr->size_y) { |
if (cons->scr.position_y >= cons->scr.size_y) { |
fb_pending_flush(); |
scr->position_y = scr->size_y - 1; |
screenbuffer_clear_line(scr, scr->top_line); |
scr->top_line = (scr->top_line + 1) % scr->size_y; |
if (console == active_console) |
cons->scr.position_y = cons->scr.size_y - 1; |
screenbuffer_clear_line(&cons->scr, cons->scr.top_line); |
cons->scr.top_line = (cons->scr.top_line + 1) % cons->scr.size_y; |
if (cons == active_console) |
async_msg_1(fb_info.phone, FB_SCROLL, 1); |
} |
scr->position_x = scr->position_x % scr->size_x; |
if (console == active_console && flush_cursor) |
curs_goto(scr->position_y, scr->position_x); |
cons->scr.position_x = cons->scr.position_x % cons->scr.size_x; |
} |
/** Switch to new console */ |
static void change_console(int newcons) |
static void change_console(console_t *cons) |
{ |
connection_t *conn; |
int i; |
int j; |
int rc; |
keyfield_t *field; |
attrs_t *attrs; |
if (newcons == active_console) |
if (cons == active_console) |
return; |
fb_pending_flush(); |
if (newcons == KERNEL_CONSOLE) { |
if (cons == kernel_console) { |
async_serialize_start(); |
curs_hide_sync(); |
gcons_in_kernel(); |
336,67 → 347,67 |
kbd_yield(); |
async_serialize_end(); |
if (__SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE)) { |
prev_console = active_console; |
active_console = KERNEL_CONSOLE; |
active_console = kernel_console; |
} else |
newcons = active_console; |
cons = active_console; |
} |
if (newcons != KERNEL_CONSOLE) { |
if (cons != kernel_console) { |
size_t x; |
size_t y; |
int rc = 0; |
async_serialize_start(); |
if (active_console == KERNEL_CONSOLE) { |
if (active_console == kernel_console) { |
screen_reclaim(); |
kbd_reclaim(); |
gcons_redraw_console(); |
} |
active_console = newcons; |
gcons_change_console(newcons); |
conn = &connections[active_console]; |
active_console = cons; |
gcons_change_console(cons->index); |
set_attrs(&conn->screenbuffer.attrs); |
set_attrs(&cons->scr.attrs); |
curs_visibility(false); |
if (interbuffer) { |
for (j = 0; j < conn->screenbuffer.size_y; j++) { |
for (i = 0; i < conn->screenbuffer.size_x; i++) { |
unsigned int size_x; |
size_x = conn->screenbuffer.size_x; |
interbuffer[j * size_x + i] = |
*get_field_at(&conn->screenbuffer, i, j); |
for (y = 0; y < cons->scr.size_y; y++) { |
for (x = 0; x < cons->scr.size_x; x++) { |
interbuffer[y * cons->scr.size_x + x] = |
*get_field_at(&cons->scr, x, y); |
} |
} |
/* This call can preempt, but we are already at the end */ |
rc = async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA, |
0, 0, conn->screenbuffer.size_x, |
conn->screenbuffer.size_y); |
0, 0, cons->scr.size_x, |
cons->scr.size_y); |
} |
if ((!interbuffer) || (rc != 0)) { |
set_attrs(&conn->screenbuffer.attrs); |
clrscr(); |
attrs = &conn->screenbuffer.attrs; |
set_attrs(&cons->scr.attrs); |
screen_clear(); |
for (j = 0; j < conn->screenbuffer.size_y; j++) |
for (i = 0; i < conn->screenbuffer.size_x; i++) { |
field = get_field_at(&conn->screenbuffer, i, j); |
if (!attrs_same(*attrs, field->attrs)) |
for (y = 0; y < cons->scr.size_y; y++) |
for (x = 0; x < cons->scr.size_x; x++) { |
keyfield_t *field = get_field_at(&cons->scr, x, y); |
if (!attrs_same(cons->scr.attrs, field->attrs)) |
set_attrs(&field->attrs); |
attrs = &field->attrs; |
cons->scr.attrs = field->attrs; |
if ((field->character == ' ') && |
(attrs_same(field->attrs, conn->screenbuffer.attrs))) |
(attrs_same(field->attrs, cons->scr.attrs))) |
continue; |
fb_putchar(field->character, j, i); |
fb_putchar(field->character, x, y); |
} |
} |
curs_goto(conn->screenbuffer.position_y, |
conn->screenbuffer.position_x); |
curs_visibility(conn->screenbuffer.is_cursor_visible); |
curs_goto(cons->scr.position_x, cons->scr.position_y); |
curs_visibility(cons->scr.is_cursor_visible); |
async_serialize_end(); |
} |
405,31 → 416,19 |
/** Handler for keyboard */ |
static void keyboard_events(ipc_callid_t iid, ipc_call_t *icall) |
{ |
ipc_callid_t callid; |
ipc_call_t call; |
int retval; |
kbd_event_t ev; |
connection_t *conn; |
int newcon; |
/* Ignore parameters, the connection is alread opened */ |
/* Ignore parameters, the connection is already opened */ |
while (true) { |
callid = async_get_call(&call); |
ipc_call_t call; |
ipc_callid_t callid = async_get_call(&call); |
int retval; |
console_event_t ev; |
switch (IPC_GET_METHOD(call)) { |
case IPC_M_PHONE_HUNGUP: |
/* TODO: Handle hangup */ |
return; |
case KBD_MS_LEFT: |
newcon = gcons_mouse_btn(IPC_GET_ARG1(call)); |
if (newcon != -1) |
change_console(newcon); |
retval = 0; |
break; |
case KBD_MS_MOVE: |
gcons_mouse_move(IPC_GET_ARG1(call), |
IPC_GET_ARG2(call)); |
retval = 0; |
break; |
case KBD_EVENT: |
/* Got event from keyboard driver. */ |
retval = 0; |
438,29 → 437,16 |
ev.mods = IPC_GET_ARG3(call); |
ev.c = IPC_GET_ARG4(call); |
/* Switch to another virtual console */ |
conn = &connections[active_console]; |
if ((ev.key >= KC_F1) && (ev.key < KC_F1 + |
CONSOLE_COUNT) && ((ev.mods & KM_CTRL) == 0)) { |
if (ev.key == KC_F12) |
change_console(KERNEL_CONSOLE); |
if (ev.key == KC_F1 + KERNEL_CONSOLE) |
change_console(kernel_console); |
else |
change_console(ev.key - KC_F1); |
change_console(&consoles[ev.key - KC_F1]); |
break; |
} |
/* If client is awaiting key, send it */ |
if (conn->keyrequest_counter > 0) { |
conn->keyrequest_counter--; |
ipc_answer_4(fifo_pop(conn->keyrequests), EOK, |
ev.type, ev.key, ev.mods, ev.c); |
break; |
} |
keybuffer_push(&conn->keybuffer, &ev); |
retval = 0; |
keybuffer_push(&active_console->keybuffer, &ev); |
break; |
default: |
retval = ENOENT; |
469,14 → 455,10 |
} |
} |
/** Handle CONSOLE_WRITE call. */ |
static void cons_write(int consnum, ipc_callid_t rid, ipc_call_t *request) |
static void cons_write(console_t *cons, ipc_callid_t rid, ipc_call_t *request) |
{ |
ipc_callid_t callid; |
size_t size; |
wchar_t ch; |
size_t off; |
if (!ipc_data_write_receive(&callid, &size)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
483,49 → 465,146 |
return; |
} |
if (size > CWRITE_BUF_SIZE) |
size = CWRITE_BUF_SIZE; |
char *buf = (char *) malloc(size); |
if (buf == NULL) { |
ipc_answer_0(callid, ENOMEM); |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
(void) ipc_data_write_finalize(callid, cwrite_buf, size); |
(void) ipc_data_write_finalize(callid, buf, size); |
async_serialize_start(); |
off = 0; |
size_t off = 0; |
while (off < size) { |
ch = str_decode(cwrite_buf, &off, size); |
write_char(consnum, ch); |
wchar_t ch = str_decode(buf, &off, size); |
write_char(cons, ch); |
} |
if (cons == active_console) |
curs_goto(cons->scr.position_x, cons->scr.position_y); |
async_serialize_end(); |
gcons_notify_char(consnum); |
gcons_notify_char(cons->index); |
ipc_answer_1(rid, EOK, size); |
free(buf); |
} |
static void cons_read(console_t *cons, ipc_callid_t rid, ipc_call_t *request) |
{ |
ipc_callid_t callid; |
size_t size; |
if (!ipc_data_read_receive(&callid, &size)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
} |
char *buf = (char *) malloc(size); |
if (buf == NULL) { |
ipc_answer_0(callid, ENOMEM); |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
async_serialize_start(); |
size_t pos = 0; |
console_event_t ev; |
while ((keybuffer_pop(&cons->keybuffer, &ev)) && (pos < size)) { |
if (ev.type == KEY_PRESS) { |
buf[pos] = ev.c; |
pos++; |
} |
} |
if (pos == size) { |
(void) ipc_data_read_finalize(callid, buf, size); |
ipc_answer_1(rid, EOK, size); |
free(buf); |
} else { |
pending_input_t *pr = (pending_input_t *) malloc(sizeof(pending_input_t)); |
if (!pr) { |
ipc_answer_0(callid, ENOMEM); |
ipc_answer_0(rid, ENOMEM); |
free(buf); |
async_serialize_end(); |
return; |
} |
pr->cons = cons; |
pr->rid = rid; |
pr->callid = callid; |
pr->pos = pos; |
pr->size = size; |
pr->data = buf; |
list_append(&pr->link, &pending_input); |
} |
async_serialize_end(); |
} |
static void cons_get_event(console_t *cons, ipc_callid_t rid, ipc_call_t *request) |
{ |
async_serialize_start(); |
console_event_t ev; |
if (keybuffer_pop(&cons->keybuffer, &ev)) { |
ipc_answer_4(rid, EOK, ev.type, ev.key, ev.mods, ev.c); |
} else { |
pending_input_t *pr = (pending_input_t *) malloc(sizeof(pending_input_t)); |
if (!pr) { |
ipc_answer_0(rid, ENOMEM); |
async_serialize_end(); |
return; |
} |
pr->cons = cons; |
pr->rid = rid; |
pr->callid = 0; |
pr->data = NULL; |
list_append(&pr->link, &pending_input); |
} |
async_serialize_end(); |
} |
/** Default thread for new connections */ |
static void client_connection(ipc_callid_t iid, ipc_call_t *icall) |
{ |
ipc_callid_t callid; |
ipc_call_t call; |
int consnum; |
ipcarg_t arg1, arg2, arg3, arg4; |
connection_t *conn; |
screenbuffer_t *scr; |
console_t *cons = NULL; |
if ((consnum = find_free_connection()) == -1) { |
ipc_answer_0(iid, ELIMIT); |
size_t i; |
for (i = 0; i < CONSOLE_COUNT; i++) { |
if (i == KERNEL_CONSOLE) |
continue; |
if (consoles[i].dev_handle == (dev_handle_t) IPC_GET_ARG1(*icall)) { |
cons = &consoles[i]; |
break; |
} |
} |
if (cons == NULL) { |
ipc_answer_0(iid, ENOENT); |
return; |
} |
conn = &connections[consnum]; |
conn->used = 1; |
ipc_callid_t callid; |
ipc_call_t call; |
ipcarg_t arg1; |
ipcarg_t arg2; |
ipcarg_t arg3; |
async_serialize_start(); |
gcons_notify_connect(consnum); |
conn->client_phone = IPC_GET_ARG5(*icall); |
screenbuffer_clear(&conn->screenbuffer); |
if (consnum == active_console) |
clrscr(); |
if (cons->refcount == 0) |
gcons_notify_connect(cons->index); |
cons->refcount++; |
/* Accept the connection */ |
ipc_answer_0(iid, EOK); |
537,64 → 616,55 |
arg1 = 0; |
arg2 = 0; |
arg3 = 0; |
arg4 = 0; |
switch (IPC_GET_METHOD(call)) { |
case IPC_M_PHONE_HUNGUP: |
gcons_notify_disconnect(consnum); |
/* Answer all pending requests */ |
while (conn->keyrequest_counter > 0) { |
conn->keyrequest_counter--; |
ipc_answer_0(fifo_pop(conn->keyrequests), |
ENOENT); |
break; |
} |
conn->used = 0; |
cons->refcount--; |
if (cons->refcount == 0) |
gcons_notify_disconnect(cons->index); |
return; |
case CONSOLE_PUTCHAR: |
write_char(consnum, IPC_GET_ARG1(call)); |
gcons_notify_char(consnum); |
break; |
case CONSOLE_WRITE: |
case VFS_READ: |
async_serialize_end(); |
cons_write(consnum, callid, &call); |
cons_read(cons, callid, &call); |
async_serialize_start(); |
continue; |
case VFS_WRITE: |
async_serialize_end(); |
cons_write(cons, callid, &call); |
async_serialize_start(); |
continue; |
case VFS_SYNC: |
fb_pending_flush(); |
if (cons == active_console) { |
async_req_0_0(fb_info.phone, FB_FLUSH); |
curs_goto(cons->scr.position_x, cons->scr.position_y); |
} |
break; |
case CONSOLE_CLEAR: |
/* Send message to fb */ |
if (consnum == active_console) { |
async_msg_0(fb_info.phone, FB_CLEAR); |
} |
if (cons == active_console) |
async_msg_0(fb_info.phone, FB_CLEAR); |
screenbuffer_clear(&conn->screenbuffer); |
screenbuffer_clear(&cons->scr); |
break; |
case CONSOLE_GOTO: |
screenbuffer_goto(&conn->screenbuffer, |
IPC_GET_ARG2(call), IPC_GET_ARG1(call)); |
if (consnum == active_console) |
screenbuffer_goto(&cons->scr, |
IPC_GET_ARG1(call), IPC_GET_ARG2(call)); |
if (cons == active_console) |
curs_goto(IPC_GET_ARG1(call), |
IPC_GET_ARG2(call)); |
break; |
case CONSOLE_GETSIZE: |
arg1 = fb_info.rows; |
arg2 = fb_info.cols; |
case CONSOLE_GET_SIZE: |
arg1 = fb_info.cols; |
arg2 = fb_info.rows; |
break; |
case CONSOLE_FLUSH: |
fb_pending_flush(); |
if (consnum == active_console) { |
async_req_0_0(fb_info.phone, FB_FLUSH); |
scr = &(connections[consnum].screenbuffer); |
curs_goto(scr->position_y, scr->position_x); |
} |
break; |
case CONSOLE_SET_STYLE: |
fb_pending_flush(); |
arg1 = IPC_GET_ARG1(call); |
screenbuffer_set_style(&conn->screenbuffer, arg1); |
if (consnum == active_console) |
screenbuffer_set_style(&cons->scr, arg1); |
if (cons == active_console) |
set_style(arg1); |
break; |
case CONSOLE_SET_COLOR: |
602,9 → 672,8 |
arg1 = IPC_GET_ARG1(call); |
arg2 = IPC_GET_ARG2(call); |
arg3 = IPC_GET_ARG3(call); |
screenbuffer_set_color(&conn->screenbuffer, arg1, |
arg2, arg3); |
if (consnum == active_console) |
screenbuffer_set_color(&cons->scr, arg1, arg2, arg3); |
if (cons == active_console) |
set_color(arg1, arg2, arg3); |
break; |
case CONSOLE_SET_RGB_COLOR: |
611,46 → 680,27 |
fb_pending_flush(); |
arg1 = IPC_GET_ARG1(call); |
arg2 = IPC_GET_ARG2(call); |
screenbuffer_set_rgb_color(&conn->screenbuffer, arg1, |
arg2); |
if (consnum == active_console) |
screenbuffer_set_rgb_color(&cons->scr, arg1, arg2); |
if (cons == active_console) |
set_rgb_color(arg1, arg2); |
break; |
case CONSOLE_CURSOR_VISIBILITY: |
fb_pending_flush(); |
arg1 = IPC_GET_ARG1(call); |
conn->screenbuffer.is_cursor_visible = arg1; |
if (consnum == active_console) |
cons->scr.is_cursor_visible = arg1; |
if (cons == active_console) |
curs_visibility(arg1); |
break; |
case CONSOLE_GETKEY: |
if (keybuffer_empty(&conn->keybuffer)) { |
/* buffer is empty -> store request */ |
if (conn->keyrequest_counter < |
MAX_KEYREQUESTS_BUFFERED) { |
fifo_push(conn->keyrequests, callid); |
conn->keyrequest_counter++; |
} else { |
/* |
* No key available and too many |
* requests => fail. |
*/ |
ipc_answer_0(callid, ELIMIT); |
} |
continue; |
} |
kbd_event_t ev; |
keybuffer_pop(&conn->keybuffer, &ev); |
arg1 = ev.type; |
arg2 = ev.key; |
arg3 = ev.mods; |
arg4 = ev.c; |
break; |
case CONSOLE_GET_EVENT: |
async_serialize_end(); |
cons_get_event(cons, callid, &call); |
async_serialize_start(); |
continue; |
case CONSOLE_KCON_ENABLE: |
change_console(KERNEL_CONSOLE); |
change_console(kernel_console); |
break; |
} |
ipc_answer_4(callid, EOK, arg1, arg2, arg3, arg4); |
ipc_answer_3(callid, EOK, arg1, arg2, arg3); |
} |
} |
659,28 → 709,26 |
change_console(prev_console); |
} |
int main(int argc, char *argv[]) |
static bool console_init(void) |
{ |
printf(NAME ": HelenOS Console service\n"); |
async_serialize_start(); |
ipcarg_t phonehash; |
size_t ib_size; |
int i; |
async_set_client_connection(client_connection); |
/* Connect to keyboard driver */ |
kbd_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_KEYBOARD, 0, 0); |
if (kbd_phone < 0) { |
printf(NAME ": Failed to connect to keyboard service\n"); |
return -1; |
async_serialize_end(); |
return false; |
} |
ipcarg_t phonehash; |
if (ipc_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) { |
printf(NAME ": Failed to create callback from keyboard service\n"); |
return -1; |
async_serialize_end(); |
return false; |
} |
async_set_pending(process_pending_input); |
async_new_connection(phonehash, 0, NULL, keyboard_events); |
/* Connect to framebuffer driver */ |
687,50 → 735,32 |
fb_info.phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VIDEO, 0, 0); |
if (fb_info.phone < 0) { |
printf(NAME ": Failed to connect to video service\n"); |
async_serialize_end(); |
return -1; |
} |
/* Disable kernel output to the console */ |
__SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE); |
/* Register driver */ |
int rc = devmap_driver_register(NAME, client_connection); |
if (rc < 0) { |
printf(NAME ": Unable to register driver (%d)\n", rc); |
async_serialize_end(); |
return false; |
} |
/* Initialize gcons */ |
gcons_init(fb_info.phone); |
/* Synchronize, the gcons can have something in queue */ |
/* Synchronize, the gcons could put something in queue */ |
async_req_0_0(fb_info.phone, FB_FLUSH); |
async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows); |
async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.rows, |
&fb_info.cols); |
set_rgb_color(DEFAULT_FOREGROUND, DEFAULT_BACKGROUND); |
clrscr(); |
/* Init virtual consoles */ |
for (i = 0; i < CONSOLE_COUNT; i++) { |
connections[i].used = 0; |
keybuffer_init(&connections[i].keybuffer); |
connections[i].keyrequests.head = 0; |
connections[i].keyrequests.tail = 0; |
connections[i].keyrequests.items = MAX_KEYREQUESTS_BUFFERED; |
connections[i].keyrequest_counter = 0; |
if (screenbuffer_init(&connections[i].screenbuffer, |
fb_info.cols, fb_info.rows) == NULL) { |
/* FIXME: handle error */ |
return -1; |
} |
} |
connections[KERNEL_CONSOLE].used = 1; |
/* Set up shared memory buffer. */ |
ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows; |
size_t ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows; |
interbuffer = as_get_mappable_page(ib_size); |
fb_pending.cnt = 0; |
if (as_area_create(interbuffer, ib_size, AS_AREA_READ | |
AS_AREA_WRITE | AS_AREA_CACHEABLE) != interbuffer) { |
AS_AREA_WRITE | AS_AREA_CACHEABLE) != interbuffer) |
interbuffer = NULL; |
} |
if (interbuffer) { |
if (ipc_share_out_start(fb_info.phone, interbuffer, |
740,14 → 770,45 |
} |
} |
fb_pending.cnt = 0; |
/* Inititalize consoles */ |
size_t i; |
for (i = 0; i < CONSOLE_COUNT; i++) { |
if (i != KERNEL_CONSOLE) { |
if (screenbuffer_init(&consoles[i].scr, |
fb_info.cols, fb_info.rows) == NULL) { |
printf(NAME ": Unable to allocate screen buffer %u\n", i); |
async_serialize_end(); |
return false; |
} |
screenbuffer_clear(&consoles[i].scr); |
keybuffer_init(&consoles[i].keybuffer); |
consoles[i].index = i; |
consoles[i].refcount = 0; |
char vc[MAX_DEVICE_NAME]; |
snprintf(vc, MAX_DEVICE_NAME, "vc%u", i); |
if (devmap_device_register(vc, &consoles[i].dev_handle) != EOK) { |
devmap_hangup_phone(DEVMAP_DRIVER); |
printf(NAME ": Unable to register device %s\n", vc); |
async_serialize_end(); |
return false; |
} |
} |
} |
/* Disable kernel output to the console */ |
__SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE); |
/* Initialize the screen */ |
gcons_redraw_console(); |
set_rgb_color(DEFAULT_FOREGROUND, DEFAULT_BACKGROUND); |
screen_clear(); |
curs_goto(0, 0); |
curs_visibility( |
connections[active_console].screenbuffer.is_cursor_visible); |
curs_visibility(active_console->scr.is_cursor_visible); |
/* Register at NS */ |
if (ipc_connect_to_me(PHONE_NS, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) |
return -1; |
/* Receive kernel notifications */ |
if (event_subscribe(EVENT_KCONSOLE, 0) != EOK) |
printf(NAME ": Error registering kconsole notifications\n"); |
754,8 → 815,18 |
async_set_interrupt_received(interrupt_received); |
// FIXME: avoid connectiong to itself, keep using klog |
// printf(NAME ": Accepting connections\n"); |
async_serialize_end(); |
return true; |
} |
int main(int argc, char *argv[]) |
{ |
printf(NAME ": HelenOS Console service\n"); |
if (!console_init()) |
return -1; |
printf(NAME ": Accepting connections\n"); |
async_manager(); |
return 0; |
/branches/dd/uspace/srv/console/gcons.c |
---|
39,6 → 39,7 |
#include <sys/mman.h> |
#include <string.h> |
#include <align.h> |
#include <bool.h> |
#include "console.h" |
#include "gcons.h" |
54,8 → 55,9 |
#define MAIN_COLOR 0xffffff |
static int use_gcons = 0; |
static ipcarg_t xres,yres; |
static bool use_gcons = false; |
static ipcarg_t xres; |
static ipcarg_t yres; |
enum butstate { |
CONS_DISCONNECTED = 0, |
77,8 → 79,15 |
static int ic_pixmaps[CONS_LAST] = {-1, -1, -1, -1, -1, -1}; |
static int animation = -1; |
static int active_console = 0; |
static size_t active_console = 0; |
size_t mouse_x; |
size_t mouse_y; |
bool btn_pressed; |
size_t btn_x; |
size_t btn_y; |
static void vp_switch(int vp) |
{ |
async_msg_1(fbphone, FB_VIEWPORT_SWITCH, vp); |
85,8 → 94,7 |
} |
/** Create view port */ |
static int vp_create(unsigned int x, unsigned int y, unsigned int width, |
unsigned int height) |
static int vp_create(size_t x, size_t y, size_t width, size_t height) |
{ |
return async_req_2_0(fbphone, FB_VIEWPORT_CREATE, (x << 16) | y, |
(width << 16) | height); |
97,48 → 105,52 |
async_msg_0(fbphone, FB_CLEAR); |
} |
static void set_rgb_color(int fgcolor, int bgcolor) |
static void set_rgb_color(uint32_t fgcolor, uint32_t bgcolor) |
{ |
async_msg_2(fbphone, FB_SET_RGB_COLOR, fgcolor, bgcolor); |
} |
/** Transparent putchar */ |
static void tran_putch(char c, int row, int col) |
static void tran_putch(wchar_t ch, size_t col, size_t row) |
{ |
async_msg_3(fbphone, FB_PUTCHAR, c, row, col); |
async_msg_3(fbphone, FB_PUTCHAR, ch, col, row); |
} |
/** Redraw the button showing state of a given console */ |
static void redraw_state(int consnum) |
static void redraw_state(size_t index) |
{ |
char data[5]; |
int i; |
enum butstate state = console_state[consnum]; |
vp_switch(cstatus_vp[index]); |
vp_switch(cstatus_vp[consnum]); |
enum butstate state = console_state[index]; |
if (ic_pixmaps[state] != -1) |
async_msg_2(fbphone, FB_VP_DRAW_PIXMAP, cstatus_vp[consnum], |
async_msg_2(fbphone, FB_VP_DRAW_PIXMAP, cstatus_vp[index], |
ic_pixmaps[state]); |
if (state != CONS_DISCONNECTED && state != CONS_KERNEL && |
state != CONS_DISCONNECTED_SEL) { |
snprintf(data, 5, "%d", consnum + 1); |
for (i = 0; data[i]; i++) |
tran_putch(data[i], 1, 2 + i); |
if ((state != CONS_DISCONNECTED) && (state != CONS_KERNEL) |
&& (state != CONS_DISCONNECTED_SEL)) { |
char data[5]; |
snprintf(data, 5, "%u", index + 1); |
size_t i; |
for (i = 0; data[i] != 0; i++) |
tran_putch(data[i], 2 + i, 1); |
} |
} |
/** Notification run on changing console (except kernel console) */ |
void gcons_change_console(int consnum) |
void gcons_change_console(size_t index) |
{ |
int i; |
if (!use_gcons) |
return; |
if (active_console == KERNEL_CONSOLE) { |
size_t i; |
for (i = 0; i < CONSOLE_COUNT; i++) |
redraw_state(i); |
if (animation != -1) |
async_msg_1(fbphone, FB_ANIM_START, animation); |
} else { |
146,73 → 158,74 |
console_state[active_console] = CONS_DISCONNECTED; |
else |
console_state[active_console] = CONS_IDLE; |
redraw_state(active_console); |
} |
active_console = consnum; |
if (console_state[consnum] == CONS_DISCONNECTED) { |
console_state[consnum] = CONS_DISCONNECTED_SEL; |
redraw_state(consnum); |
} else |
console_state[consnum] = CONS_SELECTED; |
redraw_state(consnum); |
active_console = index; |
if ((console_state[index] == CONS_DISCONNECTED) |
|| (console_state[index] == CONS_DISCONNECTED_SEL)) |
console_state[index] = CONS_DISCONNECTED_SEL; |
else |
console_state[index] = CONS_SELECTED; |
redraw_state(index); |
vp_switch(console_vp); |
} |
/** Notification function that gets called on new output to virtual console */ |
void gcons_notify_char(int consnum) |
void gcons_notify_char(size_t index) |
{ |
if (!use_gcons) |
return; |
if ((consnum == active_console) || |
(console_state[consnum] == CONS_HAS_DATA)) |
if ((index == active_console) |
|| (console_state[index] == CONS_HAS_DATA)) |
return; |
console_state[consnum] = CONS_HAS_DATA; |
console_state[index] = CONS_HAS_DATA; |
if (active_console == KERNEL_CONSOLE) |
return; |
redraw_state(consnum); |
redraw_state(index); |
vp_switch(console_vp); |
} |
/** Notification function called on service disconnect from console */ |
void gcons_notify_disconnect(int consnum) |
void gcons_notify_disconnect(size_t index) |
{ |
if (!use_gcons) |
return; |
if (active_console == consnum) |
console_state[consnum] = CONS_DISCONNECTED_SEL; |
if (index == active_console) |
console_state[index] = CONS_DISCONNECTED_SEL; |
else |
console_state[consnum] = CONS_DISCONNECTED; |
console_state[index] = CONS_DISCONNECTED; |
if (active_console == KERNEL_CONSOLE) |
return; |
redraw_state(consnum); |
redraw_state(index); |
vp_switch(console_vp); |
} |
/** Notification function called on console connect */ |
void gcons_notify_connect(int consnum) |
void gcons_notify_connect(size_t index) |
{ |
if (!use_gcons) |
return; |
if (active_console == consnum) |
console_state[consnum] = CONS_SELECTED; |
if (index == active_console) |
console_state[index] = CONS_SELECTED; |
else |
console_state[consnum] = CONS_IDLE; |
console_state[index] = CONS_IDLE; |
if (active_console == KERNEL_CONSOLE) |
return; |
redraw_state(consnum); |
redraw_state(index); |
vp_switch(console_vp); |
} |
226,25 → 239,24 |
vp_switch(0); |
} |
/** Return x, where left <= x <= right && |a-x|==min(|a-x|) is smallest */ |
static inline int limit(int a, int left, int right) |
/** Return x, where left <= x <= right && |a-x| == min(|a-x|) is smallest */ |
static inline int limit(size_t a, size_t left, size_t right) |
{ |
if (a < left) |
a = left; |
if (a >= right) |
a = right - 1; |
return a; |
} |
int mouse_x, mouse_y; |
int btn_pressed, btn_x, btn_y; |
/** Handle mouse move |
* |
* @param dx Delta X of mouse move |
* @param dy Delta Y of mouse move |
*/ |
void gcons_mouse_move(int dx, int dy) |
void gcons_mouse_move(ssize_t dx, ssize_t dy) |
{ |
mouse_x = limit(mouse_x + dx, 0, xres); |
mouse_y = limit(mouse_y + dy, 0, yres); |
272,9 → 284,9 |
/** Handle mouse click |
* |
* @param state New state (1-pressed, 0-depressed) |
* @param state New state (true - pressed, false - depressed) |
*/ |
int gcons_mouse_btn(int state) |
int gcons_mouse_btn(bool state) |
{ |
int conbut; |
281,7 → 293,7 |
if (state) { |
conbut = gcons_find_conbut(mouse_x, mouse_y); |
if (conbut != -1) { |
btn_pressed = 1; |
btn_pressed = true; |
btn_x = mouse_x; |
btn_y = mouse_y; |
} |
291,7 → 303,7 |
if ((!state) && (!btn_pressed)) |
return -1; |
btn_pressed = 0; |
btn_pressed = false; |
conbut = gcons_find_conbut(mouse_x, mouse_y); |
if (conbut == gcons_find_conbut(btn_x, btn_y)) |
373,9 → 385,11 |
* |
* @param data PPM data |
* @param size PPM data size |
* |
* @return Pixmap identification |
* |
*/ |
static int make_pixmap(char *data, int size) |
static int make_pixmap(char *data, size_t size) |
{ |
char *shm; |
int rc; |
464,13 → 478,9 |
/** Initialize nice graphical console environment */ |
void gcons_init(int phone) |
{ |
int rc; |
int i; |
int status_start = STATUS_START; |
fbphone = phone; |
rc = async_req_0_2(phone, FB_GET_RESOLUTION, &xres, &yres); |
int rc = async_req_0_2(phone, FB_GET_RESOLUTION, &xres, &yres); |
if (rc) |
return; |
483,17 → 493,21 |
console_vp = vp_create(CONSOLE_MARGIN, CONSOLE_TOP, |
ALIGN_DOWN(xres - 2 * CONSOLE_MARGIN, 8), |
ALIGN_DOWN(yres - (CONSOLE_TOP + CONSOLE_MARGIN), 16)); |
if (console_vp < 0) |
return; |
/* Create status buttons */ |
status_start += (xres - 800) / 2; |
size_t status_start = STATUS_START + (xres - 800) / 2; |
size_t i; |
for (i = 0; i < CONSOLE_COUNT; i++) { |
cstatus_vp[i] = vp_create(status_start + CONSOLE_MARGIN + |
i * (STATUS_WIDTH + STATUS_SPACE), STATUS_TOP, |
STATUS_WIDTH, STATUS_HEIGHT); |
if (cstatus_vp[i] < 0) |
return; |
vp_switch(cstatus_vp[i]); |
set_rgb_color(0x202020, 0xffffff); |
} |
501,27 → 515,28 |
/* Initialize icons */ |
ic_pixmaps[CONS_SELECTED] = |
make_pixmap(_binary_gfx_cons_selected_ppm_start, |
(int) &_binary_gfx_cons_selected_ppm_size); |
(size_t) &_binary_gfx_cons_selected_ppm_size); |
ic_pixmaps[CONS_IDLE] = |
make_pixmap(_binary_gfx_cons_idle_ppm_start, |
(int) &_binary_gfx_cons_idle_ppm_size); |
(size_t) &_binary_gfx_cons_idle_ppm_size); |
ic_pixmaps[CONS_HAS_DATA] = |
make_pixmap(_binary_gfx_cons_has_data_ppm_start, |
(int) &_binary_gfx_cons_has_data_ppm_size); |
(size_t) &_binary_gfx_cons_has_data_ppm_size); |
ic_pixmaps[CONS_DISCONNECTED] = |
make_pixmap(_binary_gfx_cons_idle_ppm_start, |
(int) &_binary_gfx_cons_idle_ppm_size); |
(size_t) &_binary_gfx_cons_idle_ppm_size); |
ic_pixmaps[CONS_KERNEL] = |
make_pixmap(_binary_gfx_cons_kernel_ppm_start, |
(int) &_binary_gfx_cons_kernel_ppm_size); |
(size_t) &_binary_gfx_cons_kernel_ppm_size); |
ic_pixmaps[CONS_DISCONNECTED_SEL] = ic_pixmaps[CONS_SELECTED]; |
make_anim(); |
use_gcons = 1; |
use_gcons = true; |
console_state[0] = CONS_DISCONNECTED_SEL; |
console_state[KERNEL_CONSOLE] = CONS_KERNEL; |
gcons_redraw_console(); |
vp_switch(console_vp); |
} |
/** @} |
/branches/dd/uspace/srv/console/screenbuffer.c |
---|
33,7 → 33,7 |
*/ |
#include <screenbuffer.h> |
#include <console/style.h> |
#include <io/style.h> |
#include <malloc.h> |
#include <unistd.h> |
66,7 → 66,7 |
* @return Pointer to screenbuffer (same as scr parameter) or NULL |
* |
*/ |
screenbuffer_t *screenbuffer_init(screenbuffer_t *scr, int size_x, int size_y) |
screenbuffer_t *screenbuffer_init(screenbuffer_t *scr, size_t size_x, size_t size_y) |
{ |
scr->buffer = (keyfield_t *) malloc(sizeof(keyfield_t) * size_x * size_y); |
if (!scr->buffer) |
90,7 → 90,7 |
*/ |
void screenbuffer_clear(screenbuffer_t *scr) |
{ |
unsigned int i; |
size_t i; |
for (i = 0; i < (scr->size_x * scr->size_y); i++) { |
scr->buffer[i].character = ' '; |
98,8 → 98,8 |
} |
scr->top_line = 0; |
scr->position_x = 0; |
scr->position_y = 0; |
scr->position_x = 0; |
} |
/** Clear one buffer line. |
108,13 → 108,13 |
* @param line One buffer line (not a screen line!) |
* |
*/ |
void screenbuffer_clear_line(screenbuffer_t *scr, unsigned int line) |
void screenbuffer_clear_line(screenbuffer_t *scr, size_t line) |
{ |
unsigned int i; |
size_t x; |
for (i = 0; i < scr->size_x; i++) { |
scr->buffer[i + line * scr->size_x].character = ' '; |
scr->buffer[i + line * scr->size_x].attrs = scr->attrs; |
for (x = 0; x < scr->size_x; x++) { |
scr->buffer[x + line * scr->size_x].character = ' '; |
scr->buffer[x + line * scr->size_x].attrs = scr->attrs; |
} |
} |
124,11 → 124,11 |
* @param dest Destination |
* |
*/ |
void screenbuffer_copy_buffer(screenbuffer_t *scr, keyfield_t *dest) |
void screenbuffer_copy_buffer(screenbuffer_t *scr, keyfield_t *dest) |
{ |
unsigned int i; |
size_t i; |
for (i = 0; i < scr->size_x * scr->size_y; i++) |
for (i = 0; i < (scr->size_x * scr->size_y); i++) |
dest[i] = scr->buffer[i]; |
} |
139,7 → 139,7 |
* @param y |
* |
*/ |
void screenbuffer_goto(screenbuffer_t *scr, unsigned int x, unsigned int y) |
void screenbuffer_goto(screenbuffer_t *scr, size_t x, size_t y) |
{ |
scr->position_x = x % scr->size_x; |
scr->position_y = y % scr->size_y; |
152,7 → 152,7 |
* @param bg_color |
* |
*/ |
void screenbuffer_set_style(screenbuffer_t *scr, int style) |
void screenbuffer_set_style(screenbuffer_t *scr, uint8_t style) |
{ |
scr->attrs.t = at_style; |
scr->attrs.a.s.style = style; |
165,7 → 165,7 |
* @param bg_color |
* |
*/ |
void screenbuffer_set_color(screenbuffer_t *scr, unsigned int fg_color, unsigned int bg_color, unsigned int flags) |
void screenbuffer_set_color(screenbuffer_t *scr, uint8_t fg_color, uint8_t bg_color, uint8_t flags) |
{ |
scr->attrs.t = at_idx; |
scr->attrs.a.i.fg_color = fg_color; |
180,7 → 180,7 |
* @param bg_color |
* |
*/ |
void screenbuffer_set_rgb_color(screenbuffer_t *scr, unsigned int fg_color, unsigned int bg_color) |
void screenbuffer_set_rgb_color(screenbuffer_t *scr, uint32_t fg_color, uint32_t bg_color) |
{ |
scr->attrs.t = at_rgb; |
scr->attrs.a.r.fg_color = fg_color; |
/branches/dd/uspace/srv/console/Makefile |
---|
46,7 → 46,7 |
GENERIC_SOURCES = \ |
console.c \ |
screenbuffer.c \ |
../kbd/generic/key_buffer.c \ |
../kbd/generic/keybuffer.c \ |
gcons.c |
IMAGES = \ |
/branches/dd/uspace/srv/bd/file_bd/file_bd.c |
---|
0,0 → 1,217 |
/* |
* Copyright (c) 2009 Jiri Svoboda |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup bd |
* @{ |
*/ |
/** |
* @file |
* @brief File-backed block device driver |
* |
* Allows accessing a file as a block device. Useful for, e.g., mounting |
* a disk image. |
*/ |
#include <stdio.h> |
#include <unistd.h> |
#include <ipc/ipc.h> |
#include <ipc/bd.h> |
#include <async.h> |
#include <as.h> |
#include <futex.h> |
#include <devmap.h> |
#include <sys/types.h> |
#include <errno.h> |
#include <bool.h> |
#define NAME "file_bd" |
static size_t comm_size; |
static FILE *img; |
static dev_handle_t dev_handle; |
static atomic_t dev_futex = FUTEX_INITIALIZER; |
static int file_bd_init(const char *fname); |
static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall); |
static int file_bd_read(off_t blk_idx, off_t size, void *buf); |
static int file_bd_write(off_t blk_idx, off_t size, void *buf); |
int main(int argc, char **argv) |
{ |
int rc; |
printf(NAME ": File-backed block device driver\n"); |
if (argc != 3) { |
printf("Expected two arguments (image name, device name).\n"); |
return -1; |
} |
if (file_bd_init(argv[1]) != EOK) |
return -1; |
rc = devmap_device_register(argv[2], &dev_handle); |
if (rc != EOK) { |
devmap_hangup_phone(DEVMAP_DRIVER); |
printf(NAME ": Unable to register device %s.\n", |
argv[2]); |
return rc; |
} |
printf(NAME ": Accepting connections\n"); |
async_manager(); |
/* Not reached */ |
return 0; |
} |
static int file_bd_init(const char *fname) |
{ |
int rc; |
rc = devmap_driver_register(NAME, file_bd_connection); |
if (rc < 0) { |
printf(NAME ": Unable to register driver.\n"); |
return rc; |
} |
img = fopen(fname, "rb+"); |
if (img == NULL) |
return EINVAL; |
return EOK; |
} |
static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall) |
{ |
void *fs_va = NULL; |
ipc_callid_t callid; |
ipc_call_t call; |
ipcarg_t method; |
int flags; |
int retval; |
off_t idx; |
off_t size; |
/* Answer the IPC_M_CONNECT_ME_TO call. */ |
ipc_answer_0(iid, EOK); |
if (!ipc_share_out_receive(&callid, &comm_size, &flags)) { |
ipc_answer_0(callid, EHANGUP); |
return; |
} |
fs_va = as_get_mappable_page(comm_size); |
if (fs_va == NULL) { |
ipc_answer_0(callid, EHANGUP); |
return; |
} |
(void) ipc_share_out_finalize(callid, fs_va); |
while (1) { |
callid = async_get_call(&call); |
method = IPC_GET_METHOD(call); |
switch (method) { |
case IPC_M_PHONE_HUNGUP: |
/* The other side has hung up. */ |
ipc_answer_0(callid, EOK); |
return; |
case BD_READ_BLOCK: |
case BD_WRITE_BLOCK: |
idx = IPC_GET_ARG1(call); |
size = IPC_GET_ARG2(call); |
if (size > comm_size) { |
retval = EINVAL; |
break; |
} |
if (method == BD_READ_BLOCK) |
retval = file_bd_read(idx, size, fs_va); |
else |
retval = file_bd_write(idx, size, fs_va); |
break; |
default: |
retval = EINVAL; |
break; |
} |
ipc_answer_0(callid, retval); |
} |
} |
static int file_bd_read(off_t blk_idx, off_t size, void *buf) |
{ |
size_t n_rd; |
printf("file_bd_read\n"); |
futex_down(&dev_futex); |
printf("seek\n"); |
fseek(img, blk_idx * size, SEEK_SET); |
printf("read\n"); |
n_rd = fread(buf, 1, size, img); |
printf("done\n"); |
printf("done\n"); |
if (ferror(img)) { |
futex_up(&dev_futex); |
return EIO; /* Read error */ |
} |
futex_up(&dev_futex); |
if (n_rd < size) |
return EINVAL; /* Read beyond end of disk */ |
return EOK; |
} |
static int file_bd_write(off_t blk_idx, off_t size, void *buf) |
{ |
size_t n_wr; |
futex_down(&dev_futex); |
fseek(img, blk_idx * size, SEEK_SET); |
n_wr = fread(buf, 1, size, img); |
if (ferror(img) || n_wr < size) { |
futex_up(&dev_futex); |
return EIO; /* Write error */ |
} |
futex_up(&dev_futex); |
return EOK; |
} |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/bd/file_bd/Makefile |
---|
0,0 → 1,76 |
# |
# Copyright (c) 2006 Martin Decky |
# All rights reserved. |
# |
# Redistribution and use in source and binary forms, with or without |
# modification, are permitted provided that the following conditions |
# are met: |
# |
# - Redistributions of source code must retain the above copyright |
# notice, this list of conditions and the following disclaimer. |
# - Redistributions in binary form must reproduce the above copyright |
# notice, this list of conditions and the following disclaimer in the |
# documentation and/or other materials provided with the distribution. |
# - The name of the author may not be used to endorse or promote products |
# derived from this software without specific prior written permission. |
# |
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
# |
## Setup toolchain |
# |
LIBC_PREFIX = ../../../lib/libc |
SOFTINT_PREFIX = ../../../lib/softint |
include $(LIBC_PREFIX)/Makefile.toolchain |
LIBS = $(LIBC_PREFIX)/libc.a |
## Sources |
# |
OUTPUT = file_bd |
SOURCES = \ |
file_bd.c |
OBJECTS := $(addsuffix .o,$(basename $(SOURCES))) |
.PHONY: all clean depend disasm |
all: $(OUTPUT) $(OUTPUT).disasm |
-include Makefile.depend |
clean: |
-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS) |
depend: |
$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend |
$(OUTPUT): $(OBJECTS) $(LIBS) |
$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map |
disasm: $(OUTPUT).disasm |
$(OUTPUT).disasm: $(OUTPUT) |
$(OBJDUMP) -d $< > $@ |
%.o: %.S |
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@ |
%.o: %.s |
$(AS) $(AFLAGS) $< -o $@ |
%.o: %.c |
$(CC) $(DEFS) $(CFLAGS) -c $< -o $@ |
/branches/dd/uspace/srv/bd/gxe_bd/gxe_bd.c |
---|
58,6 → 58,10 |
STATUS_FAILURE = 0 |
}; |
enum { |
MAX_DISKS = 2 |
}; |
typedef struct { |
uint32_t offset_lo; |
uint32_t pad0; |
72,17 → 76,12 |
uint32_t status; |
/* FIXME: Need to fix pio_enable() to support >= page_size areas. |
uint32_t pad4[3]; |
uint32_t pad5[0x3fc0]; |
uint8_t pad5[0x3fc0]; |
uint8_t buffer[512];*/ |
uint8_t buffer[512]; |
} gxe_bd_t; |
typedef struct { |
uint8_t buffer[512]; |
} gxe_buf_t; |
static const size_t block_size = 512; |
static size_t comm_size; |
89,17 → 88,19 |
static uintptr_t dev_physical = 0x13000000; |
static gxe_bd_t *dev; |
static gxe_buf_t *devbuf; |
static uint32_t disk_id = 0; |
static dev_handle_t dev_handle[MAX_DISKS]; |
static atomic_t dev_futex = FUTEX_INITIALIZER; |
static int gxe_bd_init(void); |
static void gxe_bd_connection(ipc_callid_t iid, ipc_call_t *icall); |
static int gx_bd_rdwr(ipcarg_t method, off_t offset, off_t size, void *buf); |
static int gxe_bd_read_block(uint64_t offset, size_t size, void *buf); |
static int gxe_bd_write_block(uint64_t offset, size_t size, const void *buf); |
static int gx_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, off_t size, |
void *buf); |
static int gxe_bd_read_block(int disk_id, uint64_t offset, size_t size, |
void *buf); |
static int gxe_bd_write_block(int disk_id, uint64_t offset, size_t size, |
const void *buf); |
int main(int argc, char **argv) |
{ |
117,9 → 118,9 |
static int gxe_bd_init(void) |
{ |
dev_handle_t dev_handle; |
void *vaddr; |
int rc; |
int rc, i; |
char name[16]; |
rc = devmap_driver_register(NAME, gxe_bd_connection); |
if (rc < 0) { |
135,21 → 136,17 |
dev = vaddr; |
rc = pio_enable((void *) dev_physical + 0x4000, sizeof(gxe_buf_t), &vaddr); |
if (rc != EOK) { |
printf(NAME ": Could not initialize device I/O space.\n"); |
return rc; |
for (i = 0; i < MAX_DISKS; i++) { |
snprintf(name, 16, "disk%d", i); |
rc = devmap_device_register(name, &dev_handle[i]); |
if (rc != EOK) { |
devmap_hangup_phone(DEVMAP_DRIVER); |
printf(NAME ": Unable to register device %s.\n", |
name); |
return rc; |
} |
} |
devbuf = vaddr; |
rc = devmap_device_register("disk0", &dev_handle); |
if (rc != EOK) { |
devmap_hangup_phone(DEVMAP_DRIVER); |
printf(NAME ": Unable to register device.\n"); |
return rc; |
} |
return EOK; |
} |
159,11 → 156,27 |
ipc_callid_t callid; |
ipc_call_t call; |
ipcarg_t method; |
dev_handle_t dh; |
int flags; |
int retval; |
off_t idx; |
off_t size; |
int disk_id, i; |
/* Get the device handle. */ |
dh = IPC_GET_ARG1(*icall); |
/* Determine which disk device is the client connecting to. */ |
disk_id = -1; |
for (i = 0; i < MAX_DISKS; i++) |
if (dev_handle[i] == dh) |
disk_id = i; |
if (disk_id < 0) { |
ipc_answer_0(iid, EINVAL); |
return; |
} |
/* Answer the IPC_M_CONNECT_ME_TO call. */ |
ipc_answer_0(iid, EOK); |
196,7 → 209,8 |
retval = EINVAL; |
break; |
} |
retval = gx_bd_rdwr(method, idx * size, size, fs_va); |
retval = gx_bd_rdwr(disk_id, method, idx * size, |
size, fs_va); |
break; |
default: |
retval = EINVAL; |
206,7 → 220,8 |
} |
} |
static int gx_bd_rdwr(ipcarg_t method, off_t offset, off_t size, void *buf) |
static int gx_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, off_t size, |
void *buf) |
{ |
int rc; |
size_t now; |
215,9 → 230,9 |
now = size < block_size ? size : block_size; |
if (method == BD_READ_BLOCK) |
rc = gxe_bd_read_block(offset, now, buf); |
rc = gxe_bd_read_block(disk_id, offset, now, buf); |
else |
rc = gxe_bd_write_block(offset, now, buf); |
rc = gxe_bd_write_block(disk_id, offset, now, buf); |
if (rc != EOK) |
return rc; |
234,7 → 249,8 |
return EOK; |
} |
static int gxe_bd_read_block(uint64_t offset, size_t size, void *buf) |
static int gxe_bd_read_block(int disk_id, uint64_t offset, size_t size, |
void *buf) |
{ |
uint32_t status; |
size_t i; |
252,8 → 268,7 |
} |
for (i = 0; i < size; i++) { |
((uint8_t *) buf)[i] = w = |
pio_read_8(&devbuf->buffer[i]); |
((uint8_t *) buf)[i] = w = pio_read_8(&dev->buffer[i]); |
} |
futex_up(&dev_futex); |
260,14 → 275,14 |
return EOK; |
} |
static int gxe_bd_write_block(uint64_t offset, size_t size, const void *buf) |
static int gxe_bd_write_block(int disk_id, uint64_t offset, size_t size, |
const void *buf) |
{ |
uint32_t status; |
size_t i; |
uint32_t w; |
for (i = 0; i < size; i++) { |
pio_write_8(&devbuf->buffer[i], ((const uint8_t *) buf)[i]); |
pio_write_8(&dev->buffer[i], ((const uint8_t *) buf)[i]); |
} |
futex_down(&dev_futex); |
/branches/dd/uspace/srv/bd/ata_bd/ata_bd.c |
---|
0,0 → 1,440 |
/* |
* Copyright (c) 2009 Jiri Svoboda |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup bd |
* @{ |
*/ |
/** |
* @file |
* @brief ATA disk driver |
* |
* This driver currently works only with CHS addressing and uses PIO. |
* Currently based on the (now obsolete) ANSI X3.221-1994 (ATA-1) standard. |
* At this point only reading is possible, not writing. |
*/ |
#include <stdio.h> |
#include <libarch/ddi.h> |
#include <ddi.h> |
#include <ipc/ipc.h> |
#include <ipc/bd.h> |
#include <async.h> |
#include <as.h> |
#include <futex.h> |
#include <devmap.h> |
#include <sys/types.h> |
#include <errno.h> |
#include <bool.h> |
#include "ata_bd.h" |
#define NAME "ata_bd" |
static const size_t block_size = 512; |
static size_t comm_size; |
static uintptr_t cmd_physical = 0x1f0; |
static uintptr_t ctl_physical = 0x170; |
static ata_cmd_t *cmd; |
static ata_ctl_t *ctl; |
static dev_handle_t dev_handle[MAX_DISKS]; |
static atomic_t dev_futex = FUTEX_INITIALIZER; |
static disk_t disk[MAX_DISKS]; |
static int ata_bd_init(void); |
static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall); |
static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, off_t size, |
void *buf); |
static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt, |
void *buf); |
static int ata_bd_write_block(int disk_id, uint64_t blk_idx, size_t blk_cnt, |
const void *buf); |
static int drive_identify(int drive_id, disk_t *d); |
int main(int argc, char **argv) |
{ |
uint8_t status; |
char name[16]; |
int i, rc; |
int n_disks; |
printf(NAME ": ATA disk driver\n"); |
printf("cmd_physical = 0x%x\n", cmd_physical); |
printf("ctl_physical = 0x%x\n", ctl_physical); |
if (ata_bd_init() != EOK) |
return -1; |
/* Put drives to reset, disable interrupts. */ |
printf("Reset drives...\n"); |
pio_write_8(&ctl->device_control, DCR_SRST); |
/* FIXME: Find out how to do this properly. */ |
async_usleep(100); |
pio_write_8(&ctl->device_control, 0); |
do { |
status = pio_read_8(&cmd->status); |
} while ((status & SR_BSY) != 0); |
printf("Done\n"); |
printf("Status = 0x%x\n", pio_read_8(&cmd->status)); |
(void) drive_identify(0, &disk[0]); |
(void) drive_identify(1, &disk[1]); |
n_disks = 0; |
for (i = 0; i < MAX_DISKS; i++) { |
/* Skip unattached drives. */ |
if (disk[i].present == false) |
continue; |
snprintf(name, 16, "disk%d", i); |
rc = devmap_device_register(name, &dev_handle[i]); |
if (rc != EOK) { |
devmap_hangup_phone(DEVMAP_DRIVER); |
printf(NAME ": Unable to register device %s.\n", |
name); |
return rc; |
} |
++n_disks; |
} |
if (n_disks == 0) { |
printf("No disks detected.\n"); |
return -1; |
} |
printf(NAME ": Accepting connections\n"); |
async_manager(); |
/* Not reached */ |
return 0; |
} |
static int drive_identify(int disk_id, disk_t *d) |
{ |
uint16_t data; |
uint8_t status; |
int i; |
printf("Identify drive %d\n", disk_id); |
pio_write_8(&cmd->drive_head, ((disk_id != 0) ? DHR_DRV : 0)); |
async_usleep(100); |
pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE); |
status = pio_read_8(&cmd->status); |
printf("Status = 0x%x\n", status); |
d->present = false; |
/* |
* Detect if drive is present. This is Qemu only! Need to |
* do the right thing to work with real drives. |
*/ |
if ((status & SR_DRDY) == 0) { |
printf("None attached.\n"); |
return ENOENT; |
} |
for (i = 0; i < block_size / 2; i++) { |
do { |
status = pio_read_8(&cmd->status); |
} while ((status & SR_DRDY) == 0); |
data = pio_read_16(&cmd->data_port); |
switch (i) { |
case 1: d->cylinders = data; break; |
case 3: d->heads = data; break; |
case 6: d->sectors = data; break; |
} |
} |
printf("\n\nStatus = 0x%x\n", pio_read_8(&cmd->status)); |
d->blocks = d->cylinders * d->heads * d->sectors; |
printf("Geometry: %u cylinders, %u heads, %u sectors\n", |
d->cylinders, d->heads, d->sectors); |
d->present = true; |
return EOK; |
} |
static int ata_bd_init(void) |
{ |
void *vaddr; |
int rc; |
rc = devmap_driver_register(NAME, ata_bd_connection); |
if (rc < 0) { |
printf(NAME ": Unable to register driver.\n"); |
return rc; |
} |
rc = pio_enable((void *) cmd_physical, sizeof(ata_cmd_t), &vaddr); |
if (rc != EOK) { |
printf(NAME ": Could not initialize device I/O space.\n"); |
return rc; |
} |
cmd = vaddr; |
rc = pio_enable((void *) ctl_physical, sizeof(ata_ctl_t), &vaddr); |
if (rc != EOK) { |
printf(NAME ": Could not initialize device I/O space.\n"); |
return rc; |
} |
ctl = vaddr; |
return EOK; |
} |
static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall) |
{ |
void *fs_va = NULL; |
ipc_callid_t callid; |
ipc_call_t call; |
ipcarg_t method; |
dev_handle_t dh; |
int flags; |
int retval; |
off_t idx; |
off_t size; |
int disk_id, i; |
/* Get the device handle. */ |
dh = IPC_GET_ARG1(*icall); |
/* Determine which disk device is the client connecting to. */ |
disk_id = -1; |
for (i = 0; i < MAX_DISKS; i++) |
if (dev_handle[i] == dh) |
disk_id = i; |
if (disk_id < 0 || disk[disk_id].present == false) { |
ipc_answer_0(iid, EINVAL); |
return; |
} |
/* Answer the IPC_M_CONNECT_ME_TO call. */ |
ipc_answer_0(iid, EOK); |
if (!ipc_share_out_receive(&callid, &comm_size, &flags)) { |
ipc_answer_0(callid, EHANGUP); |
return; |
} |
fs_va = as_get_mappable_page(comm_size); |
if (fs_va == NULL) { |
ipc_answer_0(callid, EHANGUP); |
return; |
} |
(void) ipc_share_out_finalize(callid, fs_va); |
while (1) { |
callid = async_get_call(&call); |
method = IPC_GET_METHOD(call); |
switch (method) { |
case IPC_M_PHONE_HUNGUP: |
/* The other side has hung up. */ |
ipc_answer_0(callid, EOK); |
return; |
case BD_READ_BLOCK: |
case BD_WRITE_BLOCK: |
idx = IPC_GET_ARG1(call); |
size = IPC_GET_ARG2(call); |
if (size > comm_size) { |
retval = EINVAL; |
break; |
} |
retval = ata_bd_rdwr(disk_id, method, idx, |
size, fs_va); |
break; |
default: |
retval = EINVAL; |
break; |
} |
ipc_answer_0(callid, retval); |
} |
} |
static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t blk_idx, off_t size, |
void *buf) |
{ |
int rc; |
off_t now; |
while (size > 0) { |
now = size < block_size ? size : (off_t) block_size; |
if (now != block_size) |
return EINVAL; |
if (method == BD_READ_BLOCK) |
rc = ata_bd_read_block(disk_id, blk_idx, 1, buf); |
else |
rc = ata_bd_write_block(disk_id, blk_idx, 1, buf); |
if (rc != EOK) |
return rc; |
buf += block_size; |
blk_idx++; |
if (size > block_size) |
size -= block_size; |
else |
size = 0; |
} |
return EOK; |
} |
static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt, |
void *buf) |
{ |
size_t i; |
uint16_t data; |
uint8_t status; |
uint64_t c, h, s; |
uint64_t idx; |
uint8_t drv_head; |
disk_t *d; |
d = &disk[disk_id]; |
/* Check device bounds. */ |
if (blk_idx >= d->blocks) |
return EINVAL; |
/* Compute CHS. */ |
c = blk_idx / (d->heads * d->sectors); |
idx = blk_idx % (d->heads * d->sectors); |
h = idx / d->sectors; |
s = 1 + (idx % d->sectors); |
/* New value for Drive/Head register */ |
drv_head = |
((disk_id != 0) ? DHR_DRV : 0) | |
(h & 0x0f); |
futex_down(&dev_futex); |
/* Program a Read Sectors operation. */ |
pio_write_8(&cmd->drive_head, drv_head); |
pio_write_8(&cmd->sector_count, 1); |
pio_write_8(&cmd->sector_number, s); |
pio_write_8(&cmd->cylinder_low, c & 0xff); |
pio_write_8(&cmd->cylinder_high, c >> 16); |
pio_write_8(&cmd->command, CMD_READ_SECTORS); |
/* Read data from the disk buffer. */ |
for (i = 0; i < block_size / 2; i++) { |
do { |
status = pio_read_8(&cmd->status); |
} while ((status & SR_DRDY) == 0); |
data = pio_read_16(&cmd->data_port); |
((uint16_t *) buf)[i] = data; |
} |
futex_up(&dev_futex); |
return EOK; |
} |
static int ata_bd_write_block(int disk_id, uint64_t blk_idx, size_t blk_cnt, |
const void *buf) |
{ |
size_t i; |
uint8_t status; |
uint64_t c, h, s; |
uint64_t idx; |
uint8_t drv_head; |
disk_t *d; |
d = &disk[disk_id]; |
/* Check device bounds. */ |
if (blk_idx >= d->blocks) |
return EINVAL; |
/* Compute CHS. */ |
c = blk_idx / (d->heads * d->sectors); |
idx = blk_idx % (d->heads * d->sectors); |
h = idx / d->sectors; |
s = 1 + (idx % d->sectors); |
/* New value for Drive/Head register */ |
drv_head = |
((disk_id != 0) ? DHR_DRV : 0) | |
(h & 0x0f); |
futex_down(&dev_futex); |
/* Program a Read Sectors operation. */ |
pio_write_8(&cmd->drive_head, drv_head); |
pio_write_8(&cmd->sector_count, 1); |
pio_write_8(&cmd->sector_number, s); |
pio_write_8(&cmd->cylinder_low, c & 0xff); |
pio_write_8(&cmd->cylinder_high, c >> 16); |
pio_write_8(&cmd->command, CMD_WRITE_SECTORS); |
/* Write data to the disk buffer. */ |
for (i = 0; i < block_size / 2; i++) { |
do { |
status = pio_read_8(&cmd->status); |
} while ((status & SR_DRDY) == 0); |
pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]); |
} |
futex_up(&dev_futex); |
return EOK; |
} |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/bd/ata_bd/ata_bd.h |
---|
0,0 → 1,137 |
/* |
* Copyright (c) 2009 Jiri Svoboda |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup bd |
* @{ |
*/ |
/** @file |
*/ |
#ifndef __ATA_BD_H__ |
#define __ATA_BD_H__ |
#include <sys/types.h> |
enum { |
CTL_READ_START = 0, |
CTL_WRITE_START = 1, |
}; |
enum { |
STATUS_FAILURE = 0 |
}; |
enum { |
MAX_DISKS = 2 |
}; |
typedef union { |
/* Read */ |
struct { |
uint8_t data_port; |
uint8_t error; |
uint8_t sector_count; |
uint8_t sector_number; |
uint8_t cylinder_low; |
uint8_t cylinder_high; |
uint8_t drive_head; |
uint8_t status; |
}; |
/* Write */ |
struct { |
uint8_t pad0[7]; |
uint8_t command; |
}; |
} ata_cmd_t; |
typedef union { |
/* Read */ |
struct { |
uint8_t pad0[6]; |
uint8_t alt_status; |
uint8_t drive_address; |
}; |
/* Write */ |
struct { |
uint8_t pad1[6]; |
uint8_t device_control; |
uint8_t pad2; |
}; |
} ata_ctl_t; |
enum devctl_bits { |
DCR_SRST = 0x04, /**< Software Reset */ |
DCR_nIEN = 0x02 /**< Interrupt Enable (negated) */ |
}; |
enum status_bits { |
SR_BSY = 0x80, /**< Busy */ |
SR_DRDY = 0x40, /**< Drive Ready */ |
SR_DWF = 0x20, /**< Drive Write Fault */ |
SR_DSC = 0x10, /**< Drive Seek Complete */ |
SR_DRQ = 0x08, /**< Data Request */ |
SR_CORR = 0x04, /**< Corrected Data */ |
SR_IDX = 0x02, /**< Index */ |
SR_ERR = 0x01 /**< Error */ |
}; |
enum drive_head_bits { |
DHR_DRV = 0x10 |
}; |
enum error_bits { |
ER_BBK = 0x80, /**< Bad Block Detected */ |
ER_UNC = 0x40, /**< Uncorrectable Data Error */ |
ER_MC = 0x20, /**< Media Changed */ |
ER_IDNF = 0x10, /**< ID Not Found */ |
ER_MCR = 0x08, /**< Media Change Request */ |
ER_ABRT = 0x04, /**< Aborted Command */ |
ER_TK0NF = 0x02, /**< Track 0 Not Found */ |
ER_AMNF = 0x01 /**< Address Mark Not Found */ |
}; |
enum ata_command { |
CMD_IDENTIFY_DRIVE = 0xEC, |
CMD_READ_SECTORS = 0x20, |
CMD_WRITE_SECTORS = 0x30 |
}; |
typedef struct { |
bool present; |
unsigned heads; |
unsigned cylinders; |
unsigned sectors; |
uint64_t blocks; |
} disk_t; |
#endif |
/** @} |
*/ |
/branches/dd/uspace/srv/bd/ata_bd/Makefile |
---|
0,0 → 1,76 |
# |
# Copyright (c) 2006 Martin Decky |
# All rights reserved. |
# |
# Redistribution and use in source and binary forms, with or without |
# modification, are permitted provided that the following conditions |
# are met: |
# |
# - Redistributions of source code must retain the above copyright |
# notice, this list of conditions and the following disclaimer. |
# - Redistributions in binary form must reproduce the above copyright |
# notice, this list of conditions and the following disclaimer in the |
# documentation and/or other materials provided with the distribution. |
# - The name of the author may not be used to endorse or promote products |
# derived from this software without specific prior written permission. |
# |
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
# |
## Setup toolchain |
# |
LIBC_PREFIX = ../../../lib/libc |
SOFTINT_PREFIX = ../../../lib/softint |
include $(LIBC_PREFIX)/Makefile.toolchain |
LIBS = $(LIBC_PREFIX)/libc.a |
## Sources |
# |
OUTPUT = ata_bd |
SOURCES = \ |
ata_bd.c |
OBJECTS := $(addsuffix .o,$(basename $(SOURCES))) |
.PHONY: all clean depend disasm |
all: $(OUTPUT) $(OUTPUT).disasm |
-include Makefile.depend |
clean: |
-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS) |
depend: |
$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend |
$(OUTPUT): $(OBJECTS) $(LIBS) |
$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map |
disasm: $(OUTPUT).disasm |
$(OUTPUT).disasm: $(OUTPUT) |
$(OBJDUMP) -d $< > $@ |
%.o: %.S |
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@ |
%.o: %.s |
$(AS) $(AFLAGS) $< -o $@ |
%.o: %.c |
$(CC) $(DEFS) $(CFLAGS) -c $< -o $@ |
/branches/dd/uspace/srv/loader/main.c |
---|
53,9 → 53,9 |
#include <ipc/services.h> |
#include <ipc/loader.h> |
#include <loader/pcb.h> |
#include <console.h> |
#include <errno.h> |
#include <async.h> |
#include <string.h> |
#include <as.h> |
#include <elf.h> |
76,6 → 76,13 |
/** Buffer holding all arguments */ |
static char *arg_buf = NULL; |
/** Number of preset files */ |
static int filc = 0; |
/** Preset files vector */ |
static char **filv = NULL; |
/** Buffer holding all preset files */ |
static fdi_node_t *fil_buf = NULL; |
static elf_info_t prog_info; |
static elf_info_t interp_info; |
84,7 → 91,7 |
/** Used to limit number of connections to one. */ |
static bool connected; |
static void loader_get_taskid(ipc_callid_t rid, ipc_call_t *request) |
static void ldr_get_taskid(ipc_callid_t rid, ipc_call_t *request) |
{ |
ipc_callid_t callid; |
task_id_t task_id; |
111,7 → 118,7 |
* @param rid |
* @param request |
*/ |
static void loader_set_pathname(ipc_callid_t rid, ipc_call_t *request) |
static void ldr_set_pathname(ipc_callid_t rid, ipc_call_t *request) |
{ |
ipc_callid_t callid; |
size_t len; |
147,7 → 154,7 |
* @param rid |
* @param request |
*/ |
static void loader_set_args(ipc_callid_t rid, ipc_call_t *request) |
static void ldr_set_args(ipc_callid_t rid, ipc_call_t *request) |
{ |
ipc_callid_t callid; |
size_t buf_size, arg_size; |
220,6 → 227,70 |
ipc_answer_0(rid, EOK); |
} |
/** Receive a call setting preset files of the program to execute. |
* |
* @param rid |
* @param request |
*/ |
static void ldr_set_files(ipc_callid_t rid, ipc_call_t *request) |
{ |
ipc_callid_t callid; |
size_t buf_size; |
if (!ipc_data_write_receive(&callid, &buf_size)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
} |
if ((buf_size % sizeof(fdi_node_t)) != 0) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
} |
if (fil_buf != NULL) { |
free(fil_buf); |
fil_buf = NULL; |
} |
if (filv != NULL) { |
free(filv); |
filv = NULL; |
} |
fil_buf = malloc(buf_size); |
if (!fil_buf) { |
ipc_answer_0(callid, ENOMEM); |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
ipc_data_write_finalize(callid, fil_buf, buf_size); |
int count = buf_size / sizeof(fdi_node_t); |
/* Allocate filvv */ |
filv = malloc((count + 1) * sizeof(fdi_node_t *)); |
if (filv == NULL) { |
free(fil_buf); |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
/* |
* Fill filv with argument pointers |
*/ |
int i; |
for (i = 0; i < count; i++) |
filv[i] = &fil_buf[i]; |
filc = count; |
filv[count] = NULL; |
ipc_answer_0(rid, EOK); |
} |
/** Load the previously selected program. |
* |
* @param rid |
226,7 → 297,7 |
* @param request |
* @return 0 on success, !0 on error. |
*/ |
static int loader_load(ipc_callid_t rid, ipc_call_t *request) |
static int ldr_load(ipc_callid_t rid, ipc_call_t *request) |
{ |
int rc; |
242,6 → 313,9 |
pcb.argc = argc; |
pcb.argv = argv; |
pcb.filc = filc; |
pcb.filv = filv; |
if (prog_info.interp == NULL) { |
/* Statically linked program */ |
is_dyn_linked = false; |
270,7 → 344,7 |
* @param request |
* @return 0 on success, !0 on error. |
*/ |
static void loader_run(ipc_callid_t rid, ipc_call_t *request) |
static void ldr_run(ipc_callid_t rid, ipc_call_t *request) |
{ |
const char *cp; |
283,17 → 357,15 |
/* Dynamically linked program */ |
DPRINTF("Run ELF interpreter.\n"); |
DPRINTF("Entry point: 0x%lx\n", interp_info.entry); |
console_close(); |
ipc_answer_0(rid, EOK); |
elf_run(&interp_info, &pcb); |
} else { |
/* Statically linked program */ |
console_close(); |
ipc_answer_0(rid, EOK); |
elf_run(&prog_info, &pcb); |
} |
} |
/* Not reached */ |
} |
302,7 → 374,7 |
* Receive and carry out commands (of which the last one should be |
* to execute the loaded program). |
*/ |
static void loader_connection(ipc_callid_t iid, ipc_call_t *icall) |
static void ldr_connection(ipc_callid_t iid, ipc_call_t *icall) |
{ |
ipc_callid_t callid; |
ipc_call_t call; |
330,19 → 402,22 |
case IPC_M_PHONE_HUNGUP: |
exit(0); |
case LOADER_GET_TASKID: |
loader_get_taskid(callid, &call); |
ldr_get_taskid(callid, &call); |
continue; |
case LOADER_SET_PATHNAME: |
loader_set_pathname(callid, &call); |
ldr_set_pathname(callid, &call); |
continue; |
case LOADER_SET_ARGS: |
loader_set_args(callid, &call); |
ldr_set_args(callid, &call); |
continue; |
case LOADER_SET_FILES: |
ldr_set_files(callid, &call); |
continue; |
case LOADER_LOAD: |
loader_load(callid, &call); |
ldr_load(callid, &call); |
continue; |
case LOADER_RUN: |
loader_run(callid, &call); |
ldr_run(callid, &call); |
/* Not reached */ |
default: |
retval = ENOENT; |
366,7 → 441,7 |
connected = false; |
/* Set a handler of incomming connections. */ |
async_set_client_connection(loader_connection); |
async_set_client_connection(ldr_connection); |
/* Register at naming service. */ |
if (ipc_connect_to_me(PHONE_NS, SERVICE_LOAD, 0, 0, &phonead) != 0) |
/branches/dd/uspace/srv/fb/ega.h |
---|
27,10 → 27,10 |
*/ |
/** @addtogroup egafb |
* @brief HelenOS EGA framebuffer. |
* @brief HelenOS EGA framebuffer. |
* @ingroup fbs |
* @{ |
*/ |
*/ |
/** @file |
*/ |
43,4 → 43,3 |
/** @} |
*/ |
/branches/dd/uspace/srv/fb/serial_console.c |
---|
43,8 → 43,9 |
#include <ipc/fb.h> |
#include <bool.h> |
#include <errno.h> |
#include <console/color.h> |
#include <console/style.h> |
#include <io/color.h> |
#include <io/style.h> |
#include <string.h> |
#include "../console/screenbuffer.h" |
#include "main.h" |
128,9 → 129,9 |
} |
void serial_goto(const unsigned int row, const unsigned int col) |
void serial_goto(const unsigned int col, const unsigned int row) |
{ |
if ((row > scr_height) || (col > scr_width)) |
if ((col > scr_width) || (row > scr_height)) |
return; |
char control[MAX_CONTROL]; |
153,7 → 154,7 |
void serial_scroll(int i) |
{ |
if (i > 0) { |
serial_goto(scr_height - 1, 0); |
serial_goto(0, scr_height - 1); |
while (i--) |
serial_puts("\033D"); |
} else if (i < 0) { |
235,17 → 236,24 |
if (fgcolor < bgcolor) |
serial_sgr(SGR_REVERSE_OFF); |
else |
serial_sgr(SGR_REVERSE); |
serial_sgr(SGR_REVERSE); |
} |
static void serial_set_attrs(const attrs_t *a) |
{ |
switch (a->t) { |
case at_style: serial_set_style(a->a.s.style); break; |
case at_rgb: serial_set_rgb(a->a.r.fg_color, a->a.r.bg_color); break; |
case at_idx: serial_set_idx(a->a.i.fg_color, |
a->a.i.bg_color, a->a.i.flags); break; |
default: break; |
case at_style: |
serial_set_style(a->a.s.style); |
break; |
case at_rgb: |
serial_set_rgb(a->a.r.fg_color, a->a.r.bg_color); |
break; |
case at_idx: |
serial_set_idx(a->a.i.fg_color, |
a->a.i.bg_color, a->a.i.flags); |
break; |
default: |
break; |
} |
} |
265,13 → 273,13 |
keyfield_t *field; |
attrs_t *a0, *a1; |
serial_goto(y, x); |
serial_goto(x, y); |
a0 = &data[0].attrs; |
serial_set_attrs(a0); |
for (j = 0; j < h; j++) { |
if (j > 0 && w != scr_width) |
serial_goto(y, x); |
serial_goto(x, j); |
for (i = 0; i < w; i++) { |
field = &data[j * w + i]; |
354,16 → 362,16 |
break; |
} |
draw_text_data(interbuf, col, row, w, h); |
lastcol = col + w; |
lastrow = row + h - 1; |
lastcol = col + w; |
retval = 0; |
break; |
case FB_PUTCHAR: |
c = IPC_GET_ARG1(call); |
row = IPC_GET_ARG2(call); |
col = IPC_GET_ARG3(call); |
col = IPC_GET_ARG2(call); |
row = IPC_GET_ARG3(call); |
if ((lastcol != col) || (lastrow != row)) |
serial_goto(row, col); |
serial_goto(col, row); |
lastcol = col + 1; |
lastrow = row; |
serial_putchar(c); |
370,15 → 378,15 |
retval = 0; |
break; |
case FB_CURSOR_GOTO: |
row = IPC_GET_ARG1(call); |
col = IPC_GET_ARG2(call); |
serial_goto(row, col); |
col = IPC_GET_ARG1(call); |
row = IPC_GET_ARG2(call); |
serial_goto(col, row); |
lastcol = col; |
lastrow = row; |
lastcol = col; |
retval = 0; |
break; |
case FB_GET_CSIZE: |
ipc_answer_2(callid, EOK, scr_height, scr_width); |
ipc_answer_2(callid, EOK, scr_width, scr_height); |
continue; |
case FB_CLEAR: |
serial_clrscr(); |
416,7 → 424,7 |
break; |
} |
serial_scroll(i); |
serial_goto(lastrow, lastcol); |
serial_goto(lastcol, lastrow); |
retval = 0; |
break; |
case FB_CURSOR_VISIBILITY: |
445,6 → 453,6 |
} |
} |
/** |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/fb/serial_console.h |
---|
43,7 → 43,7 |
typedef void (*putc_function_t)(char); |
void serial_puts(char *str); |
void serial_goto(const unsigned int row, const unsigned int col); |
void serial_goto(const unsigned int col, const unsigned int row); |
void serial_clrscr(void); |
void serial_scroll(int i); |
void serial_cursor_disable(void); |
/branches/dd/uspace/srv/fb/fb.c |
---|
51,9 → 51,10 |
#include <ipc/services.h> |
#include <kernel/errno.h> |
#include <kernel/genarch/fb/visuals.h> |
#include <console/color.h> |
#include <console/style.h> |
#include <io/color.h> |
#include <io/style.h> |
#include <async.h> |
#include <fibril.h> |
#include <bool.h> |
#include "font-8x16.h" |
375,8 → 376,8 |
*/ |
static void vport_redraw(viewport_t *vport) |
{ |
unsigned int col; |
unsigned int row; |
unsigned int col; |
for (row = 0; row < vport->rows; row++) { |
for (col = 0; col < vport->cols; col++) { |
431,8 → 432,8 |
*/ |
static void vport_scroll(viewport_t *vport, int lines) |
{ |
unsigned int col; |
unsigned int row; |
unsigned int col; |
unsigned int x; |
unsigned int y; |
uint32_t glyph; |
1038,8 → 1039,8 |
* |
* @return false if the call was not handled byt this function, true otherwise |
* |
* Note: this function is not threads safe, you would have |
* to redefine static variables with __thread |
* Note: this function is not thread-safe, you would have |
* to redefine static variables with fibril_local. |
* |
*/ |
static bool shm_handle(ipc_callid_t callid, ipc_call_t *call, int vp) |
1564,7 → 1565,7 |
unsigned int i; |
int scroll; |
wchar_t ch; |
unsigned int row, col; |
unsigned int col, row; |
if ((vport->cursor_active) || (anims_enabled)) |
callid = async_get_call_timeout(&call, 250000); |
1601,8 → 1602,8 |
case FB_PUTCHAR: |
ch = IPC_GET_ARG1(call); |
row = IPC_GET_ARG2(call); |
col = IPC_GET_ARG3(call); |
col = IPC_GET_ARG2(call); |
row = IPC_GET_ARG3(call); |
if ((col >= vport->cols) || (row >= vport->rows)) { |
retval = EINVAL; |
1620,8 → 1621,8 |
retval = EOK; |
break; |
case FB_CURSOR_GOTO: |
row = IPC_GET_ARG1(call); |
col = IPC_GET_ARG2(call); |
col = IPC_GET_ARG1(call); |
row = IPC_GET_ARG2(call); |
if ((col >= vport->cols) || (row >= vport->rows)) { |
retval = EINVAL; |
1641,7 → 1642,7 |
retval = EOK; |
break; |
case FB_GET_CSIZE: |
ipc_answer_2(callid, EOK, vport->rows, vport->cols); |
ipc_answer_2(callid, EOK, vport->cols, vport->rows); |
continue; |
case FB_SCROLL: |
scroll = IPC_GET_ARG1(call); |
/branches/dd/uspace/srv/fb/ega.c |
---|
49,8 → 49,8 |
#include <ipc/ns.h> |
#include <ipc/services.h> |
#include <libarch/ddi.h> |
#include <console/style.h> |
#include <console/color.h> |
#include <io/style.h> |
#include <io/color.h> |
#include <sys/types.h> |
#include "ega.h" |
70,7 → 70,7 |
int ega_normal_color = 0x0f; |
int ega_inverted_color = 0xf0; |
#define NORMAL_COLOR ega_normal_color |
#define NORMAL_COLOR ega_normal_color |
#define INVERTED_COLOR ega_inverted_color |
/* Allow only 1 connection */ |
95,7 → 95,7 |
} |
} |
static void cursor_goto(unsigned int row, unsigned int col) |
static void cursor_goto(unsigned int col, unsigned int row) |
{ |
int ega_cursor; |
144,12 → 144,12 |
} |
} |
static void printchar(wchar_t c, unsigned int row, unsigned int col) |
static void printchar(wchar_t c, unsigned int col, unsigned int row) |
{ |
scr_addr[(row * scr_width + col) * 2] = ega_glyph(c); |
scr_addr[(row * scr_width + col) * 2 + 1] = style; |
cursor_goto(row, col + 1); |
cursor_goto(col + 1, row); |
} |
/** Draw text data to viewport. |
241,11 → 241,15 |
static unsigned attr_to_ega_style(const attrs_t *a) |
{ |
switch (a->t) { |
case at_style: return style_to_ega_style(a->a.s.style); |
case at_rgb: return rgb_to_ega_style(a->a.r.fg_color, a->a.r.bg_color); |
case at_idx: return color_to_ega_style(a->a.i.fg_color, |
a->a.i.bg_color, a->a.i.flags); |
default: return INVERTED_COLOR; |
case at_style: |
return style_to_ega_style(a->a.s.style); |
case at_rgb: |
return rgb_to_ega_style(a->a.r.fg_color, a->a.r.bg_color); |
case at_idx: |
return color_to_ega_style(a->a.i.fg_color, |
a->a.i.bg_color, a->a.i.flags); |
default: |
return INVERTED_COLOR; |
} |
} |
312,7 → 316,7 |
retval = 0; |
break; |
case FB_GET_CSIZE: |
ipc_answer_2(callid, EOK, scr_height, scr_width); |
ipc_answer_2(callid, EOK, scr_width, scr_height); |
continue; |
case FB_CLEAR: |
clrscr(); |
320,23 → 324,23 |
break; |
case FB_PUTCHAR: |
c = IPC_GET_ARG1(call); |
row = IPC_GET_ARG2(call); |
col = IPC_GET_ARG3(call); |
col = IPC_GET_ARG2(call); |
row = IPC_GET_ARG3(call); |
if (col >= scr_width || row >= scr_height) { |
retval = EINVAL; |
break; |
} |
printchar(c, row, col); |
printchar(c, col, row); |
retval = 0; |
break; |
case FB_CURSOR_GOTO: |
row = IPC_GET_ARG1(call); |
col = IPC_GET_ARG2(call); |
col = IPC_GET_ARG1(call); |
row = IPC_GET_ARG2(call); |
if (row >= scr_height || col >= scr_width) { |
retval = EINVAL; |
break; |
} |
cursor_goto(row, col); |
cursor_goto(col, row); |
retval = 0; |
break; |
case FB_SCROLL: |
/branches/dd/uspace/srv/fs/devfs/devfs.c |
---|
28,7 → 28,7 |
/** @addtogroup fs |
* @{ |
*/ |
*/ |
/** |
* @file devfs.c |
74,6 → 74,12 |
case VFS_LOOKUP: |
devfs_lookup(callid, &call); |
break; |
case VFS_OPEN_NODE: |
devfs_open_node(callid, &call); |
break; |
case VFS_DEVICE: |
devfs_device(callid, &call); |
break; |
case VFS_READ: |
devfs_read(callid, &call); |
break; |
83,6 → 89,12 |
case VFS_TRUNCATE: |
devfs_truncate(callid, &call); |
break; |
case VFS_CLOSE: |
devfs_close(callid, &call); |
break; |
case VFS_SYNC: |
devfs_sync(callid, &call); |
break; |
case VFS_DESTROY: |
devfs_destroy(callid, &call); |
break; |
122,6 → 134,6 |
return 0; |
} |
/** |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/fs/devfs/devfs_ops.c |
---|
41,13 → 41,56 |
#include <malloc.h> |
#include <string.h> |
#include <libfs.h> |
#include <adt/hash_table.h> |
#include "devfs.h" |
#include "devfs_ops.h" |
#define PLB_GET_CHAR(pos) (devfs_reg.plb_ro[pos % PLB_SIZE]) |
/** Opened devices structure */ |
typedef struct { |
dev_handle_t handle; |
int phone; |
size_t refcount; |
link_t link; |
} device_t; |
/** Hash table of opened devices */ |
static hash_table_t devices; |
#define DEVICES_KEYS 1 |
#define DEVICES_KEY_HANDLE 0 |
#define DEVICES_BUCKETS 256 |
/* Implementation of hash table interface for the nodes hash table. */ |
static hash_index_t devices_hash(unsigned long key[]) |
{ |
return key[DEVICES_KEY_HANDLE] % DEVICES_BUCKETS; |
} |
static int devices_compare(unsigned long key[], hash_count_t keys, link_t *item) |
{ |
device_t *dev = hash_table_get_instance(item, device_t, link); |
return (dev->handle == (dev_handle_t) key[DEVICES_KEY_HANDLE]); |
} |
static void devices_remove_callback(link_t *item) |
{ |
free(hash_table_get_instance(item, device_t, link)); |
} |
static hash_table_operations_t devices_ops = { |
.hash = devices_hash, |
.compare = devices_compare, |
.remove_callback = devices_remove_callback |
}; |
bool devfs_init(void) |
{ |
if (!hash_table_create(&devices, DEVICES_BUCKETS, |
DEVICES_KEYS, &devices_ops)) |
return false; |
if (devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING) < 0) |
return false; |
103,8 → 146,7 |
return; |
} |
/* This is a read-only filesystem */ |
if ((lflag & L_CREATE) || (lflag & L_LINK) || (lflag & L_UNLINK)) { |
if ((lflag & L_LINK) || (lflag & L_UNLINK)) { |
ipc_answer_0(rid, ENOTSUP); |
return; |
} |
123,7 → 165,7 |
ipc_answer_0(rid, ENOENT); |
} else { |
if (lflag & L_FILE) { |
count_t len; |
size_t len; |
if (last >= first) |
len = last - first + 1; |
else |
135,7 → 177,7 |
return; |
} |
count_t i; |
size_t i; |
for (i = 0; i < len; i++) |
name[i] = PLB_GET_CHAR(first + i); |
148,6 → 190,38 |
return; |
} |
if (lflag & L_OPEN) { |
unsigned long key[] = { |
[DEVICES_KEY_HANDLE] = (unsigned long) handle |
}; |
link_t *lnk = hash_table_find(&devices, key); |
if (lnk == NULL) { |
int phone = devmap_device_connect(handle, 0); |
if (phone < 0) { |
free(name); |
ipc_answer_0(rid, ENOENT); |
return; |
} |
device_t *dev = (device_t *) malloc(sizeof(device_t)); |
if (dev == NULL) { |
free(name); |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
dev->handle = handle; |
dev->phone = phone; |
dev->refcount = 1; |
hash_table_insert(&devices, key, &dev->link); |
} else { |
device_t *dev = hash_table_get_instance(lnk, device_t, link); |
dev->refcount++; |
} |
} |
free(name); |
ipc_answer_5(rid, EOK, devfs_reg.fs_handle, dev_handle, handle, 0, 1); |
156,6 → 230,61 |
} |
} |
void devfs_open_node(ipc_callid_t rid, ipc_call_t *request) |
{ |
dev_handle_t handle = IPC_GET_ARG2(*request); |
unsigned long key[] = { |
[DEVICES_KEY_HANDLE] = (unsigned long) handle |
}; |
link_t *lnk = hash_table_find(&devices, key); |
if (lnk == NULL) { |
int phone = devmap_device_connect(handle, 0); |
if (phone < 0) { |
ipc_answer_0(rid, ENOENT); |
return; |
} |
device_t *dev = (device_t *) malloc(sizeof(device_t)); |
if (dev == NULL) { |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
dev->handle = handle; |
dev->phone = phone; |
dev->refcount = 1; |
hash_table_insert(&devices, key, &dev->link); |
} else { |
device_t *dev = hash_table_get_instance(lnk, device_t, link); |
dev->refcount++; |
} |
ipc_answer_3(rid, EOK, 0, 1, L_FILE); |
} |
void devfs_device(ipc_callid_t rid, ipc_call_t *request) |
{ |
fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request); |
if (index != 0) { |
unsigned long key[] = { |
[DEVICES_KEY_HANDLE] = (unsigned long) index |
}; |
link_t *lnk = hash_table_find(&devices, key); |
if (lnk == NULL) { |
ipc_answer_0(rid, ENOENT); |
return; |
} |
ipc_answer_1(rid, EOK, (ipcarg_t) index); |
} else |
ipc_answer_0(rid, ENOTSUP); |
} |
void devfs_read(ipc_callid_t rid, ipc_call_t *request) |
{ |
fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request); |
162,34 → 291,59 |
off_t pos = (off_t) IPC_GET_ARG3(*request); |
if (index != 0) { |
ipc_answer_1(rid, ENOENT, 0); |
return; |
} |
/* |
* Receive the read request. |
*/ |
ipc_callid_t callid; |
size_t size; |
if (!ipc_data_read_receive(&callid, &size)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
} |
size_t bytes = 0; |
if (index != 0) { |
(void) ipc_data_read_finalize(callid, NULL, bytes); |
unsigned long key[] = { |
[DEVICES_KEY_HANDLE] = (unsigned long) index |
}; |
link_t *lnk = hash_table_find(&devices, key); |
if (lnk == NULL) { |
ipc_answer_0(rid, ENOENT); |
return; |
} |
device_t *dev = hash_table_get_instance(lnk, device_t, link); |
ipc_callid_t callid; |
if (!ipc_data_read_receive(&callid, NULL)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
} |
/* Make a request at the driver */ |
ipc_call_t answer; |
aid_t msg = async_send_3(dev->phone, IPC_GET_METHOD(*request), |
IPC_GET_ARG1(*request), IPC_GET_ARG2(*request), |
IPC_GET_ARG3(*request), &answer); |
/* Forward the IPC_M_DATA_READ request to the driver */ |
ipc_forward_fast(callid, dev->phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); |
/* Wait for reply from the driver. */ |
ipcarg_t rc; |
async_wait_for(msg, &rc); |
size_t bytes = IPC_GET_ARG1(answer); |
/* Driver reply is the final result of the whole operation */ |
ipc_answer_1(rid, rc, bytes); |
} else { |
count_t count = devmap_device_get_count(); |
ipc_callid_t callid; |
size_t size; |
if (!ipc_data_read_receive(&callid, &size)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
} |
size_t count = devmap_device_get_count(); |
dev_desc_t *desc = malloc(count * sizeof(dev_desc_t)); |
if (desc == NULL) { |
ipc_answer_0(callid, ENOENT); |
ipc_answer_1(rid, ENOENT, 0); |
ipc_answer_0(callid, ENOMEM); |
ipc_answer_1(rid, ENOMEM, 0); |
return; |
} |
count_t max = devmap_device_get_devices(count, desc); |
size_t max = devmap_device_get_devices(count, desc); |
if (pos < max) { |
ipc_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1); |
200,10 → 354,9 |
} |
free(desc); |
bytes = 1; |
ipc_answer_1(rid, EOK, 1); |
} |
ipc_answer_1(rid, EOK, bytes); |
} |
void devfs_write(ipc_callid_t rid, ipc_call_t *request) |
211,20 → 364,46 |
fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request); |
off_t pos = (off_t) IPC_GET_ARG3(*request); |
/* |
* Receive the write request. |
*/ |
ipc_callid_t callid; |
size_t size; |
if (!ipc_data_write_receive(&callid, &size)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
if (index != 0) { |
unsigned long key[] = { |
[DEVICES_KEY_HANDLE] = (unsigned long) index |
}; |
link_t *lnk = hash_table_find(&devices, key); |
if (lnk == NULL) { |
ipc_answer_0(rid, ENOENT); |
return; |
} |
device_t *dev = hash_table_get_instance(lnk, device_t, link); |
ipc_callid_t callid; |
if (!ipc_data_write_receive(&callid, NULL)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
} |
/* Make a request at the driver */ |
ipc_call_t answer; |
aid_t msg = async_send_3(dev->phone, IPC_GET_METHOD(*request), |
IPC_GET_ARG1(*request), IPC_GET_ARG2(*request), |
IPC_GET_ARG3(*request), &answer); |
/* Forward the IPC_M_DATA_WRITE request to the driver */ |
ipc_forward_fast(callid, dev->phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); |
/* Wait for reply from the driver. */ |
ipcarg_t rc; |
async_wait_for(msg, &rc); |
size_t bytes = IPC_GET_ARG1(answer); |
/* Driver reply is the final result of the whole operation */ |
ipc_answer_1(rid, rc, bytes); |
} else { |
/* Read-only filesystem */ |
ipc_answer_0(rid, ENOTSUP); |
} |
// TODO |
ipc_answer_0(callid, ENOENT); |
ipc_answer_2(rid, ENOENT, 0, 0); |
} |
void devfs_truncate(ipc_callid_t rid, ipc_call_t *request) |
232,6 → 411,66 |
ipc_answer_0(rid, ENOTSUP); |
} |
void devfs_close(ipc_callid_t rid, ipc_call_t *request) |
{ |
fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request); |
if (index != 0) { |
unsigned long key[] = { |
[DEVICES_KEY_HANDLE] = (unsigned long) index |
}; |
link_t *lnk = hash_table_find(&devices, key); |
if (lnk == NULL) { |
ipc_answer_0(rid, ENOENT); |
return; |
} |
device_t *dev = hash_table_get_instance(lnk, device_t, link); |
dev->refcount--; |
if (dev->refcount == 0) { |
ipc_hangup(dev->phone); |
hash_table_remove(&devices, key, DEVICES_KEYS); |
} |
ipc_answer_0(rid, EOK); |
} else |
ipc_answer_0(rid, ENOTSUP); |
} |
void devfs_sync(ipc_callid_t rid, ipc_call_t *request) |
{ |
fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request); |
if (index != 0) { |
unsigned long key[] = { |
[DEVICES_KEY_HANDLE] = (unsigned long) index |
}; |
link_t *lnk = hash_table_find(&devices, key); |
if (lnk == NULL) { |
ipc_answer_0(rid, ENOENT); |
return; |
} |
device_t *dev = hash_table_get_instance(lnk, device_t, link); |
/* Make a request at the driver */ |
ipc_call_t answer; |
aid_t msg = async_send_2(dev->phone, IPC_GET_METHOD(*request), |
IPC_GET_ARG1(*request), IPC_GET_ARG2(*request), &answer); |
/* Wait for reply from the driver */ |
ipcarg_t rc; |
async_wait_for(msg, &rc); |
/* Driver reply is the final result of the whole operation */ |
ipc_answer_0(rid, rc); |
} else |
ipc_answer_0(rid, ENOTSUP); |
} |
void devfs_destroy(ipc_callid_t rid, ipc_call_t *request) |
{ |
ipc_answer_0(rid, ENOTSUP); |
239,4 → 478,4 |
/** |
* @} |
*/ |
*/ |
/branches/dd/uspace/srv/fs/devfs/devfs_ops.h |
---|
28,7 → 28,7 |
/** @addtogroup fs |
* @{ |
*/ |
*/ |
#ifndef DEVFS_DEVFS_OPS_H_ |
#define DEVFS_DEVFS_OPS_H_ |
41,9 → 41,13 |
extern void devfs_mounted(ipc_callid_t, ipc_call_t *); |
extern void devfs_mount(ipc_callid_t, ipc_call_t *); |
extern void devfs_lookup(ipc_callid_t, ipc_call_t *); |
extern void devfs_open_node(ipc_callid_t, ipc_call_t *); |
extern void devfs_device(ipc_callid_t, ipc_call_t *); |
extern void devfs_sync(ipc_callid_t, ipc_call_t *); |
extern void devfs_read(ipc_callid_t, ipc_call_t *); |
extern void devfs_write(ipc_callid_t, ipc_call_t *); |
extern void devfs_truncate(ipc_callid_t, ipc_call_t *); |
extern void devfs_close(ipc_callid_t, ipc_call_t *); |
extern void devfs_destroy(ipc_callid_t, ipc_call_t *); |
#endif |
/branches/dd/uspace/srv/fs/tmpfs/tmpfs.h |
---|
38,7 → 38,7 |
#include <atomic.h> |
#include <sys/types.h> |
#include <bool.h> |
#include <libadt/hash_table.h> |
#include <adt/hash_table.h> |
#ifndef dprintf |
#define dprintf(...) printf(__VA_ARGS__) |
86,7 → 86,11 |
extern void tmpfs_read(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_write(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_truncate(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_close(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_destroy(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_open_node(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_device(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_sync(ipc_callid_t, ipc_call_t *); |
extern bool tmpfs_restore(dev_handle_t); |
/branches/dd/uspace/srv/fs/tmpfs/tmpfs.c |
---|
114,9 → 114,21 |
case VFS_TRUNCATE: |
tmpfs_truncate(callid, &call); |
break; |
case VFS_CLOSE: |
tmpfs_close(callid, &call); |
break; |
case VFS_DESTROY: |
tmpfs_destroy(callid, &call); |
break; |
case VFS_OPEN_NODE: |
tmpfs_open_node(callid, &call); |
break; |
case VFS_DEVICE: |
tmpfs_device(callid, &call); |
break; |
case VFS_SYNC: |
tmpfs_sync(callid, &call); |
break; |
default: |
ipc_answer_0(callid, ENOTSUP); |
break; |
/branches/dd/uspace/srv/fs/tmpfs/tmpfs_ops.c |
---|
47,7 → 47,7 |
#include <stdio.h> |
#include <assert.h> |
#include <sys/types.h> |
#include <libadt/hash_table.h> |
#include <adt/hash_table.h> |
#include <as.h> |
#include <libfs.h> |
596,6 → 596,11 |
ipc_answer_0(rid, EOK); |
} |
void tmpfs_close(ipc_callid_t rid, ipc_call_t *request) |
{ |
ipc_answer_0(rid, EOK); |
} |
void tmpfs_destroy(ipc_callid_t rid, ipc_call_t *request) |
{ |
dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request); |
618,6 → 623,22 |
ipc_answer_0(rid, rc); |
} |
void tmpfs_open_node(ipc_callid_t rid, ipc_call_t *request) |
{ |
libfs_open_node(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request); |
} |
void tmpfs_device(ipc_callid_t rid, ipc_call_t *request) |
{ |
ipc_answer_0(rid, ENOTSUP); |
} |
void tmpfs_sync(ipc_callid_t rid, ipc_call_t *request) |
{ |
/* Dummy implementation */ |
ipc_answer_0(rid, EOK); |
} |
/** |
* @} |
*/ |
*/ |
/branches/dd/uspace/srv/fs/fat/fat_idx.c |
---|
39,8 → 39,8 |
#include "../../vfs/vfs.h" |
#include <errno.h> |
#include <string.h> |
#include <libadt/hash_table.h> |
#include <libadt/list.h> |
#include <adt/hash_table.h> |
#include <adt/list.h> |
#include <assert.h> |
#include <futex.h> |
/branches/dd/uspace/srv/fs/fat/fat.h |
---|
206,7 → 206,11 |
extern void fat_read(ipc_callid_t, ipc_call_t *); |
extern void fat_write(ipc_callid_t, ipc_call_t *); |
extern void fat_truncate(ipc_callid_t, ipc_call_t *); |
extern void fat_close(ipc_callid_t, ipc_call_t *); |
extern void fat_destroy(ipc_callid_t, ipc_call_t *); |
extern void fat_open_node(ipc_callid_t, ipc_call_t *); |
extern void fat_device(ipc_callid_t, ipc_call_t *); |
extern void fat_sync(ipc_callid_t, ipc_call_t *); |
extern fat_idx_t *fat_idx_get_new(dev_handle_t); |
extern fat_idx_t *fat_idx_get_by_pos(dev_handle_t, fat_cluster_t, unsigned); |
/branches/dd/uspace/srv/fs/fat/fat_fat.c |
---|
46,6 → 46,7 |
#include <align.h> |
#include <assert.h> |
#include <futex.h> |
#include <mem.h> |
/** |
* The fat_alloc_lock futex protects all copies of the File Allocation Table |
/branches/dd/uspace/srv/fs/fat/fat.c |
---|
107,9 → 107,21 |
case VFS_TRUNCATE: |
fat_truncate(callid, &call); |
break; |
case VFS_CLOSE: |
fat_close(callid, &call); |
break; |
case VFS_DESTROY: |
fat_destroy(callid, &call); |
break; |
case VFS_OPEN_NODE: |
fat_open_node(callid, &call); |
break; |
case VFS_DEVICE: |
fat_device(callid, &call); |
break; |
case VFS_SYNC: |
fat_sync(callid, &call); |
break; |
default: |
ipc_answer_0(callid, ENOTSUP); |
break; |
/branches/dd/uspace/srv/fs/fat/fat_ops.c |
---|
48,8 → 48,8 |
#include <errno.h> |
#include <string.h> |
#include <byteorder.h> |
#include <libadt/hash_table.h> |
#include <libadt/list.h> |
#include <adt/hash_table.h> |
#include <adt/list.h> |
#include <assert.h> |
#include <futex.h> |
#include <sys/mman.h> |
1169,6 → 1169,11 |
return; |
} |
void fat_close(ipc_callid_t rid, ipc_call_t *request) |
{ |
ipc_answer_0(rid, EOK); |
} |
void fat_destroy(ipc_callid_t rid, ipc_call_t *request) |
{ |
dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request); |
1185,6 → 1190,22 |
ipc_answer_0(rid, rc); |
} |
void fat_open_node(ipc_callid_t rid, ipc_call_t *request) |
{ |
libfs_open_node(&fat_libfs_ops, fat_reg.fs_handle, rid, request); |
} |
void fat_device(ipc_callid_t rid, ipc_call_t *request) |
{ |
ipc_answer_0(rid, ENOTSUP); |
} |
void fat_sync(ipc_callid_t rid, ipc_call_t *request) |
{ |
/* Dummy implementation */ |
ipc_answer_0(rid, EOK); |
} |
/** |
* @} |
*/ |
*/ |
/branches/dd/uspace/srv/pci/pci.h |
---|
2,9 → 2,10 |
#define PCI_H |
//#include <arch/types.h> |
#include <libadt/list.h> |
#include <adt/list.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
struct pci_drv; |
struct pci_dev; |
/branches/dd/uspace/srv/devmap/devmap.c |
---|
41,7 → 41,7 |
#include <stdio.h> |
#include <errno.h> |
#include <bool.h> |
#include <futex.h> |
#include <fibril_sync.h> |
#include <stdlib.h> |
#include <string.h> |
#include <ipc/devmap.h> |
62,8 → 62,8 |
ipcarg_t phone; |
/** Device driver name */ |
char *name; |
/** Futex for list of devices owned by this driver */ |
atomic_t devices_futex; |
/** Fibril mutex for list of devices owned by this driver */ |
fibril_mutex_t devices_mutex; |
} devmap_driver_t; |
/** Info about registered device |
95,15 → 95,15 |
LIST_INITIALIZE(pending_req); |
/* Locking order: |
* drivers_list_futex |
* devices_list_futex |
* (devmap_driver_t *)->devices_futex |
* create_handle_futex |
* drivers_list_mutex |
* devices_list_mutex |
* (devmap_driver_t *)->devices_mutex |
* create_handle_mutex |
**/ |
static atomic_t devices_list_futex = FUTEX_INITIALIZER; |
static atomic_t drivers_list_futex = FUTEX_INITIALIZER; |
static atomic_t create_handle_futex = FUTEX_INITIALIZER; |
static FIBRIL_MUTEX_INITIALIZE(devices_list_mutex); |
static FIBRIL_MUTEX_INITIALIZE(drivers_list_mutex); |
static FIBRIL_MUTEX_INITIALIZE(create_handle_mutex); |
static dev_handle_t last_handle = 0; |
110,13 → 110,12 |
static dev_handle_t devmap_create_handle(void) |
{ |
/* TODO: allow reusing old handles after their unregistration |
* and implement some version of LRU algorithm |
* and implement some version of LRU algorithm, avoid overflow |
*/ |
/* FIXME: overflow */ |
futex_down(&create_handle_futex); |
fibril_mutex_lock(&create_handle_mutex); |
last_handle++; |
futex_up(&create_handle_futex); |
fibril_mutex_unlock(&create_handle_mutex); |
return last_handle; |
} |
131,7 → 130,7 |
while (item != &devices_list) { |
device = list_get_instance(item, devmap_device_t, devices); |
if (0 == str_cmp(device->name, name)) |
if (str_cmp(device->name, name) == 0) |
break; |
item = item->next; |
} |
150,7 → 149,7 |
*/ |
static devmap_device_t *devmap_device_find_handle(dev_handle_t handle) |
{ |
futex_down(&devices_list_futex); |
fibril_mutex_lock(&devices_list_mutex); |
link_t *item = (&devices_list)->next; |
devmap_device_t *device = NULL; |
163,13 → 162,13 |
} |
if (item == &devices_list) { |
futex_up(&devices_list_futex); |
fibril_mutex_unlock(&devices_list_mutex); |
return NULL; |
} |
device = list_get_instance(item, devmap_device_t, devices); |
futex_up(&devices_list_futex); |
fibril_mutex_unlock(&devices_list_mutex); |
return device; |
} |
249,7 → 248,7 |
/* |
* Send confirmation to sender and get data into buffer. |
*/ |
if (EOK != ipc_data_write_finalize(callid, driver->name, name_size)) { |
if (ipc_data_write_finalize(callid, driver->name, name_size) != EOK) { |
free(driver->name); |
free(driver); |
ipc_answer_0(iid, EREFUSED); |
258,21 → 257,21 |
driver->name[name_size] = 0; |
/* Initialize futex for list of devices owned by this driver */ |
futex_initialize(&(driver->devices_futex), 1); |
/* Initialize mutex for list of devices owned by this driver */ |
fibril_mutex_initialize(&driver->devices_mutex); |
/* |
* Initialize list of asociated devices |
*/ |
list_initialize(&(driver->devices)); |
list_initialize(&driver->devices); |
/* |
* Create connection to the driver |
* Create connection to the driver |
*/ |
ipc_call_t call; |
callid = async_get_call(&call); |
if (IPC_M_CONNECT_TO_ME != IPC_GET_METHOD(call)) { |
if (IPC_GET_METHOD(call) != IPC_M_CONNECT_TO_ME) { |
ipc_answer_0(callid, ENOTSUP); |
free(driver->name); |
287,7 → 286,7 |
list_initialize(&(driver->drivers)); |
futex_down(&drivers_list_futex); |
fibril_mutex_lock(&drivers_list_mutex); |
/* TODO: |
* check that no driver with name equal to driver->name is registered |
297,7 → 296,7 |
* Insert new driver into list of registered drivers |
*/ |
list_append(&(driver->drivers), &drivers_list); |
futex_up(&drivers_list_futex); |
fibril_mutex_unlock(&drivers_list_mutex); |
ipc_answer_0(iid, EOK); |
314,7 → 313,7 |
if (driver == NULL) |
return EEXISTS; |
futex_down(&drivers_list_futex); |
fibril_mutex_lock(&drivers_list_mutex); |
if (driver->phone != 0) |
ipc_hangup(driver->phone); |
323,8 → 322,8 |
list_remove(&(driver->drivers)); |
/* Unregister all its devices */ |
futex_down(&devices_list_futex); |
futex_down(&(driver->devices_futex)); |
fibril_mutex_lock(&devices_list_mutex); |
fibril_mutex_lock(&driver->devices_mutex); |
while (!list_empty(&(driver->devices))) { |
devmap_device_t *device = list_get_instance(driver->devices.next, |
332,9 → 331,9 |
devmap_device_unregister_core(device); |
} |
futex_up(&(driver->devices_futex)); |
futex_up(&devices_list_futex); |
futex_up(&drivers_list_futex); |
fibril_mutex_unlock(&driver->devices_mutex); |
fibril_mutex_unlock(&devices_list_mutex); |
fibril_mutex_unlock(&drivers_list_mutex); |
/* free name and driver */ |
if (driver->name != NULL) |
347,7 → 346,7 |
/** Process pending lookup requests */ |
static void process_pending_lookup() |
static void process_pending_lookup(void) |
{ |
link_t *cur; |
364,6 → 363,7 |
free(pr->name); |
list_remove(cur); |
free(pr); |
goto loop; |
} |
} |
419,12 → 419,12 |
list_initialize(&(device->devices)); |
list_initialize(&(device->driver_devices)); |
futex_down(&devices_list_futex); |
fibril_mutex_lock(&devices_list_mutex); |
/* Check that device with such name is not already registered */ |
if (NULL != devmap_device_find_name(device->name)) { |
printf(NAME ": Device '%s' already registered\n", device->name); |
futex_up(&devices_list_futex); |
fibril_mutex_unlock(&devices_list_mutex); |
free(device->name); |
free(device); |
ipc_answer_0(iid, EEXISTS); |
440,16 → 440,14 |
list_append(&device->devices, &devices_list); |
/* Insert device into list of devices that belog to one driver */ |
futex_down(&device->driver->devices_futex); |
fibril_mutex_lock(&device->driver->devices_mutex); |
list_append(&device->driver_devices, &device->driver->devices); |
futex_up(&device->driver->devices_futex); |
futex_up(&devices_list_futex); |
fibril_mutex_unlock(&device->driver->devices_mutex); |
fibril_mutex_unlock(&devices_list_mutex); |
ipc_answer_1(iid, EOK, device->handle); |
process_pending_lookup(); |
} |
/** |
600,14 → 598,14 |
static void devmap_get_count(ipc_callid_t iid, ipc_call_t *icall) |
{ |
futex_down(&devices_list_futex); |
fibril_mutex_lock(&devices_list_mutex); |
ipc_answer_1(iid, EOK, list_count(&devices_list)); |
futex_up(&devices_list_futex); |
fibril_mutex_unlock(&devices_list_mutex); |
} |
static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall) |
{ |
futex_down(&devices_list_futex); |
fibril_mutex_lock(&devices_list_mutex); |
ipc_callid_t callid; |
size_t size; |
623,7 → 621,7 |
return; |
} |
count_t count = size / sizeof(dev_desc_t); |
size_t count = size / sizeof(dev_desc_t); |
dev_desc_t *desc = (dev_desc_t *) malloc(size); |
if (desc == NULL) { |
ipc_answer_0(callid, ENOMEM); |
631,7 → 629,7 |
return; |
} |
count_t pos = 0; |
size_t pos = 0; |
link_t *item = devices_list.next; |
while ((item != &devices_list) && (pos < count)) { |
652,7 → 650,7 |
free(desc); |
futex_up(&devices_list_futex); |
fibril_mutex_unlock(&devices_list_mutex); |
ipc_answer_1(iid, EOK, pos); |
} |
677,7 → 675,7 |
list_initialize(&(device->devices)); |
list_initialize(&(device->driver_devices)); |
futex_down(&devices_list_futex); |
fibril_mutex_lock(&devices_list_mutex); |
/* Get unique device handle */ |
device->handle = devmap_create_handle(); |
686,7 → 684,7 |
/* Insert device into list of all devices */ |
list_append(&device->devices, &devices_list); |
futex_up(&devices_list_futex); |
fibril_mutex_unlock(&devices_list_mutex); |
return true; |
} |
699,7 → 697,7 |
/* Accept connection */ |
ipc_answer_0(iid, EOK); |
devmap_driver_t *driver = NULL; |
devmap_driver_t *driver = NULL; |
devmap_driver_register(&driver); |
if (NULL == driver) |
713,7 → 711,6 |
switch (IPC_GET_METHOD(call)) { |
case IPC_M_PHONE_HUNGUP: |
cont = false; |
/* Exit thread */ |
continue; |
case DEVMAP_DRIVER_UNREGISTER: |
if (NULL == driver) |
766,7 → 763,6 |
switch (IPC_GET_METHOD(call)) { |
case IPC_M_PHONE_HUNGUP: |
cont = false; |
/* Exit thread */ |
continue; |
case DEVMAP_DEVICE_GET_HANDLE: |
devmap_get_handle(callid, &call); |
806,7 → 802,7 |
break; |
default: |
/* No such interface */ |
ipc_answer_0(iid, ENOENT); |
ipc_answer_0(iid, ENOENT); |
} |
} |
822,7 → 818,9 |
return -1; |
} |
/* Set a handler of incomming connections */ |
/* Set a handler of incomming connections and |
pending operations */ |
async_set_pending(process_pending_lookup); |
async_set_client_connection(devmap_connection); |
/* Register device mapper at naming service */ |
/branches/dd/uspace/srv/cir/obio/Makefile |
---|
0,0 → 1,76 |
# |
# Copyright (c) 2006 Martin Decky |
# All rights reserved. |
# |
# Redistribution and use in source and binary forms, with or without |
# modification, are permitted provided that the following conditions |
# are met: |
# |
# - Redistributions of source code must retain the above copyright |
# notice, this list of conditions and the following disclaimer. |
# - Redistributions in binary form must reproduce the above copyright |
# notice, this list of conditions and the following disclaimer in the |
# documentation and/or other materials provided with the distribution. |
# - The name of the author may not be used to endorse or promote products |
# derived from this software without specific prior written permission. |
# |
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
# |
## Setup toolchain |
# |
LIBC_PREFIX = ../../../lib/libc |
SOFTINT_PREFIX = ../../../lib/softint |
include $(LIBC_PREFIX)/Makefile.toolchain |
LIBS = $(LIBC_PREFIX)/libc.a |
## Sources |
# |
OUTPUT = obio |
SOURCES = \ |
obio.c |
OBJECTS := $(addsuffix .o,$(basename $(SOURCES))) |
.PHONY: all clean depend disasm |
all: $(OUTPUT) $(OUTPUT).disasm |
-include Makefile.depend |
clean: |
-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS) |
depend: |
$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend |
$(OUTPUT): $(OBJECTS) $(LIBS) |
$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map |
disasm: $(OUTPUT).disasm |
$(OUTPUT).disasm: $(OUTPUT) |
$(OBJDUMP) -d $< > $@ |
%.o: %.S |
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@ |
%.o: %.s |
$(AS) $(AFLAGS) $< -o $@ |
%.o: %.c |
$(CC) $(DEFS) $(CFLAGS) -c $< -o $@ |
/branches/dd/uspace/srv/cir/obio/obio.c |
---|
0,0 → 1,158 |
/* |
* Copyright (c) 2009 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup obio |
* @{ |
*/ |
/** |
* @file obio.c |
* @brief OBIO driver. |
* |
* OBIO is a short for on-board I/O. On UltraSPARC IIi and systems with U2P, |
* there is a piece of the root PCI bus controller address space, which |
* contains interrupt mapping and clear registers for all on-board devices. |
* Although UltraSPARC IIi and U2P are different in general, these registers can |
* be found at the same addresses. |
*/ |
#include <ipc/ipc.h> |
#include <ipc/services.h> |
#include <ipc/bus.h> |
#include <ipc/ns.h> |
#include <sysinfo.h> |
#include <as.h> |
#include <ddi.h> |
#include <align.h> |
#include <bool.h> |
#include <errno.h> |
#include <async.h> |
#include <align.h> |
#include <async.h> |
#include <stdio.h> |
#include <ipc/devmap.h> |
#define NAME "obio" |
#define OBIO_SIZE 0x1898 |
#define OBIO_IMR_BASE 0x200 |
#define OBIO_IMR(ino) (OBIO_IMR_BASE + ((ino) & INO_MASK)) |
#define OBIO_CIR_BASE 0x300 |
#define OBIO_CIR(ino) (OBIO_CIR_BASE + ((ino) & INO_MASK)) |
#define INO_MASK 0x1f |
static void *base_phys; |
static volatile uint64_t *base_virt; |
/** Handle one connection to obio. |
* |
* @param iid Hash of the request that opened the connection. |
* @param icall Call data of the request that opened the connection. |
*/ |
static void obio_connection(ipc_callid_t iid, ipc_call_t *icall) |
{ |
ipc_callid_t callid; |
ipc_call_t call; |
/* |
* Answer the first IPC_M_CONNECT_ME_TO call. |
*/ |
ipc_answer_0(iid, EOK); |
while (1) { |
int inr; |
callid = async_get_call(&call); |
switch (IPC_GET_METHOD(call)) { |
case BUS_CLEAR_INTERRUPT: |
inr = IPC_GET_ARG1(call); |
base_virt[OBIO_CIR(inr & INO_MASK)] = 0; |
ipc_answer_0(callid, EOK); |
break; |
default: |
ipc_answer_0(callid, EINVAL); |
break; |
} |
} |
} |
/** Initialize the OBIO driver. |
* |
* So far, the driver heavily depends on information provided by the kernel via |
* sysinfo. In the future, there should be a standalone OBIO driver. |
*/ |
static bool obio_init(void) |
{ |
ipcarg_t phonead; |
base_phys = (void *) sysinfo_value("obio.base.physical"); |
if (!base_phys) { |
printf(NAME ": no OBIO registers found\n"); |
return false; |
} |
base_virt = as_get_mappable_page(OBIO_SIZE); |
int flags = AS_AREA_READ | AS_AREA_WRITE; |
int retval = physmem_map(base_phys, (void *) base_virt, |
ALIGN_UP(OBIO_SIZE, PAGE_SIZE) >> PAGE_WIDTH, flags); |
if (retval < 0) { |
printf(NAME ": Error mapping OBIO registers\n"); |
return false; |
} |
printf(NAME ": OBIO registers with base at %p\n", base_phys); |
async_set_client_connection(obio_connection); |
ipc_connect_to_me(PHONE_NS, SERVICE_OBIO, 0, 0, &phonead); |
return true; |
} |
int main(int argc, char **argv) |
{ |
printf(NAME ": HelenOS OBIO driver\n"); |
if (!obio_init()) |
return -1; |
printf(NAME ": Accepting connections\n"); |
async_manager(); |
/* Never reached */ |
return 0; |
} |
/** |
* @} |
*/ |
Property changes: |
Added: svn:mergeinfo |
/branches/dd/uspace/srv/cir/obio |
---|
Property changes: |
Added: svn:mergeinfo |
/branches/dd/uspace/srv/cir/fhc/Makefile |
---|
0,0 → 1,76 |
# |
# Copyright (c) 2006 Martin Decky |
# All rights reserved. |
# |
# Redistribution and use in source and binary forms, with or without |
# modification, are permitted provided that the following conditions |
# are met: |
# |
# - Redistributions of source code must retain the above copyright |
# notice, this list of conditions and the following disclaimer. |
# - Redistributions in binary form must reproduce the above copyright |
# notice, this list of conditions and the following disclaimer in the |
# documentation and/or other materials provided with the distribution. |
# - The name of the author may not be used to endorse or promote products |
# derived from this software without specific prior written permission. |
# |
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
# |
## Setup toolchain |
# |
LIBC_PREFIX = ../../../lib/libc |
SOFTINT_PREFIX = ../../../lib/softint |
include $(LIBC_PREFIX)/Makefile.toolchain |
LIBS = $(LIBC_PREFIX)/libc.a |
## Sources |
# |
OUTPUT = fhc |
SOURCES = \ |
fhc.c |
OBJECTS := $(addsuffix .o,$(basename $(SOURCES))) |
.PHONY: all clean depend disasm |
all: $(OUTPUT) $(OUTPUT).disasm |
-include Makefile.depend |
clean: |
-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS) |
depend: |
$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend |
$(OUTPUT): $(OBJECTS) $(LIBS) |
$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map |
disasm: $(OUTPUT).disasm |
$(OUTPUT).disasm: $(OUTPUT) |
$(OBJDUMP) -d $< > $@ |
%.o: %.S |
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@ |
%.o: %.s |
$(AS) $(AFLAGS) $< -o $@ |
%.o: %.c |
$(CC) $(DEFS) $(CFLAGS) -c $< -o $@ |
/branches/dd/uspace/srv/cir/fhc/fhc.c |
---|
0,0 → 1,157 |
/* |
* Copyright (c) 2009 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup fhc |
* @{ |
*/ |
/** |
* @file fhc.c |
* @brief FHC bus controller driver. |
*/ |
#include <ipc/ipc.h> |
#include <ipc/services.h> |
#include <ipc/bus.h> |
#include <ipc/ns.h> |
#include <sysinfo.h> |
#include <as.h> |
#include <ddi.h> |
#include <align.h> |
#include <bool.h> |
#include <errno.h> |
#include <async.h> |
#include <align.h> |
#include <async.h> |
#include <stdio.h> |
#include <ipc/devmap.h> |
#define NAME "fhc" |
#define FHC_UART_INR 0x39 |
#define FHC_UART_IMAP 0x0 |
#define FHC_UART_ICLR 0x4 |
static void *fhc_uart_phys; |
static volatile uint32_t *fhc_uart_virt; |
static size_t fhc_uart_size; |
/** Handle one connection to fhc. |
* |
* @param iid Hash of the request that opened the connection. |
* @param icall Call data of the request that opened the connection. |
*/ |
static void fhc_connection(ipc_callid_t iid, ipc_call_t *icall) |
{ |
ipc_callid_t callid; |
ipc_call_t call; |
/* |
* Answer the first IPC_M_CONNECT_ME_TO call. |
*/ |
ipc_answer_0(iid, EOK); |
while (1) { |
int inr; |
callid = async_get_call(&call); |
switch (IPC_GET_METHOD(call)) { |
case BUS_CLEAR_INTERRUPT: |
inr = IPC_GET_ARG1(call); |
switch (inr) { |
case FHC_UART_INR: |
fhc_uart_virt[FHC_UART_ICLR] = 0; |
ipc_answer_0(callid, EOK); |
break; |
default: |
ipc_answer_0(callid, ENOTSUP); |
break; |
} |
break; |
default: |
ipc_answer_0(callid, EINVAL); |
break; |
} |
} |
} |
/** Initialize the FHC driver. |
* |
* So far, the driver heavily depends on information provided by the kernel via |
* sysinfo. In the future, there should be a standalone FHC driver. |
*/ |
static bool fhc_init(void) |
{ |
ipcarg_t phonead; |
fhc_uart_size = sysinfo_value("fhc.uart.size"); |
fhc_uart_phys = (void *) sysinfo_value("fhc.uart.physical"); |
if (!fhc_uart_size) { |
printf(NAME ": no FHC UART registers found\n"); |
return false; |
} |
fhc_uart_virt = as_get_mappable_page(fhc_uart_size); |
int flags = AS_AREA_READ | AS_AREA_WRITE; |
int retval = physmem_map(fhc_uart_phys, (void *) fhc_uart_virt, |
ALIGN_UP(fhc_uart_size, PAGE_SIZE) >> PAGE_WIDTH, flags); |
if (retval < 0) { |
printf(NAME ": Error mapping FHC UART registers\n"); |
return false; |
} |
printf(NAME ": FHC UART registers at %p, %d bytes\n", fhc_uart_phys, |
fhc_uart_size); |
async_set_client_connection(fhc_connection); |
ipc_connect_to_me(PHONE_NS, SERVICE_FHC, 0, 0, &phonead); |
return true; |
} |
int main(int argc, char **argv) |
{ |
printf(NAME ": HelenOS FHC bus controller driver\n"); |
if (!fhc_init()) |
return -1; |
printf(NAME ": Accepting connections\n"); |
async_manager(); |
/* Never reached */ |
return 0; |
} |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/vfs/vfs.c |
---|
43,7 → 43,7 |
#include <bool.h> |
#include <string.h> |
#include <as.h> |
#include <libadt/list.h> |
#include <adt/list.h> |
#include <atomic.h> |
#include "vfs.h" |
94,6 → 94,9 |
case VFS_OPEN: |
vfs_open(callid, &call); |
break; |
case VFS_OPEN_NODE: |
vfs_open_node(callid, &call); |
break; |
case VFS_CLOSE: |
vfs_close(callid, &call); |
break; |
118,6 → 121,15 |
case VFS_RENAME: |
vfs_rename(callid, &call); |
break; |
case VFS_DEVICE: |
vfs_device(callid, &call); |
break; |
case VFS_SYNC: |
vfs_sync(callid, &call); |
break; |
case VFS_NODE: |
vfs_node(callid, &call); |
break; |
default: |
ipc_answer_0(callid, ENOTSUP); |
break; |
164,6 → 176,7 |
/* |
* Set a connectio handling function/fibril. |
*/ |
async_set_pending(vfs_process_pending_mount); |
async_set_client_connection(vfs_connection); |
/* |
/branches/dd/uspace/srv/vfs/vfs_ops.c |
---|
44,8 → 44,8 |
#include <string.h> |
#include <bool.h> |
#include <futex.h> |
#include <rwlock.h> |
#include <libadt/list.h> |
#include <fibril_sync.h> |
#include <adt/list.h> |
#include <unistd.h> |
#include <ctype.h> |
#include <fcntl.h> |
66,6 → 66,7 |
dev_handle_t dev_handle; /**< Device handle */ |
} pending_req_t; |
FIBRIL_MUTEX_INITIALIZE(pending_lock); |
LIST_INITIALIZE(pending_req); |
/** |
72,7 → 73,7 |
* This rwlock prevents the race between a triplet-to-VFS-node resolution and a |
* concurrent VFS operation which modifies the file system namespace. |
*/ |
RWLOCK_INITIALIZE(namespace_rwlock); |
FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock); |
vfs_pair_t rootfs = { |
.fs_handle = 0, |
93,15 → 94,15 |
int phone; |
aid_t msg; |
ipc_call_t answer; |
/* Resolve the path to the mountpoint. */ |
rwlock_write_lock(&namespace_rwlock); |
fibril_rwlock_write_lock(&namespace_rwlock); |
if (rootfs.fs_handle) { |
/* We already have the root FS. */ |
if (str_cmp(mp, "/") == 0) { |
/* Trying to mount root FS over root FS */ |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, EBUSY); |
rwlock_write_unlock(&namespace_rwlock); |
return; |
} |
108,15 → 109,15 |
rc = vfs_lookup_internal(mp, L_DIRECTORY, &mp_res, NULL); |
if (rc != EOK) { |
/* The lookup failed for some reason. */ |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, rc); |
rwlock_write_unlock(&namespace_rwlock); |
return; |
} |
mp_node = vfs_node_get(&mp_res); |
if (!mp_node) { |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, ENOMEM); |
rwlock_write_unlock(&namespace_rwlock); |
return; |
} |
141,18 → 142,18 |
rc = ipc_data_write_start(phone, (void *)opts, |
str_size(opts)); |
if (rc != EOK) { |
vfs_release_phone(phone); |
async_wait_for(msg, NULL); |
vfs_release_phone(phone); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, rc); |
rwlock_write_unlock(&namespace_rwlock); |
return; |
} |
vfs_release_phone(phone); |
async_wait_for(msg, &rc); |
vfs_release_phone(phone); |
if (rc != EOK) { |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, rc); |
rwlock_write_unlock(&namespace_rwlock); |
return; |
} |
174,8 → 175,8 |
mr_node = vfs_node_get(&mr_res); |
assert(mr_node); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, rc); |
rwlock_write_unlock(&namespace_rwlock); |
return; |
} else { |
/* |
182,8 → 183,8 |
* We can't resolve this without the root filesystem |
* being mounted first. |
*/ |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, ENOENT); |
rwlock_write_unlock(&namespace_rwlock); |
return; |
} |
} |
207,13 → 208,13 |
/* send connection */ |
rc = async_req_1_0(phone, IPC_M_CONNECTION_CLONE, mountee_phone); |
if (rc != EOK) { |
vfs_release_phone(phone); |
async_wait_for(msg, NULL); |
vfs_release_phone(phone); |
/* Mount failed, drop reference to mp_node. */ |
if (mp_node) |
vfs_node_put(mp_node); |
ipc_answer_0(rid, rc); |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
return; |
} |
220,17 → 221,17 |
/* send the mount options */ |
rc = ipc_data_write_start(phone, (void *)opts, str_size(opts)); |
if (rc != EOK) { |
vfs_release_phone(phone); |
async_wait_for(msg, NULL); |
vfs_release_phone(phone); |
/* Mount failed, drop reference to mp_node. */ |
if (mp_node) |
vfs_node_put(mp_node); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, rc); |
rwlock_write_unlock(&namespace_rwlock); |
return; |
} |
vfs_release_phone(phone); |
async_wait_for(msg, &rc); |
vfs_release_phone(phone); |
if (rc == EOK) { |
rindex = (fs_index_t) IPC_GET_ARG1(answer); |
254,7 → 255,7 |
} |
ipc_answer_0(rid, rc); |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
} |
/** Process pending mount requests */ |
263,9 → 264,10 |
link_t *cur; |
loop: |
fibril_mutex_lock(&pending_lock); |
for (cur = pending_req.next; cur != &pending_req; cur = cur->next) { |
pending_req_t *pr = list_get_instance(cur, pending_req_t, link); |
fs_handle_t fs_handle = fs_name_to_handle(pr->fs_name, true); |
if (!fs_handle) |
continue; |
282,8 → 284,11 |
free(pr->opts); |
list_remove(cur); |
free(pr); |
fibril_mutex_unlock(&pending_lock); |
fibril_yield(); |
goto loop; |
} |
fibril_mutex_unlock(&pending_lock); |
} |
void vfs_mount(ipc_callid_t rid, ipc_call_t *request) |
462,7 → 467,9 |
pr->rid = rid; |
pr->dev_handle = dev_handle; |
link_initialize(&pr->link); |
fibril_mutex_lock(&pending_lock); |
list_append(&pr->link, &pending_req); |
fibril_mutex_unlock(&pending_lock); |
return; |
} |
490,7 → 497,7 |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
/* |
* The POSIX interface is open(path, oflag, mode). |
* We can receive oflags and mode along with the VFS_OPEN call; the path |
503,29 → 510,30 |
int oflag = IPC_GET_ARG2(*request); |
int mode = IPC_GET_ARG3(*request); |
size_t len; |
/* |
* Make sure that we are called with exactly one of L_FILE and |
* L_DIRECTORY. |
* L_DIRECTORY. Make sure that the user does not pass L_OPEN. |
*/ |
if ((lflag & (L_FILE | L_DIRECTORY)) == 0 || |
(lflag & (L_FILE | L_DIRECTORY)) == (L_FILE | L_DIRECTORY)) { |
if (((lflag & (L_FILE | L_DIRECTORY)) == 0) || |
((lflag & (L_FILE | L_DIRECTORY)) == (L_FILE | L_DIRECTORY)) || |
((lflag & L_OPEN) != 0)) { |
ipc_answer_0(rid, EINVAL); |
return; |
} |
if (oflag & O_CREAT) |
lflag |= L_CREATE; |
if (oflag & O_EXCL) |
lflag |= L_EXCLUSIVE; |
ipc_callid_t callid; |
if (!ipc_data_write_receive(&callid, &len)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
} |
char *path = malloc(len + 1); |
if (!path) { |
ipc_answer_0(callid, ENOMEM); |
532,6 → 540,7 |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
int rc; |
if ((rc = ipc_data_write_finalize(callid, path, len))) { |
ipc_answer_0(rid, rc); |
546,40 → 555,40 |
* triplet. |
*/ |
if (lflag & L_CREATE) |
rwlock_write_lock(&namespace_rwlock); |
fibril_rwlock_write_lock(&namespace_rwlock); |
else |
rwlock_read_lock(&namespace_rwlock); |
fibril_rwlock_read_lock(&namespace_rwlock); |
/* The path is now populated and we can call vfs_lookup_internal(). */ |
vfs_lookup_res_t lr; |
rc = vfs_lookup_internal(path, lflag, &lr, NULL); |
if (rc) { |
rc = vfs_lookup_internal(path, lflag | L_OPEN, &lr, NULL); |
if (rc != EOK) { |
if (lflag & L_CREATE) |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
else |
rwlock_read_unlock(&namespace_rwlock); |
fibril_rwlock_read_unlock(&namespace_rwlock); |
ipc_answer_0(rid, rc); |
free(path); |
return; |
} |
/* Path is no longer needed. */ |
free(path); |
vfs_node_t *node = vfs_node_get(&lr); |
if (lflag & L_CREATE) |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
else |
rwlock_read_unlock(&namespace_rwlock); |
fibril_rwlock_read_unlock(&namespace_rwlock); |
/* Truncate the file if requested and if necessary. */ |
if (oflag & O_TRUNC) { |
rwlock_write_lock(&node->contents_rwlock); |
fibril_rwlock_write_lock(&node->contents_rwlock); |
if (node->size) { |
rc = vfs_truncate_internal(node->fs_handle, |
node->dev_handle, node->index, 0); |
if (rc) { |
rwlock_write_unlock(&node->contents_rwlock); |
fibril_rwlock_write_unlock(&node->contents_rwlock); |
vfs_node_put(node); |
ipc_answer_0(rid, rc); |
return; |
586,9 → 595,9 |
} |
node->size = 0; |
} |
rwlock_write_unlock(&node->contents_rwlock); |
fibril_rwlock_write_unlock(&node->contents_rwlock); |
} |
/* |
* Get ourselves a file descriptor and the corresponding vfs_file_t |
* structure. |
601,10 → 610,87 |
} |
vfs_file_t *file = vfs_file_get(fd); |
file->node = node; |
if (oflag & O_APPEND) |
if (oflag & O_APPEND) |
file->append = true; |
/* |
* The following increase in reference count is for the fact that the |
* file is being opened and that a file structure is pointing to it. |
* It is necessary so that the file will not disappear when |
* vfs_node_put() is called. The reference will be dropped by the |
* respective VFS_CLOSE. |
*/ |
vfs_node_addref(node); |
vfs_node_put(node); |
/* Success! Return the new file descriptor to the client. */ |
ipc_answer_1(rid, EOK, fd); |
} |
void vfs_open_node(ipc_callid_t rid, ipc_call_t *request) |
{ |
// FIXME: check for sanity of the supplied fs, dev and index |
if (!vfs_files_init()) { |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
/* |
* The interface is open_node(fs, dev, index, oflag). |
*/ |
vfs_lookup_res_t lr; |
lr.triplet.fs_handle = IPC_GET_ARG1(*request); |
lr.triplet.dev_handle = IPC_GET_ARG2(*request); |
lr.triplet.index = IPC_GET_ARG3(*request); |
int oflag = IPC_GET_ARG4(*request); |
fibril_rwlock_read_lock(&namespace_rwlock); |
int rc = vfs_open_node_internal(&lr); |
if (rc != EOK) { |
fibril_rwlock_read_unlock(&namespace_rwlock); |
ipc_answer_0(rid, rc); |
return; |
} |
vfs_node_t *node = vfs_node_get(&lr); |
fibril_rwlock_read_unlock(&namespace_rwlock); |
/* Truncate the file if requested and if necessary. */ |
if (oflag & O_TRUNC) { |
fibril_rwlock_write_lock(&node->contents_rwlock); |
if (node->size) { |
rc = vfs_truncate_internal(node->fs_handle, |
node->dev_handle, node->index, 0); |
if (rc) { |
fibril_rwlock_write_unlock(&node->contents_rwlock); |
vfs_node_put(node); |
ipc_answer_0(rid, rc); |
return; |
} |
node->size = 0; |
} |
fibril_rwlock_write_unlock(&node->contents_rwlock); |
} |
/* |
* Get ourselves a file descriptor and the corresponding vfs_file_t |
* structure. |
*/ |
int fd = vfs_fd_alloc(); |
if (fd < 0) { |
vfs_node_put(node); |
ipc_answer_0(rid, fd); |
return; |
} |
vfs_file_t *file = vfs_file_get(fd); |
file->node = node; |
if (oflag & O_APPEND) |
file->append = true; |
/* |
* The following increase in reference count is for the fact that the |
* file is being opened and that a file structure is pointing to it. |
* It is necessary so that the file will not disappear when |
613,18 → 699,137 |
*/ |
vfs_node_addref(node); |
vfs_node_put(node); |
/* Success! Return the new file descriptor to the client. */ |
ipc_answer_1(rid, EOK, fd); |
} |
void vfs_close(ipc_callid_t rid, ipc_call_t *request) |
void vfs_node(ipc_callid_t rid, ipc_call_t *request) |
{ |
int fd = IPC_GET_ARG1(*request); |
int rc = vfs_fd_free(fd); |
/* Lookup the file structure corresponding to the file descriptor. */ |
vfs_file_t *file = vfs_file_get(fd); |
if (!file) { |
ipc_answer_0(rid, ENOENT); |
return; |
} |
ipc_answer_3(rid, EOK, file->node->fs_handle, file->node->dev_handle, |
file->node->index); |
} |
void vfs_device(ipc_callid_t rid, ipc_call_t *request) |
{ |
int fd = IPC_GET_ARG1(*request); |
/* Lookup the file structure corresponding to the file descriptor. */ |
vfs_file_t *file = vfs_file_get(fd); |
if (!file) { |
ipc_answer_0(rid, ENOENT); |
return; |
} |
/* |
* Lock the open file structure so that no other thread can manipulate |
* the same open file at a time. |
*/ |
fibril_mutex_lock(&file->lock); |
int fs_phone = vfs_grab_phone(file->node->fs_handle); |
/* Make a VFS_DEVICE request at the destination FS server. */ |
aid_t msg; |
ipc_call_t answer; |
msg = async_send_2(fs_phone, IPC_GET_METHOD(*request), |
file->node->dev_handle, file->node->index, &answer); |
vfs_release_phone(fs_phone); |
/* Wait for reply from the FS server. */ |
ipcarg_t rc; |
async_wait_for(msg, &rc); |
fibril_mutex_unlock(&file->lock); |
ipc_answer_1(rid, EOK, IPC_GET_ARG1(answer)); |
} |
void vfs_sync(ipc_callid_t rid, ipc_call_t *request) |
{ |
int fd = IPC_GET_ARG1(*request); |
/* Lookup the file structure corresponding to the file descriptor. */ |
vfs_file_t *file = vfs_file_get(fd); |
if (!file) { |
ipc_answer_0(rid, ENOENT); |
return; |
} |
/* |
* Lock the open file structure so that no other thread can manipulate |
* the same open file at a time. |
*/ |
fibril_mutex_lock(&file->lock); |
int fs_phone = vfs_grab_phone(file->node->fs_handle); |
/* Make a VFS_SYMC request at the destination FS server. */ |
aid_t msg; |
ipc_call_t answer; |
msg = async_send_2(fs_phone, IPC_GET_METHOD(*request), |
file->node->dev_handle, file->node->index, &answer); |
vfs_release_phone(fs_phone); |
/* Wait for reply from the FS server. */ |
ipcarg_t rc; |
async_wait_for(msg, &rc); |
fibril_mutex_unlock(&file->lock); |
ipc_answer_0(rid, rc); |
} |
void vfs_close(ipc_callid_t rid, ipc_call_t *request) |
{ |
int fd = IPC_GET_ARG1(*request); |
/* Lookup the file structure corresponding to the file descriptor. */ |
vfs_file_t *file = vfs_file_get(fd); |
if (!file) { |
ipc_answer_0(rid, ENOENT); |
return; |
} |
/* |
* Lock the open file structure so that no other thread can manipulate |
* the same open file at a time. |
*/ |
fibril_mutex_lock(&file->lock); |
int fs_phone = vfs_grab_phone(file->node->fs_handle); |
/* Make a VFS_CLOSE request at the destination FS server. */ |
aid_t msg; |
ipc_call_t answer; |
msg = async_send_2(fs_phone, IPC_GET_METHOD(*request), |
file->node->dev_handle, file->node->index, &answer); |
vfs_release_phone(fs_phone); |
/* Wait for reply from the FS server. */ |
ipcarg_t rc; |
async_wait_for(msg, &rc); |
fibril_mutex_unlock(&file->lock); |
int retval = IPC_GET_ARG1(answer); |
if (retval != EOK) |
ipc_answer_0(rid, retval); |
retval = vfs_fd_free(fd); |
ipc_answer_0(rid, retval); |
} |
static void vfs_rdwr(ipc_callid_t rid, ipc_call_t *request, bool read) |
{ |
667,7 → 872,7 |
* Lock the open file structure so that no other thread can manipulate |
* the same open file at a time. |
*/ |
futex_down(&file->lock); |
fibril_mutex_lock(&file->lock); |
/* |
* Lock the file's node so that no other client can read/write to it at |
674,9 → 879,9 |
* the same time. |
*/ |
if (read) |
rwlock_read_lock(&file->node->contents_rwlock); |
fibril_rwlock_read_lock(&file->node->contents_rwlock); |
else |
rwlock_write_lock(&file->node->contents_rwlock); |
fibril_rwlock_write_lock(&file->node->contents_rwlock); |
if (file->node->type == VFS_NODE_DIRECTORY) { |
/* |
684,7 → 889,7 |
* while we are in readdir(). |
*/ |
assert(read); |
rwlock_read_lock(&namespace_rwlock); |
fibril_rwlock_read_lock(&namespace_rwlock); |
} |
int fs_phone = vfs_grab_phone(file->node->fs_handle); |
704,31 → 909,32 |
* don't have to bother. |
*/ |
ipc_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); |
vfs_release_phone(fs_phone); |
/* Wait for reply from the FS server. */ |
ipcarg_t rc; |
async_wait_for(msg, &rc); |
size_t bytes = IPC_GET_ARG1(answer); |
if (file->node->type == VFS_NODE_DIRECTORY) |
rwlock_read_unlock(&namespace_rwlock); |
fibril_rwlock_read_unlock(&namespace_rwlock); |
/* Unlock the VFS node. */ |
if (read) |
rwlock_read_unlock(&file->node->contents_rwlock); |
fibril_rwlock_read_unlock(&file->node->contents_rwlock); |
else { |
/* Update the cached version of node's size. */ |
if (rc == EOK) |
file->node->size = IPC_GET_ARG2(answer); |
rwlock_write_unlock(&file->node->contents_rwlock); |
fibril_rwlock_write_unlock(&file->node->contents_rwlock); |
} |
/* Update the position pointer and unlock the open file. */ |
if (rc == EOK) |
file->pos += bytes; |
futex_up(&file->lock); |
fibril_mutex_unlock(&file->lock); |
/* |
* FS server's reply is the final result of the whole operation we |
762,40 → 968,40 |
} |
off_t newpos; |
futex_down(&file->lock); |
fibril_mutex_lock(&file->lock); |
if (whence == SEEK_SET) { |
file->pos = off; |
futex_up(&file->lock); |
fibril_mutex_unlock(&file->lock); |
ipc_answer_1(rid, EOK, off); |
return; |
} |
if (whence == SEEK_CUR) { |
if (file->pos + off < file->pos) { |
futex_up(&file->lock); |
fibril_mutex_unlock(&file->lock); |
ipc_answer_0(rid, EOVERFLOW); |
return; |
} |
file->pos += off; |
newpos = file->pos; |
futex_up(&file->lock); |
fibril_mutex_unlock(&file->lock); |
ipc_answer_1(rid, EOK, newpos); |
return; |
} |
if (whence == SEEK_END) { |
rwlock_read_lock(&file->node->contents_rwlock); |
fibril_rwlock_read_lock(&file->node->contents_rwlock); |
size_t size = file->node->size; |
rwlock_read_unlock(&file->node->contents_rwlock); |
fibril_rwlock_read_unlock(&file->node->contents_rwlock); |
if (size + off < size) { |
futex_up(&file->lock); |
fibril_mutex_unlock(&file->lock); |
ipc_answer_0(rid, EOVERFLOW); |
return; |
} |
newpos = size + off; |
futex_up(&file->lock); |
fibril_mutex_unlock(&file->lock); |
ipc_answer_1(rid, EOK, newpos); |
return; |
} |
futex_up(&file->lock); |
fibril_mutex_unlock(&file->lock); |
ipc_answer_0(rid, EINVAL); |
} |
824,16 → 1030,16 |
ipc_answer_0(rid, ENOENT); |
return; |
} |
futex_down(&file->lock); |
fibril_mutex_lock(&file->lock); |
rwlock_write_lock(&file->node->contents_rwlock); |
fibril_rwlock_write_lock(&file->node->contents_rwlock); |
rc = vfs_truncate_internal(file->node->fs_handle, |
file->node->dev_handle, file->node->index, size); |
if (rc == EOK) |
file->node->size = size; |
rwlock_write_unlock(&file->node->contents_rwlock); |
fibril_rwlock_write_unlock(&file->node->contents_rwlock); |
futex_up(&file->lock); |
fibril_mutex_unlock(&file->lock); |
ipc_answer_0(rid, (ipcarg_t)rc); |
} |
863,10 → 1069,10 |
} |
path[len] = '\0'; |
rwlock_write_lock(&namespace_rwlock); |
fibril_rwlock_write_lock(&namespace_rwlock); |
int lflag = L_DIRECTORY | L_CREATE | L_EXCLUSIVE; |
rc = vfs_lookup_internal(path, lflag, NULL, NULL); |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
free(path); |
ipc_answer_0(rid, rc); |
} |
897,13 → 1103,13 |
} |
path[len] = '\0'; |
rwlock_write_lock(&namespace_rwlock); |
fibril_rwlock_write_lock(&namespace_rwlock); |
lflag &= L_DIRECTORY; /* sanitize lflag */ |
vfs_lookup_res_t lr; |
rc = vfs_lookup_internal(path, lflag | L_UNLINK, &lr, NULL); |
free(path); |
if (rc != EOK) { |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, rc); |
return; |
} |
917,7 → 1123,7 |
futex_down(&nodes_futex); |
node->lnkcnt--; |
futex_up(&nodes_futex); |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
vfs_node_put(node); |
ipc_answer_0(rid, EOK); |
} |
998,11 → 1204,11 |
vfs_lookup_res_t old_lr; |
vfs_lookup_res_t new_lr; |
vfs_lookup_res_t new_par_lr; |
rwlock_write_lock(&namespace_rwlock); |
fibril_rwlock_write_lock(&namespace_rwlock); |
/* Lookup the node belonging to the old file name. */ |
rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL); |
if (rc != EOK) { |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, rc); |
free(old); |
free(new); |
1010,7 → 1216,7 |
} |
vfs_node_t *old_node = vfs_node_get(&old_lr); |
if (!old_node) { |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, ENOMEM); |
free(old); |
free(new); |
1019,7 → 1225,7 |
/* Determine the path to the parent of the node with the new name. */ |
char *parentc = str_dup(newc); |
if (!parentc) { |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, rc); |
free(old); |
free(new); |
1034,7 → 1240,7 |
rc = vfs_lookup_internal(parentc, L_NONE, &new_par_lr, NULL); |
free(parentc); /* not needed anymore */ |
if (rc != EOK) { |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, rc); |
free(old); |
free(new); |
1043,7 → 1249,7 |
/* Check whether linking to the same file system instance. */ |
if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) || |
(old_node->dev_handle != new_par_lr.triplet.dev_handle)) { |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, EXDEV); /* different file systems */ |
free(old); |
free(new); |
1059,7 → 1265,7 |
case EOK: |
new_node = vfs_node_get(&new_lr); |
if (!new_node) { |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, ENOMEM); |
free(old); |
free(new); |
1070,7 → 1276,7 |
futex_up(&nodes_futex); |
break; |
default: |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
ipc_answer_0(rid, ENOTEMPTY); |
free(old); |
free(new); |
1079,7 → 1285,7 |
/* Create the new link for the new name. */ |
rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index); |
if (rc != EOK) { |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
if (new_node) |
vfs_node_put(new_node); |
ipc_answer_0(rid, rc); |
1093,7 → 1299,7 |
/* Destroy the link for the old name. */ |
rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL); |
if (rc != EOK) { |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
vfs_node_put(old_node); |
if (new_node) |
vfs_node_put(new_node); |
1105,7 → 1311,7 |
futex_down(&nodes_futex); |
old_node->lnkcnt--; |
futex_up(&nodes_futex); |
rwlock_write_unlock(&namespace_rwlock); |
fibril_rwlock_write_unlock(&namespace_rwlock); |
vfs_node_put(old_node); |
if (new_node) |
vfs_node_put(new_node); |
1116,4 → 1322,4 |
/** |
* @} |
*/ |
*/ |
/branches/dd/uspace/srv/vfs/vfs_register.c |
---|
45,14 → 45,14 |
#include <string.h> |
#include <ctype.h> |
#include <bool.h> |
#include <futex.h> |
#include <libadt/list.h> |
#include <fibril_sync.h> |
#include <adt/list.h> |
#include <as.h> |
#include <assert.h> |
#include <atomic.h> |
#include "vfs.h" |
atomic_t fs_head_futex = FUTEX_INITIALIZER; |
FIBRIL_MUTEX_INITIALIZE(fs_head_lock); |
link_t fs_head; |
atomic_t fs_handle_next = { |
159,7 → 159,7 |
return; |
} |
link_initialize(&fs_info->fs_link); |
futex_initialize(&fs_info->phone_futex, 1); |
fibril_mutex_initialize(&fs_info->phone_lock); |
rc = ipc_data_write_finalize(callid, &fs_info->vfs_info, size); |
if (rc != EOK) { |
180,8 → 180,7 |
return; |
} |
futex_down(&fs_head_futex); |
fibril_inc_sercount(); |
fibril_mutex_lock(&fs_head_lock); |
/* |
* Check for duplicit registrations. |
191,8 → 190,7 |
* We already register a fs like this. |
*/ |
dprintf("FS is already registered.\n"); |
fibril_dec_sercount(); |
futex_up(&fs_head_futex); |
fibril_mutex_unlock(&fs_head_lock); |
free(fs_info); |
ipc_answer_0(callid, EEXISTS); |
ipc_answer_0(rid, EEXISTS); |
214,8 → 212,7 |
if (IPC_GET_METHOD(call) != IPC_M_CONNECT_TO_ME) { |
dprintf("Unexpected call, method = %d\n", IPC_GET_METHOD(call)); |
list_remove(&fs_info->fs_link); |
fibril_dec_sercount(); |
futex_up(&fs_head_futex); |
fibril_mutex_unlock(&fs_head_lock); |
free(fs_info); |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
233,8 → 230,7 |
if (!ipc_share_in_receive(&callid, &size)) { |
dprintf("Unexpected call, method = %d\n", IPC_GET_METHOD(call)); |
list_remove(&fs_info->fs_link); |
fibril_dec_sercount(); |
futex_up(&fs_head_futex); |
fibril_mutex_unlock(&fs_head_lock); |
ipc_hangup(fs_info->phone); |
free(fs_info); |
ipc_answer_0(callid, EINVAL); |
248,8 → 244,7 |
if (size != PLB_SIZE) { |
dprintf("Client suggests wrong size of PFB, size = %d\n", size); |
list_remove(&fs_info->fs_link); |
fibril_dec_sercount(); |
futex_up(&fs_head_futex); |
fibril_mutex_unlock(&fs_head_lock); |
ipc_hangup(fs_info->phone); |
free(fs_info); |
ipc_answer_0(callid, EINVAL); |
273,16 → 268,10 |
fs_info->fs_handle = (fs_handle_t) atomic_postinc(&fs_handle_next); |
ipc_answer_1(rid, EOK, (ipcarg_t) fs_info->fs_handle); |
fibril_dec_sercount(); |
futex_up(&fs_head_futex); |
fibril_mutex_unlock(&fs_head_lock); |
dprintf("\"%.*s\" filesystem successfully registered, handle=%d.\n", |
FS_NAME_MAXLEN, fs_info->vfs_info.name, fs_info->fs_handle); |
/* Process pending mount requests possibly waiting |
* for this filesystem implementation. |
*/ |
vfs_process_pending_mount(); |
} |
/** For a given file system handle, implement policy for allocating a phone. |
302,28 → 291,18 |
* be more demanding). Instead, we simply take the respective |
* phone_futex and keep it until vfs_release_phone(). |
*/ |
futex_down(&fs_head_futex); |
fibril_mutex_lock(&fs_head_lock); |
link_t *cur; |
fs_info_t *fs; |
for (cur = fs_head.next; cur != &fs_head; cur = cur->next) { |
fs = list_get_instance(cur, fs_info_t, fs_link); |
if (fs->fs_handle == handle) { |
futex_up(&fs_head_futex); |
/* |
* For now, take the futex unconditionally. |
* Oh yeah, serialization rocks. |
* It will be up'ed in vfs_release_phone(). |
*/ |
futex_down(&fs->phone_futex); |
/* |
* Avoid deadlock with other fibrils in the same thread |
* by disabling fibril preemption. |
*/ |
fibril_inc_sercount(); |
return fs->phone; |
fibril_mutex_unlock(&fs_head_lock); |
fibril_mutex_lock(&fs->phone_lock); |
return fs->phone; |
} |
} |
futex_up(&fs_head_futex); |
fibril_mutex_unlock(&fs_head_lock); |
return 0; |
} |
335,23 → 314,18 |
{ |
bool found = false; |
/* |
* Undo the fibril_inc_sercount() done in vfs_grab_phone(). |
*/ |
fibril_dec_sercount(); |
futex_down(&fs_head_futex); |
fibril_mutex_lock(&fs_head_lock); |
link_t *cur; |
for (cur = fs_head.next; cur != &fs_head; cur = cur->next) { |
fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link); |
if (fs->phone == phone) { |
found = true; |
futex_up(&fs_head_futex); |
futex_up(&fs->phone_futex); |
fibril_mutex_unlock(&fs_head_lock); |
fibril_mutex_unlock(&fs->phone_lock); |
return; |
} |
} |
futex_up(&fs_head_futex); |
fibril_mutex_unlock(&fs_head_lock); |
/* |
* Not good to get here. |
362,8 → 336,8 |
/** Convert file system name to its handle. |
* |
* @param name File system name. |
* @param lock If true, the function will down and up the |
* fs_head_futex. |
* @param lock If true, the function will lock and unlock the |
* fs_head_lock. |
* |
* @return File system handle or zero if file system not found. |
*/ |
372,7 → 346,7 |
int handle = 0; |
if (lock) |
futex_down(&fs_head_futex); |
fibril_mutex_lock(&fs_head_lock); |
link_t *cur; |
for (cur = fs_head.next; cur != &fs_head; cur = cur->next) { |
fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link); |
382,7 → 356,7 |
} |
} |
if (lock) |
futex_up(&fs_head_futex); |
fibril_mutex_unlock(&fs_head_lock); |
return handle; |
} |
/branches/dd/uspace/srv/vfs/vfs.h |
---|
28,70 → 28,26 |
/** @addtogroup fs |
* @{ |
*/ |
*/ |
#ifndef VFS_VFS_H_ |
#define VFS_VFS_H_ |
#include <ipc/ipc.h> |
#include <libadt/list.h> |
#include <adt/list.h> |
#include <fibril_sync.h> |
#include <futex.h> |
#include <rwlock.h> |
#include <sys/types.h> |
#include <devmap.h> |
#include <bool.h> |
#include <ipc/vfs.h> |
// FIXME: according to CONFIG_DEBUG |
// #define dprintf(...) printf(__VA_ARGS__) |
// #define dprintf(...) printf(__VA_ARGS__) |
#define dprintf(...) |
#define VFS_FIRST IPC_FIRST_USER_METHOD |
/* Basic types. */ |
typedef int16_t fs_handle_t; |
typedef uint32_t fs_index_t; |
typedef enum { |
VFS_READ = VFS_FIRST, |
VFS_WRITE, |
VFS_TRUNCATE, |
VFS_MOUNT, |
VFS_UNMOUNT, |
VFS_LAST_CMN, /* keep this the last member of this enum */ |
} vfs_request_cmn_t; |
typedef enum { |
VFS_LOOKUP = VFS_LAST_CMN, |
VFS_MOUNTED, |
VFS_DESTROY, |
VFS_LAST_CLNT, /* keep this the last member of this enum */ |
} vfs_request_clnt_t; |
typedef enum { |
VFS_REGISTER = VFS_LAST_CMN, |
VFS_OPEN, |
VFS_CLOSE, |
VFS_SEEK, |
VFS_MKDIR, |
VFS_UNLINK, |
VFS_RENAME, |
VFS_LAST_SRV, /* keep this the last member of this enum */ |
} vfs_request_srv_t; |
#define FS_NAME_MAXLEN 20 |
/** |
* A structure like this is passed to VFS by each individual FS upon its |
* registration. It assosiates a human-readable identifier with each |
* registered FS. |
*/ |
typedef struct { |
/** Unique identifier of the fs. */ |
char name[FS_NAME_MAXLEN + 1]; |
} vfs_info_t; |
/** |
* A structure like this will be allocated for each registered file system. |
*/ |
typedef struct { |
98,7 → 54,7 |
link_t fs_link; |
vfs_info_t vfs_info; |
fs_handle_t fs_handle; |
futex_t phone_futex; /**< Phone serializing futex. */ |
fibril_mutex_t phone_lock; |
ipcarg_t phone; |
} fs_info_t; |
105,8 → 61,8 |
/** |
* VFS_PAIR uniquely represents a file system instance. |
*/ |
#define VFS_PAIR \ |
fs_handle_t fs_handle; \ |
#define VFS_PAIR \ |
fs_handle_t fs_handle; \ |
dev_handle_t dev_handle; |
/** |
116,8 → 72,8 |
* @note fs_handle, dev_handle and index are meant to be returned in one |
* IPC reply. |
*/ |
#define VFS_TRIPLET \ |
VFS_PAIR; \ |
#define VFS_TRIPLET \ |
VFS_PAIR; \ |
fs_index_t index; |
typedef struct { |
128,45 → 84,6 |
VFS_TRIPLET; |
} vfs_triplet_t; |
/* |
* Lookup flags. |
*/ |
/** |
* No lookup flags used. |
*/ |
#define L_NONE 0 |
/** |
* Lookup will succeed only if the object is a regular file. If L_CREATE is |
* specified, an empty file will be created. This flag is mutually exclusive |
* with L_DIRECTORY. |
*/ |
#define L_FILE 1 |
/** |
* Lookup wil succeed only if the object is a directory. If L_CREATE is |
* specified, an empty directory will be created. This flag is mutually |
* exclusive with L_FILE. |
*/ |
#define L_DIRECTORY 2 |
/** |
* When used with L_CREATE, L_EXCLUSIVE will cause the lookup to fail if the |
* object already exists. L_EXCLUSIVE is implied when L_DIRECTORY is used. |
*/ |
#define L_EXCLUSIVE 4 |
/** |
* L_CREATE is used for creating both regular files and directories. |
*/ |
#define L_CREATE 8 |
/** |
* L_LINK is used for linking to an already existing nodes. |
*/ |
#define L_LINK 16 |
/** |
* L_UNLINK is used to remove leaves from the file system namespace. This flag |
* cannot be passed directly by the client, but will be set by VFS during |
* VFS_UNLINK. |
*/ |
#define L_UNLINK 32 |
typedef enum vfs_node_type { |
VFS_NODE_UNKNOWN, |
VFS_NODE_FILE, |
205,7 → 122,7 |
/** |
* Holding this rwlock prevents modifications of the node's contents. |
*/ |
rwlock_t contents_rwlock; |
fibril_rwlock_t contents_rwlock; |
} vfs_node_t; |
/** |
214,7 → 131,7 |
*/ |
typedef struct { |
/** Serializes access to this open file. */ |
futex_t lock; |
fibril_mutex_t lock; |
vfs_node_t *node; |
234,10 → 151,6 |
extern vfs_pair_t rootfs; /**< Root file system. */ |
#define MAX_PATH_LEN (64 * 1024) |
#define PLB_SIZE (2 * MAX_PATH_LEN) |
/** Each instance of this type describes one path lookup in progress. */ |
typedef struct { |
link_t plb_link; /**< Active PLB entries list link. */ |
252,7 → 165,7 |
#define MAX_MNTOPTS_LEN 256 |
/** Holding this rwlock prevents changes in file system namespace. */ |
extern rwlock_t namespace_rwlock; |
extern fibril_rwlock_t namespace_rwlock; |
extern int vfs_grab_phone(fs_handle_t); |
extern void vfs_release_phone(int); |
259,8 → 172,9 |
extern fs_handle_t fs_name_to_handle(char *, bool); |
extern int vfs_lookup_internal(char *, int, vfs_lookup_res_t *, vfs_pair_t *, |
...); |
extern int vfs_lookup_internal(char *, int, vfs_lookup_res_t *, |
vfs_pair_t *, ...); |
extern int vfs_open_node_internal(vfs_lookup_res_t *); |
extern bool vfs_nodes_init(void); |
extern vfs_node_t *vfs_node_get(vfs_lookup_res_t *); |
283,6 → 197,10 |
extern void vfs_register(ipc_callid_t, ipc_call_t *); |
extern void vfs_mount(ipc_callid_t, ipc_call_t *); |
extern void vfs_open(ipc_callid_t, ipc_call_t *); |
extern void vfs_open_node(ipc_callid_t, ipc_call_t *); |
extern void vfs_device(ipc_callid_t, ipc_call_t *); |
extern void vfs_sync(ipc_callid_t, ipc_call_t *); |
extern void vfs_node(ipc_callid_t, ipc_call_t *); |
extern void vfs_close(ipc_callid_t, ipc_call_t *); |
extern void vfs_read(ipc_callid_t, ipc_call_t *); |
extern void vfs_write(ipc_callid_t, ipc_call_t *); |
/branches/dd/uspace/srv/vfs/vfs_node.c |
---|
39,8 → 39,8 |
#include <stdlib.h> |
#include <string.h> |
#include <futex.h> |
#include <rwlock.h> |
#include <libadt/hash_table.h> |
#include <fibril_sync.h> |
#include <adt/hash_table.h> |
#include <assert.h> |
#include <async.h> |
#include <errno.h> |
177,10 → 177,10 |
node->lnkcnt = result->lnkcnt; |
node->type = result->type; |
link_initialize(&node->nh_link); |
rwlock_initialize(&node->contents_rwlock); |
fibril_rwlock_initialize(&node->contents_rwlock); |
hash_table_insert(&nodes, key, &node->nh_link); |
} else { |
node = hash_table_get_instance(tmp, vfs_node_t, nh_link); |
node = hash_table_get_instance(tmp, vfs_node_t, nh_link); |
if (node->type == VFS_NODE_UNKNOWN && |
result->type != VFS_NODE_UNKNOWN) { |
/* Upgrade the node type. */ |
233,4 → 233,4 |
/** |
* @} |
*/ |
*/ |
/branches/dd/uspace/srv/vfs/vfs_lookup.c |
---|
28,10 → 28,10 |
/** @addtogroup fs |
* @{ |
*/ |
*/ |
/** |
* @file vfs_lookup.c |
* @file vfs_lookup.c |
* @brief |
*/ |
43,26 → 43,27 |
#include <stdarg.h> |
#include <bool.h> |
#include <futex.h> |
#include <libadt/list.h> |
#include <adt/list.h> |
#include <vfs/canonify.h> |
#define min(a, b) ((a) < (b) ? (a) : (b)) |
#define min(a, b) ((a) < (b) ? (a) : (b)) |
futex_t plb_futex = FUTEX_INITIALIZER; |
link_t plb_head; /**< PLB entry ring buffer. */ |
link_t plb_head; /**< PLB entry ring buffer. */ |
uint8_t *plb = NULL; |
/** Perform a path lookup. |
* |
* @param path Path to be resolved; it must be a NULL-terminated |
* string. |
* @param lflag Flags to be used during lookup. |
* @param result Empty structure where the lookup result will be stored. |
* Can be NULL. |
* @param altroot If non-empty, will be used instead of rootfs as the root |
* of the whole VFS tree. |
* @param path Path to be resolved; it must be a NULL-terminated |
* string. |
* @param lflag Flags to be used during lookup. |
* @param result Empty structure where the lookup result will be stored. |
* Can be NULL. |
* @param altroot If non-empty, will be used instead of rootfs as the root |
* of the whole VFS tree. |
* |
* @return EOK on success or an error code from errno.h. |
* @return EOK on success or an error code from errno.h. |
* |
*/ |
int vfs_lookup_internal(char *path, int lflag, vfs_lookup_res_t *result, |
vfs_pair_t *altroot, ...) |
163,10 → 164,10 |
(ipcarg_t) root->dev_handle, (ipcarg_t) lflag, (ipcarg_t) index, |
&answer); |
vfs_release_phone(phone); |
ipcarg_t rc; |
async_wait_for(req, &rc); |
futex_down(&plb_futex); |
list_remove(&entry.plb_link); |
/* |
176,7 → 177,7 |
memset(plb, 0, cnt2); |
futex_up(&plb_futex); |
if ((rc == EOK) && result) { |
if ((rc == EOK) && (result)) { |
result->triplet.fs_handle = (fs_handle_t) IPC_GET_ARG1(answer); |
result->triplet.dev_handle = (dev_handle_t) IPC_GET_ARG2(answer); |
result->triplet.index = (fs_index_t) IPC_GET_ARG3(answer); |
193,6 → 194,39 |
return rc; |
} |
/** Perform a node open operation. |
* |
* @return EOK on success or an error code from errno.h. |
* |
*/ |
int vfs_open_node_internal(vfs_lookup_res_t *result) |
{ |
int phone = vfs_grab_phone(result->triplet.fs_handle); |
ipc_call_t answer; |
aid_t req = async_send_2(phone, VFS_OPEN_NODE, |
(ipcarg_t) result->triplet.dev_handle, |
(ipcarg_t) result->triplet.index, &answer); |
vfs_release_phone(phone); |
ipcarg_t rc; |
async_wait_for(req, &rc); |
if (rc == EOK) { |
result->size = (size_t) IPC_GET_ARG1(answer); |
result->lnkcnt = (unsigned) IPC_GET_ARG2(answer); |
if (IPC_GET_ARG3(answer) & L_FILE) |
result->type = VFS_NODE_FILE; |
else if (IPC_GET_ARG3(answer) & L_DIRECTORY) |
result->type = VFS_NODE_DIRECTORY; |
else |
result->type = VFS_NODE_UNKNOWN; |
} |
return rc; |
} |
/** |
* @} |
*/ |
/branches/dd/uspace/srv/vfs/vfs_file.c |
---|
40,6 → 40,8 |
#include <string.h> |
#include <assert.h> |
#include <bool.h> |
#include <fibril.h> |
#include <fibril_sync.h> |
#include "vfs.h" |
/** |
57,7 → 59,7 |
* This resource being per-connection and, in the first place, per-fibril, we |
* don't need to protect it by a futex. |
*/ |
__thread vfs_file_t **files = NULL; |
fibril_local vfs_file_t **files = NULL; |
/** Initialize the table of open files. */ |
bool vfs_files_init(void) |
89,7 → 91,7 |
return ENOMEM; |
memset(files[i], 0, sizeof(vfs_file_t)); |
futex_initialize(&files[i]->lock, 1); |
fibril_mutex_initialize(&files[i]->lock); |
vfs_file_addref(files[i]); |
return (int) i; |
} |