helenos-nicf team mailing list archive
-
helenos-nicf team
-
Mailing list archive
-
Message #00181
Jak shodit IPC v revizi 939
Ahoj,
posilam patch na revizi 939, ktera shodi IPC komunikaci.
Honza
=== modified file 'boot/Makefile.common'
--- boot/Makefile.common 2011-05-01 19:00:40 +0000
+++ boot/Makefile.common 2011-08-30 21:00:32 +0000
@@ -91,6 +91,7 @@
RD_SRVS_NON_ESSENTIAL = \
$(USPACE_PATH)/srv/bd/file_bd/file_bd \
+ $(USPACE_PATH)/srv/dma_srv/dma_srv \
$(USPACE_PATH)/srv/bd/part/guid_part/g_part \
$(USPACE_PATH)/srv/bd/part/mbr_part/mbr_part \
$(USPACE_PATH)/srv/clip/clip \
@@ -134,6 +135,7 @@
RD_APPS_NON_ESSENTIAL = \
$(USPACE_PATH)/app/dltest/dltest \
+ $(USPACE_PATH)/app/dma_test/dma_test \
$(USPACE_PATH)/app/dltest2/dltest2 \
$(USPACE_PATH)/app/dload/dload \
$(USPACE_PATH)/app/edit/edit \
=== modified file 'uspace/Makefile'
--- uspace/Makefile 2011-05-01 12:33:18 +0000
+++ uspace/Makefile 2011-08-30 20:57:50 +0000
@@ -34,6 +34,7 @@
DIRS = \
app/bdsh \
+ app/dma_test \
app/edit \
app/getterm \
app/init \
@@ -56,6 +57,7 @@
app/websrv \
app/sysinfo \
srv/clip \
+ srv/dma_srv \
srv/devmap \
srv/devman \
srv/loader \
=== added directory 'uspace/app/dma_test'
=== added file 'uspace/app/dma_test/Makefile'
--- uspace/app/dma_test/Makefile 1970-01-01 00:00:00 +0000
+++ uspace/app/dma_test/Makefile 2011-05-16 07:00:35 +0000
@@ -0,0 +1,34 @@
+
+# Copyright (c) 2010 Jan Zaloha
+#
+# 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 = ../..
+BINARY = dma_test
+
+SOURCES = \
+ dma_test.c
+
+include $(USPACE_PREFIX)/Makefile.common
\ No newline at end of file
=== added file 'uspace/app/dma_test/dma_test.c'
--- uspace/app/dma_test/dma_test.c 1970-01-01 00:00:00 +0000
+++ uspace/app/dma_test/dma_test.c 2011-08-30 21:24:03 +0000
@@ -0,0 +1,209 @@
+/**
+ * @file
+ * @brief DMA testing process (should be removed in future).
+ */
+#include <stdio.h>
+#include <dma.h>
+#include <errno.h>
+#include <ipc/services.h>
+#include <ipc/ns.h>
+#include <async.h>
+
+#define NAME "DMA SERVER"
+
+#define TEST_MAX_AREAS 250
+#define LARGE_SIZE 30
+
+
+/**
+ * Tests sharing out DMA memory.
+ * @param[in] iid id of the call
+ * @param[in] icall arguments of the call
+ *
+ */
+static void dma_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
+{
+ async_answer_0(iid, EOK);
+ ipc_callid_t callid;
+ size_t size;
+
+ if (!async_share_in_receive(&callid, &size)) {
+ async_answer_0(callid, EINVAL);
+ return;
+ }
+ size_t s = size / PAGE_SIZE;
+ //++s;
+
+ dma_mem_t dmt;
+
+ dmt.mapping_flags = AS_AREA_READ | AS_AREA_WRITE;
+ dmt.size = s;
+ int i;
+ i = dma_allocate_anonymous(&dmt, 0);
+
+
+ if (i != EOK) {
+ printf("Share starting failed with error %d\n", i);
+ async_answer_0(callid, ENOMEM);
+ exit(0);
+ }
+
+ async_share_in_finalize(callid, (void*) dmt.virtual, PROTO_READ
+ | PROTO_WRITE);
+
+ printf("Share in succeded\n");
+ printf("All tests passed\n");
+ exit(0);
+
+}
+
+
+/**
+ * Tests many parallel shares to DMA server from two IDs
+ * @param[in] id connection server.
+ *
+ * @return EOK when success, otherwise error code.
+ */
+
+static int dma_test_server_many_shares_two(dma_srv_dev_id_t * id)
+{
+ dma_srv_dev_id_t id2;
+ dma_cli_register("dma_test/sever", &id2);
+ printf("sdfg\n");
+ void * areas[TEST_MAX_AREAS];
+ void * faddrs[TEST_MAX_AREAS];
+ int i;
+ size_t dummy_size;
+
+ for (i = 0; i < TEST_MAX_AREAS; ++i) {
+ size_t size = (3 * (i + 1));
+ void * addr = as_get_mappable_page(size * PAGE_SIZE);
+ if ((areas[i] = as_area_create(addr, size * PAGE_SIZE, AS_AREA_READ
+ | AS_AREA_WRITE)) == NULL) {
+ return ENOMEM;
+ }
+ printf("a\n");
+ }
+ int rc = 0;
+ for (i = 0; i < TEST_MAX_AREAS; ++i) {
+ printf("b\n");
+ if ((rc = dma_cli_set_ownership(areas[i], i + 1, i + 1, AS_AREA_READ
+ | AS_AREA_WRITE, id))) {
+ return rc;
+ }
+ if ((rc = dma_cli_set_ownership(areas[i], i + 1, i + 1, AS_AREA_READ
+ | AS_AREA_WRITE, &id2))) {
+ return rc;
+ }
+ printf("asdfds\n");
+ dma_lock((void*) (((uintptr_t) areas[i]) + (i + 1) * PAGE_SIZE),
+ &faddrs[i], 1, &dummy_size);
+ }
+
+ for (i = 0; i < TEST_MAX_AREAS; ++i) {
+ if ((rc = dma_cli_clear_ownership(faddrs[i], id))) {
+ as_area_destroy(areas[i]);
+ return rc;
+ }
+ }
+ if (dma_cli_unregister(&id2) == EOK) {
+ return EINVAL;
+ }
+
+ if ((rc = dma_cli_cleanup(&id2)) != EOK) {
+ return rc;
+ }
+
+ if ((rc = dma_cli_unregister(&id2)) != EOK) {
+ return rc;
+ }
+
+ return EOK;
+
+}
+
+
+/**
+ * Tests many parallel shares to DMA server.
+ * @param[in] id connection server.
+ *
+ * @return EOK when success, otherwise error code.
+ */
+static int dma_test_server_many_shares(dma_srv_dev_id_t * id)
+{
+ void * areas[TEST_MAX_AREAS];
+ int i;
+ for (i = 0; i < TEST_MAX_AREAS; ++i) {
+ size_t size = (3 * (i + 1));
+ void * addr = as_get_mappable_page(size * PAGE_SIZE);
+ if ((areas[i] = as_area_create(addr, size * PAGE_SIZE, AS_AREA_READ
+ | AS_AREA_WRITE)) == NULL) {
+ return ENOMEM;
+ }
+ }
+ int rc = 0;
+ for (i = 0; i < TEST_MAX_AREAS; ++i) {
+ if ((rc = dma_cli_set_ownership(areas[i], i + 1, i + 1, AS_AREA_READ
+ | AS_AREA_WRITE, id))) {
+ return rc;
+ }
+ as_area_destroy(areas[i]);
+ uspace_dma_print("Iteration %d\n", i);
+ }
+ return dma_cli_cleanup(id);
+
+}
+
+
+/**
+ * Handling procedure for sharing memory out
+ */
+static void dma_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+ switch ((sysarg_t)(IPC_GET_ARG1(*icall))) {
+ case DMA_SHARE:
+ dma_connection_driver(iid, icall);
+ break;
+
+ default:
+ /* No such interface */
+ async_answer_0(iid, ENOENT);
+ }
+
+}
+
+dma_mem_t dmt;
+int main(void)
+{
+ dma_srv_dev_id_t id;
+ int rc;
+ printf("%d\n", dma_allocator_init());
+ dma_cli_register("dma_test/server", &id);
+ printf("%d\n", (int) id.id);
+ dma_cli_cleanup(&id);
+ printf("%d\n", (int) id.id);
+ if ((rc = dma_test_server_many_shares_two(&id))) {
+ printf("DMA test server many shares two failed with code %d\n", rc);
+ } else {
+ printf("DMA test server many shares two succeeded\n");
+ }
+
+ if ((rc = dma_test_server_many_shares(&id))) {
+ printf("DMA test server many shares failed with code %d\n", rc);
+ } else {
+ printf("DMA test server many shares succeeded\n");
+ }
+
+
+ dma_cli_cleanup(&id);
+ async_set_client_connection(dma_connection);
+
+ if (service_register(1000) != EOK) {
+ printf("Failed registering as a service.\n");
+ return -1;
+ }
+ printf("Entering share in stage, run dma_clie\n");
+ async_manager();
+
+ return 0;
+}
=== modified file 'uspace/app/init/init.c'
--- uspace/app/init/init.c 2011-03-31 18:22:14 +0000
+++ uspace/app/init/init.c 2011-08-30 21:10:10 +0000
@@ -274,6 +274,7 @@
#ifdef CONFIG_START_DEVMAN
spawn("/srv/devman");
#endif
+ //spawn("/srv/dma_srv");
spawn("/srv/apic");
spawn("/srv/i8259");
spawn("/srv/fhc");
=== modified file 'uspace/lib/c/Makefile'
--- uspace/lib/c/Makefile 2011-05-01 19:00:40 +0000
+++ uspace/lib/c/Makefile 2011-08-30 20:53:27 +0000
@@ -78,6 +78,8 @@
generic/fibril.c \
generic/fibril_synch.c \
generic/pcb.c \
+ generic/adt/avltree_generic.c \
+ generic/dma.c \
generic/smc.c \
generic/thread.c \
generic/tls.c \
=== added file 'uspace/lib/c/generic/adt/avltree_generic.c'
--- uspace/lib/c/generic/adt/avltree_generic.c 1970-01-01 00:00:00 +0000
+++ uspace/lib/c/generic/adt/avltree_generic.c 2011-08-24 08:58:33 +0000
@@ -0,0 +1,932 @@
+/*
+ * Copyright (c) 2011 Radim Vansa, Jan Zaloha
+ * 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 genericadt
+ * @{
+ */
+
+/**
+ * @file
+ * @brief generic avltree implementation.
+ *
+ * This file implements avltree type and operations. It is a bit slower than hardcoded avltree, but
+ * it is much powerful. User can search by specified condition in the tree, not only to equal.
+ *
+ * The avltree has the following properties:
+ * @li it is a ballanced binary tree
+ * @li each node in tree has the property, that distinction of depth of left and right subtree is at most 1
+ * @li values are stored in all nodes
+ *
+ */
+
+#include "adt/avltree_generic.h"
+#ifdef KERNEL
+#include "print.h"
+#else
+#include <stdio.h>
+#endif
+
+#define COND_PAR_SET(x, y) if ((x) != NULL) {(x)->parent = y;}
+#define A_HIGH_SET_PARENT \
+ if (a->parent == NULL){ \
+ tree->root = b; \
+ } else { \
+ if (a->parent->left_son == a) { \
+ a->parent->left_son = b; \
+ } else { \
+ a->parent->right_son = b; \
+ } \
+ }
+#define B_HIGH_SET_PARENT \
+ if (b->parent == NULL){ \
+ tree->root = a; \
+ } else { \
+ if (b->parent->left_son == b) { \
+ b->parent->left_son = a; \
+ } else { \
+ b->parent->right_son = a; \
+ } \
+ }
+
+/**
+ * Function for swapping nodes.
+ * @param tree tree, where swapping is done
+ * @param a first node to swap
+ * @param b second node to swap
+ */
+static void _swap_nodes(avltree_gen_t *tree, avltree_gen_node_t *a,
+ avltree_gen_node_t *b)
+{
+ avltree_gen_node_t *a_parent = a->parent;
+ avltree_gen_node_t *a_left = a->left_son;
+ avltree_gen_node_t *a_right = a->right_son;
+ avltree_gen_node_t *b_parent = b->parent;
+ avltree_gen_node_t *b_left = b->left_son;
+ avltree_gen_node_t *b_right = b->right_son;
+ SWAP(a->balance, b->balance);
+ if (a_left == b) {
+ a->right_son = b_right;
+ COND_PAR_SET(b_right, a);
+ a->left_son = b_left;
+ COND_PAR_SET(b_left, a);
+ b->left_son = a;
+ b->right_son = a_right;
+ COND_PAR_SET(a_right, b);
+ A_HIGH_SET_PARENT;
+ a->parent = b;
+ b->parent = a_parent;
+ return;
+ }
+ if (a_right == b) {
+ a->left_son = b_left;
+ COND_PAR_SET(b_left, a);
+ a->right_son = b_right;
+ COND_PAR_SET(b_right, a);
+ b->left_son = a_left;
+ COND_PAR_SET(a_left, b);
+ b->right_son = a;
+ A_HIGH_SET_PARENT;
+ a->parent = b;
+ b->parent = a_parent;
+ return;
+ }
+ if (b_left == a) {
+ b->left_son = a_left;
+ COND_PAR_SET(a_left, b);
+ b->right_son = a_right;
+ COND_PAR_SET(a_right, b);
+ a->left_son = b;
+ a->right_son = b_right;
+ COND_PAR_SET(b_right, a);
+ B_HIGH_SET_PARENT;
+ b->parent = a;
+ a->parent = b_parent;
+ return;
+ }
+ if (b_right == a) {
+ b->left_son = a_left;
+ COND_PAR_SET(a_left, b);
+ b->right_son = a_right;
+ COND_PAR_SET(a_right, b);
+ a->left_son = b_left;
+ COND_PAR_SET(b_left, a);
+ a->right_son = b;
+ B_HIGH_SET_PARENT;
+ b->parent = a;
+ a->parent = b_parent;
+ return;
+ }
+ // no relation
+ a->left_son = b_left;
+ COND_PAR_SET(b_left, a);
+ a->right_son = b_right;
+ COND_PAR_SET(b_right, a);
+ b->left_son = a_left;
+ COND_PAR_SET(a_left, b);
+ b->right_son = a_right;
+ COND_PAR_SET(a_right, b);
+ A_HIGH_SET_PARENT;
+ B_HIGH_SET_PARENT;
+ a->parent = b_parent;
+ b->parent = a_parent;
+}
+
+/**
+ * Does right rotation on node. Do NOT call this procedure from outside.
+ *
+ * @param input_tree Pointer to AVL tree where the rotation is proceeded.
+ * @param actual_node Pointer to node of tree, which is root of rotated subtree.
+ *
+ * @return Pointer to new root of rotated subtree.
+ */
+
+static avltree_gen_node_t * right_rotation(avltree_gen_t * input_tree,
+ avltree_gen_node_t * actual_node)
+{
+ /*
+ * Left son of root will be new root.
+ */
+ avltree_gen_node_t * new_root = actual_node->left_son;
+ /*
+ * We should remember parent of old root to change pointer
+ * to its corresponding subtree.
+ */
+ avltree_gen_node_t * temp_parent = actual_node->parent;
+ /*
+ * Right son of left son of old root of subtree will be reconected.
+ */
+ avltree_gen_node_t * rejoined_node = actual_node->left_son->right_son;
+ /*
+ * Reconnecting pointers.
+ */
+ new_root->parent = temp_parent;
+ new_root->right_son = actual_node;
+ actual_node->parent = new_root;
+ actual_node->left_son = rejoined_node;
+
+ /*
+ * If rejoined subtree isn't empty, we should correct it's parent.
+ */
+ if (rejoined_node != NULL) {
+ rejoined_node->parent = actual_node;
+ }
+ /*
+ * If we are at root of all tree, set new root.
+ * In other case correct the corresponding pointer from parent.
+ */
+ if (new_root->parent == NULL) {
+ input_tree->root = new_root;
+ } else {
+ if (new_root->parent->left_son == actual_node) {
+ new_root->parent->left_son = new_root;
+ } else {
+ new_root->parent->right_son = new_root;
+ }
+ }
+ return new_root;
+}
+
+/**
+ * Does left rotation on node. Do NOT call this procedure from outside.
+ *
+ * @param input_tree Pointer to AVL tree where the rotation is proceeded.
+ * @param actual_node Pointer to node of tree, which is root of rotated subtree.
+ *
+ * @return Pointer to new root of rotated subtree.
+ */
+static avltree_gen_node_t * left_rotation(avltree_gen_t * input_tree,
+ avltree_gen_node_t * actual_node)
+{
+ /*
+ * Right son of root will be new root.
+ */
+ avltree_gen_node_t * new_root = actual_node->right_son;
+ /*
+ * We should remember parent of old root to change pointer
+ * to its corresponding subtree.
+ */
+ avltree_gen_node_t * temp_parent = actual_node->parent;
+ /*
+ * Left son of right son of old root of subtree will be reconected.
+ */
+ avltree_gen_node_t * rejoined_node = actual_node->right_son->left_son;
+ /*
+ * Reconnecting pointers.
+ */
+ actual_node->parent = new_root;
+ new_root->parent = temp_parent;
+ new_root->left_son = actual_node;
+ actual_node->right_son = rejoined_node;
+
+ /*
+ * If rejoined subtree isn't empty, we should correct it's parent.
+ */
+ if (rejoined_node != NULL) {
+ rejoined_node->parent = actual_node;
+ }
+ /*
+ * If we are at root of all tree, set new root.
+ * In other case correct the corresponding pointer from parent.
+ */
+ if (new_root->parent == NULL) {
+ input_tree->root = new_root;
+ } else {
+ if (new_root->parent->left_son == actual_node) {
+ new_root->parent->left_son = new_root;
+ } else {
+ new_root->parent->right_son = new_root;
+ }
+ }
+ return new_root;
+}
+
+static avltree_gen_node_t * subst_deleted_node(avltree_gen_t *source,
+ avltree_gen_node_t * input_node)
+{
+ while (RIGHT_LIGHTER) {
+ /*
+ * If node is leaf, just return pointer to it.
+ */
+ if (input_node->left_son == NULL && input_node->right_son == NULL) {
+ return input_node;
+ }
+ /*
+ * If node has only right son, find the most left node in it's subtree, save value
+ * from it to root of subtree and do the same thing on it.
+ */
+ else if (input_node->left_son == NULL) {
+ avltree_gen_node_t * deleted = input_node->right_son;
+ while (deleted->left_son != NULL) {
+ deleted = deleted->left_son;
+ }
+ _swap_nodes(source, input_node, deleted);
+ continue;
+ /*
+ * If node has only left son, find the most right node in it's subtree, save value
+ * from it to root of subtree and do the same thing on it.
+ */
+ } else if (input_node->right_son == NULL) {
+ avltree_gen_node_t * deleted = input_node->left_son;
+ while (deleted->right_son != NULL) {
+ deleted = deleted->right_son;
+ }
+ _swap_nodes(source, input_node, deleted);
+ //input_node=deleted;
+ continue;
+ } else {
+ /*
+ * If node has both sons, find the most right node in it's left subtree, save value
+ * from it to root and do the same thing on it.
+ */
+ avltree_gen_node_t * deleted = input_node->left_son;
+ while (deleted->right_son != NULL) {
+ deleted = deleted->right_son;
+ }
+ _swap_nodes(source, input_node, deleted);
+ //input_node=deleted;
+ continue;
+ }
+ }
+}
+
+/**
+ * Fixes balancing condition after removal of a node from AVL tree.
+ * Do NOT call from outside.
+ *
+ * @param input_tree Pointer to tree, from which was a node removed.
+ * @param actual_node Pointer to node, where should be the AVL condition fixed.
+ */
+static void avltree_gen_fix_remove(avltree_gen_t * input_tree,
+ avltree_gen_node_t * actual_node)
+{
+
+ while (RIGHT_LIGHTER) {
+ if (actual_node->balance == RIGHT_TOO_LIGHT) {
+ if (actual_node->left_son->balance == RIGHT_LIGHTER) {
+ avltree_gen_node_t * new_root = right_rotation(input_tree,
+ actual_node);
+ new_root->right_son->balance = BALANCED;
+ new_root->balance = BALANCED;
+ if (new_root->parent != NULL) {
+ if (new_root->parent->left_son == new_root) {
+ --new_root->parent->balance;
+ } else {
+ ++new_root->parent->balance;
+ }
+ actual_node = new_root->parent;
+ continue;
+ } else {
+ return;
+ }
+ }
+ if (actual_node->left_son->balance == BALANCED) {
+ avltree_gen_node_t * new_root = right_rotation(input_tree,
+ actual_node);
+ new_root->right_son->balance = RIGHT_LIGHTER;
+ new_root->balance = LEFT_LIGHTER;
+ return;
+ }
+ if (actual_node->left_son->balance == LEFT_LIGHTER) {
+ int post_balance;
+ avltree_gen_node_t * new_root;
+ if (actual_node->left_son->right_son->balance == LEFT_LIGHTER) {
+ post_balance = LEFT_LIGHTER;
+ } else if (actual_node->left_son->right_son->balance
+ == BALANCED) {
+ post_balance = BALANCED;
+ } else {
+ post_balance = RIGHT_LIGHTER;
+ }
+ left_rotation(input_tree, actual_node->left_son);
+ new_root = right_rotation(input_tree, actual_node);
+ new_root->balance = BALANCED;
+ if (post_balance == RIGHT_LIGHTER) {
+ new_root->left_son->balance = BALANCED;
+ new_root->right_son->balance = LEFT_LIGHTER;
+ } else if (post_balance == BALANCED) {
+ new_root->left_son->balance = BALANCED;
+ new_root->right_son->balance = BALANCED;
+ } else {
+ new_root->left_son->balance = RIGHT_LIGHTER;
+ new_root->right_son->balance = BALANCED;
+ }
+ if (new_root->parent == NULL) {
+ return;
+ }
+ if (new_root->parent->left_son == new_root) {
+ --new_root->parent->balance;
+ } else {
+ ++new_root->parent->balance;
+ }
+ actual_node = new_root->parent;
+ continue;
+ }
+ }
+ if (actual_node->balance == (LEFT_TOO_LIGHT)) {
+ if (actual_node->right_son->balance == LEFT_LIGHTER) {
+ avltree_gen_node_t * new_root = left_rotation(input_tree,
+ actual_node);
+ new_root->left_son->balance = BALANCED;
+ new_root->balance = BALANCED;
+ if (new_root->parent != NULL) {
+ if (new_root->parent->left_son == new_root) {
+ --new_root->parent->balance;
+ } else {
+ ++new_root->parent->balance;
+ }
+ actual_node = new_root->parent;
+ continue;
+ } else {
+ return;
+ }
+
+ }
+ if (actual_node->right_son->balance == BALANCED) {
+ avltree_gen_node_t * new_root = left_rotation(input_tree,
+ actual_node);
+ new_root->left_son->balance = LEFT_LIGHTER;
+ new_root->balance = RIGHT_LIGHTER;
+ return;
+ }
+ if (actual_node->right_son->balance == RIGHT_LIGHTER) {
+ int post_balance;
+ avltree_gen_node_t * new_root;
+ if (actual_node->right_son->left_son->balance == LEFT_LIGHTER) {
+ post_balance = LEFT_LIGHTER;
+ } else if (actual_node->right_son->left_son->balance
+ == BALANCED) {
+ post_balance = BALANCED;
+ } else {
+ post_balance = RIGHT_LIGHTER;
+ }
+ right_rotation(input_tree, actual_node->right_son);
+ new_root = left_rotation(input_tree, actual_node);
+ new_root->balance = BALANCED;
+ if (post_balance == RIGHT_LIGHTER) {
+ new_root->left_son->balance = BALANCED;
+ new_root->right_son->balance = LEFT_LIGHTER;
+ } else if (post_balance == BALANCED) {
+ new_root->left_son->balance = BALANCED;
+ new_root->right_son->balance = BALANCED;
+ } else {
+ new_root->left_son->balance = RIGHT_LIGHTER;
+ new_root->right_son->balance = BALANCED;
+ }
+ if (new_root->parent == NULL) {
+ return;
+ }
+ if (new_root->parent->left_son == new_root) {
+ --new_root->parent->balance;
+ } else {
+ ++new_root->parent->balance;
+ }
+ actual_node = new_root->parent;
+ continue;
+ }
+
+ }
+ if (actual_node->parent == NULL) {
+ return;
+ }
+ if (actual_node->balance == RIGHT_LIGHTER || actual_node->balance
+ == LEFT_LIGHTER) {
+ return;
+ }
+ if (actual_node->balance == BALANCED) {
+ if (actual_node->parent->left_son == actual_node) {
+ --actual_node->parent->balance;
+ } else {
+ ++actual_node->parent->balance;
+ }
+ actual_node = actual_node->parent;
+ continue;
+ }
+ }
+}
+
+/**
+ * This function does balancing. Do NOT call it from outside.
+ *
+ * @param input_tree Pointer to target AVL tree, where is the balancing processed.
+ * @param actual_node Pointer to node, which was inserted and from where the balacing
+ * process should be started (parent of inserted node).
+ * This node should have correct balancing information according
+ * the depth of it's subtrees.
+ */
+
+static void avltree_gen_fix_add(avltree_gen_t * input_tree,
+ avltree_gen_node_t * actual_node)
+{
+ /*
+ * First we watch, whether we should send the balancing information
+ * upwards.
+ */
+ while (actual_node->balance == RIGHT_LIGHTER || actual_node->balance
+ == LEFT_LIGHTER) {
+ /*
+ * If we reached the top of the tree, stop.
+ */
+ if (actual_node->parent == NULL) {
+ return;
+ }
+ /*
+ * Fix balance info of actual node's parent.
+ */
+ if (actual_node->parent->left_son == actual_node) {
+ ++actual_node->parent->balance;
+ } else {
+ --actual_node->parent->balance;
+ }
+ /*
+ * Rise one level upwards.
+ */
+ actual_node = actual_node->parent;
+ }
+ /*
+ * If this level is perfectly balanced, no action needed, stop.
+ */
+ if (actual_node->balance == BALANCED) {
+ return;
+ }
+
+ /*
+ * This code balances the tree.
+ */
+ if (actual_node->balance == RIGHT_TOO_LIGHT) {
+ if (actual_node->left_son->balance == RIGHT_LIGHTER) {
+ avltree_gen_node_t * new_root = right_rotation(input_tree,
+ actual_node);
+ new_root->balance = BALANCED;
+ new_root->right_son->balance = BALANCED;
+ return;
+ } else {
+ int post_balancing;
+ avltree_gen_node_t * new_root;
+ if (actual_node->left_son->right_son->balance > BALANCED) {
+ post_balancing = RIGHT_LIGHTER;
+ } else {
+ if (actual_node->left_son->right_son->balance == BALANCED) {
+ post_balancing = BALANCED;
+ } else {
+ post_balancing = LEFT_LIGHTER;
+ }
+ }
+ left_rotation(input_tree, actual_node->left_son);
+ new_root = right_rotation(input_tree, actual_node);
+ new_root->balance = BALANCED;
+ if (post_balancing == RIGHT_LIGHTER) {
+ new_root->left_son->balance = BALANCED;
+ new_root->right_son->balance = LEFT_LIGHTER;
+ } else {
+ if (post_balancing == BALANCED) {
+ new_root->left_son->balance = BALANCED;
+ new_root->right_son->balance = BALANCED;
+ } else {
+ new_root->left_son->balance = RIGHT_LIGHTER;
+ new_root->right_son->balance = BALANCED;
+ }
+ }
+ }
+ } else {
+ if (actual_node->right_son->balance == LEFT_LIGHTER) {
+ avltree_gen_node_t * new_root = left_rotation(input_tree,
+ actual_node);
+ new_root->balance = BALANCED;
+ new_root->left_son->balance = BALANCED;
+ } else {
+ int post_balancing;
+ avltree_gen_node_t * new_root;
+ if (actual_node->right_son->balance == BALANCED) {
+ //int * p=BALANCED;
+ //(*p);
+ }
+ if (actual_node->right_son->left_son->balance > BALANCED) {
+ post_balancing = RIGHT_LIGHTER;
+ } else {
+ if (actual_node->right_son->left_son->balance == BALANCED) {
+ post_balancing = BALANCED;
+ } else {
+ post_balancing = LEFT_LIGHTER;
+ }
+ }
+ right_rotation(input_tree, actual_node->right_son);
+ new_root = left_rotation(input_tree, actual_node);
+ new_root->balance = BALANCED;
+ if (post_balancing == RIGHT_LIGHTER) {
+ new_root->left_son->balance = BALANCED;
+ new_root->right_son->balance = LEFT_LIGHTER;
+ } else {
+ if (post_balancing == BALANCED) {
+ new_root->left_son->balance = BALANCED;
+ new_root->right_son->balance = BALANCED;
+ } else {
+ new_root->left_son->balance = RIGHT_LIGHTER;
+ new_root->right_son->balance = BALANCED;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Initializes AVL tree structure, it corresponds with constructor
+ *
+ * @param input_tree Pointer to initialized structure
+ * @param cmp Pointer to function, which compares two pointers to structure inserted
+ * into the tree. It should return LEFT_LIGHTER when the first its argument is less then
+ * the second, RIGHT_LIGHTER when inits first argument is greater then second and BALANCED when
+ * they are equal.
+ */
+void avltree_gen_init(avltree_gen_t * input_tree, int(*cmp)(void*, void*))
+{
+ input_tree->root = NULL;
+ input_tree->compare_keys = cmp;
+}
+
+/**
+ * Initializes new node inserted into AVL tree. Do NOT call it from outside.
+ *
+ * @param input_node Pointer to initialized node.
+ * @param key Key, which should be assigned to node.
+ */
+void avltree_gen_node_init(avltree_gen_node_t * input_node, void *key)
+{
+ input_node->balance = BALANCED;
+ input_node->key = key;
+ input_node->left_son = NULL;
+ input_node->right_son = NULL;
+ input_node->parent = NULL;
+}
+
+/**
+ * Inserts new value to AVL tree and automatically does balancing.
+ *
+ * @param input_tree Pointer to AVL tree, where the value is inserted.
+ * @param new_node Pointer to inserted value.
+ *
+ * @return When the function successes, it returns pointer equal to second
+ parameter, when it fails, it returns NULL pointer.
+ */
+void avltree_gen_insert(avltree_gen_t * input_tree,
+ avltree_gen_node_t *new_node)
+{
+ avltree_gen_node_t * actual = input_tree->root;
+ avltree_gen_node_t * parent = NULL;
+ if (input_tree->root == NULL) {
+ input_tree->root = new_node;
+ return;
+ }
+ while (actual != NULL) {
+ parent = actual;
+ if (input_tree->compare_keys(new_node->key, actual->key) < BALANCED) {
+ actual = actual->left_son;
+ } else {
+ actual = actual->right_son;
+ }
+ }
+
+ if (input_tree->compare_keys(new_node->key, parent->key) < BALANCED) {
+ parent->left_son = new_node;
+ ++parent->balance;
+ } else {
+ parent->right_son = new_node;
+ --parent->balance;
+ }
+ new_node->parent = parent;
+ avltree_gen_fix_add(input_tree, new_node->parent);
+ return;
+}
+
+/**
+ * DEBUG funtion.
+ */
+void avltree_gen_traverse(const avltree_gen_node_t * a, unsigned int tabs)
+{
+ if (a == NULL) {
+ return;
+ }
+ if (a == (void *) 0x800F61B0) {
+ printf("\nL%p R%p\n", a->left_son, a->right_son);
+ }
+ avltree_gen_traverse(a->left_son, tabs + 1);
+ //i=a->data;
+ unsigned int i;
+ for (i = 0; i < tabs; ++i) {
+ printf("%c", ' ');
+ }
+ printf("%p\n", a->key);
+ avltree_gen_traverse(a->right_son, tabs + 1);
+}
+
+/**
+ * Finds pointer to first data structure in AVL tree, which corresponds to
+ * the key.
+ *
+ * @param source Pointer to ALV tree, where is the pointer founded.
+ * @param key Pointer to key, which is searched.
+ *
+ * @return If the procedure successes, it returns pointer to founded structure.
+ * If it fails, it returns NULL pointer.
+ */
+avltree_gen_node_t * avltree_gen_find(avltree_gen_t * source, void * key)
+{
+ avltree_gen_node_t * actual = source->root;
+ while (actual != NULL && source->compare_keys(key, actual->key) != BALANCED) {
+ if (source->compare_keys(key, actual->key) < BALANCED) {
+ actual = actual->left_son;
+ } else {
+ actual = actual->right_son;
+ }
+ }
+ return actual;
+}
+
+/**
+ * Finds pointer to first data structure in AVL tree, which corresponds to
+ * the key.
+ *
+ * @param source Pointer to ALV tree, where is the pointer founded.
+ * @param key Pointer to key, which is searched.
+ * @param cmp Pointer to function used when the tree is traversed, which compares pointers to key and
+ * to structure inserted into the tree. It should return LEFT_LIGHTER when the first its
+ * argument is less then the second, RIGHT_LIGHTER when first argument is greater then
+ * second and BALANCED when they are equal.
+ *
+ * @return If the procedure successes, it returns pointer to found structure.
+ * If it fails, it returns NULL pointer.
+ */
+avltree_gen_node_t * avltree_gen_find_parametrized(avltree_gen_t * source,
+ void * key, int(*cmp)(void*, void*))
+{
+ avltree_gen_node_t * actual = source->root;
+ while (actual != NULL && cmp(key, actual->key) != BALANCED) {
+ if (cmp(key, actual->key) < BALANCED) {
+ actual = actual->left_son;
+ } else {
+ actual = actual->right_son;
+ }
+ }
+ return actual;
+}
+
+/**
+ * This procedure tries to drop first AVL tree node corresponding to key from the tree.
+ *
+ * @param source Pointer to AVL tree structure, from which is the node deleted.
+ * @param key Pointer to key, which should be dropped
+ *
+ * @return If the procedure successes, it returns pointer to structure removed from tree.
+ * If it fails, it returns NULL pointer.
+ */
+avltree_gen_node_t * avltree_gen_drop(avltree_gen_t * source, void * key)
+{
+ /*
+ * First we find the corresponding node. If it doesn't exist, return NULL.
+ */
+ avltree_gen_node_t * ret_val_node = avltree_gen_find(source, key);
+ if (ret_val_node == NULL) {
+ return NULL;
+ }
+
+ return avltree_gen_rem_node(source, ret_val_node);
+
+}
+
+/**
+ * This procedure tries to drop first AVL tree node corresponding to key from the tree.
+ *
+ * @param source Pointer to AVL tree structure, from which is the node deleted.
+ * @param key Pointer to key, which should be dropped
+ * @param cmp Pointer to function used when the tree is traversed, which compares pointers to key and
+ * to structure inserted into the tree. It should return LEFT_LIGHTER when the first its
+ * argument is less then the second, RIGHT_LIGHTER when first argument is greater then
+ * second and BALANCED when they are equal.
+ *
+ * @return If the procedure successes, it returns pointer to structure removed from tree.
+ * If it fails, it returns NULL pointer.
+ */
+avltree_gen_node_t * avltree_gen_drop_parametrized(avltree_gen_t * source,
+ void * key, int(*cmp)(void*, void*))
+{
+ /*
+ * First we find the corresponding node. If it doesn't exist, return NULL.
+ */
+ avltree_gen_node_t * ret_val_node = avltree_gen_find_parametrized(source,
+ key, cmp);
+ if (ret_val_node == NULL) {
+ return NULL;
+ }
+
+ return avltree_gen_rem_node(source, ret_val_node);
+}
+
+/**
+ * This procedure tries to drop first AVL tree node corresponding to key from the tree.
+ *
+ * @param source Pointer to AVL tree structure, from which is the node deleted.
+ * @param key Pointer to key, which should be dropped
+
+ * @return If the procedure successes, it returns pointer to structure removed from tree.
+ * If it fails, it returns NULL pointer.
+ */
+
+avltree_gen_node_t * avltree_gen_rem_node(avltree_gen_t * source,
+ avltree_gen_node_t * node)
+{
+
+ avltree_gen_node_t * ret_val_node = node;
+
+ /*
+ * Remember pointer to contained data and transform problem to removal of a leaf.
+ */
+
+ subst_deleted_node(source, ret_val_node);
+
+ /*
+ * If the leaf is root, just empty the tree.
+ * In other case disconnect the leaf from tree and run balancing procedure.
+ */
+ if (ret_val_node->parent == NULL) {
+ source->root = NULL;
+ } else {
+ if (ret_val_node->parent->left_son == ret_val_node) {
+ --(ret_val_node->parent->balance);
+ ret_val_node->parent->left_son = NULL;
+ } else {
+ ++(ret_val_node->parent->balance);
+ ret_val_node->parent->right_son = NULL;
+ }
+ avltree_gen_fix_remove(source, ret_val_node->parent);
+ }
+
+ ret_val_node->balance = BALANCED;
+ ret_val_node->left_son = NULL;
+ ret_val_node->right_son = NULL;
+ ret_val_node->parent = NULL;
+ return ret_val_node;
+}
+
+/**
+ * Converts problem of deleting ordinal node in AVL tree to problem of
+ * deleting leaf. Could be launched on ordinal BST. Do NOT call from outside.
+ *
+ * @param node Node which is chosen to be deleted
+ *
+ * @return Pointer to real node, which will be deleted
+ */
+static inline void _print_node(avltree_gen_node_t *node)
+{
+ printf("N: %p, P: %p, L: %p, R: %p\n", node, node->parent, node->left_son,
+ node->right_son);
+}
+
+int avltree_gen_test_cond(avltree_gen_t * input)
+{
+ if (input->root == NULL) {
+ return RIGHT_LIGHTER;
+ }
+
+ return avltree_gen_test(input->root);
+}
+
+/**
+ * Prints value handled by node and it's subtree.
+ * @param node poiter to node to be printed
+ * @param printer pointer to printer function
+ */
+static void avltree_print_node_gen(avltree_gen_node_t * node, void(*printer)(
+ void*))
+{
+ if (node == NULL) {
+ return;
+ }
+
+ avltree_print_node_gen(node->left_son, printer);
+ printer(node->key);
+ avltree_print_node_gen(node->right_son, printer);
+
+}
+
+/**
+ * Traverses and prints sorted values from avl tree.
+ * @param source poiter to tree to be traversed and printed
+ * @param printer pointer to printer function
+ */
+
+void avltree_gen_print_parametrized(avltree_gen_t * source, void(*printer)(
+ void*))
+{
+ avltree_print_node_gen(source->root, printer);
+}
+
+/**
+ * Returns the most left node in AVL tree
+ * @param source pointer to traversed tree
+ *
+ * @return NULL on empty tree, otherwise pointer to node with least key
+ * value in default comparision
+ */
+avltree_gen_node_t * avltree_gen_get_min(avltree_gen_t * source)
+{
+ avltree_gen_node_t * actual = source->root;
+ avltree_gen_node_t * parent = NULL;
+
+ while (actual != NULL) {
+ parent = actual;
+ actual = actual->left_son;
+ }
+ return parent;
+}
+
+/**
+ * avltree_gen_tests AVL tree condition (subtraction of depths of subtrees is not
+ * bigger than one) for specified AVL tree. If the condition is not
+ * passed writes "ERROR" to console.
+ *
+ * @param input avltree_gen_tested tree root.
+ *
+ * @return
+ */
+int avltree_gen_test(avltree_gen_node_t * input)
+{
+ int right_subtree;
+ int left_subtree;
+ if (input == NULL) {
+ return BALANCED;
+ }
+ right_subtree = avltree_gen_test(input->right_son);
+ left_subtree = avltree_gen_test(input->left_son);
+ if (left_subtree - right_subtree - input->balance != BALANCED) {
+ puts("ERROR");
+ }
+ if (left_subtree > right_subtree) {
+ return left_subtree + RIGHT_LIGHTER;
+ } else {
+ return right_subtree + RIGHT_LIGHTER;
+ }
+}
=== added file 'uspace/lib/c/generic/dma.c'
--- uspace/lib/c/generic/dma.c 1970-01-01 00:00:00 +0000
+++ uspace/lib/c/generic/dma.c 2011-08-30 21:23:03 +0000
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2011 Jan Zaloha
+ * 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.
+ */
+
+#include <ddi.h>
+#include <dma.h>
+#include <errno.h>
+#include <libc.h>
+#include <ipc/ns.h>
+#include <ipc/services.h>
+#include <async.h>
+#include <str.h>
+/** @addtogroup dma_userspace
+ * @{
+ */
+
+/**
+ * @file
+ * @brief DMA related standard library functions
+ */
+
+static int dma_srv_phone = -1;
+
+/**
+ * Highlevel interface of DMA allocator
+ *
+ * @param[out] pphys_addr pointer to memory, where should be placed address of begin of physical memory block
+ * @param[in] virt_addr pointer to virtual memory area, where should be allocated memory mapped
+ * @param[out] handle pointer to memory, where should be placed handle to allocated object
+ * -required, but unused, will be filled with 0
+ * @param[in] pages number of pages to be allocated (only supported value is 1)
+ * @param[in] flags1 flags same as flags for as_area_create
+ * @param[in] flags2 flags for searching free block, should be 0
+ *
+ * @return on success EOK, otherwise proper errno value
+ */
+int dma_allocate(void ** pphys_addr, void * virt_addr, unsigned long pages,
+ int flags1, int flags2)
+{
+ return EOK;
+}
+/**
+ * Registers client with server
+ * @param[in] client_identifier systemwide unique identifier
+ * @param[out] id id of the device
+ * @return according to dma_srv_register
+ */
+int dma_cli_register(const char * client_identifier, dma_srv_dev_id_t * id)
+{
+ size_t size = str_length(client_identifier) + 1;
+ int rc2;
+ sysarg_t rc1;
+ ipc_call_t answer;
+
+ if (dma_srv_phone < 0) {
+ return EPARTY;
+ }
+ aid_t req = async_send_0(dma_srv_phone, DMA_SRV_REGISTER, &answer);
+ rc2 = async_data_write_start(dma_srv_phone, client_identifier, size);
+ async_wait_for(req, &rc1);
+ if (rc1 != EOK || rc2 != EOK) {
+ return rc1;
+ id->id = 0;
+ }
+
+ (id->id) = IPC_GET_ARG1(answer);
+ uspace_dma_print("ID = %d\n", (int) (id->id));
+ return EOK;
+}
+
+/**
+ * Unegisters client with server
+ * @param[in] id id of the device
+ * @return according to dma_srv_unregister
+ */
+int dma_cli_unregister(dma_srv_dev_id_t * id)
+{
+ sysarg_t rc1;
+ ipc_call_t answer;
+
+ if (dma_srv_phone < 0) {
+ return EPARTY;
+ }
+
+ aid_t req =
+ async_send_1(dma_srv_phone, DMA_SRV_UNREGISTER, id->id, &answer);
+ async_wait_for(req, &rc1);
+ return rc1;
+}
+
+/**
+ * Cleans all memory attached to client's id
+ * @param[in] id id of the device
+ * @return according to dma_cli_cleanup
+ */
+int dma_cli_cleanup(dma_srv_dev_id_t * id)
+{
+ sysarg_t rc1;
+ ipc_call_t answer;
+ if (dma_srv_phone < 0) {
+ return EPARTY;
+ }
+ aid_t req = async_send_1(dma_srv_phone, DMA_SRV_CLEANUP, id->id, &answer);
+ async_wait_for(req, &rc1);
+ return rc1;
+}
+
+/**
+ * Locks memory at server.
+ * @param[in] area pointer to begin of area
+ * @param[in] offset offset in pages to DMA locked memory from begin of the area
+ * @param[in] pages how many pages should be locked in memory
+ * @param[in] flags flags of shared memory
+ * @param[in] id id of the device
+ * @return according to dma_srv_set_ownership
+ */
+int dma_cli_set_ownership(void * area, size_t offset, size_t pages,
+ unsigned int flags, dma_srv_dev_id_t * id)
+{
+ sysarg_t rc1;
+ ipc_call_t answer;
+ uspace_dma_print("Set ownership\n");
+ if (dma_srv_phone < 0) {
+ return EPARTY;
+ }
+ aid_t req = async_send_3(dma_srv_phone, DMA_SRV_SET_OWNERSHIP, id->id,
+ offset, pages, &answer);
+ int rc2 = async_share_out_start(dma_srv_phone, area, flags);
+ async_wait_for(req, &rc1);
+ if (rc1 != EOK || rc2 != EOK) {
+ uspace_dma_print("rc1 %d, rc2 %d\n", (int) rc1, rc2);
+ return rc1;
+ }
+ return EOK;
+}
+
+/**
+ * Unlocks memory at server.
+ * @param[in] paddr pointer to first physical frame of locked area
+ * @param[in] id id of the device
+ * @return according to dma_srv_clear_ownership
+ */
+int dma_cli_clear_ownership(void * paddr, dma_srv_dev_id_t * id)
+{
+ sysarg_t rc1;
+ ipc_call_t answer;
+ if (dma_srv_phone < 0) {
+ return EPARTY;
+ }
+ aid_t req = async_send_2(dma_srv_phone, DMA_SRV_CLEAR_OWNERSHIP, id->id,
+ (sysarg_t) paddr, &answer);
+ async_wait_for(req, &rc1);
+ return rc1;
+
+}
+
+/**
+ * Initialization of DMA library
+ *
+ * @return on success EOK, otherwise proper errno value
+ */
+
+int dma_allocator_init(void)
+{
+ dma_srv_phone = service_connect_blocking(SERVICE_DMA, 0, 0);
+ if (dma_srv_phone < 0) {
+ return dma_srv_phone;
+ }
+ return EOK;
+}
+
+/**
+ * Unmaps and destroys DMA memory area.
+ * @param[in] virt_addr pointer to begin of the memory area.
+ *
+ * @return EOK on success or a value from @ref errno.h on failure.
+ */
+int dma_unmap(void * virt_addr)
+{
+ return as_area_destroy(virt_addr);
+}
+
+/**
+ * Highlevel interface of DMA allocator. Finds suitable virtual memory area to
+ * map physical memory.
+ *
+ * @param[in,out] mem_desc Structure describing memory block to be allocated,
+ * physmem and hadle parts will be filled
+ * @param[in] dma_flags flags for type of allocated block
+ *
+ * @return on success EOK, otherwise proper errno value
+ */
+int dma_allocate_anonymous(dma_mem_t * mem_desc, int dma_flags)
+{
+ mem_desc->virtual = as_get_mappable_page(mem_desc->size * PAGE_SIZE);
+ return dma_allocate(&(mem_desc->physical), mem_desc->virtual,
+ mem_desc->size, mem_desc->mapping_flags, dma_flags);
+
+}
+
+/**
+ * Unmaps and destroys DMA memory area.
+ * @param[in] mem pointer to memory area description.
+ *
+ * @return EOK on success or a value from @ref errno.h on failure.
+ */
+
+int dma_free(dma_mem_t * mem)
+{
+ return dma_unmap(mem->virtual);
+}
+
+
+
+/**
+ * Locks continguos memory area and fills to parameter it's physical address
+ * @param[in] vaddr pointer to begin of virtual memory area
+ * @param[out] faddr pointer to place where physical address of the continguos
+ * physical memory area should be filled
+ * @param[in] size_in maximum size of locked area (in pages)
+ * @param[out] size_out size of locked continguos area (in pages)
+ *
+ * @return EOK on success (faddr and size_out are corrctly filled), otherwise
+ * proper error code according to code according to dma_lock_mem or
+ * copy_from_upsace copy_to_uspace
+ */
+
+int dma_lock(void * vaddr, void ** faddr, size_t size_in, size_t * size_out)
+{
+ (*size_out) = size_in;
+ return EOK;
+}
+
+
+/**
+ * Unlocks allready locked memory area and fills to parameter it's size
+ * @param[in] vaddr pointer to begin of virtual memory area
+ * @param[in] size_in maximum size of unlocked area
+ * @param[out] size_out size of unlocked continguos area
+ *
+ * @return EOK on success (faddr and size_out are corrctly filled), otherwise
+ * proper error code according to code according to dma_unlock_mem or
+ * copy_from_upsace copy_to_uspace
+ */
+
+int dma_unlock(void * vaddr, size_t size_in, size_t * size_out)
+{
+
+ return EOK;
+}
+
+/** @}
+ */
+
=== added file 'uspace/lib/c/include/adt/avltree_generic.h'
--- uspace/lib/c/include/adt/avltree_generic.h 1970-01-01 00:00:00 +0000
+++ uspace/lib/c/include/adt/avltree_generic.h 2011-08-24 08:54:55 +0000
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2011 Radim Vansa, Jan Zaloha
+ * 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 genericadt
+ * @{
+ */
+
+/**
+ * @file
+ */
+#ifndef _AVLTREE_GENERIC_H_
+#define _AVLTREE_GENERIC_H_
+
+#ifdef KERNEL
+#include "print.h"
+typedef native_t avl_native_t;
+#else
+typedef int avl_native_t;
+#endif
+
+#define LEFT_TOO_LIGHT -2
+#define RIGHT_TOO_LIGHT 2
+#define LEFT_LIGHTER -1
+#define RIGHT_LIGHTER 1
+#define BALANCED 0
+
+#define SWAP(a, b) {a = (typeof(a))(((avl_native_t)(a))^((avl_native_t)(b)));\
+ b = (typeof(a))(((avl_native_t)(a))^((avl_native_t)(b)));\
+ a = (typeof(a))(((avl_native_t)(a))^((avl_native_t)(b)));}
+
+/**
+ * Node of AVL tree
+ * Contains pointer to left son, right son, parent and key
+ */
+typedef struct avltree_gen_node{
+ /**
+ * Data of the node
+ */
+ void *key;
+ /**
+ * Left subtree of the node
+ */
+ struct avltree_gen_node * left_son;
+ /**
+ * Right subtree of the node
+ */
+ struct avltree_gen_node * right_son;
+ /**
+ * Parent of current node (NULL for root)
+ */
+ struct avltree_gen_node * parent;
+ /**
+ * Balance of subtrees in well balanced tree could be LEFT_LIGHTER, RIGHT_LIGHTER or BALANCED
+ */
+ avl_native_t balance;
+} avltree_gen_node_t;
+
+extern void avltree_gen_node_init(avltree_gen_node_t * input_node, void *key);
+
+/**
+ * Wrapper of AVL tree
+ */
+typedef struct avltree_gen{
+ /**
+ * Function to compare nodes during adding or default saerching
+ */
+ int (*compare_keys)(void *, void*);
+ /**
+ * Root of the tree.
+ */
+ avltree_gen_node_t * root;
+} avltree_gen_t;
+
+extern void avltree_gen_init(avltree_gen_t * input_tree, int (*cmp)(void*, void*));
+extern void avltree_gen_insert(avltree_gen_t * input_tree, avltree_gen_node_t *node);
+extern avltree_gen_node_t * avltree_gen_find(avltree_gen_t * source, void * key);
+extern avltree_gen_node_t * avltree_gen_find_parametrized(avltree_gen_t * source, void * key, int (*cmp)(void*, void*));
+extern avltree_gen_node_t * avltree_gen_drop(avltree_gen_t * source, void * key);
+extern avltree_gen_node_t * avltree_gen_drop_parametrized(avltree_gen_t * source, void * key, int (*cmp)(void*, void*));
+extern void avltree_gen_traverse(const avltree_gen_node_t * a, unsigned int tabs);
+extern avltree_gen_node_t * avltree_gen_rem_node(avltree_gen_t * source, avltree_gen_node_t * node);
+extern void avltree_gen_print_parametrized(avltree_gen_t * source, void (*printer)(void*));
+extern avltree_gen_node_t * avltree_gen_get_min(avltree_gen_t * source);
+
+
+extern int avltree_gen_test(avltree_gen_node_t * input);
+extern int avltree_gen_test_cond(avltree_gen_t * input);
+
+#endif
=== added file 'uspace/lib/c/include/dma.h'
--- uspace/lib/c/include/dma.h 1970-01-01 00:00:00 +0000
+++ uspace/lib/c/include/dma.h 2011-08-30 20:40:10 +0000
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2011 Jan Zaloha
+ * 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 dma_userspace
+ * @{
+ */
+
+/**
+ * @file
+ * @brief DMA related standard library functions
+ */
+
+#ifndef _DMA_H_
+#define _DMA_H_
+
+#include <sys/mman.h>
+#include <as.h>
+#include <stdio.h>
+
+#define DMA_24_BITS FRAME_DMA_24_BITS
+#define DMA_32_BITS FRAME_DMA_32_BITS
+
+#define DMA_SHARE 1
+//#define USPACE_DMA_DEBUG
+
+#ifdef USPACE_DMA_DEBUG
+#define uspace_dma_print(...) printf(__VA_ARGS__)
+#else
+#define uspace_dma_print(...)
+#endif
+
+/**
+ * Structure describing block of dma allocated memory
+ */
+typedef struct dma_mem {
+ /**
+ * Pointer to physical memory
+ */
+ void * physical;
+ /**
+ * Pointer to virtual memory
+ */
+ void * virtual;
+ /**
+ * Size in pages
+ */
+ unsigned long size;
+ /**
+ * Flags describing type of mapping
+ */
+ int mapping_flags;
+} dma_mem_t;
+
+/**
+ * Unique identifier of DMA transfer
+ */
+typedef struct dma_transfer_id {
+ /**
+ * ID of the transfer
+ */
+ int id;
+} dma_transfer_id_t;
+
+#define DMA_TRANSFER_ID_TO_INT(x) (x).id
+#define DMA_TRANSFER_ID_INIT(x, y) (x).id = y
+
+#define DMA_MAN_MAX_SPECIFIC 32
+/**
+ * Capabilities of DMA manager driver
+ */
+typedef struct dma_man_capabilities {
+ /**
+ * Can destroy transfer
+ */
+ bool destroy_transfer;
+ /**
+ * Supports set_ procedures
+ */
+ bool set_procedures;
+ /**
+ * Supports get_ procedures
+ */
+ bool add_procedures;
+ /**
+ * Supports mem_ procedures
+ */
+ bool mem_procedures;
+ /**
+ * Device specific data
+ */
+ int specific[DMA_MAN_MAX_SPECIFIC];
+} dma_man_capabilities_t;
+
+/**
+ * Status of a DMA transfer
+ */
+typedef struct dma_transfer_status {
+ /**
+ * Bitfield describing status of the transfer
+ */
+ int status;
+ /**
+ * Size of completed part of transfer
+ */
+ size_t size;
+} dma_transfer_status_t;
+
+/**
+ * Unknown transfer
+ */
+#define DMA_STATUS_UNKNOWN 0x00000001
+/**
+ * Transfer is waiting to be ready
+ */
+#define DMA_STATUS_ENQUED 0x00000002
+/**
+ * Transfer is ready to begin, but not started
+ */
+#define DMA_STATUS_READY 0x00000004
+/**
+ * Transfer is in progress
+ */
+#define DMA_STATUS_PENDING 0x00000008
+/**
+ * Transfer has been finished
+ */
+#define DMA_STATUS_FINISHED 0x00000010
+/**
+ * Transfer has failed
+ */
+#define DMA_STATUS_FAILED 0x00000020
+
+#define DMA_TRANSFER_QUERY_UNKNOWN(x) ((x).status & DMA_STATUS_UNKNOWN)
+#define DMA_TRANSFER_QUERY_ENQUED(x) ((x).status & DMA_STATUS_ENQUED)
+#define DMA_TRANSFER_QUERY_READY(x) ((x).status & DMA_STATUS_READY)
+#define DMA_TRANSFER_QUERY_PENDING(x) ((x).status & DMA_STATUS_PENDING)
+#define DMA_TRANSFER_QUERY_FINISHED(x) ((x).status & DMA_STATUS_FINISHED)
+#define DMA_TRANSFER_QUERY_FAILED(x) ((x).status & DMA_STATUS_FAILED)
+
+#define DMA_TRANSFER_QUERY_COMPLETED_SIZE(x) (x).size
+
+/**
+ * Structure describing channel of DMA transfer
+ */
+typedef struct dma_channel {
+ /**
+ * ID of the channel
+ */
+ int id;
+} dma_channel_t;
+
+/**
+ * Structure describing server registered instance
+ */
+typedef struct dma_srv_dev_id {
+ /**
+ * Id of the instance
+ */
+ uint64_t id;
+} dma_srv_dev_id_t;
+
+#define DMA_CHANNEL_TO_INT(x) (x).id
+#define DMA_CHANNEL_INIT(x, y) (x).id = y
+
+/**
+ * Structure describing flags of DMA transfer
+ */
+typedef struct dma_flags {
+ /**
+ * ID of the channel
+ */
+ int flags;
+} dma_flags_t;
+
+#define DMA_FLAGS_TO_INT(x) (x).flags
+#define DMA_FLAGS_INIT(x, y) (x).flags = y
+
+#define DMA_SRV_REGISTER 100
+#define DMA_SRV_UNREGISTER 101
+#define DMA_SRV_CLEANUP 102
+#define DMA_SRV_SET_OWNERSHIP 103
+#define DMA_SRV_CLEAR_OWNERSHIP 104
+
+extern int dma_allocate(void **, void*, unsigned long, int, int);
+extern int dma_allocate_anonymous(dma_mem_t *, int);
+extern int dma_allocator_init(void);
+extern int dma_unmap(void *);
+extern int dma_free(dma_mem_t *);
+extern int dma_lock(void * vaddr, void ** faddr, size_t size_in,
+ size_t * size_out);
+extern int dma_unlock(void * vaddr, size_t size_in, size_t * size_out);
+extern int dma_cli_register(const char * client_identifier, dma_srv_dev_id_t *id);
+extern int dma_cli_unregister(dma_srv_dev_id_t * id);
+extern int dma_cli_cleanup(dma_srv_dev_id_t * id);
+extern int dma_cli_set_ownership(void * area, size_t offset, size_t number,
+ unsigned int flags, dma_srv_dev_id_t * id);
+extern int dma_cli_clear_ownership(void * paddr, dma_srv_dev_id_t* id);
+
+#endif
+
+/** @}
+ */
=== modified file 'uspace/lib/c/include/ipc/services.h'
--- uspace/lib/c/include/ipc/services.h 2011-03-23 17:15:15 +0000
+++ uspace/lib/c/include/ipc/services.h 2011-08-30 20:43:29 +0000
@@ -59,7 +59,8 @@
SERVICE_ICMP,
SERVICE_UDP,
SERVICE_TCP,
- SERVICE_SOCKET
+ SERVICE_SOCKET,
+ SERVICE_DMA
} services_t;
#endif
=== added directory 'uspace/srv/dma_srv'
=== added file 'uspace/srv/dma_srv/Makefile'
--- uspace/srv/dma_srv/Makefile 1970-01-01 00:00:00 +0000
+++ uspace/srv/dma_srv/Makefile 2011-08-24 08:54:55 +0000
@@ -0,0 +1,9 @@
+
+USPACE_PREFIX = ../..
+BINARY = dma_srv
+STATIC_NEEDED = y
+
+SOURCES = \
+ dma_srv.c
+
+include $(USPACE_PREFIX)/Makefile.common
\ No newline at end of file
=== added file 'uspace/srv/dma_srv/dma_srv.c'
--- uspace/srv/dma_srv/dma_srv.c 1970-01-01 00:00:00 +0000
+++ uspace/srv/dma_srv/dma_srv.c 2011-08-30 21:09:16 +0000
@@ -0,0 +1,657 @@
+/*
+ * Copyright (c) 2011 Jan Zaloha
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fibril_synch.h>
+#include <fibril.h>
+#include <errno.h>
+#include <dma.h>
+#include <async.h>
+#include <ipc/ns.h>
+#include <str.h>
+#include <ipc/services.h>
+#include <adt/avltree_generic.h>
+
+/** @addtogroup dma_userspace
+ * @{
+ */
+
+/**
+ * @file
+ * @brief DMA related standard library functions
+ */
+
+/**
+ * Strucutre describing the range of locked memory area
+ */
+typedef struct dma_srv_mem_area {
+ /**
+ * Physical address of first frame
+ */
+ void * paddr;
+ /**
+ * Begin of reserved virtual memory area
+ */
+ void * vaddr;
+ /**
+ * Size in pages of the area
+ */
+ size_t size;
+} dma_srv_mem_area_t;
+
+/**
+ * Strucuture containing tree of locked areas by one process
+ */
+typedef struct dma_client_tree {
+ /**
+ * Tree of allready locked areas
+ */
+ avltree_gen_t areas;
+ /**
+ * Text identifier of the process
+ */
+ char * name;
+ /**
+ * Unique ID of session
+ */
+ uint64_t id;
+} dma_client_tree_t;
+
+avltree_gen_t process_tree_name;
+avltree_gen_t process_tree_id;
+fibril_mutex_t process_lock;
+uint64_t id_gen;
+
+/**
+ * Compares two dma_srv_mem_area_t structures by physical address
+ * @param[in] a pointer to left dma_srv_mem_area_t
+ * @param[in] b pointer to right dma_srv_mem_area_t
+ * @return LEFT_LIGHTER when left node has lower physical address
+ * RIGHT_LIGHTER when right node has lower physical address
+ * BALANCED when both nodes has same physical address
+ */
+static int dma_srv_area_cmp(void * a, void * b)
+{
+ dma_srv_mem_area_t * l = (dma_srv_mem_area_t*) a;
+ dma_srv_mem_area_t * r = (dma_srv_mem_area_t*) b;
+ if (l->paddr < r->paddr) {
+ return LEFT_LIGHTER;
+ } else if (l->paddr > r->paddr) {
+ return RIGHT_LIGHTER;
+ } else {
+ return BALANCED;
+ }
+}
+
+/**
+ * Compares two dma_srv_client_t structures by string name
+ * @param[in] a pointer to left dma_srv_client_t
+ * @param[in] b pointer to right dma_srv_client_t
+ * @return LEFT_LIGHTER when left node has lower name
+ * RIGHT_LIGHTER when right node has lower name
+ * BALANCED when both nodes has same name
+ */
+static int dma_srv_client_cmp_name(void * a, void * b)
+{
+ dma_client_tree_t * l = (dma_client_tree_t*) a;
+ dma_client_tree_t * r = (dma_client_tree_t*) b;
+
+ int ret = str_cmp(l->name, r->name);
+ if (ret == -1) {
+ return LEFT_LIGHTER;
+ }
+ if (ret == 1) {
+ return RIGHT_LIGHTER;
+ }
+ return BALANCED;
+}
+
+/**
+ * Compares two dma_srv_client_t structures by id
+ * @param[in] a pointer to left dma_srv_client_t
+ * @param[in] b pointer to right dma_srv_client_t
+ * @return LEFT_LIGHTER when left node has lower id
+ * RIGHT_LIGHTER when right node has lower id
+ * BALANCED when both nodes has same id
+ */
+static int dma_srv_client_cmp_id(void * a, void * b)
+{
+ dma_client_tree_t * l = (dma_client_tree_t*) a;
+ dma_client_tree_t * r = (dma_client_tree_t*) b;
+
+ if (l->id < r->id) {
+ return LEFT_LIGHTER;
+ } else if (l->id > r->id) {
+ return RIGHT_LIGHTER;
+ }
+ return BALANCED;
+}
+
+/**
+ * Unlocks memory area represented by dma_srv_mem_area_t
+ * @param[in] area Pointer to area which should be unlocked
+ *
+ * @return same as dma_unlock.
+ */
+static int dma_srv_unlock_area(dma_srv_mem_area_t * area)
+{
+ size_t count;
+ return dma_unlock(area->vaddr, area->size, &count);
+}
+
+/**
+ * Locks memory area represented by dma_srv_mem_area_t
+ * @param[in] area Pointer to area which should be locked
+ *
+ * @return EOK.
+ */
+static int dma_srv_lock_area(dma_srv_mem_area_t * area, size_t offset,
+ size_t size)
+{
+ size_t count = size;
+ size_t currently_locked;
+ void * temp;
+ int * vaddr = (int*) (((void*) area->vaddr) + PAGE_SIZE * offset);
+ uspace_dma_print("dma_srv_lock_area\n");
+ if(dma_lock(vaddr, &(temp), count, ¤tly_locked) != EOK){
+ uspace_dma_print("error\n");
+ return EINVAL;
+ }
+ uspace_dma_print("Locked %d/%d, %p\n", (int) currently_locked, (int) count,
+ vaddr);
+ area->paddr = temp;
+
+ count -= currently_locked;
+ vaddr = (void*)(((uintptr_t)vaddr) + currently_locked * PAGE_SIZE);
+ while (count > 0) {
+ dma_lock(vaddr, &temp, count, ¤tly_locked);
+ //uspace_dma_print("Locked %d/%d, %p\n", currently_locked, count, vaddr);
+ count -= currently_locked;
+ if (currently_locked == 0) {
+ return EINVAL;
+ }
+ vaddr = (void*)(((uintptr_t)vaddr) + currently_locked * PAGE_SIZE);
+ }
+ return EOK;
+
+}
+/**
+ * Inits main strucutures of the server.
+ */
+
+static void dma_srv_init()
+{
+ fibril_mutex_initialize(&process_lock);
+ avltree_gen_init(&process_tree_name, dma_srv_client_cmp_name);
+ avltree_gen_init(&process_tree_id, dma_srv_client_cmp_id);
+ id_gen = 444;
+}
+
+/**
+ * Creates all data structures needed for communication with client side
+ * @param[in] rid id of invocation call
+ * @param[in] call pointer to call parameters
+ *
+ * @return EOK on success, ENOMEM on low memory, otherwise same as
+ * async_data_write_receive
+ */
+static int dma_srv_register(ipc_callid_t rid, ipc_call_t *call)
+{
+ uspace_dma_print("DMA server register\n");
+ dma_client_tree_t * new_client = NULL;
+ avltree_gen_node_t * node_name = NULL;
+ avltree_gen_node_t * node_id = NULL;
+ avltree_gen_node_t * temp;
+ size_t length;
+ ipc_callid_t callid;
+ uint64_t id;
+ int rc = ENOMEM;
+
+ if ((new_client = malloc(sizeof(dma_client_tree_t))) == NULL) {
+ goto err;
+ }
+ if ((node_name = malloc(sizeof(avltree_gen_node_t))) == NULL) {
+ goto err;
+ }
+ if ((node_id = malloc(sizeof(avltree_gen_node_t))) == NULL) {
+ goto err;
+ }
+
+ avltree_gen_node_init(node_name, new_client);
+ avltree_gen_node_init(node_id, new_client);
+
+ if (!(rc = async_data_write_receive(&callid, &length))) {
+ async_answer_0(callid, rc);
+ goto err;
+ }
+ uspace_dma_print("DMA server register: buffer len: %d\n", (int)length);
+ if ((new_client->name = malloc((length + 1) * sizeof(char))) == NULL) {
+ rc = ENOMEM;
+ async_answer_0(callid, rc);
+ goto err;
+ }
+
+ if ((rc = async_data_write_finalize(callid, new_client->name, length))) {
+ uspace_dma_print("DMA server register failed: error %d\n", rc);
+ async_answer_0(callid, rc);
+ goto err;
+ }
+ uspace_dma_print("DMA server register: name %s\n", new_client->name);
+ uspace_dma_print("Data = %p\n", new_client);
+ fibril_mutex_lock(&process_lock);
+ if ((temp = avltree_gen_find(&process_tree_name, new_client)) == NULL) {
+ new_client->id = id_gen;
+ avltree_gen_init(&(new_client->areas), dma_srv_area_cmp);
+ id = id_gen;
+ ++id_gen;
+ avltree_gen_insert(&process_tree_name, node_name);
+ avltree_gen_insert(&process_tree_id, node_id);
+ } else {
+ id = ((dma_client_tree_t*) (temp->key))->id;
+ free(new_client->name);
+ free(new_client);
+ free(node_name);
+ free(node_id);
+ }
+ fibril_mutex_unlock(&process_lock);
+
+ async_answer_0(callid, EOK);
+ async_answer_1(rid, EOK, id);
+
+ return EOK;
+ err: async_answer_1(rid, rc, 0);
+ if (new_client != NULL && new_client->name != NULL) {
+ free(new_client->name);
+ }
+ if (new_client != NULL) {
+ free(new_client);
+ }
+ if (node_name != NULL) {
+ free(node_name);
+ }
+ if (node_id != NULL) {
+ free(node_id);
+ }
+ return rc;
+}
+
+/**
+ * Destroys all data structures needed for communication with client side
+ * @param[in] rid id of invocation call
+ * @param[in] call pointer to call parameters
+ *
+ * @return EOK on success, ENOTSUP when locked area for the client still exists,
+ * EINVAL when client id does not exist
+ */
+static int dma_srv_unregister(ipc_callid_t callid, ipc_call_t *call)
+{
+ dma_client_tree_t node;
+ node.id = IPC_GET_ARG1(*call);
+ fibril_mutex_lock(&process_lock);
+
+ avltree_gen_node_t * n = avltree_gen_find(&process_tree_id, &node);
+ dma_client_tree_t * real_node = (dma_client_tree_t*) n->key;
+
+ if (real_node == NULL) {
+ fibril_mutex_unlock(&process_lock);
+ async_answer_0(callid, EINVAL);
+ return EINVAL;
+ }
+
+ if ((avltree_gen_get_min(&(real_node->areas))) != NULL) {
+ fibril_mutex_unlock(&process_lock);
+ async_answer_0(callid, ENOTSUP);
+ return ENOTSUP;
+ }
+
+ avltree_gen_node_t * m = avltree_gen_find(&process_tree_name, real_node);
+ avltree_gen_rem_node(&process_tree_name, m);
+ avltree_gen_rem_node(&process_tree_id, n);
+ fibril_mutex_unlock(&process_lock);
+
+ free(real_node->name);
+ free(real_node);
+ free(m);
+ free(n);
+ async_answer_0(callid, EOK);
+ return EOK;
+}
+
+/**
+ * Destroys all areas locked by the client
+ * @param[in] rid id of invocation call
+ * @param[in] call pointer to call parameters
+ *
+ * @return EOK on success, EINVAL when client id does not exist
+ */
+static int dma_srv_cleanup(ipc_callid_t callid, ipc_call_t *call)
+{
+ dma_client_tree_t n;
+ n.id = IPC_GET_ARG1(*call);
+ fibril_mutex_lock(&process_lock);
+ uspace_dma_print("Cleanup\n");
+ avltree_gen_node_t * node = avltree_gen_find(&process_tree_id, &n);
+ if (node == NULL) {
+ fibril_mutex_unlock(&process_lock);
+ async_answer_0(callid, EINVAL);
+ return EINVAL;
+ }
+
+ dma_client_tree_t * tree = (dma_client_tree_t*) node->key;
+
+ while ((node = avltree_gen_get_min(&(tree->areas))) != NULL) {
+ uspace_dma_print("Unlock %p\n", node->key);
+ avltree_gen_rem_node(&(tree->areas), node);
+ dma_srv_unlock_area((dma_srv_mem_area_t*) node->key);
+ as_area_destroy(((dma_srv_mem_area_t*) node->key)->vaddr);
+ uspace_dma_print("free 1\n");
+ free(node->key);
+ uspace_dma_print("free 2\n");
+ free(node);
+ }
+
+ fibril_mutex_unlock(&process_lock);
+
+ async_answer_0(callid, EOK);
+ return EOK;
+}
+
+/**
+ * Destroys one locked area owned by client
+ * @param[in] rid id of invocation call
+ * @param[in] call pointer to call parameters
+ *
+ * @return EOK on success, EINVAL when client id or area does not exist
+ */
+static int dma_srv_clear_ownership(ipc_callid_t callid, ipc_call_t *call)
+{
+
+ dma_client_tree_t d;
+ d.id = IPC_GET_ARG1(*call);
+ dma_srv_mem_area_t area;
+ area.paddr = (void*) IPC_GET_ARG2(*call);
+
+ fibril_mutex_lock(&process_lock);
+ avltree_gen_node_t * node = avltree_gen_find(&process_tree_id, &d);
+
+ uspace_dma_print("Srv clear\n");
+ if (node == NULL) {
+ fibril_mutex_unlock(&process_lock);
+ async_answer_0(callid, EINVAL);
+ return EINVAL;
+ }
+
+ uspace_dma_print("Srv clear stage 1\n");
+ dma_client_tree_t * cli_tree = (dma_client_tree_t*) node->key;
+ uspace_dma_print("Srv clear stage 1.5 %p\n", cli_tree);
+ node = avltree_gen_find(&(cli_tree->areas), &area);
+
+ if (node == NULL) {
+ fibril_mutex_unlock(&process_lock);
+ async_answer_0(callid, EINVAL);
+ return EINVAL;
+ }
+
+ uspace_dma_print("Srv clear stage 2\n");
+ avltree_gen_rem_node(&(cli_tree->areas), node);
+ fibril_mutex_unlock(&process_lock);
+ uspace_dma_print("Srv clear stage 3\n");
+
+ dma_srv_unlock_area((dma_srv_mem_area_t*) node->key);
+ as_area_destroy(((dma_srv_mem_area_t*) node->key)->vaddr);
+ free(node->key);
+ free(node);
+ async_answer_0(callid, EOK);
+ return EOK;
+}
+
+/**
+ * Creates one locked area owned by client
+ * @param[in] rid id of invocation call
+ * @param[in] call pointer to call parameters
+ *
+ * @return EOK on success, EINVAL when client passes bad data,
+ * ENOMEM on low memory
+ */
+static int dma_srv_set_ownership(ipc_callid_t rid, ipc_call_t *call)
+{
+ avltree_gen_node_t * node = NULL;
+ dma_srv_mem_area_t * area = NULL;
+ int rc = EINVAL;
+ ipc_callid_t callid;
+ size_t size;
+ unsigned flags;
+
+ uspace_dma_print("ownership\n");
+ node = malloc(sizeof(avltree_gen_node_t));
+ area = malloc(sizeof(dma_srv_mem_area_t));
+ if (node == NULL || area == NULL) {
+ rc = ENOMEM;
+ async_answer_0(rid, rc);
+ goto err;
+ }
+
+ dma_client_tree_t searched_node;
+ avltree_gen_node_t * n;
+ searched_node.id = IPC_GET_ARG1(*call);
+ size_t offset = IPC_GET_ARG2(*call);
+ size_t declared_size = IPC_GET_ARG3(*call);
+
+ fibril_mutex_lock(&process_lock);
+ uspace_dma_print("ownership from id %d\n", (int) searched_node.id);
+
+ if ((n = avltree_gen_find(&process_tree_id, &searched_node)) == NULL) {
+ async_answer_0(rid, rc);
+ fibril_mutex_unlock(&process_lock);
+ goto err;
+ }
+
+ uspace_dma_print("ownership from id %d stage 2\n", (int) searched_node.id);
+ fibril_mutex_unlock(&process_lock);
+
+ if (!(rc = async_share_out_receive(&callid, &size, &flags))) {
+ rc = EINVAL;
+ uspace_dma_print("ownership from id %d failed code %d\n",
+ (int) searched_node.id, rc);
+ async_answer_0(callid, rc);
+ async_answer_0(rid, rc);
+ goto err;
+ }
+
+ if (size / PAGE_SIZE < offset + declared_size) {
+ rc = EINVAL;
+ uspace_dma_print("ownership from id %d failed code %d\n",
+ (int) searched_node.id, rc);
+ async_answer_0(callid, rc);
+ async_answer_0(rid, rc);
+ goto err;
+ }
+
+ uspace_dma_print("ownership from id %d stage 3\n", (int) searched_node.id);
+
+ if (size % PAGE_SIZE || size == 0) {
+ rc = EINVAL;
+ uspace_dma_print("ownership from id %d failed\n",
+ (int) searched_node.id);
+ async_answer_0(callid, rc);
+ async_answer_0(rid, rc);
+ goto err;
+ }
+
+ area->vaddr = as_get_mappable_page(size);
+
+ if (area->vaddr == NULL) {
+ rc = ENOMEM;
+ uspace_dma_print("ownership from id %d failed enomem\n",
+ (int) searched_node.id);
+ async_answer_0(callid, rc);
+ async_answer_0(rid, rc);
+ goto err;
+
+ }
+
+ uspace_dma_print("ownership from id %d stage 3,5\n", (int) searched_node.id);
+ async_share_out_finalize(callid, (area->vaddr));
+ uspace_dma_print("ownership from id %d stage 4, %p\n",
+ (int) searched_node.id, area->vaddr);
+ area->size = size / PAGE_SIZE;
+ uspace_dma_print("offset %d, size %d", (int)offset, (int)declared_size);
+ if ((rc = dma_srv_lock_area(area, offset, declared_size)) != EOK) {
+ async_answer_0(rid, rc);
+ as_area_destroy(area->vaddr);
+ goto err;
+ }
+
+ avltree_gen_node_init(node, area);
+ dma_client_tree_t * tree = (dma_client_tree_t*) n->key;
+
+ uspace_dma_print("ownership from id %d stage 5\n", (int) searched_node.id);
+
+ fibril_mutex_lock(&process_lock);
+ if (avltree_gen_find(&(tree->areas), node) != NULL) {
+ dma_srv_unlock_area(area);
+ as_area_destroy(area->vaddr);
+ rc = EINVAL;
+ goto err;
+ }
+ avltree_gen_insert(&(tree->areas), node);
+ fibril_mutex_unlock(&process_lock);
+
+ async_answer_0(rid, EOK);
+ uspace_dma_print("ownership from id %d finished\n", (int) searched_node.id);
+ return EOK;
+
+ err: if (node != NULL) {
+ free(node);
+ }
+ if (area != NULL) {
+ free(area);
+ }
+ return rc;
+}
+
+/** Process the module message.
+ *
+ * Distribute the message to the right module.
+ *
+ * @param[in] callid The message identifier.
+ * @param[in] call The message parameters.
+ *
+ * @return EOK on success.
+ * @return ENOTSUP if the message is not known.
+ * @return Other error codes.
+ *
+ */
+static int dma_proc_message(ipc_callid_t callid, ipc_call_t *call)
+{
+ int rc = ENOTSUP;
+ switch (IPC_GET_IMETHOD(*call)) {
+ case DMA_SRV_REGISTER:
+ rc = dma_srv_register(callid, call);
+ break;
+ case DMA_SRV_UNREGISTER:
+ rc = dma_srv_unregister(callid, call);
+ break;
+ case DMA_SRV_CLEANUP:
+ rc = dma_srv_cleanup(callid, call);
+ break;
+ case DMA_SRV_SET_OWNERSHIP:
+ rc = dma_srv_set_ownership(callid, call);
+ break;
+ case DMA_SRV_CLEAR_OWNERSHIP:
+ rc = dma_srv_clear_ownership(callid, call);
+ break;
+ default:
+ break;
+ }
+ return rc;
+}
+
+/** Default thread for new connections.
+ *
+ * @param[in] iid The initial message identifier.
+ * @param[in] icall The initial message call structure.
+ *
+ */
+
+static void dma_client_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+ async_answer_0(iid, EOK);
+
+ while (true) {
+ ipc_call_t call;
+ uspace_dma_print("Waiting for call\n");
+ ipc_callid_t callid = async_get_call(&call);
+
+ int rc = dma_proc_message(callid, &call);
+
+ if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) || (rc == EHANGUP))
+ return;
+ }
+}
+
+/**
+ * Starts the DMA memory server
+ * @param[in] client_connetion procedure processes IPC requests
+ *
+ * @return according to client_connection return code
+ */
+
+static int dma_srv_module_start(async_client_conn_t client_connection)
+{
+ int rc;
+
+ dma_srv_init();
+ async_set_client_connection(client_connection);
+
+ rc = async_connect_to_me(PHONE_NS, SERVICE_DMA, 0, 0, NULL);
+ if (rc != EOK) {
+ printf("asdf\n");
+ goto error;
+ }
+
+ async_manager();
+
+ error: return rc;
+}
+
+int main(int argc, char * argv[])
+{
+ int rc;
+
+ rc = dma_srv_module_start(dma_client_connection);
+ if (rc != EOK) {
+ return rc;
+ }
+
+ return EOK;
+
+}
+/** @}
+ */