Subversion Repositories HelenOS

Compare Revisions

No changes between revisions

Ignore whitespace Rev 4536 → Rev 4537

/branches/dd/uspace/srv/fhc/Makefile
File deleted
/branches/dd/uspace/srv/fhc/fhc.c
File deleted
/branches/dd/uspace/srv/obio/obio.c
File deleted
/branches/dd/uspace/srv/obio/Makefile
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;
}