Index: uspace/lib/graph/Makefile
===================================================================
--- uspace/lib/graph/Makefile	(revision 6d5e378b28e2c858f3813b5d4d57fa46f709d753)
+++ uspace/lib/graph/Makefile	(revision 6d5e378b28e2c858f3813b5d4d57fa46f709d753)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2011 Petr Koupy
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBRARY = libgraph
+SLIBRARY = libgraph.so.0.0
+LSONAME = libgraph.so0
+
+SOURCES = \
+	graph.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/graph/graph.c
===================================================================
--- uspace/lib/graph/graph.c	(revision 6d5e378b28e2c858f3813b5d4d57fa46f709d753)
+++ uspace/lib/graph/graph.c	(revision 6d5e378b28e2c858f3813b5d4d57fa46f709d753)
@@ -0,0 +1,650 @@
+/*
+ * Copyright (c) 2011 Petr Koupy
+ * 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 graph
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <as.h>
+#include "graph.h"
+
+#define NAMESPACE         "graphemu"
+#define VISUALIZER_NAME   "vsl"
+#define RENDERER_NAME     "rnd"
+
+static sysarg_t namespace_idx = 0;
+static sysarg_t visualizer_idx = 0;
+static sysarg_t renderer_idx = 0;
+
+static LIST_INITIALIZE(visualizer_list);
+static LIST_INITIALIZE(renderer_list);
+
+static FIBRIL_MUTEX_INITIALIZE(visualizer_list_mtx);
+static FIBRIL_MUTEX_INITIALIZE(renderer_list_mtx);
+
+visualizer_t *graph_alloc_visualizer(void)
+{
+	visualizer_t *vs = (visualizer_t *) malloc(sizeof(visualizer_t));
+	if (vs == NULL) {
+		return NULL;
+	}
+	
+	return vs;
+}
+
+renderer_t *graph_alloc_renderer(void)
+{
+	// TODO
+	renderer_t *rnd = (renderer_t *) malloc(sizeof(renderer_t));
+	if (rnd == NULL) {
+		return NULL;
+	}
+
+	return rnd;
+}
+
+void graph_init_visualizer(visualizer_t *vs)
+{
+	link_initialize(&vs->link);
+	atomic_set(&vs->ref_cnt, 0);
+	vs->notif_sess = NULL;
+	fibril_mutex_initialize(&vs->mode_mtx);
+	list_initialize(&vs->modes);
+	vs->mode_set = false;
+	vs->cells.data = NULL;
+	vs->dev_ctx = NULL;
+}
+
+void graph_init_renderer(renderer_t *rnd)
+{
+	// TODO
+	link_initialize(&rnd->link);
+	atomic_set(&rnd->ref_cnt, 0);
+}
+
+int graph_register_visualizer(visualizer_t *vs)
+{
+	int rc = EOK;
+	
+	char node[LOC_NAME_MAXLEN + 1];
+	snprintf(node, LOC_NAME_MAXLEN, "%s%zu/%s%zu", NAMESPACE,
+	    namespace_idx, VISUALIZER_NAME, visualizer_idx++);
+
+	category_id_t cat;
+	rc = loc_category_get_id("visualizer", &cat, 0);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = loc_service_register(node, &vs->reg_svc_handle);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = loc_service_add_to_cat(vs->reg_svc_handle, cat);
+	if (rc != EOK) {
+		loc_service_unregister(vs->reg_svc_handle);
+		return rc;
+	}
+
+	fibril_mutex_lock(&visualizer_list_mtx);
+	list_append(&vs->link, &visualizer_list);
+	fibril_mutex_unlock(&visualizer_list_mtx);
+
+	return rc;
+}
+
+int graph_register_renderer(renderer_t *rnd)
+{
+	int rc = EOK;
+
+	char node[LOC_NAME_MAXLEN + 1];
+	snprintf(node, LOC_NAME_MAXLEN, "%s%zu/%s%zu", NAMESPACE,
+	    namespace_idx, RENDERER_NAME, renderer_idx++);
+
+	category_id_t cat;
+	rc = loc_category_get_id("renderer", &cat, 0);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = loc_service_register(node, &rnd->reg_svc_handle);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = loc_service_add_to_cat(rnd->reg_svc_handle, cat);
+	if (rc != EOK) {
+		loc_service_unregister(rnd->reg_svc_handle);
+		return rc;
+	}
+
+	fibril_mutex_lock(&renderer_list_mtx);
+	list_append(&rnd->link, &renderer_list);
+	fibril_mutex_unlock(&renderer_list_mtx);
+
+	return rc;
+}
+
+visualizer_t *graph_get_visualizer(sysarg_t handle)
+{
+	visualizer_t *vs = NULL;
+
+	fibril_mutex_lock(&visualizer_list_mtx);
+	list_foreach(visualizer_list, link) {
+		visualizer_t *cur = list_get_instance(link, visualizer_t, link);
+		if (cur->reg_svc_handle == handle) {
+			vs = cur;
+			break;
+		}
+	}
+	fibril_mutex_unlock(&visualizer_list_mtx);
+
+	return vs;
+}
+
+renderer_t *graph_get_renderer(sysarg_t handle)
+{
+	renderer_t *rnd = NULL;
+
+	fibril_mutex_lock(&renderer_list_mtx);
+	list_foreach(renderer_list, link) {
+		renderer_t *cur = list_get_instance(link, renderer_t, link);
+		if (cur->reg_svc_handle == handle) {
+			rnd = cur;
+			break;
+		}
+	}
+	fibril_mutex_unlock(&renderer_list_mtx);
+
+	return rnd;
+}
+
+int graph_unregister_visualizer(visualizer_t *vs)
+{
+	int rc = EOK;
+
+	fibril_mutex_lock(&visualizer_list_mtx);
+	rc = loc_service_unregister(vs->reg_svc_handle);
+	list_remove(&vs->link);
+	fibril_mutex_unlock(&visualizer_list_mtx);
+
+	return rc;
+}
+
+int graph_unregister_renderer(renderer_t *rnd)
+{
+	int rc = EOK;
+
+	fibril_mutex_lock(&renderer_list_mtx);
+	rc = loc_service_unregister(rnd->reg_svc_handle);
+	list_remove(&rnd->link);
+	fibril_mutex_unlock(&renderer_list_mtx);
+
+	return rc;
+}
+
+void graph_destroy_visualizer(visualizer_t *vs)
+{
+	assert(atomic_get(&vs->ref_cnt) == 0);
+	assert(vs->notif_sess == NULL);
+	assert(!fibril_mutex_is_locked(&vs->mode_mtx));
+	assert(list_empty(&vs->modes));
+	assert(vs->mode_set == false);
+	assert(vs->cells.data == NULL);
+	assert(vs->dev_ctx == NULL);
+
+	free(vs);
+}
+
+void graph_destroy_renderer(renderer_t *rnd)
+{
+	// TODO
+	assert(atomic_get(&rnd->ref_cnt) == 0);
+
+	free(rnd);
+}
+
+int graph_notify_mode_change(async_sess_t *sess, sysarg_t handle, sysarg_t mode_idx)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	int ret = async_req_2_0(exch, VISUALIZER_MODE_CHANGE, handle, mode_idx);
+	async_exchange_end(exch);
+
+	return ret;
+}
+
+int graph_notify_disconnect(async_sess_t *sess, sysarg_t handle)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	int ret = async_req_1_0(exch, VISUALIZER_DISCONNECT, handle);
+	async_exchange_end(exch);
+
+	async_hangup(sess);
+
+	return ret;
+}
+
+static void vs_claim(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
+{
+	vs->client_side_handle = IPC_GET_ARG1(*icall);
+	int rc = vs->ops.claim(vs);
+	async_answer_0(iid, rc);
+}
+
+static void vs_yield(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
+{
+	/* Deallocate resources for the current mode. */
+	if (vs->mode_set) {
+		if (vs->cells.data != NULL) {
+			as_area_destroy((void *) vs->cells.data);
+			vs->cells.data = NULL;
+		}
+	}
+
+	/* Driver might also deallocate resources for the current mode. */
+	int rc = vs->ops.yield(vs);
+
+	/* Now that the driver was given a chance to deallocate resources,
+	 * current mode can be unset. */
+	if (vs->mode_set) {
+		vs->mode_set = false;
+	}
+
+	async_answer_0(iid, rc);
+}
+
+static void vs_enumerate_modes(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
+{
+	fibril_mutex_lock(&vs->mode_mtx);
+	link_t *link = list_nth(&vs->modes, IPC_GET_ARG1(*icall));
+
+	if (link != NULL) {
+		vslmode_list_element_t *mode_elem =
+		    list_get_instance(link, vslmode_list_element_t, link);
+		vslmode_t mode = mode_elem->mode;
+		fibril_mutex_unlock(&vs->mode_mtx);
+
+		ipc_callid_t callid;
+		size_t len;
+
+        if (!async_data_read_receive(&callid, &len)) {
+			async_answer_0(iid, EINVAL);
+			return;
+        }
+        int rc = async_data_read_finalize(callid, &mode, len);
+		if (rc != EOK) {
+			async_answer_0(iid, ENOMEM);
+			return;
+		}
+
+		async_answer_0(iid, EOK);
+	} else {
+		async_answer_0(iid, ENOENT);
+	}
+}
+
+static void vs_get_default_mode(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
+{
+	fibril_mutex_lock(&vs->mode_mtx);
+	vslmode_list_element_t *mode_elem = NULL;
+	list_foreach(vs->modes, link) {
+		vslmode_list_element_t *cur = list_get_instance(link, vslmode_list_element_t, link);
+		if (cur->mode.index == vs->def_mode_idx) {
+			mode_elem = cur;
+			break;
+		}
+	}
+
+	vslmode_t mode;
+	if (mode_elem != NULL) {
+		mode = mode_elem->mode;
+		fibril_mutex_unlock(&vs->mode_mtx);
+
+		ipc_callid_t callid;
+		size_t len;
+
+		if (!async_data_read_receive(&callid, &len)) {
+			async_answer_0(iid, EINVAL);
+			return;
+		}
+		int rc = async_data_read_finalize(callid, &mode, len);
+		if (rc != EOK) {
+			async_answer_0(iid, ENOMEM);
+			return;
+		}
+		async_answer_0(iid, EOK);
+	} else {
+		fibril_mutex_unlock(&vs->mode_mtx);
+		async_answer_0(iid, ENOENT);
+	}
+}
+
+static void vs_get_current_mode(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
+{
+	if (vs->mode_set) {
+		ipc_callid_t callid;
+		size_t len;
+
+		if (!async_data_read_receive(&callid, &len)) {
+			async_answer_0(iid, EINVAL);
+			return;
+		}
+		int rc = async_data_read_finalize(callid, &vs->cur_mode, len);
+		if (rc != EOK) {
+			async_answer_0(iid, ENOMEM);
+			return;
+		}
+
+		async_answer_0(iid, EOK);
+	} else {
+		async_answer_0(iid, ENOENT);
+	}
+}
+
+static void vs_get_mode(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
+{
+	sysarg_t mode_idx = IPC_GET_ARG1(*icall);
+
+	fibril_mutex_lock(&vs->mode_mtx);
+	vslmode_list_element_t *mode_elem = NULL;
+	list_foreach(vs->modes, link) {
+		vslmode_list_element_t *cur = list_get_instance(link, vslmode_list_element_t, link);
+		if (cur->mode.index == mode_idx) {
+			mode_elem = cur;
+			break;
+		}
+	}
+
+	vslmode_t mode;
+	if (mode_elem != NULL) {
+		mode = mode_elem->mode;
+		fibril_mutex_unlock(&vs->mode_mtx);
+
+		ipc_callid_t callid;
+		size_t len;
+
+		if (!async_data_read_receive(&callid, &len)) {
+			async_answer_0(iid, EINVAL);
+			return;
+		}
+		int rc = async_data_read_finalize(callid, &mode, len);
+		if (rc != EOK) {
+			async_answer_0(iid, ENOMEM);
+			return;
+		}
+		async_answer_0(iid, EOK);
+	} else {
+		fibril_mutex_unlock(&vs->mode_mtx);
+		async_answer_0(iid, ENOENT);
+	}
+}
+
+static void vs_set_mode(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
+{
+	int rc = EOK;
+
+	/* Retrieve mode index and version. */
+	sysarg_t mode_idx = IPC_GET_ARG1(*icall);
+	sysarg_t mode_version = IPC_GET_ARG2(*icall);
+
+	/* Find mode in the list. */
+	fibril_mutex_lock(&vs->mode_mtx);
+	vslmode_list_element_t *mode_elem = NULL;
+	list_foreach(vs->modes, link) {
+		vslmode_list_element_t *cur = list_get_instance(link, vslmode_list_element_t, link);
+		if (cur->mode.index == mode_idx) {
+			mode_elem = cur;
+			break;
+		}
+	}
+
+	/* Extract mode description from the list node. */
+	vslmode_t new_mode;
+	if (mode_elem != NULL) {
+		new_mode = mode_elem->mode;
+		fibril_mutex_unlock(&vs->mode_mtx);
+	} else {
+		fibril_mutex_unlock(&vs->mode_mtx);
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+
+	/* Check whether the mode is still up-to-date. */
+	if (new_mode.version != mode_version) {
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+
+	ipc_callid_t callid;
+	size_t size;
+	unsigned int flags;
+
+	/* Retrieve the shared cell storage for the new mode. */
+	if (!async_share_out_receive(&callid, &size, &flags)) {
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+	void *new_cell_storage;
+	rc = async_share_out_finalize(callid, &new_cell_storage);
+	if ((rc != EOK) || (new_cell_storage == AS_MAP_FAILED)) {
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+
+	/* Change device internal state. */
+	rc = vs->ops.change_mode(vs, new_mode);
+
+	/* Device driver could not establish new mode. Rollback. */
+	if (rc != EOK) {
+		as_area_destroy(new_cell_storage);
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+
+	/* Because resources for the new mode were successfully claimed,
+	 * it is finally possible to free resources allocated for the old mode. */
+	if (vs->mode_set) {
+		if (vs->cells.data != NULL) {
+			as_area_destroy((void *) vs->cells.data);
+			vs->cells.data = NULL;
+		}
+	}
+
+	/* Insert new mode into the visualizer. */
+	vs->cells.width = new_mode.screen_width;
+	vs->cells.height = new_mode.screen_height;
+	vs->cells.data = (pixel_t *) new_cell_storage;
+	vs->cur_mode = new_mode;
+	vs->mode_set = true;
+
+	async_answer_0(iid, EOK);
+}
+
+static void vs_update_damaged_region(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
+{
+#ifdef __32_BITS__
+	sysarg_t x_offset = (IPC_GET_ARG5(*icall) >> 16);
+	sysarg_t y_offset = (IPC_GET_ARG5(*icall) & 0x0000ffff);
+#else
+	sysarg_t x_offset = (IPC_GET_ARG5(*icall) >> 32);
+	sysarg_t y_offset = (IPC_GET_ARG5(*icall) & 0xffffffff);
+#endif
+
+	int rc = vs->ops.handle_damage(vs,
+	    IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall),
+	    IPC_GET_ARG3(*icall), IPC_GET_ARG4(*icall),
+		x_offset, y_offset);
+	async_answer_0(iid, rc);
+}
+
+static void vs_suspend(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
+{
+	int rc = vs->ops.suspend(vs);
+	async_answer_0(iid, rc);
+}
+
+static void vs_wakeup(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
+{
+	int rc = vs->ops.wakeup(vs);
+	async_answer_0(iid, rc);
+}
+
+void graph_visualizer_connection(visualizer_t *vs,
+    ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	ipc_call_t call;
+	ipc_callid_t callid;
+
+	/* Claim the visualizer. */
+	if (!cas(&vs->ref_cnt, 0, 1)) {
+		async_answer_0(iid, ELIMIT);
+		return;
+	}
+
+	/* Accept the connection. */
+	async_answer_0(iid, EOK);
+
+	/* Establish callback session. */
+	callid = async_get_call(&call);
+	vs->notif_sess = async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
+	if (vs->notif_sess != NULL) {
+		async_answer_0(callid, EOK);
+	} else {
+		async_answer_0(callid, ELIMIT);
+	}
+
+	/* Enter command loop. */
+	while (true) {
+		callid = async_get_call(&call);
+
+		if (!IPC_GET_IMETHOD(call)) {
+			async_answer_0(callid, EINVAL);
+			break;
+		}
+
+		switch (IPC_GET_IMETHOD(call)) {
+		case VISUALIZER_CLAIM:
+			vs_claim(vs, callid, &call);
+			break;
+		case VISUALIZER_YIELD:
+			vs_yield(vs, callid, &call);
+			goto terminate;
+		case VISUALIZER_ENUMERATE_MODES:
+			vs_enumerate_modes(vs, callid, &call);
+			break;
+		case VISUALIZER_GET_DEFAULT_MODE:
+			vs_get_default_mode(vs, callid, &call);
+			break;
+		case VISUALIZER_GET_CURRENT_MODE:
+			vs_get_current_mode(vs, callid, &call);
+			break;
+		case VISUALIZER_GET_MODE:
+			vs_get_mode(vs, callid, &call);
+			break;
+		case VISUALIZER_SET_MODE:
+			vs_set_mode(vs, callid, &call);
+			break;
+		case VISUALIZER_UPDATE_DAMAGED_REGION:
+			vs_update_damaged_region(vs, callid, &call);
+			break;
+		case VISUALIZER_SUSPEND:
+			vs_suspend(vs, callid, &call);
+			break;
+		case VISUALIZER_WAKE_UP:
+			vs_wakeup(vs, callid, &call);
+			break;
+		default:
+			async_answer_0(callid, EINVAL);
+			goto terminate;
+		}
+	}
+
+terminate:
+	async_hangup(vs->notif_sess);
+	vs->notif_sess = NULL;
+	atomic_set(&vs->ref_cnt, 0);
+}
+
+void graph_renderer_connection(renderer_t *rnd,
+    ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	// TODO
+
+	ipc_call_t call;
+	ipc_callid_t callid;
+
+	/* Accept the connection. */
+	atomic_inc(&rnd->ref_cnt);
+	async_answer_0(iid, EOK);
+
+	/* Enter command loop. */
+	while (true) {
+		callid = async_get_call(&call);
+
+		if (!IPC_GET_IMETHOD(call)) {
+			async_answer_0(callid, EINVAL);
+			break;
+		}
+
+		switch (IPC_GET_IMETHOD(call)) {
+		default:
+			async_answer_0(callid, EINVAL);
+			goto terminate;
+		}
+	}
+
+terminate:
+	atomic_dec(&rnd->ref_cnt);
+}
+
+void graph_client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	/* Find the visualizer or renderer with the given service ID. */
+	visualizer_t *vs = graph_get_visualizer(IPC_GET_ARG1(*icall));
+	renderer_t *rnd = graph_get_renderer(IPC_GET_ARG1(*icall));
+
+	if (vs != NULL) {
+		graph_visualizer_connection(vs, iid, icall, arg);
+	} else if (rnd != NULL) {
+		graph_renderer_connection(rnd, iid, icall, arg);
+	} else {
+		async_answer_0(iid, ENOENT);
+	}
+}
+
+/** @}
+ */
Index: uspace/lib/graph/graph.h
===================================================================
--- uspace/lib/graph/graph.h	(revision 6d5e378b28e2c858f3813b5d4d57fa46f709d753)
+++ uspace/lib/graph/graph.h	(revision 6d5e378b28e2c858f3813b5d4d57fa46f709d753)
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2011 Petr Koupy
+ * 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 graph
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef GRAPH_GRAPH_H_
+#define GRAPH_GRAPH_H_
+
+#include <sys/types.h>
+#include <bool.h>
+#include <loc.h>
+#include <async.h>
+#include <atomic.h>
+#include <fibril_synch.h>
+#include <adt/list.h>
+#include <io/mode.h>
+#include <io/pixelmap.h>
+#include <ipc/graph.h>
+
+struct visualizer;
+struct renderer;
+
+typedef struct {
+	/**
+	 * Device driver shall allocate any necessary internal structures
+	 * specific for a claimed visualizer. */
+	int (* claim)(struct visualizer *vs);
+	
+	/**
+	 * Device driver shall deallocate any necessary internal structures
+	 * specific for a claimed visualizer. Driver shall also check whether
+	 * the mode is set and if so it shall change its internal state
+	 * accordingly (e.g. deallocate frame buffers). */
+	int (* yield)(struct visualizer *vs);
+	
+	/**
+	 * Device driver shall first try to claim all resources required for
+	 * a new mode (e.g. allocate new framebuffers) and only if successful
+	 * it shall free resources for the old mode. Although such behaviour
+	 * might not be always possible, it is preferable since libgraph tries to
+	 * keep current mode functional if the new mode cannot be set (for any
+	 * reason). If it is convenient for the device driver (e.g. for better
+	 * optimization), the pointer to the handle_damage operation can be
+	 * changed at this point. */
+	int (* change_mode)(struct visualizer *vs, vslmode_t new_mode);
+	
+	/**
+	 * Device driver shall render the cells from damaged region into its
+	 * internal framebuffer. In case the driver use multi-buffering, it
+	 * shall also switch internal buffers (e.g. by pageflip). Offsets
+	 * are intended to support basic vertical and horizontal scrolling on
+	 * the shared backbuffer (i.e. when reading from backbuffer, the offsets
+	 * shall be added to the coordinates and if necessary the result shall be
+	 * wrapped around the edge of the backbuffer). */
+	int (* handle_damage)(struct visualizer *vs,
+	    sysarg_t x, sysarg_t y, sysarg_t width, sysarg_t height,
+		sysarg_t x_offset, sysarg_t y_offset);
+	
+	/**
+	 * Upper layers of the graphic stack might report inactivity. In such
+	 * case, device driver might enable power saving mode on the device
+	 * corresponding to the visualizer. */
+	int (* suspend)(struct visualizer *vs);
+	
+	/**
+	 * When upper layers detect activity on suspended visualizer, device
+	 * driver shall disable power saving mode on the corresponding device. */
+	int (* wakeup)(struct visualizer *vs);
+} visualizer_ops_t;
+
+/**
+ * Represents final output device (e.g. monitor connected to the port
+ * on the graphic adapter, serial console, local/remote virtual monitor).
+ */
+typedef struct visualizer {
+	/**
+	 * Link to the list of all visualizers belonging to the graphic device.
+	 * Field is fully managed by libgraph. */
+	link_t link;
+	
+	/**
+	 * When reference count equals 1, visualizer is claimed by a client,
+	 * when equals 0, visualizer is not claimed. At the time, visualizer
+	 * can be claimed only by a single client.
+	 * Field is fully managed by libgraph. */
+	atomic_t ref_cnt;
+	
+	/**
+	 * Visualizer ID assigned by some particular registration service
+	 * in the system (either location service or device manager). Intended
+	 * for cleanup duties (e.g. unregistering visualizer).
+	 * If the visualizer is registered through libgraph functions, then the
+	 * field is fully managed by libgraph. Otherwise, it is a driver
+	 * responsibility to set and update this field. */
+	sysarg_t reg_svc_handle;
+	
+	/**
+	 * Visualizer ID in the client context. When client gets notified by
+	 * libgraph about some event, it can use this identification to lookup
+	 * data structures corresponding to a particular visualizer (e.g. viewports
+	 * in the compositor).
+	 * Field is fully managed by libgraph. It is assigned when the visualizer
+	 * gets claimed and is valid until it is yielded. */
+	sysarg_t client_side_handle;
+	
+	/**
+	 * Callback session to the client. Established by libgraph during initial
+	 * phase of client connection. Can be used to notify client about
+	 * external asynchronous changes to the output device state
+	 * (e.g. monitor gets disconnected from the graphic adapter, virtual
+	 * monitor is terminated by the user, pivot monitor is rotated by 90
+	 * degrees, virtual monitor is resized by the user).
+	 * Field is fully managed by libgraph. Device driver can use it indirectly
+	 * through notification functions. */
+	async_sess_t *notif_sess;
+	
+	/**
+	 * Mutex protecting the mode list and default mode index. This is required
+	 * for the case when device driver might asynchronously update these
+	 * upon the request from the final output device (e.g. to change mode
+	 * dimensions when virtual monitor is resized).
+	 * Both device driver and libgraph must lock on this mutex when accessing
+	 * modes list or default mode index. */
+	fibril_mutex_t mode_mtx;
+	
+	/**
+	 * List of all modes that can be set by this visualizer. List is populated
+	 * by device driver when creating a new visualizer or when handling the
+	 * request from the final output device to change the available modes.
+	 * When this happens, the device driver is expected to increment version
+	 * numbers in the modified modes. Modes in the list typically represent
+	 * the intersection of modes supported by device driver (graphic adapter)
+	 * and final output device (e.g. monitor).
+	 * Field is fully managed by device driver, libgraph reads it with locked
+	 * mutex. */
+	list_t modes;
+	
+	/**
+	 * Index of the default mode. Might come in handy to the clients that are
+	 * not able to enumerate modes and present the choice to the user
+	 * (either the client does not have such functionality or the client is
+	 * bootstraping without any preliminary knowledge). Device driver shall
+	 * maintain this field at the same time when it is doing any changes to the
+	 * mode list.
+	 * Field is fully managed by device driver, libgraph reads it with locked
+	 * mutex. */
+	sysarg_t def_mode_idx;
+	
+	/**
+	 * Copy of the currently established mode. It is read by both libgraph and
+	 * device driver when deallocating resources for the current mode. Device
+	 * driver can also read it to properly interpret the cell type and its
+	 * internal structures when handling the damage.
+	 * Field is fully managed by libgraph, can be read by device driver. */
+	vslmode_t cur_mode;
+	
+	/**
+	 * Determines whether the visualizer is currently set to some mode or not,
+	 * that is whether cur_mode field contains up-to-date data.
+	 * Field is fully managed by libgraph, can be read by device driver. */
+	bool mode_set;
+	
+	/**
+	 * Device driver function pointers.
+	 * Field is fully managed by device driver, libgraph invokes driver's
+	 * functions through it. */
+	visualizer_ops_t ops;
+	
+	/**
+	 * Backbuffer shared with the client. Sharing is established by libgraph.
+	 * Device driver reads the cells when handling damage. Cells shall be
+	 * interpreted according to the currently set mode.
+	 * Field is fully managed by libgraph, can be read by device driver. */
+	pixelmap_t cells;
+	
+	/**
+	 * Device driver context, completely opaque to the libgraph. Intended to
+	 * contain pointers to frontbuffers or information representing the
+	 * final output device (e.g. hardware port for physical monitor).
+	 * Field is fully managed by device driver. */
+	void *dev_ctx;
+} visualizer_t;
+
+typedef struct {
+	// TODO
+	int dummy;
+} renderer_ops_t;
+
+/**
+ * NOTE: Following description is just a result of brainstorming on how the
+ *       driver of real physical graphic accelerator could be supported by
+ *       libgraph.
+ *
+ * Renderer represents the hardware graphic accelerator. If the device driver
+ * handles more than one physical accelerator (e.g. graphic cards connected in
+ * SLI mode or single graphic card with two GPUs), it is up to the driver
+ * whether the load balancing will be exposed to the clients (that is the
+ * driver will provide multiple renderers) or not (just a single renderer
+ * handling the load balancing internally).
+ *
+ * At runtime, renderer is represented by scheduling thread and multiple
+ * connection fibrils handling client requests. For each client, there is
+ * command queue, condition variable and device context. Connection fibril puts
+ * the command into the command queue and blocks on the condition variable.
+ * Scheduling thread decides what client to serve, switches corresponding device
+ * context into the accelerator, consumes the command from the command queue and
+ * executes it on the accelerator. When the command execution is finished, the
+ * condition variable si signalled and the connection fibril answers the client.
+ *
+ * Operations that are not implemented in the hardware of the accelerator might
+ * be carried out by worker threads managed by scheduling thread. If the
+ * accelerator physical memory is mapped to the address space of the driver, it
+ * could be extended by allowing scheduling thread to page out the memory and
+ * to handle the page faults.
+ *
+ * NOTE: It is not entirely clear which parts should be implemented in libgraph
+ *       and which in the device driver. As a rough sketch, the connection
+ *       fibril routine, command queue and memory paging should be handled
+ *       by libgraph. The scheduling thread and device context should be
+ *       provided by device driver.
+ */
+typedef struct renderer {
+	// TODO
+	link_t link;
+	
+	atomic_t ref_cnt;
+	
+	sysarg_t reg_svc_handle;
+	
+	renderer_ops_t ops;
+} renderer_t;
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Fill in the basic visualizer structure. The device driver shall take the
+ * created torso and to complete it by adding its specific structures
+ * (device context, modes). */
+extern void graph_init_visualizer(visualizer_t *);
+
+extern void graph_init_renderer(renderer_t *);
+
+/*----------------------------------------------------------------------------*/
+
+/*
+ * NOTE: All functions in this section are intended to be used only by various
+ *       driver emulators (e.g. compositor client containing emulated driver
+ *       to render the framebuffer of other compositor or console server).
+ *       Driver of the physical hardware shall instead use similar functions
+ *       from libdrv.
+ */
+
+/**
+ * Allocate the visualizer so it can be initialized. */
+extern visualizer_t *graph_alloc_visualizer(void);
+
+/**
+ * Register the completely prepared visualizer to the location service and
+ * add it to the driver visualizer list. After the registration, the visualizer
+ * is considered ready to handle client connection. Since visualizer
+ * list is guarded by the mutex, visualizers might be added even after the
+ * initialialization of the device driver. */
+extern int graph_register_visualizer(visualizer_t *);
+
+/** 
+ * Retrieve the visualizer from the visualizer list according to its
+ * service ID. */
+extern visualizer_t *graph_get_visualizer(sysarg_t);
+
+/**
+ * Unregister the visualizer from the location service and remove it 
+ * from the driver visualizer list. Function shall be called by device driver
+ * before deallocating the resources for the visualizer. */
+extern int graph_unregister_visualizer(visualizer_t *);
+
+/** 
+ * Destroy the rest of the visualizer. Device driver shall call this function
+ * only after it has unregistered the visualizer and deallocated all the
+ * resources for which the driver is responsible. */
+extern void graph_destroy_visualizer(visualizer_t *);
+
+extern renderer_t *graph_alloc_renderer(void);
+extern int graph_register_renderer(renderer_t *);
+extern renderer_t *graph_get_renderer(sysarg_t);
+extern int graph_unregister_renderer(renderer_t *);
+extern void graph_destroy_renderer(renderer_t *);
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Device driver can call this function to notify the client through the
+ * callback connection that the visualizer with a specified service ID should
+ * be switched to the mode with the given index. */
+extern int graph_notify_mode_change(async_sess_t *, sysarg_t, sysarg_t);
+
+/**
+ * Device driver can call this function to notify the client through the
+ * callback connection that the visualizer with a specified service ID has
+ * lost its output device (e.g. virtual monitor was closed by a user). */
+extern int graph_notify_disconnect(async_sess_t *, sysarg_t);
+
+/*----------------------------------------------------------------------------*/
+
+/** Shall be registered to libdrv by physical device driver. */
+extern void graph_visualizer_connection(visualizer_t *, ipc_callid_t, ipc_call_t *, void *);
+
+/** Shall be registered to libdrv by physical device driver. */
+extern void graph_renderer_connection(renderer_t *, ipc_callid_t, ipc_call_t *, void *);
+
+/** Shall be registered to location service by emulated device driver. */
+extern void graph_client_connection(ipc_callid_t, ipc_call_t *, void *);
+
+#endif
+
+/** @}
+ */
