diff options
-rw-r--r-- | package/fusion/fusion.h | 277 | ||||
-rw-r--r-- | package/fusion/fusion.mk | 41 | ||||
-rw-r--r-- | package/fusion/linux-2.6.22.1-008-fusion.patch | 6265 | ||||
-rw-r--r-- | package/linux-fusion/40-fusion.rules (renamed from package/fusion/40-fusion.rules) | 0 | ||||
-rw-r--r-- | package/linux-fusion/Config.in (renamed from package/fusion/Config.in) | 1 | ||||
-rw-r--r-- | package/linux-fusion/linux-fusion-8.0.2-cross-compile.patch | 100 | ||||
-rw-r--r-- | package/linux-fusion/linux-fusion.mk | 83 |
7 files changed, 183 insertions, 6584 deletions
diff --git a/package/fusion/fusion.h b/package/fusion/fusion.h deleted file mode 100644 index d9139fc6d..000000000 --- a/package/fusion/fusion.h +++ /dev/null @@ -1,277 +0,0 @@ -#ifndef __LINUX__FUSION_H__ -#define __LINUX__FUSION_H__ - -#include <asm/ioctl.h> - -/* - * Fusion Kernel Device API Version - */ -#define FUSION_API_MAJOR 3 /* Increased if backward compatibility is dropped. */ -#define FUSION_API_MINOR 2 /* Increased if new features are added. */ - -/* - * The Fusion ID is a unique identifier for one process consisting of threads. - */ -typedef unsigned long FusionID; - -#define FUSION_ID_MASTER 1 /* This is the fusion id of the master (first process). */ - -/* - * Entering a world - */ -typedef struct { - struct { - int major; /* Must be set to FUSION_API_MAJOR before entering. */ - int minor; /* Must be set to FUSION_API_MINOR before entering. */ - } api; - - FusionID fusion_id; /* Returns the fusion id of the entering process. */ -} FusionEnter; - -/* - * Forking in world - */ -typedef struct { - FusionID fusion_id; /* Returns the fusion id of the new (forked) fusionee. */ -} FusionFork; - -/* - * Sending a message - */ -typedef struct { - FusionID fusion_id; /* recipient */ - - int msg_id; /* optional message identifier */ - int msg_size; /* message size, must be greater than zero */ - const void *msg_data; /* message data, must not be NULL */ -} FusionSendMessage; - -/* - * Receiving a message - */ -typedef enum { - FMT_SEND, /* msg_id is an optional custom id */ - FMT_CALL, /* msg_id is the call id */ - FMT_REACTOR, /* msg_id is the reactor id */ - FMT_SHMPOOL /* msg_id is the pool id */ -} FusionMessageType; - -typedef struct { - FusionMessageType msg_type; /* type (origin) of message */ - - int msg_id; /* message id (custom id or call/reactor/pool id) */ - int msg_size; /* size of the following message data */ - - /* message data follows */ -} FusionReadMessage; - -/* - * Dispatching a message via a reactor - */ -typedef struct { - int reactor_id; - int self; - - int msg_size; /* message size, must be greater than zero */ - const void *msg_data; /* message data, must not be NULL */ -} FusionReactorDispatch; - -/* - * Calling (synchronous RPC) - */ -typedef struct { - int call_id; /* new call id returned */ - - void *handler; /* function pointer of handler to install */ - void *ctx; /* optional handler context */ -} FusionCallNew; - -typedef enum { - FCEF_NONE = 0x00000000, - FCEF_ONEWAY = 0x00000001, - FCEF_ALL = 0x00000001 -} FusionCallExecFlags; - -typedef struct { - int ret_val; /* return value of the call */ - - int call_id; /* id of the requested call, each call has a fixed owner */ - - int call_arg; /* optional int argument */ - void *call_ptr; /* optional pointer argument (shared memory) */ - - FusionCallExecFlags flags; /* execution flags */ -} FusionCallExecute; - -typedef struct { - int call_id; /* id of currently executing call */ - - int val; /* value to return */ -} FusionCallReturn; - -typedef struct { - void *handler; /* function pointer of handler to call */ - void *ctx; /* optional handler context */ - - int caller; /* fusion id of the caller or zero if called from Fusion */ - int call_arg; /* optional call parameter */ - void *call_ptr; /* optional call parameter */ -} FusionCallMessage; - -/* - * Watching a reference - * - * This information is needed to have a specific call being executed if the - * reference count reaches zero. Currently one watch per reference is allowed. - * - * The call is made by Fusion and therefor has a caller id of zero. - * - */ -typedef struct { - int id; /* id of the reference to watch */ - - int call_id; /* id of the call to execute */ - int call_arg; /* optional call parameter, e.g. the id of a user - space resource associated with that reference */ -} FusionRefWatch; - -/* - * Inheriting local count from other reference - */ -typedef struct { - int id; /* own reference id */ - int from; /* id of the reference to inherit from */ -} FusionRefInherit; - -/* - * Killing other fusionees (experimental) - */ -typedef struct { - FusionID fusion_id; /* fusionee to kill, zero means all but ourself */ - int signal; /* signal to be delivered, e.g. SIGTERM */ - int timeout_ms; /* -1 means no timeout, 0 means infinite, otherwise the - max. time to wait until the fusionee(s) terminated */ -} FusionKill; - - -/* - * Shared memory pools - */ -typedef struct { - int max_size; /* Maximum size that this pool will be allowed to grow to. */ - - int pool_id; /* Returns the new pool id. */ - void *addr_base; /* Returns the base of the reserved virtual memory address space. */ -} FusionSHMPoolNew; - -typedef struct { - int pool_id; /* The id of the pool to attach to. */ - - void *addr_base; /* Returns the base of the reserved virtual memory address space. */ - int size; /* Returns the current size of the pool. */ -} FusionSHMPoolAttach; - -typedef struct { - int pool_id; /* The id of the pool to notify. */ - - int size; /* New size of the pool. */ -} FusionSHMPoolDispatch; - -typedef enum { - FSMT_REMAP, /* Remap the pool due to a change of its size. */ - FSMT_UNMAP /* Unmap the pool due to its destruction. */ -} FusionSHMPoolMessageType; - -typedef struct { - FusionSHMPoolMessageType type; /* Type of the message. */ - - int size; /* New size of the pool, if type is FSMT_REMAP. */ -} FusionSHMPoolMessage; - - -/* - * Fusion types - */ -typedef enum { - FT_LOUNGE, - FT_MESSAGING, - FT_CALL, - FT_REF, - FT_SKIRMISH, - FT_PROPERTY, - FT_REACTOR, - FT_SHMPOOL -} FusionType; - - -/* - * Set attributes like 'name' for an entry of the specified type. - */ -#define FUSION_ENTRY_INFO_NAME_LENGTH 24 - -typedef struct { - FusionType type; - int id; - - char name[FUSION_ENTRY_INFO_NAME_LENGTH]; -} FusionEntryInfo; - - - -#define FUSION_ENTER _IOR(FT_LOUNGE, 0x00, FusionEnter) -#define FUSION_UNBLOCK _IO (FT_LOUNGE, 0x01) -#define FUSION_KILL _IOW(FT_LOUNGE, 0x02, FusionKill) - -#define FUSION_ENTRY_SET_INFO _IOW(FT_LOUNGE, 0x03, FusionEntryInfo) -#define FUSION_ENTRY_GET_INFO _IOW(FT_LOUNGE, 0x04, FusionEntryInfo) - -#define FUSION_FORK _IOW(FT_LOUNGE, 0x05, FusionFork) - -#define FUSION_SEND_MESSAGE _IOW(FT_MESSAGING, 0x00, FusionSendMessage) - -#define FUSION_CALL_NEW _IOW(FT_CALL, 0x00, FusionCallNew) -#define FUSION_CALL_EXECUTE _IOW(FT_CALL, 0x01, FusionCallExecute) -#define FUSION_CALL_RETURN _IOW(FT_CALL, 0x02, FusionCallReturn) -#define FUSION_CALL_DESTROY _IOW(FT_CALL, 0x03, int) - -#define FUSION_REF_NEW _IOW(FT_REF, 0x00, int) -#define FUSION_REF_UP _IOW(FT_REF, 0x01, int) -#define FUSION_REF_UP_GLOBAL _IOW(FT_REF, 0x02, int) -#define FUSION_REF_DOWN _IOW(FT_REF, 0x03, int) -#define FUSION_REF_DOWN_GLOBAL _IOW(FT_REF, 0x04, int) -#define FUSION_REF_ZERO_LOCK _IOW(FT_REF, 0x05, int) -#define FUSION_REF_ZERO_TRYLOCK _IOW(FT_REF, 0x06, int) -#define FUSION_REF_UNLOCK _IOW(FT_REF, 0x07, int) -#define FUSION_REF_STAT _IOW(FT_REF, 0x08, int) -#define FUSION_REF_WATCH _IOW(FT_REF, 0x09, FusionRefWatch) -#define FUSION_REF_INHERIT _IOW(FT_REF, 0x0A, FusionRefInherit) -#define FUSION_REF_DESTROY _IOW(FT_REF, 0x0B, int) - -#define FUSION_SKIRMISH_NEW _IOW(FT_SKIRMISH, 0x00, int) -#define FUSION_SKIRMISH_PREVAIL _IOW(FT_SKIRMISH, 0x01, int) -#define FUSION_SKIRMISH_SWOOP _IOW(FT_SKIRMISH, 0x02, int) -#define FUSION_SKIRMISH_DISMISS _IOW(FT_SKIRMISH, 0x03, int) -#define FUSION_SKIRMISH_DESTROY _IOW(FT_SKIRMISH, 0x04, int) -#define FUSION_SKIRMISH_LOCK_COUNT _IOW(FT_SKIRMISH, 0x05, int) - -#define FUSION_PROPERTY_NEW _IOW(FT_PROPERTY, 0x00, int) -#define FUSION_PROPERTY_LEASE _IOW(FT_PROPERTY, 0x01, int) -#define FUSION_PROPERTY_PURCHASE _IOW(FT_PROPERTY, 0x02, int) -#define FUSION_PROPERTY_CEDE _IOW(FT_PROPERTY, 0x03, int) -#define FUSION_PROPERTY_HOLDUP _IOW(FT_PROPERTY, 0x04, int) -#define FUSION_PROPERTY_DESTROY _IOW(FT_PROPERTY, 0x05, int) - -#define FUSION_REACTOR_NEW _IOW(FT_REACTOR, 0x00, int) -#define FUSION_REACTOR_ATTACH _IOW(FT_REACTOR, 0x01, int) -#define FUSION_REACTOR_DETACH _IOW(FT_REACTOR, 0x02, int) -#define FUSION_REACTOR_DISPATCH _IOW(FT_REACTOR, 0x03, FusionReactorDispatch) -#define FUSION_REACTOR_DESTROY _IOW(FT_REACTOR, 0x04, int) - -#define FUSION_SHMPOOL_NEW _IOW(FT_SHMPOOL, 0x00, FusionSHMPoolNew) -#define FUSION_SHMPOOL_ATTACH _IOW(FT_SHMPOOL, 0x01, FusionSHMPoolAttach) -#define FUSION_SHMPOOL_DETACH _IOW(FT_SHMPOOL, 0x02, int) -#define FUSION_SHMPOOL_DISPATCH _IOW(FT_SHMPOOL, 0x03, FusionSHMPoolDispatch) -#define FUSION_SHMPOOL_DESTROY _IOW(FT_SHMPOOL, 0x04, int) - -#endif - diff --git a/package/fusion/fusion.mk b/package/fusion/fusion.mk deleted file mode 100644 index 8158c00a0..000000000 --- a/package/fusion/fusion.mk +++ /dev/null @@ -1,41 +0,0 @@ -############################################################# -# -# linux-fusion -# -############################################################# -LINUX_FUSION_VERSION:=3.2.3 -LINUX_FUSION_SOURCE:=linux-fusion-$(LINUX_FUSION_VERSION).tar.gz -LINUX_FUSION_SITE:=http://www.directfb.org/downloads/Core -LINUX_FUSION_CAT:=$(ZCAT) -LINUX_FUSION_DIR:=$(TARGET_DIR)/etc/udev/rules.d -LINUX_FUSION:=40-fusion.rules -LINUX_FUSION_HEADER=$(STAGING_DIR)/usr/include/linux/fusion.h - -############################################################# -# -# build linux-fusion -# -############################################################# - -$(LINUX_FUSION_HEADER): - cp -dpf package/fusion/fusion.h $(LINUX_FUSION_HEADER) - -$(LINUX_FUSION_DIR)/$(LINUX_FUSION): - mkdir -p $(LINUX_FUSION_DIR) - cp -dpf package/fusion/40-fusion.rules $(LINUX_FUSION_DIR) - touch -c $@ - -linux-fusion: $(LINUX_FUSION_DIR)/$(LINUX_FUSION) $(LINUX_FUSION_HEADER) - -linux-fusion-clean: - rm -f $(LINUX_FUSION_DIR)/$(LINUX_FUSION) - -############################################################# -# -# Toplevel Makefile options -# -############################################################# -ifeq ($(BR2_PACKAGE_LINUX_FUSION),y) -TARGETS+=linux-fusion -endif - diff --git a/package/fusion/linux-2.6.22.1-008-fusion.patch b/package/fusion/linux-2.6.22.1-008-fusion.patch deleted file mode 100644 index 81d98afad..000000000 --- a/package/fusion/linux-2.6.22.1-008-fusion.patch +++ /dev/null @@ -1,6265 +0,0 @@ -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/call.c linux-2.6.22.1/drivers/char/fusion/call.c ---- linux-2.6.22.1-0rig/drivers/char/fusion/call.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/call.c 2007-01-20 05:03:01.000000000 +0100 -@@ -0,0 +1,478 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifdef HAVE_LINUX_CONFIG_H -+#include <linux/config.h> -+#endif -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/smp_lock.h> -+#include <linux/sched.h> -+ -+#include <linux/fusion.h> -+ -+#include "fusiondev.h" -+#include "fusionee.h" -+#include "list.h" -+#include "call.h" -+ -+typedef struct { -+ FusionLink link; -+ -+ Fusionee *caller; -+ -+ int ret_val; -+ -+ bool executed; -+ -+ wait_queue_head_t wait; -+} FusionCallExecution; -+ -+typedef struct { -+ FusionLink link; -+ -+ struct semaphore lock; -+ -+ int id; /* call id */ -+ -+ int pid; /* owner pid */ -+ int fusion_id; /* owner fusion id */ -+ -+ void *handler; -+ void *ctx; -+ -+ FusionLink *executions; /* prepending! */ -+ FusionLink *last; /* points to the last item of executions */ -+ -+ int count; /* number of calls ever made */ -+} FusionCall; -+ -+/******************************************************************************/ -+ -+static int lookup_call (FusionDev *dev, int id, FusionCall **ret_call); -+static int lock_call (FusionDev *dev, int id, FusionCall **ret_call); -+static void unlock_call (FusionCall *call); -+ -+static FusionCallExecution *add_execution (FusionCall *call, -+ Fusionee *caller, -+ FusionCallExecute *execute); -+static void remove_execution (FusionCall *call, -+ FusionCallExecution *execution); -+static void free_all_executions (FusionCall *call); -+ -+/******************************************************************************/ -+ -+static int -+fusion_call_read_proc (char *buf, char **start, off_t offset, -+ int len, int *eof, void *private) -+{ -+ FusionLink *l, *e; -+ FusionDev *dev = private; -+ int written = 0; -+ -+ if (down_interruptible (&dev->call.lock)) -+ return -EINTR; -+ -+ fusion_list_foreach (l, dev->call.list) { -+ bool idle = true; -+ FusionCall *call = (FusionCall*) l; -+ -+ if (call->executions) -+ idle = ((FusionCallExecution*) call->executions)->executed; -+ -+ written += sprintf(buf+written, -+ "(%5d) 0x%08x (%d calls) %s", -+ call->pid, call->id, call->count, -+ idle ? "idle" : "executing"); -+ -+ fusion_list_foreach (e, call->executions) { -+ FusionCallExecution *exec = (FusionCallExecution *) e; -+ -+ written += sprintf(buf+written, " [0x%08lx]", exec->caller ? fusionee_id( exec->caller ) : 0); -+ } -+ -+ written += sprintf(buf+written, "\n"); -+ -+ if (written < offset) { -+ offset -= written; -+ written = 0; -+ } -+ -+ if (written >= len) -+ break; -+ } -+ -+ up (&dev->call.lock); -+ -+ *start = buf + offset; -+ written -= offset; -+ if (written > len) { -+ *eof = 0; -+ return len; -+ } -+ -+ *eof = 1; -+ return(written<0) ? 0 : written; -+} -+ -+int -+fusion_call_init (FusionDev *dev) -+{ -+ create_proc_read_entry("calls", 0, dev->proc_dir, -+ fusion_call_read_proc, dev); -+ -+ init_MUTEX(&dev->call.lock); -+ -+ return 0; -+} -+ -+void -+fusion_call_deinit (FusionDev *dev) -+{ -+ FusionLink *l; -+ -+ down (&dev->call.lock); -+ -+ remove_proc_entry ("calls", dev->proc_dir); -+ -+ l = dev->call.list; -+ while (l) { -+ FusionLink *next = l->next; -+ FusionCall *call = (FusionCall *) l; -+ -+ free_all_executions (call); -+ -+ kfree (call); -+ -+ l = next; -+ } -+ -+ up (&dev->call.lock); -+} -+ -+/******************************************************************************/ -+ -+int -+fusion_call_new (FusionDev *dev, int fusion_id, FusionCallNew *call_new) -+{ -+ FusionCall *call; -+ -+ call = kmalloc (sizeof(FusionCall), GFP_KERNEL); -+ if (!call) -+ return -ENOMEM; -+ -+ memset (call, 0, sizeof(FusionCall)); -+ -+ if (down_interruptible (&dev->call.lock)) { -+ kfree (call); -+ return -EINTR; -+ } -+ -+ call->id = dev->call.ids++; -+ call->pid = current->pid; -+ call->fusion_id = fusion_id; -+ call->handler = call_new->handler; -+ call->ctx = call_new->ctx; -+ -+ init_MUTEX (&call->lock); -+ -+ fusion_list_prepend (&dev->call.list, &call->link); -+ -+ up (&dev->call.lock); -+ -+ call_new->call_id = call->id; -+ -+ return 0; -+} -+ -+int -+fusion_call_execute (FusionDev *dev, Fusionee *fusionee, FusionCallExecute *execute) -+{ -+ int ret; -+ FusionCall *call; -+ FusionCallExecution *execution; -+ FusionCallMessage message; -+ -+ ret = lock_call (dev, execute->call_id, &call); -+ if (ret) -+ return ret; -+ -+ execution = add_execution (call, fusionee, execute); -+ if (!execution) { -+ unlock_call (call); -+ return -ENOMEM; -+ } -+ -+ /* Send call message. */ -+ message.handler = call->handler; -+ message.ctx = call->ctx; -+ -+ message.caller = fusionee ? fusionee_id( fusionee ) : 0; -+ -+ message.call_arg = execute->call_arg; -+ message.call_ptr = execute->call_ptr; -+ -+ ret = fusionee_send_message (dev, fusionee, call->fusion_id, FMT_CALL, -+ call->id, sizeof(message), &message); -+ if (ret) { -+ remove_execution (call, execution); -+ kfree (execution); -+ unlock_call (call); -+ return ret; -+ } -+ -+ call->count++; -+ -+ if (fusionee && !(execute->flags & FCEF_ONEWAY)) { -+ /* TODO: implement timeout */ -+ fusion_sleep_on (&execution->wait, &call->lock, 0); -+ -+ ret = lock_call (dev, execute->call_id, &call); -+ if (ret) -+ return ret == -EINVAL ? -EIDRM : ret; -+ -+ if (signal_pending(current)) { -+ execution->caller = 0; -+ unlock_call (call); -+ return -EINTR; -+ } -+ -+ execute->ret_val = execution->ret_val; -+ -+ remove_execution (call, execution); -+ -+ kfree (execution); -+ } -+ -+ unlock_call (call); -+ -+ return 0; -+} -+ -+int -+fusion_call_return (FusionDev *dev, int fusion_id, FusionCallReturn *call_ret) -+{ -+ int ret; -+ FusionLink *l; -+ FusionCall *call; -+ -+ ret = lock_call (dev, call_ret->call_id, &call); -+ if (ret) -+ return ret; -+ -+ l = call->last; -+ while (l) { -+ FusionCallExecution *execution = (FusionCallExecution*) l; -+ -+ if (execution->executed) { -+ l = l->prev; -+ continue; -+ } -+ -+ if (execution->caller) { -+ execution->ret_val = call_ret->val; -+ execution->executed = true; -+ -+ wake_up_interruptible_all (&execution->wait); -+ } -+ else { -+ remove_execution (call, execution); -+ -+ kfree (execution); -+ } -+ -+ unlock_call (call); -+ -+ return 0; -+ } -+ -+ unlock_call (call); -+ -+ return -EIO; -+} -+ -+int -+fusion_call_destroy (FusionDev *dev, int fusion_id, int call_id) -+{ -+ int ret; -+ FusionCall *call; -+ -+ ret = lookup_call (dev, call_id, &call); -+ if (ret) -+ return ret; -+ -+ if (call->fusion_id != fusion_id) { -+ up (&dev->call.lock); -+ return -EIO; -+ } -+ -+ if (down_interruptible (&call->lock)) { -+ up (&dev->call.lock); -+ return -EINTR; -+ } -+ -+ fusion_list_remove (&dev->call.list, &call->link); -+ -+ free_all_executions (call); -+ -+ up (&dev->call.lock); -+ -+ up (&call->lock); -+ -+ kfree (call); -+ -+ return 0; -+} -+ -+void -+fusion_call_destroy_all (FusionDev *dev, int fusion_id) -+{ -+ FusionLink *l; -+ -+ down (&dev->call.lock); -+ -+ l = dev->call.list; -+ -+ while (l) { -+ FusionLink *next = l->next; -+ FusionCall *call = (FusionCall *) l; -+ -+ down (&call->lock); -+ -+ if (call->fusion_id == fusion_id) { -+ free_all_executions (call); -+ -+ fusion_list_remove (&dev->call.list, &call->link); -+ -+ up (&call->lock); -+ -+ kfree (call); -+ } -+ else -+ up (&call->lock); -+ -+ l = next; -+ } -+ -+ up (&dev->call.lock); -+} -+ -+/******************************************************************************/ -+ -+static int -+lookup_call (FusionDev *dev, int id, FusionCall **ret_call) -+{ -+ FusionLink *l; -+ -+ if (down_interruptible (&dev->call.lock)) -+ return -EINTR; -+ -+ fusion_list_foreach (l, dev->call.list) { -+ FusionCall *call = (FusionCall *) l; -+ -+ if (call->id == id) { -+ *ret_call = call; -+ return 0; -+ } -+ } -+ -+ up (&dev->call.lock); -+ -+ return -EINVAL; -+} -+ -+static int -+lock_call (FusionDev *dev, int id, FusionCall **ret_call) -+{ -+ int ret; -+ FusionCall *call; -+ -+ ret = lookup_call (dev, id, &call); -+ if (ret) -+ return ret; -+ -+ if (call) { -+ fusion_list_move_to_front (&dev->call.list, &call->link); -+ -+ if (down_interruptible (&call->lock)) { -+ up (&dev->call.lock); -+ return -EINTR; -+ } -+ -+ up (&dev->call.lock); -+ } -+ -+ *ret_call = call; -+ -+ return 0; -+} -+ -+static void -+unlock_call (FusionCall *call) -+{ -+ up (&call->lock); -+} -+ -+static FusionCallExecution * -+add_execution (FusionCall *call, -+ Fusionee *caller, -+ FusionCallExecute *execute) -+{ -+ FusionCallExecution *execution; -+ -+ /* Allocate execution. */ -+ execution = kmalloc (sizeof(FusionCallExecution), GFP_KERNEL); -+ if (!execution) -+ return NULL; -+ -+ /* Initialize execution. */ -+ memset (execution, 0, sizeof(FusionCallExecution)); -+ -+ execution->caller = caller; -+ -+ init_waitqueue_head (&execution->wait); -+ -+ /* Add execution. */ -+ fusion_list_prepend (&call->executions, &execution->link); -+ -+ if (!call->last) -+ call->last = &execution->link; -+ -+ return execution; -+} -+ -+static void -+remove_execution (FusionCall *call, -+ FusionCallExecution *execution) -+{ -+ if (call->last == &execution->link) -+ call->last = execution->link.prev; -+ -+ fusion_list_remove (&call->executions, &execution->link); -+} -+ -+static void -+free_all_executions (FusionCall *call) -+{ -+ while (call->last) { -+ FusionCallExecution *execution = (FusionCallExecution *) call->last; -+ -+ remove_execution (call, execution); -+ -+ wake_up_interruptible_all (&execution->wait); -+ -+ kfree (execution); -+ } -+} -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/call.h linux-2.6.22.1/drivers/char/fusion/call.h ---- linux-2.6.22.1-0rig/drivers/char/fusion/call.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/call.h 2007-01-20 05:03:01.000000000 +0100 -@@ -0,0 +1,52 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifndef __FUSION__CALL_H__ -+#define __FUSION__CALL_H__ -+ -+#include <linux/fusion.h> -+ -+#include "fusiondev.h" -+ -+/* module init/cleanup */ -+ -+int fusion_call_init (FusionDev *dev); -+void fusion_call_deinit (FusionDev *dev); -+ -+ -+/* public API */ -+ -+int fusion_call_new (FusionDev *dev, -+ int fusion_id, -+ FusionCallNew *call); -+ -+int fusion_call_execute (FusionDev *dev, -+ Fusionee *fusionee, /* NULL if call is from kernel */ -+ FusionCallExecute *execute); -+ -+int fusion_call_return (FusionDev *dev, -+ int fusion_id, -+ FusionCallReturn *call_ret); -+ -+int fusion_call_destroy (FusionDev *dev, -+ int fusion_id, -+ int call_id); -+ -+ -+/* internal functions */ -+ -+void fusion_call_destroy_all (FusionDev *dev, -+ int fusion_id); -+ -+#endif -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/.cvsignore linux-2.6.22.1/drivers/char/fusion/.cvsignore ---- linux-2.6.22.1-0rig/drivers/char/fusion/.cvsignore 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/.cvsignore 2005-10-29 07:11:10.000000000 +0200 -@@ -0,0 +1,6 @@ -+*.o.flags -+*.cmd -+Makefile -+fusion.ko -+fusion.mod.c -+.tmp_versions -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/entries.c linux-2.6.22.1/drivers/char/fusion/entries.c ---- linux-2.6.22.1-0rig/drivers/char/fusion/entries.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/entries.c 2007-03-08 14:02:04.000000000 +0100 -@@ -0,0 +1,438 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifdef HAVE_LINUX_CONFIG_H -+#include <linux/config.h> -+#endif -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/smp_lock.h> -+#include <linux/sched.h> -+#include <linux/time.h> -+#include <linux/version.h> -+ -+#include <linux/fusion.h> -+ -+#include "fusiondev.h" -+#include "entries.h" -+ -+ -+void -+fusion_entries_init( FusionEntries *entries, -+ FusionEntryClass *class, -+ void *ctx ) -+{ -+ FUSION_ASSERT( entries != NULL ); -+ FUSION_ASSERT( class != NULL ); -+ FUSION_ASSERT( class->object_size >= sizeof(FusionEntry) ); -+ -+ memset( entries, 0, sizeof(FusionEntries) ); -+ -+ entries->class = class; -+ entries->ctx = ctx; -+ -+ init_MUTEX( &entries->lock ); -+} -+ -+void -+fusion_entries_deinit( FusionEntries *entries ) -+{ -+ FusionLink *tmp; -+ FusionEntry *entry; -+ FusionEntryClass *class; -+ -+ FUSION_ASSERT( entries != NULL ); -+ FUSION_ASSERT( entries->class != NULL ); -+ -+ class = entries->class; -+ -+ down( &entries->lock ); -+ -+ fusion_list_foreach_safe (entry, tmp, entries->list) { -+ if (class->Destroy) -+ class->Destroy( entry, entries->ctx ); -+ -+ kfree( entry ); -+ } -+ -+ up( &entries->lock ); -+} -+ -+int -+fusion_entries_read_proc(char *buf, char **start, off_t offset, -+ int len, int *eof, void *private) -+{ -+ FusionEntry *entry; -+ FusionEntryClass *class; -+ FusionEntries *entries = private; -+ int written = 0; -+ struct timeval now; -+ -+ FUSION_ASSERT( entries != NULL ); -+ FUSION_ASSERT( entries->class != NULL ); -+ -+ class = entries->class; -+ -+ if (!class->Print) -+ return -ENOTSUPP; -+ -+ if (down_interruptible (&entries->lock)) -+ return -EINTR; -+ -+ do_gettimeofday( &now ); -+ -+ fusion_list_foreach (entry, entries->list) { -+ if (entry->last_lock.tv_sec) { -+ int diff = ((now.tv_sec - entry->last_lock.tv_sec) * 1000 + -+ (now.tv_usec - entry->last_lock.tv_usec) / 1000); -+ -+ if (diff < 1000) { -+ written += sprintf( buf + written, "%3d ms ", diff ); -+ } -+ else if (diff < 1000000) { -+ written += sprintf( buf + written, "%3d.%d s ", -+ diff / 1000, (diff % 1000) / 100 ); -+ } -+ else { -+ diff = ( now.tv_sec - entry->last_lock.tv_sec + -+ (now.tv_usec - entry->last_lock.tv_usec) / 1000000); -+ -+ written += sprintf( buf + written, "%3d.%d h ", -+ diff / 3600, (diff % 3600) / 360 ); -+ } -+ } -+ else -+ written += sprintf( buf + written, " -.- " ); -+ -+ -+ written += sprintf( buf + written, "(%5d) 0x%08x ", entry->pid, entry->id ); -+ -+ written += sprintf( buf + written, "%-24s ", entry->name[0] ? entry->name : "" ); -+ -+ written += class->Print( entry, entries->ctx, buf + written ); -+ -+ if (written < offset) { -+ offset -= written; -+ written = 0; -+ } -+ -+ if (written >= len) -+ break; -+ } -+ -+ up (&entries->lock); -+ -+ *start = buf + offset; -+ written -= offset; -+ if (written > len) { -+ *eof = 0; -+ return len; -+ } -+ -+ *eof = 1; -+ -+ return (written<0) ? 0 : written; -+} -+ -+int -+fusion_entry_create( FusionEntries *entries, -+ int *ret_id, -+ void *create_ctx ) -+{ -+ int ret; -+ FusionEntry *entry; -+ FusionEntryClass *class; -+ -+ FUSION_ASSERT( entries != NULL ); -+ FUSION_ASSERT( entries->class != NULL ); -+ FUSION_ASSERT( ret_id != NULL ); -+ -+ class = entries->class; -+ -+ entry = kmalloc( class->object_size, GFP_KERNEL ); -+ if (!entry) -+ return -ENOMEM; -+ -+ memset( entry, 0, class->object_size ); -+ -+ if (down_interruptible( &entries->lock )) { -+ kfree( entry ); -+ return -EINTR; -+ } -+ -+ entry->entries = entries; -+ entry->id = entries->ids++; -+ entry->pid = current->pid; -+ -+ init_MUTEX( &entry->lock ); -+ -+ init_waitqueue_head( &entry->wait ); -+ -+ if (class->Init) { -+ ret = class->Init( entry, entries->ctx, create_ctx ); -+ if (ret) { -+ up( &entries->lock ); -+ kfree( entry ); -+ return ret; -+ } -+ } -+ -+ fusion_list_prepend( &entries->list, &entry->link ); -+ -+ up( &entries->lock ); -+ -+ *ret_id = entry->id; -+ -+ return 0; -+} -+ -+int -+fusion_entry_destroy( FusionEntries *entries, -+ int id ) -+{ -+ FusionEntry *entry; -+ FusionEntryClass *class; -+ -+ FUSION_ASSERT( entries != NULL ); -+ FUSION_ASSERT( entries->class != NULL ); -+ -+ class = entries->class; -+ -+ /* Lock entries. */ -+ if (down_interruptible( &entries->lock )) -+ return -EINTR; -+ -+ /* Lookup the entry. */ -+ fusion_list_foreach (entry, entries->list) { -+ if (entry->id == id) -+ break; -+ } -+ -+ /* Check if no entry was found. */ -+ if (!entry) { -+ up( &entries->lock ); -+ return -EINVAL; -+ } -+ -+ /* Lock the entry. */ -+ if (down_interruptible( &entry->lock )) { -+ up( &entries->lock ); -+ return -EINTR; -+ } -+ -+ /* Destroy it now. */ -+ fusion_entry_destroy_locked( entries, entry ); -+ -+ /* Unlock entries. */ -+ up( &entries->lock ); -+ -+ return 0; -+} -+ -+void -+fusion_entry_destroy_locked( FusionEntries *entries, -+ FusionEntry *entry ) -+{ -+ FusionEntryClass *class; -+ -+ FUSION_ASSERT( entries != NULL ); -+ FUSION_ASSERT( entries->class != NULL ); -+ -+ class = entries->class; -+ -+ /* Remove the entry from the list. */ -+ fusion_list_remove( &entries->list, &entry->link ); -+ -+ /* Wake up any waiting process. */ -+ wake_up_interruptible_all( &entry->wait ); -+ -+ /* Call the destroy function. */ -+ if (class->Destroy) -+ class->Destroy( entry, entries->ctx ); -+ -+ /* Unlock the entry. */ -+ up( &entry->lock ); -+ -+ /* Deallocate the entry. */ -+ kfree( entry ); -+} -+ -+int -+fusion_entry_set_info( FusionEntries *entries, -+ const FusionEntryInfo *info ) -+{ -+ int ret; -+ FusionEntry *entry; -+ -+ FUSION_ASSERT( entries != NULL ); -+ FUSION_ASSERT( info != NULL ); -+ -+ ret = fusion_entry_lock( entries, info->id, false, &entry ); -+ if (ret) -+ return ret; -+ -+ snprintf( entry->name, FUSION_ENTRY_INFO_NAME_LENGTH, info->name ); -+ -+ fusion_entry_unlock( entry ); -+ -+ return 0; -+} -+ -+int -+fusion_entry_get_info( FusionEntries *entries, -+ FusionEntryInfo *info ) -+{ -+ int ret; -+ FusionEntry *entry; -+ -+ FUSION_ASSERT( entries != NULL ); -+ FUSION_ASSERT( info != NULL ); -+ -+ ret = fusion_entry_lock( entries, info->id, false, &entry ); -+ if (ret) -+ return ret; -+ -+ snprintf( info->name, FUSION_ENTRY_INFO_NAME_LENGTH, entry->name ); -+ -+ fusion_entry_unlock( entry ); -+ -+ return 0; -+} -+ -+int -+fusion_entry_lock( FusionEntries *entries, -+ int id, -+ bool keep_entries_lock, -+ FusionEntry **ret_entry ) -+{ -+ FusionEntry *entry; -+ -+ FUSION_ASSERT( entries != NULL ); -+ FUSION_ASSERT( ret_entry != NULL ); -+ -+ /* Lock entries. */ -+ if (down_interruptible( &entries->lock )) -+ return -EINTR; -+ -+ /* Lookup the entry. */ -+ fusion_list_foreach (entry, entries->list) { -+ if (entry->id == id) -+ break; -+ } -+ -+ /* Check if no entry was found. */ -+ if (!entry) { -+ up( &entries->lock ); -+ return -EINVAL; -+ } -+ -+ FUSION_ASSUME( entry->lock_pid != current->pid ); -+ -+ /* Move the entry to the front of all entries. */ -+ fusion_list_move_to_front( &entries->list, &entry->link ); -+ -+ /* Lock the entry. */ -+ if (down_interruptible( &entry->lock )) { -+ up( &entries->lock ); -+ return -EINTR; -+ } -+ -+ /* Mark as locked. */ -+ entry->lock_pid = current->pid; -+ -+ /* Keep timestamp, but use the slightly -+ inexact version to avoid performance impacts. */ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && defined _STRUCT_TIMESPEC -+ entry->last_lock.tv_sec = xtime.tv_sec; -+ entry->last_lock.tv_usec = xtime.tv_nsec / 1000; -+#else -+ entry->last_lock = xtime; -+#endif -+ -+ /* Unlock entries. */ -+ if (!keep_entries_lock) -+ up( &entries->lock ); -+ -+ /* Return the locked entry. */ -+ *ret_entry = entry; -+ -+ return 0; -+} -+ -+void -+fusion_entry_unlock( FusionEntry *entry ) -+{ -+ FUSION_ASSERT( entry != NULL ); -+ FUSION_ASSUME( entry->lock_pid == current->pid ); -+ -+ entry->lock_pid = 0; -+ -+ /* Unlock the entry. */ -+ up( &entry->lock ); -+} -+ -+int -+fusion_entry_wait( FusionEntry *entry, long *timeout ) -+{ -+ int ret; -+ int id; -+ FusionEntries *entries; -+ FusionEntry *entry2; -+ -+ FUSION_ASSERT( entry != NULL ); -+ FUSION_ASSERT( entry->entries != NULL ); -+ FUSION_ASSUME( entry->lock_pid == current->pid ); -+ -+ id = entry->id; -+ entries = entry->entries; -+ -+ entry->waiters++; -+ -+ entry->lock_pid = 0; -+ fusion_sleep_on( &entry->wait, &entry->lock, timeout ); -+ -+ entry->waiters--; -+ -+ if (signal_pending(current)) -+ return -EINTR; -+ -+ if (timeout && !*timeout) -+ return -ETIMEDOUT; -+ -+ ret = fusion_entry_lock( entries, id, false, &entry2 ); -+ switch (ret) { -+ case -EINVAL: -+ return -EIDRM; -+ -+ case 0: -+ if (entry != entry2) -+ BUG(); -+ } -+ -+ return ret; -+} -+ -+void -+fusion_entry_notify( FusionEntry *entry, bool all ) -+{ -+ FUSION_ASSERT( entry != NULL ); -+ FUSION_ASSUME( entry->lock_pid == current->pid ); -+ -+ if (all) -+ wake_up_interruptible_all( &entry->wait ); -+ else -+ wake_up_interruptible( &entry->wait ); -+} -+ -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/entries.h linux-2.6.22.1/drivers/char/fusion/entries.h ---- linux-2.6.22.1-0rig/drivers/char/fusion/entries.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/entries.h 2006-09-03 13:50:55.000000000 +0200 -@@ -0,0 +1,179 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifndef __FUSION__ENTRIES_H__ -+#define __FUSION__ENTRIES_H__ -+ -+#include "types.h" -+#include "list.h" -+ -+ -+typedef struct __FD_FusionEntry FusionEntry; -+ -+ -+typedef const struct { -+ int object_size; -+ -+ int (*Init) ( FusionEntry *entry, void *ctx, void *create_ctx ); -+ void (*Destroy)( FusionEntry *entry, void *ctx ); -+ int (*Print) ( FusionEntry *entry, void *ctx, char *buf ); -+} FusionEntryClass; -+ -+ -+typedef struct { -+ FusionEntryClass *class; -+ void *ctx; -+ -+ FusionLink *list; -+ int ids; -+ struct semaphore lock; -+} FusionEntries; -+ -+ -+struct __FD_FusionEntry { -+ FusionLink link; -+ -+ FusionEntries *entries; -+ -+ int id; -+ pid_t pid; -+ -+ pid_t lock_pid; -+ -+ struct semaphore lock; -+ wait_queue_head_t wait; -+ int waiters; -+ -+ struct timeval last_lock; -+ -+ char name[FUSION_ENTRY_INFO_NAME_LENGTH]; -+}; -+ -+ -+/* Entries Init & DeInit */ -+ -+void fusion_entries_init ( FusionEntries *entries, -+ FusionEntryClass *class, -+ void *ctx ); -+ -+void fusion_entries_deinit( FusionEntries *entries ); -+ -+ -+/* '/proc' support */ -+ -+int fusion_entries_read_proc( char *buf, char **start, off_t offset, -+ int len, int *eof, void *private ); -+ -+ -+/* Create & Destroy */ -+ -+int fusion_entry_create ( FusionEntries *entries, -+ int *ret_id, -+ void *create_ctx ); -+ -+int fusion_entry_destroy ( FusionEntries *entries, -+ int id ); -+ -+void fusion_entry_destroy_locked( FusionEntries *entries, -+ FusionEntry *entry ); -+ -+/* Information */ -+ -+int fusion_entry_set_info( FusionEntries *entries, -+ const FusionEntryInfo *info ); -+ -+int fusion_entry_get_info( FusionEntries *entries, -+ FusionEntryInfo *info ); -+ -+ -+/* Lock & Unlock */ -+ -+int fusion_entry_lock ( FusionEntries *entries, -+ int id, -+ bool keep_entries_lock, -+ FusionEntry **ret_entry ); -+ -+void fusion_entry_unlock ( FusionEntry *entry ); -+ -+ -+/** Wait & Notify **/ -+ -+/* -+ * Wait for the entry to be notified with an optional timeout. -+ * -+ * The entry -+ * (1) has to be locked prior to calling this function. -+ * (2) is temporarily unlocked while being waited for. -+ * -+ * If this function returns an error, the entry is not locked again! -+ * -+ * Possible errors are: -+ * -EIDRM Entry has been removed while being waited for. -+ * -ETIMEDOUT Timeout occured. -+ * -EINTR A signal has been received. -+ */ -+int fusion_entry_wait ( FusionEntry *entry, -+ long *timeout ); -+ -+/* -+ * Wake up one or all processes waiting for the entry to be notified. -+ * -+ * The entry has to be locked prior to calling this function. -+ */ -+void fusion_entry_notify ( FusionEntry *entry, -+ bool all ); -+ -+ -+#define FUSION_ENTRY_CLASS( Type, name, init_func, destroy_func, print_func ) \ -+ \ -+ static FusionEntryClass name##_class = { \ -+ .object_size = sizeof(Type), \ -+ .Init = init_func, \ -+ .Destroy = destroy_func, \ -+ .Print = print_func \ -+ }; \ -+ \ -+ static inline int fusion_##name##_lock( FusionEntries *entries, \ -+ int id, \ -+ bool keep, \ -+ Type **ret_##name ) \ -+ { \ -+ int ret; \ -+ FusionEntry *entry; \ -+ \ -+ ret = fusion_entry_lock( entries, id, keep, &entry ); \ -+ \ -+ if (!ret) \ -+ *ret_##name = (Type *) entry; \ -+ \ -+ return ret; \ -+ } \ -+ \ -+ static inline void fusion_##name##_unlock( Type *name ) \ -+ { \ -+ fusion_entry_unlock( (FusionEntry*) name ); \ -+ } \ -+ \ -+ static inline int fusion_##name##_wait( Type *name, long *timeout ) \ -+ { \ -+ return fusion_entry_wait( (FusionEntry*) name, timeout ); \ -+ } \ -+ \ -+ static inline void fusion_##name##_notify( Type *name, bool all ) \ -+ { \ -+ fusion_entry_notify( (FusionEntry*) name, all ); \ -+ } -+ -+ -+#endif -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/fifo.c linux-2.6.22.1/drivers/char/fusion/fifo.c ---- linux-2.6.22.1-0rig/drivers/char/fusion/fifo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/fifo.c 2003-06-16 19:47:03.000000000 +0200 -@@ -0,0 +1,53 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#include <linux/types.h> -+ -+#include "fifo.h" -+ -+void -+fusion_fifo_put (FusionFifo *fifo, FusionLink *link) -+{ -+ link->prev = fifo->last; -+ link->next = NULL; -+ -+ if (fifo->last) -+ fifo->last->next = link; -+ else -+ fifo->first = link; -+ -+ fifo->last = link; -+ -+ fifo->count++; -+} -+ -+FusionLink * -+fusion_fifo_get (FusionFifo *fifo) -+{ -+ FusionLink *first = fifo->first; -+ -+ if (!first) -+ return NULL; -+ -+ fifo->first = first->next; -+ -+ if (fifo->last == first) -+ fifo->last = NULL; -+ else -+ fifo->first->prev = NULL; -+ -+ fifo->count--; -+ -+ return first; -+} -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/fifo.h linux-2.6.22.1/drivers/char/fusion/fifo.h ---- linux-2.6.22.1-0rig/drivers/char/fusion/fifo.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/fifo.h 2003-06-16 19:47:03.000000000 +0200 -@@ -0,0 +1,36 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifndef __FUSION__FIFO_H__ -+#define __FUSION__FIFO_H__ -+ -+#include "types.h" -+#include "list.h" -+ -+typedef struct { -+ FusionLink *first; -+ FusionLink *last; -+ -+ int count; -+} FusionFifo; -+ -+void fusion_fifo_put (FusionFifo *fifo, -+ FusionLink *link); -+ -+FusionLink *fusion_fifo_get (FusionFifo *fifo); -+ -+int fusion_fifo_count (FusionFifo *fifo); -+ -+#endif /* __FUSION__LIST_H__ */ -+ -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/fusiondev.c linux-2.6.22.1/drivers/char/fusion/fusiondev.c ---- linux-2.6.22.1-0rig/drivers/char/fusion/fusiondev.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/fusiondev.c 2007-03-08 14:02:47.000000000 +0100 -@@ -0,0 +1,1187 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#include <linux/version.h> -+#include <linux/module.h> -+#ifdef HAVE_LINUX_CONFIG_H -+#include <linux/config.h> -+#endif -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/fs.h> -+#include <linux/slab.h> -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) -+#include <linux/devfs_fs_kernel.h> -+#endif -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) -+#include <linux/page-flags.h> -+#include <linux/mm.h> -+#endif -+ -+#include <linux/proc_fs.h> -+#include <linux/poll.h> -+#include <linux/init.h> -+#include <asm/io.h> -+#include <asm/uaccess.h> -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 2) -+#include <linux/device.h> -+#endif -+ -+#include <linux/fusion.h> -+ -+#include "call.h" -+#include "fusiondev.h" -+#include "fusionee.h" -+#include "property.h" -+#include "reactor.h" -+#include "ref.h" -+#include "skirmish.h" -+#include "shmpool.h" -+ -+#if 0 -+#define DEBUG(x...) printk (KERN_DEBUG "Fusion: " x) -+#else -+#define DEBUG(x...) do {} while (0) -+#endif -+ -+#ifndef FUSION_MAJOR -+#define FUSION_MAJOR 252 -+#endif -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Denis Oliver Kropp <dok@directfb.org>"); -+ -+struct proc_dir_entry *proc_fusion_dir; -+ -+#define NUM_MINORS 8 -+ -+static FusionDev *fusion_devs[NUM_MINORS] = { 0 }; -+static DECLARE_MUTEX(devs_lock); -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) -+static devfs_handle_t devfs_handles[NUM_MINORS]; -+static inline unsigned iminor(struct inode *inode) -+{ -+ return MINOR(inode->i_rdev); -+} -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 2) -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -+static struct class *fusion_class; -+#else -+static struct class_simple *fusion_class; -+#endif -+#endif -+ -+/******************************************************************************/ -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -+void -+fusion_sleep_on(wait_queue_head_t *q, struct semaphore *lock, signed long *timeout) -+{ -+ DEFINE_WAIT(wait); -+ -+ prepare_to_wait( q, &wait, TASK_INTERRUPTIBLE ); -+ -+ up( lock ); -+ -+ if (timeout) -+ *timeout = schedule_timeout(*timeout); -+ else -+ schedule(); -+ -+ finish_wait( q, &wait ); -+} -+#else -+void -+fusion_sleep_on(wait_queue_head_t *q, struct semaphore *lock, signed long *timeout) -+{ -+ wait_queue_t wait; -+ -+ init_waitqueue_entry (&wait, current); -+ -+ current->state = TASK_INTERRUPTIBLE; -+ -+ write_lock (&q->lock); -+ __add_wait_queue (q, &wait); -+ write_unlock (&q->lock); -+ -+ up (lock); -+ -+ if (timeout) -+ *timeout = schedule_timeout(*timeout); -+ else -+ schedule(); -+ -+ write_lock (&q->lock); -+ __remove_wait_queue (q, &wait); -+ write_unlock (&q->lock); -+} -+#endif -+ -+/******************************************************************************/ -+ -+static int -+fusiondev_stat_read_proc(char *buf, char **start, off_t offset, -+ int len, int *eof, void *private) -+{ -+ FusionDev *dev = private; -+ int written = 0; -+ -+ written += snprintf( buf, len, -+ "lease/purchase cede attach detach " -+ "ref up ref down prevail/swoop dismiss\n" ); -+ if (written < offset) { -+ offset -= written; -+ written = 0; -+ } -+ -+ if (written < len) { -+ written += snprintf( buf+written, len - written, -+ "%10d %10d %10d %10d %10d %10d %10d %10d\n", -+ dev->stat.property_lease_purchase, -+ dev->stat.property_cede, -+ dev->stat.reactor_attach, -+ dev->stat.reactor_detach, -+ dev->stat.ref_up, -+ dev->stat.ref_down, -+ dev->stat.skirmish_prevail_swoop, -+ dev->stat.skirmish_dismiss ); -+ if (written < offset) { -+ offset -= written; -+ written = 0; -+ } -+ } -+ -+ *start = buf + offset; -+ written -= offset; -+ if (written > len) { -+ *eof = 0; -+ return len; -+ } -+ -+ *eof = 1; -+ return(written<0) ? 0 : written; -+} -+ -+/******************************************************************************/ -+ -+static int -+fusiondev_init (FusionDev *dev) -+{ -+ int ret; -+ -+ init_MUTEX( &dev->enter_lock ); -+ init_waitqueue_head( &dev->enter_wait ); -+ -+ ret = fusionee_init (dev); -+ if (ret) -+ goto error_fusionee; -+ -+ ret = fusion_ref_init (dev); -+ if (ret) -+ goto error_ref; -+ -+ ret = fusion_skirmish_init (dev); -+ if (ret) -+ goto error_skirmish; -+ -+ ret = fusion_property_init (dev); -+ if (ret) -+ goto error_property; -+ -+ ret = fusion_reactor_init (dev); -+ if (ret) -+ goto error_reactor; -+ -+ ret = fusion_shmpool_init (dev); -+ if (ret) -+ goto error_shmpool; -+ -+ ret = fusion_call_init (dev); -+ if (ret) -+ goto error_call; -+ -+ create_proc_read_entry( "stat", 0, dev->proc_dir, -+ fusiondev_stat_read_proc, dev ); -+ -+ return 0; -+ -+ -+error_call: -+ fusion_shmpool_deinit (dev); -+ -+error_shmpool: -+ fusion_reactor_deinit (dev); -+ -+error_reactor: -+ fusion_property_deinit (dev); -+ -+error_property: -+ fusion_skirmish_deinit (dev); -+ -+error_skirmish: -+ fusion_ref_deinit (dev); -+ -+error_ref: -+ fusionee_deinit (dev); -+ -+error_fusionee: -+ return ret; -+} -+ -+static void -+fusiondev_deinit (FusionDev *dev) -+{ -+ remove_proc_entry ("stat", dev->proc_dir); -+ -+ fusion_call_deinit (dev); -+ fusion_shmpool_deinit (dev); -+ fusion_reactor_deinit (dev); -+ fusion_property_deinit (dev); -+ fusion_skirmish_deinit (dev); -+ fusion_ref_deinit (dev); -+ fusionee_deinit (dev); -+ -+ if (dev->shared_area) { -+ ClearPageReserved( virt_to_page(dev->shared_area) ); -+ free_page( dev->shared_area ); -+ } -+} -+ -+/******************************************************************************/ -+ -+static int -+fusion_open (struct inode *inode, struct file *file) -+{ -+ int ret; -+ Fusionee *fusionee; -+ int minor = iminor(inode); -+ -+ DEBUG( "fusion_open( %p, %d )\n", file, atomic_read(&file->f_count) ); -+ -+ if (down_interruptible (&devs_lock)) -+ return -EINTR; -+ -+ if (!fusion_devs[minor]) { -+ char buf[4]; -+ -+ fusion_devs[minor] = kmalloc (sizeof(FusionDev), GFP_KERNEL); -+ if (!fusion_devs[minor]) { -+ up (&devs_lock); -+ return -ENOMEM; -+ } -+ -+ memset (fusion_devs[minor], 0, sizeof(FusionDev)); -+ -+ snprintf (buf, 4, "%d", minor); -+ -+ fusion_devs[minor]->proc_dir = proc_mkdir (buf, proc_fusion_dir); -+ fusion_devs[minor]->index = minor; -+ -+ ret = fusiondev_init (fusion_devs[minor]); -+ if (ret) { -+ remove_proc_entry (buf, proc_fusion_dir); -+ -+ kfree (fusion_devs[minor]); -+ fusion_devs[minor] = NULL; -+ -+ up (&devs_lock); -+ -+ return ret; -+ } -+ } -+ else if (file->f_flags & O_EXCL) { -+ if (fusion_devs[minor]->fusionee.last_id) { -+ up (&devs_lock); -+ return -EBUSY; -+ } -+ } -+ -+ ret = fusionee_new (fusion_devs[minor], !!(file->f_flags & O_APPEND), &fusionee); -+ if (ret) { -+ if (!fusion_devs[minor]->refs) { -+ fusiondev_deinit (fusion_devs[minor]); -+ -+ remove_proc_entry (fusion_devs[minor]->proc_dir->name, -+ proc_fusion_dir); -+ -+ kfree (fusion_devs[minor]); -+ fusion_devs[minor] = NULL; -+ } -+ -+ up (&devs_lock); -+ -+ return ret; -+ } -+ -+ fusion_devs[minor]->refs++; -+ -+ up (&devs_lock); -+ -+ -+ file->private_data = fusionee; -+ -+ return 0; -+} -+ -+static int -+fusion_release (struct inode *inode, struct file *file) -+{ -+ int minor = iminor(inode); -+ Fusionee *fusionee = file->private_data; -+ -+ DEBUG( "fusion_release( %p, %d )\n", file, atomic_read(&file->f_count) ); -+ -+ fusionee_destroy (fusion_devs[minor], fusionee); -+ -+ down (&devs_lock); -+ -+ if (! --fusion_devs[minor]->refs) { -+ fusiondev_deinit (fusion_devs[minor]); -+ -+ remove_proc_entry (fusion_devs[minor]->proc_dir->name, -+ proc_fusion_dir); -+ -+ kfree (fusion_devs[minor]); -+ fusion_devs[minor] = NULL; -+ } -+ -+ up (&devs_lock); -+ -+ return 0; -+} -+ -+static int -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) -+fusion_flush (struct file *file, fl_owner_t id) -+#else -+fusion_flush (struct file *file) -+#endif -+{ -+ Fusionee *fusionee = file->private_data; -+ FusionDev *dev = fusion_devs[iminor(file->f_dentry->d_inode)]; -+ -+ (void) fusionee; -+ -+ DEBUG( "fusion_flush( %p, %d, 0x%08x %d )\n", file, atomic_read(&file->f_count), fusionee_id(fusionee), current->pid ); -+ -+ if (current->flags & PF_EXITING) -+ fusion_skirmish_dismiss_all_from_pid (dev, current->pid); -+ -+ return 0; -+} -+ -+static ssize_t -+fusion_read (struct file *file, char *buf, size_t count, loff_t *ppos) -+{ -+ Fusionee *fusionee = file->private_data; -+ FusionDev *dev = fusion_devs[iminor(file->f_dentry->d_inode)]; -+ -+ DEBUG( "fusion_read( %p, %d, %d )\n", file, atomic_read(&file->f_count), count ); -+ -+ return fusionee_get_messages (dev, fusionee, buf, count, -+ !(file->f_flags & O_NONBLOCK)); -+} -+ -+static unsigned int -+fusion_poll (struct file *file, poll_table * wait) -+{ -+ Fusionee *fusionee = file->private_data; -+ FusionDev *dev = fusion_devs[iminor(file->f_dentry->d_inode)]; -+ -+ DEBUG( "fusion_poll( %p, %d )\n", file, atomic_read(&file->f_count) ); -+ -+ return fusionee_poll (dev, fusionee, file, wait); -+} -+ -+static int -+lounge_ioctl (struct file *file, FusionDev *dev, Fusionee *fusionee, -+ unsigned int cmd, unsigned long arg) -+{ -+ int ret; -+ FusionEnter enter; -+ FusionKill kill; -+ FusionEntryInfo info; -+ FusionFork fork = {0}; -+ -+ switch (_IOC_NR(cmd)) { -+ case _IOC_NR(FUSION_ENTER): -+ if (copy_from_user (&enter, (FusionEnter*) arg, sizeof(enter))) -+ return -EFAULT; -+ -+ ret = fusionee_enter( dev, &enter, fusionee ); -+ if (ret) -+ return ret; -+ -+ if (copy_to_user ((FusionEnter*) arg, &enter, sizeof(enter))) -+ return -EFAULT; -+ -+ return 0; -+ -+ case _IOC_NR(FUSION_UNBLOCK): -+ if (fusionee_id( fusionee ) != FUSION_ID_MASTER) -+ return -EPERM; -+ -+ if (down_interruptible( &dev->enter_lock )) -+ return -EINTR; -+ -+ dev->enter_ok = 1; -+ -+ wake_up_interruptible_all( &dev->enter_wait ); -+ -+ up( &dev->enter_lock ); -+ -+ return 0; -+ -+ case _IOC_NR(FUSION_KILL): -+ if (copy_from_user (&kill, (FusionKill*) arg, sizeof(kill))) -+ return -EFAULT; -+ -+ return fusionee_kill (dev, fusionee, -+ kill.fusion_id, kill.signal, kill.timeout_ms); -+ -+ case _IOC_NR(FUSION_ENTRY_SET_INFO): -+ if (copy_from_user (&info, (FusionEntryInfo*) arg, sizeof(info))) -+ return -EFAULT; -+ -+ switch (info.type) { -+ case FT_SKIRMISH: -+ return fusion_entry_set_info (&dev->skirmish, &info); -+ -+ case FT_PROPERTY: -+ return fusion_entry_set_info (&dev->properties, &info); -+ -+ case FT_REACTOR: -+ return fusion_entry_set_info (&dev->reactor, &info); -+ -+ case FT_REF: -+ return fusion_entry_set_info (&dev->ref, &info); -+ -+ case FT_SHMPOOL: -+ return fusion_entry_set_info (&dev->shmpool, &info); -+ -+ default: -+ return -ENOSYS; -+ } -+ -+ case _IOC_NR(FUSION_ENTRY_GET_INFO): -+ if (copy_from_user (&info, (FusionEntryInfo*) arg, sizeof(info))) -+ return -EFAULT; -+ -+ switch (info.type) { -+ case FT_SKIRMISH: -+ ret = fusion_entry_get_info (&dev->skirmish, &info); -+ break; -+ -+ case FT_PROPERTY: -+ ret = fusion_entry_get_info (&dev->properties, &info); -+ break; -+ -+ case FT_REACTOR: -+ ret = fusion_entry_get_info (&dev->reactor, &info); -+ break; -+ -+ case FT_REF: -+ ret = fusion_entry_get_info (&dev->ref, &info); -+ break; -+ -+ case FT_SHMPOOL: -+ ret = fusion_entry_get_info (&dev->shmpool, &info); -+ break; -+ -+ default: -+ return -ENOSYS; -+ } -+ -+ if (ret) -+ return ret; -+ -+ if (copy_to_user ((FusionEntryInfo*) arg, &info, sizeof(info))) -+ return -EFAULT; -+ -+ return 0; -+ -+ case _IOC_NR(FUSION_FORK): -+ if (copy_from_user( &fork, (FusionFork*) arg, sizeof(fork) )) -+ return -EFAULT; -+ -+ ret = fusionee_fork( dev, &fork, fusionee ); -+ if (ret) -+ return ret; -+ -+ if (copy_to_user( (FusionFork*) arg, &fork, sizeof(fork) )) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ return -ENOSYS; -+} -+ -+static int -+messaging_ioctl (FusionDev *dev, Fusionee *fusionee, -+ unsigned int cmd, unsigned long arg) -+{ -+ FusionSendMessage send; -+ -+ switch (_IOC_NR(cmd)) { -+ case _IOC_NR(FUSION_SEND_MESSAGE): -+ if (copy_from_user (&send, (FusionSendMessage*) arg, sizeof(send))) -+ return -EFAULT; -+ -+ if (send.msg_size <= 0) -+ return -EINVAL; -+ -+ /* message data > 64k should be stored in shared memory */ -+ if (send.msg_size > 0x10000) -+ return -EMSGSIZE; -+ -+ return fusionee_send_message (dev, fusionee, send.fusion_id, FMT_SEND, -+ send.msg_id, send.msg_size, send.msg_data); -+ } -+ -+ return -ENOSYS; -+} -+ -+static int -+call_ioctl (FusionDev *dev, Fusionee *fusionee, -+ unsigned int cmd, unsigned long arg) -+{ -+ int id; -+ int ret; -+ FusionCallNew call; -+ FusionCallExecute execute; -+ FusionCallReturn call_ret; -+ FusionID fusion_id = fusionee_id( fusionee ); -+ -+ switch (_IOC_NR(cmd)) { -+ case _IOC_NR(FUSION_CALL_NEW): -+ if (copy_from_user (&call, (FusionCallNew*) arg, sizeof(call))) -+ return -EFAULT; -+ -+ ret = fusion_call_new (dev, fusion_id, &call); -+ if (ret) -+ return ret; -+ -+ if (put_user (call.call_id, (int*) arg)) { -+ fusion_call_destroy (dev, fusion_id, call.call_id); -+ return -EFAULT; -+ } -+ return 0; -+ -+ case _IOC_NR(FUSION_CALL_EXECUTE): -+ if (copy_from_user (&execute, (FusionCallExecute*) arg, sizeof(execute))) -+ return -EFAULT; -+ -+ ret = fusion_call_execute (dev, fusionee, &execute); -+ if (ret) -+ return ret; -+ -+ if (put_user (execute.ret_val, (int*) arg)) -+ return -EFAULT; -+ return 0; -+ -+ case _IOC_NR(FUSION_CALL_RETURN): -+ if (copy_from_user (&call_ret, (FusionCallReturn*) arg, sizeof(call_ret))) -+ return -EFAULT; -+ -+ return fusion_call_return (dev, fusion_id, &call_ret); -+ -+ case _IOC_NR(FUSION_CALL_DESTROY): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_call_destroy (dev, fusion_id, id); -+ } -+ -+ return -ENOSYS; -+} -+ -+static int -+ref_ioctl (FusionDev *dev, Fusionee *fusionee, -+ unsigned int cmd, unsigned long arg) -+{ -+ int id; -+ int ret; -+ int refs; -+ FusionRefWatch watch; -+ FusionRefInherit inherit; -+ FusionID fusion_id = fusionee_id( fusionee ); -+ -+ switch (_IOC_NR(cmd)) { -+ case _IOC_NR(FUSION_REF_NEW): -+ ret = fusion_ref_new (dev, &id); -+ if (ret) -+ return ret; -+ -+ if (put_user (id, (int*) arg)) { -+ fusion_ref_destroy (dev, id); -+ return -EFAULT; -+ } -+ return 0; -+ -+ case _IOC_NR(FUSION_REF_UP): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_ref_up (dev, id, fusion_id); -+ -+ case _IOC_NR(FUSION_REF_UP_GLOBAL): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_ref_up (dev, id, 0); -+ -+ case _IOC_NR(FUSION_REF_DOWN): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_ref_down (dev, id, fusion_id); -+ -+ case _IOC_NR(FUSION_REF_DOWN_GLOBAL): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_ref_down (dev, id, 0); -+ -+ case _IOC_NR(FUSION_REF_ZERO_LOCK): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_ref_zero_lock (dev, id, fusion_id); -+ -+ case _IOC_NR(FUSION_REF_ZERO_TRYLOCK): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_ref_zero_trylock (dev, id, fusion_id); -+ -+ case _IOC_NR(FUSION_REF_UNLOCK): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_ref_zero_unlock (dev, id, fusion_id); -+ -+ case _IOC_NR(FUSION_REF_STAT): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ ret = fusion_ref_stat (dev, id, &refs); -+ if (ret) -+ return ret; -+ -+ return refs; -+ -+ case _IOC_NR(FUSION_REF_WATCH): -+ if (copy_from_user (&watch, (FusionRefWatch*) arg, sizeof(watch))) -+ return -EFAULT; -+ -+ return fusion_ref_watch (dev, watch.id, watch.call_id, watch.call_arg); -+ -+ case _IOC_NR(FUSION_REF_INHERIT): -+ if (copy_from_user (&inherit, (FusionRefInherit*) arg, sizeof(inherit))) -+ return -EFAULT; -+ -+ return fusion_ref_inherit (dev, inherit.id, inherit.from); -+ -+ case _IOC_NR(FUSION_REF_DESTROY): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_ref_destroy (dev, id); -+ } -+ -+ return -ENOSYS; -+} -+ -+static int -+skirmish_ioctl (FusionDev *dev, Fusionee *fusionee, -+ unsigned int cmd, unsigned long arg) -+{ -+ int id; -+ int ret; -+ int lock_count; -+ FusionID fusion_id = fusionee_id( fusionee ); -+ -+ switch (_IOC_NR(cmd)) { -+ case _IOC_NR(FUSION_SKIRMISH_NEW): -+ ret = fusion_skirmish_new (dev, &id); -+ if (ret) -+ return ret; -+ -+ if (put_user (id, (int*) arg)) { -+ fusion_skirmish_destroy (dev, id); -+ return -EFAULT; -+ } -+ return 0; -+ -+ case _IOC_NR(FUSION_SKIRMISH_PREVAIL): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_skirmish_prevail (dev, id, fusion_id); -+ -+ case _IOC_NR(FUSION_SKIRMISH_SWOOP): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_skirmish_swoop (dev, id, fusion_id); -+ -+ case _IOC_NR(FUSION_SKIRMISH_DISMISS): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_skirmish_dismiss (dev, id, fusion_id); -+ -+ case _IOC_NR(FUSION_SKIRMISH_DESTROY): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_skirmish_destroy (dev, id); -+ -+ case _IOC_NR(FUSION_SKIRMISH_LOCK_COUNT): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ ret = fusion_skirmish_lock_count (dev, id, fusion_id, &lock_count); -+ if (put_user(lock_count, ((int*)arg)+1)) -+ return -EFAULT; -+ -+ return ret; -+ } -+ -+ return -ENOSYS; -+} -+ -+static int -+property_ioctl (FusionDev *dev, Fusionee *fusionee, -+ unsigned int cmd, unsigned long arg) -+{ -+ int id; -+ int ret; -+ FusionID fusion_id = fusionee_id( fusionee ); -+ -+ switch (_IOC_NR(cmd)) { -+ case _IOC_NR(FUSION_PROPERTY_NEW): -+ ret = fusion_property_new (dev, &id); -+ if (ret) -+ return ret; -+ -+ if (put_user (id, (int*) arg)) { -+ fusion_property_destroy (dev, id); -+ return -EFAULT; -+ } -+ return 0; -+ -+ case _IOC_NR(FUSION_PROPERTY_LEASE): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_property_lease (dev, id, fusion_id); -+ -+ case _IOC_NR(FUSION_PROPERTY_PURCHASE): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_property_purchase (dev, id, fusion_id); -+ -+ case _IOC_NR(FUSION_PROPERTY_CEDE): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_property_cede (dev, id, fusion_id); -+ -+ case _IOC_NR(FUSION_PROPERTY_HOLDUP): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_property_holdup (dev, id, fusionee); -+ -+ case _IOC_NR(FUSION_PROPERTY_DESTROY): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_property_destroy (dev, id); -+ } -+ -+ return -ENOSYS; -+} -+ -+static int -+reactor_ioctl (FusionDev *dev, Fusionee *fusionee, -+ unsigned int cmd, unsigned long arg) -+{ -+ int id; -+ int ret; -+ FusionReactorDispatch dispatch; -+ FusionID fusion_id = fusionee_id( fusionee ); -+ -+ switch (_IOC_NR(cmd)) { -+ case _IOC_NR(FUSION_REACTOR_NEW): -+ ret = fusion_reactor_new (dev, &id); -+ if (ret) -+ return ret; -+ -+ if (put_user (id, (int*) arg)) { -+ fusion_reactor_destroy (dev, id); -+ return -EFAULT; -+ } -+ return 0; -+ -+ case _IOC_NR(FUSION_REACTOR_ATTACH): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_reactor_attach (dev, id, fusion_id); -+ -+ case _IOC_NR(FUSION_REACTOR_DETACH): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_reactor_detach (dev, id, fusion_id); -+ -+ case _IOC_NR(FUSION_REACTOR_DISPATCH): -+ if (copy_from_user (&dispatch, -+ (FusionReactorDispatch*) arg, sizeof(dispatch))) -+ return -EFAULT; -+ -+ if (dispatch.msg_size <= 0) -+ return -EINVAL; -+ -+ /* message data > 64k should be stored in shared memory */ -+ if (dispatch.msg_size > 0x10000) -+ return -EMSGSIZE; -+ -+ return fusion_reactor_dispatch (dev, dispatch.reactor_id, -+ dispatch.self ? NULL : fusionee, -+ dispatch.msg_size, dispatch.msg_data); -+ -+ case _IOC_NR(FUSION_REACTOR_DESTROY): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_reactor_destroy (dev, id); -+ } -+ -+ return -ENOSYS; -+} -+ -+static int -+shmpool_ioctl (FusionDev *dev, Fusionee *fusionee, -+ unsigned int cmd, unsigned long arg) -+{ -+ int id; -+ int ret; -+ FusionSHMPoolNew pool; -+ FusionSHMPoolAttach attach; -+ FusionSHMPoolDispatch dispatch; -+ FusionID fusion_id = fusionee_id( fusionee ); -+ -+ switch (_IOC_NR(cmd)) { -+ case _IOC_NR(FUSION_SHMPOOL_NEW): -+ if (copy_from_user (&pool, (FusionSHMPoolNew*) arg, sizeof(pool))) -+ return -EFAULT; -+ -+ ret = fusion_shmpool_new (dev, &pool); -+ if (ret) -+ return ret; -+ -+ if (copy_to_user ((FusionSHMPoolNew*) arg, &pool, sizeof(pool))) { -+ fusion_shmpool_destroy (dev, pool.pool_id); -+ return -EFAULT; -+ } -+ -+ return 0; -+ -+ case _IOC_NR(FUSION_SHMPOOL_ATTACH): -+ if (copy_from_user (&attach, -+ (FusionSHMPoolAttach*) arg, sizeof(attach))) -+ return -EFAULT; -+ -+ ret = fusion_shmpool_attach (dev, &attach, fusion_id); -+ if (ret) -+ return ret; -+ -+ if (copy_to_user ((FusionSHMPoolAttach*) arg, &attach, sizeof(attach))) { -+ fusion_shmpool_detach (dev, attach.pool_id, fusion_id); -+ return -EFAULT; -+ } -+ -+ return 0; -+ -+ case _IOC_NR(FUSION_SHMPOOL_DETACH): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_shmpool_detach (dev, id, fusion_id); -+ -+ case _IOC_NR(FUSION_SHMPOOL_DISPATCH): -+ if (copy_from_user (&dispatch, -+ (FusionSHMPoolDispatch*) arg, sizeof(dispatch))) -+ return -EFAULT; -+ -+ return fusion_shmpool_dispatch (dev, &dispatch, fusionee); -+ -+ case _IOC_NR(FUSION_SHMPOOL_DESTROY): -+ if (get_user (id, (int*) arg)) -+ return -EFAULT; -+ -+ return fusion_shmpool_destroy (dev, id); -+ } -+ -+ return -ENOSYS; -+} -+ -+static int -+fusion_ioctl (struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ Fusionee *fusionee = file->private_data; -+ FusionDev *dev = fusion_devs[iminor(inode)]; -+ -+ DEBUG( "fusion_ioctl (0x%08x)\n", cmd ); -+ -+ switch (_IOC_TYPE(cmd)) { -+ case FT_LOUNGE: -+ return lounge_ioctl( file, dev, fusionee, cmd, arg ); -+ -+ case FT_MESSAGING: -+ return messaging_ioctl( dev, fusionee, cmd, arg ); -+ -+ case FT_CALL: -+ return call_ioctl( dev, fusionee, cmd, arg ); -+ -+ case FT_REF: -+ return ref_ioctl( dev, fusionee, cmd, arg ); -+ -+ case FT_SKIRMISH: -+ return skirmish_ioctl( dev, fusionee, cmd, arg ); -+ -+ case FT_PROPERTY: -+ return property_ioctl( dev, fusionee, cmd, arg ); -+ -+ case FT_REACTOR: -+ return reactor_ioctl( dev, fusionee, cmd, arg ); -+ -+ case FT_SHMPOOL: -+ return shmpool_ioctl( dev, fusionee, cmd, arg ); -+ } -+ -+ return -ENOSYS; -+} -+ -+static int -+fusion_mmap( struct file *file, -+ struct vm_area_struct *vma ) -+{ -+ Fusionee *fusionee = file->private_data; -+ FusionDev *dev = fusion_devs[iminor(file->f_dentry->d_inode)]; -+ unsigned int size; -+ -+ if (vma->vm_pgoff != 0) -+ return -EINVAL; -+ -+ size = vma->vm_end - vma->vm_start; -+ if (!size || size > PAGE_SIZE) -+ return -EINVAL; -+ -+ if (!dev->shared_area) { -+ if (fusionee_id( fusionee ) != FUSION_ID_MASTER) -+ return -EPERM; -+ -+ dev->shared_area = get_zeroed_page( GFP_KERNEL ); -+ if (!dev->shared_area) -+ return -ENOMEM; -+ -+ SetPageReserved( virt_to_page(dev->shared_area) ); -+ } -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -+ return remap_pfn_range( vma, vma->vm_start, -+ virt_to_phys((void*)dev->shared_area) >> PAGE_SHIFT, -+ PAGE_SIZE, vma->vm_page_prot ); -+#else -+ return io_remap_page_range( vma->vm_start, -+ virt_to_phys((void*)dev->shared_area), -+ PAGE_SIZE, vma->vm_page_prot ); -+#endif -+} -+ -+static struct file_operations fusion_fops = { -+ .owner = THIS_MODULE, -+ .open = fusion_open, -+ .flush = fusion_flush, -+ .release = fusion_release, -+ .read = fusion_read, -+ .poll = fusion_poll, -+ .ioctl = fusion_ioctl, -+ .mmap = fusion_mmap -+}; -+ -+/******************************************************************************/ -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -+static int __init -+register_devices(void) -+{ -+ int i; -+ -+ if (register_chrdev (FUSION_MAJOR, "fusion", &fusion_fops)) { -+ printk (KERN_ERR "fusion: unable to get major %d\n", FUSION_MAJOR); -+ return -EIO; -+ } -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 2) -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -+ fusion_class = class_create (THIS_MODULE, "fusion"); -+#else -+ fusion_class = class_simple_create (THIS_MODULE, "fusion"); -+#endif -+ if (IS_ERR(fusion_class)) { -+ unregister_chrdev (FUSION_MAJOR, "fusion"); -+ return PTR_ERR(fusion_class); -+ } -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) -+ devfs_mk_dir("fusion"); -+#endif -+ -+ for (i=0; i<NUM_MINORS; i++) { -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 15) -+ class_device_create (fusion_class, -+ NULL, -+ MKDEV(FUSION_MAJOR, i), -+ NULL, "fusion%d", i); -+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -+ class_device_create (fusion_class, -+ MKDEV(FUSION_MAJOR, i), -+ NULL, "fusion%d", i); -+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 2) -+ class_simple_device_add (fusion_class, -+ MKDEV(FUSION_MAJOR, i), -+ NULL, "fusion%d", i); -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) -+ devfs_mk_cdev (MKDEV(FUSION_MAJOR, i), -+ S_IFCHR | S_IRUSR | S_IWUSR, -+ "fusion/%d", i); -+#endif -+ } -+ -+ return 0; -+} -+#else -+static int __init -+register_devices(void) -+{ -+ int i; -+ char buf[16]; -+ -+ if (devfs_register_chrdev (FUSION_MAJOR, "fusion", &fusion_fops)) { -+ printk (KERN_ERR "fusion: unable to get major %d\n", FUSION_MAJOR); -+ return -EIO; -+ } -+ -+ for (i=0; i<NUM_MINORS; i++) { -+ snprintf (buf, 16, "fusion/%d", i); -+ -+ devfs_handles[i] = devfs_register (NULL, buf, DEVFS_FL_DEFAULT, -+ FUSION_MAJOR, i, -+ S_IFCHR | S_IRUSR | S_IWUSR, -+ &fusion_fops, NULL); -+ } -+ -+ return 0; -+} -+#endif -+ -+int __init -+fusion_init(void) -+{ -+ int ret; -+ -+ ret = register_devices(); -+ if (ret) -+ return ret; -+ -+ proc_fusion_dir = proc_mkdir ("fusion", NULL); -+ -+ return 0; -+} -+ -+/******************************************************************************/ -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -+static void __exit -+deregister_devices(void) -+{ -+ int i; -+ -+ unregister_chrdev (FUSION_MAJOR, "fusion"); -+ -+ for (i=0; i<NUM_MINORS; i++) { -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 2) -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -+ class_device_destroy (fusion_class, MKDEV(FUSION_MAJOR, i)); -+#else -+ class_simple_device_remove (MKDEV(FUSION_MAJOR, i)); -+#endif -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) -+ devfs_remove ("fusion/%d", i); -+#endif -+ } -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 2) -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -+ class_destroy (fusion_class); -+#else -+ class_simple_destroy (fusion_class); -+#endif -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) -+ devfs_remove ("fusion"); -+#endif -+} -+#else -+static void __exit -+deregister_devices(void) -+{ -+ int i; -+ -+ devfs_unregister_chrdev (FUSION_MAJOR, "fusion"); -+ -+ for (i=0; i<NUM_MINORS; i++) -+ devfs_unregister (devfs_handles[i]); -+} -+#endif -+ -+void __exit -+fusion_exit(void) -+{ -+ deregister_devices(); -+ -+ remove_proc_entry ("fusion", NULL); -+} -+ -+module_init(fusion_init); -+module_exit(fusion_exit); -+ -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/fusiondev.h linux-2.6.22.1/drivers/char/fusion/fusiondev.h ---- linux-2.6.22.1-0rig/drivers/char/fusion/fusiondev.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/fusiondev.h 2006-08-04 18:28:01.000000000 +0200 -@@ -0,0 +1,83 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifndef __FUSIONDEV_H__ -+#define __FUSIONDEV_H__ -+ -+#include <linux/proc_fs.h> -+ -+#include "entries.h" -+#include "list.h" -+ -+#define FUSION_ASSERT(exp) if (!(exp)) BUG() -+#define FUSION_ASSUME(exp) if (!(exp)) printk( KERN_ERR "fusiondev: assumption '" #exp "' failed!\n" ) -+ -+typedef struct { -+ int refs; -+ int index; -+ -+ struct semaphore enter_lock; -+ int enter_ok; -+ wait_queue_head_t enter_wait; -+ -+ unsigned long shared_area; -+ -+ struct proc_dir_entry *proc_dir; -+ -+ struct { -+ int property_lease_purchase; -+ int property_cede; -+ -+ int reactor_attach; -+ int reactor_detach; -+ -+ int ref_up; -+ int ref_down; -+ -+ int skirmish_prevail_swoop; -+ int skirmish_dismiss; -+ -+ int shmpool_attach; -+ int shmpool_detach; -+ } stat; -+ -+ struct { -+ int ids; -+ FusionLink *list; -+ struct semaphore lock; -+ } call; -+ -+ struct { -+ int last_id; -+ FusionLink *list; -+ struct semaphore lock; -+ wait_queue_head_t wait; -+ } fusionee; -+ -+ FusionEntries properties; -+ FusionEntries reactor; -+ FusionEntries ref; -+ FusionEntries shmpool; -+ FusionEntries skirmish; -+} FusionDev; -+ -+/* -+ * Special version of interruptible_sleep_on() that unlocks the mutex -+ * after adding the entry to the queue (just before schedule). -+ */ -+void fusion_sleep_on (wait_queue_head_t *q, -+ struct semaphore *lock, -+ signed long *timeout_ms); -+ -+#endif -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/fusionee.c linux-2.6.22.1/drivers/char/fusion/fusionee.c ---- linux-2.6.22.1-0rig/drivers/char/fusion/fusionee.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/fusionee.c 2007-01-29 00:31:00.000000000 +0100 -@@ -0,0 +1,584 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifdef HAVE_LINUX_CONFIG_H -+#include <linux/config.h> -+#endif -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/smp_lock.h> -+#include <asm/uaccess.h> -+ -+#include <linux/fusion.h> -+ -+#include "call.h" -+#include "fifo.h" -+#include "list.h" -+#include "fusiondev.h" -+#include "fusionee.h" -+#include "property.h" -+#include "reactor.h" -+#include "ref.h" -+#include "skirmish.h" -+#include "shmpool.h" -+ -+#if 0 -+#define DEBUG(x...) printk (KERN_DEBUG "Fusion: " x) -+#else -+#define DEBUG(x...) do {} while (0) -+#endif -+ -+struct __Fusion_Fusionee { -+ FusionLink link; -+ -+ struct semaphore lock; -+ -+ FusionID id; -+ int pid; -+ -+ FusionFifo messages; -+ -+ int rcv_total; /* Total number of messages received. */ -+ int snd_total; /* Total number of messages sent. */ -+ -+ wait_queue_head_t wait; -+ -+ bool force_slave; -+}; -+ -+typedef struct { -+ FusionLink link; -+ -+ FusionMessageType type; -+ FusionID id; -+ int size; -+ void *data; -+} Message; -+ -+/******************************************************************************/ -+ -+static int lookup_fusionee (FusionDev *dev, FusionID id, Fusionee **ret_fusionee); -+static int lock_fusionee (FusionDev *dev, FusionID id, Fusionee **ret_fusionee); -+static void unlock_fusionee (Fusionee *fusionee); -+ -+/******************************************************************************/ -+ -+static int -+fusionees_read_proc(char *buf, char **start, off_t offset, -+ int len, int *eof, void *private) -+{ -+ FusionLink *l; -+ FusionDev *dev = private; -+ int written = 0; -+ -+ if (down_interruptible (&dev->fusionee.lock)) -+ return -EINTR; -+ -+ fusion_list_foreach (l, dev->fusionee.list) { -+ Fusionee *fusionee = (Fusionee*) l; -+ -+ written += sprintf(buf+written, "(%5d) 0x%08lx (%4d messages waiting, %7d received, %7d sent)\n", -+ fusionee->pid, fusionee->id, fusionee->messages.count, fusionee->rcv_total, fusionee->snd_total); -+ if (written < offset) { -+ offset -= written; -+ written = 0; -+ } -+ -+ if (written >= len) -+ break; -+ } -+ -+ up (&dev->fusionee.lock); -+ -+ *start = buf + offset; -+ written -= offset; -+ if (written > len) { -+ *eof = 0; -+ return len; -+ } -+ -+ *eof = 1; -+ return(written<0) ? 0 : written; -+} -+ -+int -+fusionee_init (FusionDev *dev) -+{ -+ init_waitqueue_head (&dev->fusionee.wait); -+ -+ init_MUTEX (&dev->fusionee.lock); -+ -+ create_proc_read_entry("fusionees", 0, dev->proc_dir, -+ fusionees_read_proc, dev); -+ -+ return 0; -+} -+ -+void -+fusionee_deinit (FusionDev *dev) -+{ -+ FusionLink *l; -+ -+ down (&dev->fusionee.lock); -+ -+ remove_proc_entry ("fusionees", dev->proc_dir); -+ -+ l = dev->fusionee.list; -+ while (l) { -+ FusionLink *next = l->next; -+ Fusionee *fusionee = (Fusionee *) l; -+ -+ while (fusionee->messages.count) { -+ Message *message = (Message*) fusion_fifo_get (&fusionee->messages); -+ -+ kfree (message); -+ } -+ -+ kfree (fusionee); -+ -+ l = next; -+ } -+ -+ up (&dev->fusionee.lock); -+} -+ -+/******************************************************************************/ -+ -+int -+fusionee_new( FusionDev *dev, -+ bool force_slave, -+ Fusionee **ret_fusionee ) -+{ -+ Fusionee *fusionee; -+ -+ fusionee = kmalloc (sizeof(Fusionee), GFP_KERNEL); -+ if (!fusionee) -+ return -ENOMEM; -+ -+ memset (fusionee, 0, sizeof(Fusionee)); -+ -+ if (down_interruptible (&dev->fusionee.lock)) { -+ kfree (fusionee); -+ return -EINTR; -+ } -+ -+ fusionee->pid = current->pid; -+ fusionee->force_slave = force_slave; -+ -+ init_MUTEX (&fusionee->lock); -+ -+ init_waitqueue_head (&fusionee->wait); -+ -+ fusion_list_prepend (&dev->fusionee.list, &fusionee->link); -+ -+ up (&dev->fusionee.lock); -+ -+ *ret_fusionee = fusionee; -+ -+ return 0; -+} -+ -+int -+fusionee_enter( FusionDev *dev, -+ FusionEnter *enter, -+ Fusionee *fusionee ) -+{ -+ if (enter->api.major != FUSION_API_MAJOR || enter->api.minor > FUSION_API_MINOR) -+ return -ENOPROTOOPT; -+ -+ if (down_interruptible( &dev->enter_lock )) -+ return -EINTR; -+ -+ if (dev->fusionee.last_id || fusionee->force_slave) { -+ while (!dev->enter_ok) { -+ fusion_sleep_on( &dev->enter_wait, &dev->enter_lock, NULL ); -+ -+ if (signal_pending(current)) -+ return -EINTR; -+ -+ if (down_interruptible( &dev->enter_lock )) -+ return -EINTR; -+ } -+ -+ FUSION_ASSERT( dev->fusionee.last_id != 0 ); -+ } -+ -+ fusionee->id = ++dev->fusionee.last_id; -+ -+ up( &dev->enter_lock ); -+ -+ enter->fusion_id = fusionee->id; -+ -+ return 0; -+} -+ -+int -+fusionee_fork( FusionDev *dev, -+ FusionFork *fork, -+ Fusionee *fusionee ) -+{ -+ int ret; -+ -+ ret = fusion_shmpool_fork_all( dev, fusionee->id, fork->fusion_id ); -+ if (ret) -+ return ret; -+ -+ ret = fusion_reactor_fork_all( dev, fusionee->id, fork->fusion_id ); -+ if (ret) -+ return ret; -+ -+ ret = fusion_ref_fork_all_local( dev, fusionee->id, fork->fusion_id ); -+ if (ret) -+ return ret; -+ -+ fork->fusion_id = fusionee->id; -+ -+ return 0; -+} -+ -+int -+fusionee_send_message (FusionDev *dev, -+ Fusionee *sender, -+ FusionID recipient, -+ FusionMessageType msg_type, -+ int msg_id, -+ int msg_size, -+ const void *msg_data) -+{ -+ int ret; -+ Message *message; -+ Fusionee *fusionee; -+ -+ DEBUG( "fusionee_send_message (%d -> %d, type %d, id %d, size %d)\n", -+ fusionee->id, recipient, msg_type, msg_id, msg_size ); -+ -+ ret = lookup_fusionee (dev, recipient, &fusionee); -+ if (ret) -+ return ret; -+ -+ if (down_interruptible (&fusionee->lock)) { -+ up (&dev->fusionee.lock); -+ return -EINTR; -+ } -+ -+ if (sender && sender != fusionee) { -+ if (down_interruptible (&sender->lock)) { -+ unlock_fusionee (fusionee); -+ up (&dev->fusionee.lock); -+ return -EINTR; -+ } -+ } -+ -+ up (&dev->fusionee.lock); -+ -+ -+ message = kmalloc (sizeof(Message) + msg_size, GFP_KERNEL); -+ if (!message) { -+ if (sender && sender != fusionee) -+ unlock_fusionee (sender); -+ unlock_fusionee (fusionee); -+ return -ENOMEM; -+ } -+ -+ message->data = message + 1; -+ -+ if (msg_type == FMT_CALL || msg_type == FMT_SHMPOOL) -+ memcpy (message->data, msg_data, msg_size); -+ else if (copy_from_user (message->data, msg_data, msg_size)) { -+ kfree (message); -+ if (sender && sender != fusionee) -+ unlock_fusionee (sender); -+ unlock_fusionee (fusionee); -+ return -EFAULT; -+ } -+ -+ message->type = msg_type; -+ message->id = msg_id; -+ message->size = msg_size; -+ -+ fusion_fifo_put (&fusionee->messages, &message->link); -+ -+ fusionee->rcv_total++; -+ if (sender) -+ sender->snd_total++; -+ -+ wake_up_interruptible_all (&fusionee->wait); -+ -+ if (sender && sender != fusionee) -+ unlock_fusionee (sender); -+ -+ unlock_fusionee (fusionee); -+ -+ return 0; -+} -+ -+int -+fusionee_get_messages (FusionDev *dev, -+ Fusionee *fusionee, -+ void *buf, -+ int buf_size, -+ bool block) -+{ -+ int written = 0; -+ -+ if (down_interruptible (&fusionee->lock)) -+ return -EINTR; -+ -+ while (!fusionee->messages.count) { -+ if (!block) { -+ unlock_fusionee (fusionee); -+ return -EAGAIN; -+ } -+ -+ fusion_sleep_on (&fusionee->wait, &fusionee->lock, 0); -+ -+ if (signal_pending(current)) -+ return -EINTR; -+ -+ if (down_interruptible (&fusionee->lock)) -+ return -EINTR; -+ } -+ -+ while (fusionee->messages.count) { -+ FusionReadMessage header; -+ Message *message = (Message*) fusionee->messages.first; -+ int bytes = message->size + sizeof(header); -+ -+ if (bytes > buf_size) { -+ if (!written) { -+ unlock_fusionee (fusionee); -+ return -EMSGSIZE; -+ } -+ -+ break; -+ } -+ -+ header.msg_type = message->type; -+ header.msg_id = message->id; -+ header.msg_size = message->size; -+ -+ if (copy_to_user (buf, &header, sizeof(header)) || -+ copy_to_user (buf + sizeof(header), message->data, message->size)) { -+ unlock_fusionee (fusionee); -+ return -EFAULT; -+ } -+ -+ written += bytes; -+ buf += bytes; -+ buf_size -= bytes; -+ -+ fusion_fifo_get (&fusionee->messages); -+ -+ kfree (message); -+ } -+ -+ unlock_fusionee (fusionee); -+ -+ return written; -+} -+ -+unsigned int -+fusionee_poll (FusionDev *dev, -+ Fusionee *fusionee, -+ struct file *file, -+ poll_table *wait) -+{ -+ int ret; -+ FusionID id = fusionee->id; -+ -+ poll_wait (file, &fusionee->wait, wait); -+ -+ -+ ret = lock_fusionee (dev, id, &fusionee); -+ if (ret) -+ return POLLERR; -+ -+ if (fusionee->messages.count) { -+ unlock_fusionee (fusionee); -+ -+ return POLLIN | POLLRDNORM; -+ } -+ -+ unlock_fusionee (fusionee); -+ -+ return 0; -+} -+ -+int -+fusionee_kill (FusionDev *dev, -+ Fusionee *fusionee, -+ FusionID target, -+ int signal, -+ int timeout_ms) -+{ -+ long timeout = -1; -+ -+ while (true) { -+ FusionLink *l; -+ int killed = 0; -+ -+ if (down_interruptible (&dev->fusionee.lock)) -+ return -EINTR; -+ -+ fusion_list_foreach (l, dev->fusionee.list) { -+ Fusionee *f = (Fusionee*) l; -+ -+ if (f != fusionee && (!target || target == f->id)) { -+ kill_proc (f->pid, signal, 0); -+ killed++; -+ } -+ } -+ -+ if (!killed || timeout_ms < 0) { -+ up (&dev->fusionee.lock); -+ break; -+ } -+ -+ if (timeout_ms) { -+ switch (timeout) { -+ case 0: /* timed out */ -+ up (&dev->fusionee.lock); -+ return -ETIMEDOUT; -+ -+ case -1: /* setup timeout */ -+ timeout = (timeout_ms * HZ + 500) / 1000; -+ if (!timeout) -+ timeout = 1; -+ -+ /* fall through */ -+ -+ default: -+ fusion_sleep_on (&dev->fusionee.wait, -+ &dev->fusionee.lock, &timeout); -+ break; -+ } -+ } -+ else -+ fusion_sleep_on (&dev->fusionee.wait, &dev->fusionee.lock, NULL); -+ -+ if (signal_pending(current)) -+ return -EINTR; -+ } -+ -+ return 0; -+} -+ -+void -+fusionee_destroy (FusionDev *dev, -+ Fusionee *fusionee) -+{ -+ /* Lock list. */ -+ down (&dev->fusionee.lock); -+ -+ /* Lock fusionee. */ -+ down (&fusionee->lock); -+ -+ /* Remove from list. */ -+ fusion_list_remove (&dev->fusionee.list, &fusionee->link); -+ -+ /* Wake up waiting killer. */ -+ wake_up_interruptible_all (&dev->fusionee.wait); -+ -+ /* Unlock list. */ -+ up (&dev->fusionee.lock); -+ -+ -+ /* Release locks, references, ... */ -+ fusion_call_destroy_all (dev, fusionee->id); -+ fusion_skirmish_dismiss_all (dev, fusionee->id); -+ fusion_reactor_detach_all (dev, fusionee->id); -+ fusion_property_cede_all (dev, fusionee->id); -+ fusion_ref_clear_all_local (dev, fusionee->id); -+ fusion_shmpool_detach_all (dev, fusionee->id); -+ -+ /* Free all pending messages. */ -+ while (fusionee->messages.count) { -+ Message *message = (Message*) fusion_fifo_get (&fusionee->messages); -+ -+ kfree (message); -+ } -+ -+ /* Unlock fusionee. */ -+ up (&fusionee->lock); -+ -+ -+ /* Free fusionee data. */ -+ kfree (fusionee); -+} -+ -+FusionID -+fusionee_id( const Fusionee *fusionee ) -+{ -+ return fusionee->id; -+} -+ -+/******************************************************************************/ -+ -+static int -+lookup_fusionee (FusionDev *dev, -+ FusionID id, -+ Fusionee **ret_fusionee) -+{ -+ FusionLink *l; -+ -+ if (down_interruptible (&dev->fusionee.lock)) -+ return -EINTR; -+ -+ fusion_list_foreach (l, dev->fusionee.list) { -+ Fusionee *fusionee = (Fusionee *) l; -+ -+ if (fusionee->id == id) { -+ *ret_fusionee = fusionee; -+ return 0; -+ } -+ } -+ -+ up (&dev->fusionee.lock); -+ -+ return -EINVAL; -+} -+ -+static int -+lock_fusionee (FusionDev *dev, -+ FusionID id, -+ Fusionee **ret_fusionee) -+{ -+ int ret; -+ Fusionee *fusionee; -+ -+ ret = lookup_fusionee (dev, id, &fusionee); -+ if (ret) -+ return ret; -+ -+ fusion_list_move_to_front (&dev->fusionee.list, &fusionee->link); -+ -+ if (down_interruptible (&fusionee->lock)) { -+ up (&dev->fusionee.lock); -+ return -EINTR; -+ } -+ -+ up (&dev->fusionee.lock); -+ -+ *ret_fusionee = fusionee; -+ -+ return 0; -+} -+ -+static void -+unlock_fusionee (Fusionee *fusionee) -+{ -+ up (&fusionee->lock); -+} -+ -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/fusionee.h linux-2.6.22.1/drivers/char/fusion/fusionee.h ---- linux-2.6.22.1-0rig/drivers/char/fusion/fusionee.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/fusionee.h 2007-01-23 22:19:25.000000000 +0100 -@@ -0,0 +1,75 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifndef __FUSIONEE_H__ -+#define __FUSIONEE_H__ -+ -+#include <linux/poll.h> -+#include <linux/fusion.h> -+ -+#include "fusiondev.h" -+#include "types.h" -+ -+/* module init/cleanup */ -+ -+int fusionee_init (FusionDev *dev); -+void fusionee_deinit (FusionDev *dev); -+ -+ -+/* internal functions */ -+ -+int fusionee_new (FusionDev *dev, -+ bool force_slave, -+ Fusionee **ret_fusionee); -+ -+int fusionee_enter (FusionDev *dev, -+ FusionEnter *enter, -+ Fusionee *fusionee); -+ -+int fusionee_fork (FusionDev *dev, -+ FusionFork *fork, -+ Fusionee *fusionee); -+ -+int fusionee_send_message (FusionDev *dev, -+ Fusionee *fusionee, -+ FusionID recipient, -+ FusionMessageType msg_type, -+ int msg_id, -+ int msg_size, -+ const void *msg_data); -+ -+int fusionee_get_messages (FusionDev *dev, -+ Fusionee *fusionee, -+ void *buf, -+ int buf_size, -+ bool block); -+ -+unsigned -+int fusionee_poll (FusionDev *dev, -+ Fusionee *fusionee, -+ struct file *file, -+ poll_table *wait); -+ -+int fusionee_kill (FusionDev *dev, -+ Fusionee *fusionee, -+ FusionID target, -+ int signal, -+ int timeout_ms); -+ -+void fusionee_destroy (FusionDev *dev, -+ Fusionee *fusionee); -+ -+FusionID fusionee_id( const Fusionee *fusionee ); -+ -+#endif -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/Kconfig linux-2.6.22.1/drivers/char/fusion/Kconfig ---- linux-2.6.22.1-0rig/drivers/char/fusion/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/Kconfig 2007-08-12 19:33:38.000000000 +0200 -@@ -0,0 +1,8 @@ -+config FUSION_DEVICE -+ tristate "Fusion device for DirectFB" -+ default m -+ ---help--- -+ The fusion device is a software device allowing the DirectFB -+ (Direct Frame Buffer) to support multiple applications -+ It is safe to say N unless you need to run several DirectFB -+ applications concurrently. -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/list.c linux-2.6.22.1/drivers/char/fusion/list.c ---- linux-2.6.22.1-0rig/drivers/char/fusion/list.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/list.c 2003-06-16 19:47:03.000000000 +0200 -@@ -0,0 +1,62 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#include <linux/types.h> -+ -+#include "list.h" -+ -+void -+fusion_list_prepend (FusionLink **list, FusionLink *link) -+{ -+ link->prev = NULL; -+ link->next = *list; -+ -+ if (*list) -+ (*list)->prev = link; -+ -+ *list = link; -+} -+ -+void -+fusion_list_remove (FusionLink **list, FusionLink *link) -+{ -+ if (link->prev) -+ link->prev->next = link->next; -+ else -+ *list = link->next; -+ -+ if (link->next) -+ link->next->prev = link->prev; -+ -+ link->next = link->prev = NULL; -+} -+ -+void -+fusion_list_move_to_front (FusionLink **list, FusionLink *link) -+{ -+ if (*list == link) -+ return; -+ -+ link->prev->next = link->next; -+ -+ if (link->next) -+ link->next->prev = link->prev; -+ -+ link->prev = NULL; -+ link->next = *list; -+ -+ (*list)->prev = link; -+ -+ *list = link; -+} -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/list.h linux-2.6.22.1/drivers/char/fusion/list.h ---- linux-2.6.22.1-0rig/drivers/char/fusion/list.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/list.h 2004-08-17 19:24:36.000000000 +0200 -@@ -0,0 +1,39 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifndef __FUSION__LIST_H__ -+#define __FUSION__LIST_H__ -+ -+typedef struct _FusionLink { -+ struct _FusionLink *next; -+ struct _FusionLink *prev; -+} FusionLink; -+ -+void fusion_list_prepend (FusionLink **list, FusionLink *link); -+void fusion_list_remove (FusionLink **list, FusionLink *link); -+void fusion_list_move_to_front (FusionLink **list, FusionLink *link); -+ -+ -+#define fusion_list_foreach(elem, list) \ -+ for (elem = (void*)(list); \ -+ elem; \ -+ elem = (void*)(((FusionLink*)(elem))->next)) -+ -+#define fusion_list_foreach_safe(elem, temp, list) \ -+ for (elem = (void*)(list), temp = ((elem) ? (void*)(((FusionLink*)(elem))->next) : NULL); \ -+ elem; \ -+ elem = (void*)(temp), temp = ((elem) ? (void*)(((FusionLink*)(elem))->next) : NULL)) -+ -+#endif /* __FUSION__LIST_H__ */ -+ -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/Makefile linux-2.6.22.1/drivers/char/fusion/Makefile ---- linux-2.6.22.1-0rig/drivers/char/fusion/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/Makefile 2005-10-29 02:38:05.000000000 +0200 -@@ -0,0 +1,3 @@ -+obj-$(CONFIG_FUSION_DEVICE) += fusion.o -+ -+fusion-y := call.o entries.o fifo.o fusiondev.o fusionee.o list.o property.o reactor.o ref.o skirmish.o shmpool.o -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/property.c linux-2.6.22.1/drivers/char/fusion/property.c ---- linux-2.6.22.1-0rig/drivers/char/fusion/property.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/property.c 2007-01-20 05:03:01.000000000 +0100 -@@ -0,0 +1,340 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifdef HAVE_LINUX_CONFIG_H -+#include <linux/config.h> -+#endif -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/smp_lock.h> -+#include <linux/sched.h> -+ -+#ifndef yield -+#define yield schedule -+#endif -+ -+#include <linux/fusion.h> -+ -+#include "entries.h" -+#include "fusiondev.h" -+#include "fusionee.h" -+#include "list.h" -+#include "property.h" -+ -+typedef enum { -+ FUSION_PROPERTY_AVAILABLE = 0, -+ FUSION_PROPERTY_LEASED, -+ FUSION_PROPERTY_PURCHASED -+} FusionPropertyState; -+ -+typedef struct { -+ FusionEntry entry; -+ -+ FusionPropertyState state; -+ int fusion_id; /* non-zero if leased/purchased */ -+ unsigned long purchase_stamp; -+ int lock_pid; -+ int count; /* lock counter */ -+} FusionProperty; -+ -+static int -+fusion_property_print( FusionEntry *entry, -+ void *ctx, -+ char *buf ) -+{ -+ FusionProperty *property = (FusionProperty*) entry; -+ -+ if (property->state != FUSION_PROPERTY_AVAILABLE) { -+ return sprintf( buf, "%s by 0x%08x (%d) %dx\n", -+ property->state == FUSION_PROPERTY_LEASED ? "leased" : "purchased", -+ property->fusion_id, property->lock_pid, property->count ); -+ } -+ -+ return sprintf( buf, "\n" ); -+} -+ -+FUSION_ENTRY_CLASS( FusionProperty, property, NULL, NULL, fusion_property_print ) -+ -+/******************************************************************************/ -+ -+int -+fusion_property_init( FusionDev *dev ) -+{ -+ fusion_entries_init( &dev->properties, &property_class, dev ); -+ -+ create_proc_read_entry( "properties", 0, dev->proc_dir, -+ fusion_entries_read_proc, &dev->properties ); -+ -+ return 0; -+} -+ -+void -+fusion_property_deinit( FusionDev *dev ) -+{ -+ remove_proc_entry( "properties", dev->proc_dir ); -+ -+ fusion_entries_deinit( &dev->properties ); -+} -+ -+/******************************************************************************/ -+ -+int -+fusion_property_new( FusionDev *dev, int *ret_id ) -+{ -+ return fusion_entry_create( &dev->properties, ret_id, NULL ); -+} -+ -+int -+fusion_property_lease( FusionDev *dev, int id, int fusion_id ) -+{ -+ int ret; -+ FusionProperty *property; -+ long timeout = -1; -+ -+ dev->stat.property_lease_purchase++; -+ -+ ret = fusion_property_lock( &dev->properties, id, false, &property ); -+ if (ret) -+ return ret; -+ -+ while (true) { -+ switch (property->state) { -+ case FUSION_PROPERTY_AVAILABLE: -+ property->state = FUSION_PROPERTY_LEASED; -+ property->fusion_id = fusion_id; -+ property->lock_pid = current->pid; -+ property->count = 1; -+ -+ fusion_property_unlock( property ); -+ return 0; -+ -+ case FUSION_PROPERTY_LEASED: -+ if (property->lock_pid == current->pid) { -+ property->count++; -+ -+ fusion_property_unlock( property ); -+ return 0; -+ } -+ -+ ret = fusion_property_wait( property, NULL ); -+ if (ret) -+ return ret; -+ -+ break; -+ -+ case FUSION_PROPERTY_PURCHASED: -+ if (property->lock_pid == current->pid) { -+ fusion_property_unlock( property ); -+ return -EIO; -+ } -+ -+ if (timeout == -1) { -+ if (jiffies - property->purchase_stamp > HZ / 10) { -+ fusion_property_unlock( property ); -+ return -EAGAIN; -+ } -+ -+ timeout = HZ / 10; -+ } -+ -+ ret = fusion_property_wait( property, &timeout ); -+ if (ret) -+ return ret; -+ -+ break; -+ -+ default: -+ BUG(); -+ } -+ } -+ -+ BUG(); -+ -+ /* won't reach this */ -+ return -1; -+} -+ -+int -+fusion_property_purchase( FusionDev *dev, int id, int fusion_id ) -+{ -+ int ret; -+ FusionProperty *property; -+ signed long timeout = -1; -+ -+ dev->stat.property_lease_purchase++; -+ -+ ret = fusion_property_lock( &dev->properties, id, false, &property ); -+ if (ret) -+ return ret; -+ -+ while (true) { -+ switch (property->state) { -+ case FUSION_PROPERTY_AVAILABLE: -+ property->state = FUSION_PROPERTY_PURCHASED; -+ property->fusion_id = fusion_id; -+ property->purchase_stamp = jiffies; -+ property->lock_pid = current->pid; -+ property->count = 1; -+ -+ fusion_property_notify( property, true ); -+ -+ fusion_property_unlock( property ); -+ return 0; -+ -+ case FUSION_PROPERTY_LEASED: -+ if (property->lock_pid == current->pid) { -+ fusion_property_unlock( property ); -+ return -EIO; -+ } -+ -+ ret = fusion_property_wait( property, NULL ); -+ if (ret) -+ return ret; -+ -+ break; -+ -+ case FUSION_PROPERTY_PURCHASED: -+ if (property->lock_pid == current->pid) { -+ property->count++; -+ -+ fusion_property_unlock( property ); -+ return 0; -+ } -+ -+ if (timeout == -1) { -+ if (jiffies - property->purchase_stamp > HZ) { -+ fusion_property_unlock( property ); -+ return -EAGAIN; -+ } -+ -+ timeout = HZ; -+ } -+ -+ ret = fusion_property_wait( property, &timeout ); -+ if (ret) -+ return ret; -+ -+ break; -+ -+ default: -+ BUG(); -+ } -+ } -+ -+ BUG(); -+ -+ /* won't reach this */ -+ return -1; -+} -+ -+int -+fusion_property_cede( FusionDev *dev, int id, int fusion_id ) -+{ -+ int ret; -+ FusionProperty *property; -+ bool purchased; -+ -+ dev->stat.property_cede++; -+ -+ ret = fusion_property_lock( &dev->properties, id, false, &property ); -+ if (ret) -+ return ret; -+ -+ if (property->lock_pid != current->pid) { -+ fusion_property_unlock( property ); -+ return -EIO; -+ } -+ -+ if (--property->count) { -+ fusion_property_unlock( property ); -+ return 0; -+ } -+ -+ purchased = (property->state == FUSION_PROPERTY_PURCHASED); -+ -+ property->state = FUSION_PROPERTY_AVAILABLE; -+ property->fusion_id = 0; -+ property->lock_pid = 0; -+ -+ fusion_property_notify( property, true ); -+ -+ fusion_property_unlock( property ); -+ -+ if (purchased) -+ yield(); -+ -+ return 0; -+} -+ -+int -+fusion_property_holdup( FusionDev *dev, int id, Fusionee *fusionee ) -+{ -+ int ret; -+ FusionProperty *property; -+ FusionID fusion_id = fusionee_id( fusionee ); -+ -+ if (fusion_id > 1) -+ return -EPERM; -+ -+ ret = fusion_property_lock( &dev->properties, id, false, &property ); -+ if (ret) -+ return ret; -+ -+ if (property->state == FUSION_PROPERTY_PURCHASED) { -+ if (property->fusion_id == fusion_id) { -+ fusion_property_unlock( property ); -+ return -EIO; -+ } -+ -+ fusionee_kill( dev, fusionee, property->fusion_id, SIGKILL, -1 ); -+ } -+ -+ fusion_property_unlock( property ); -+ -+ return 0; -+} -+ -+int -+fusion_property_destroy( FusionDev *dev, int id ) -+{ -+ return fusion_entry_destroy( &dev->properties, id ); -+} -+ -+void -+fusion_property_cede_all( FusionDev *dev, int fusion_id ) -+{ -+ FusionLink *l; -+ -+ down( &dev->properties.lock ); -+ -+ fusion_list_foreach (l, dev->properties.list) { -+ FusionProperty *property = (FusionProperty *) l; -+ -+ down( &property->entry.lock ); -+ -+ if (property->fusion_id == fusion_id) { -+ property->state = FUSION_PROPERTY_AVAILABLE; -+ property->fusion_id = 0; -+ property->lock_pid = 0; -+ -+ wake_up_interruptible_all (&property->entry.wait); -+ } -+ -+ up( &property->entry.lock ); -+ } -+ -+ up( &dev->properties.lock ); -+} -+ -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/property.h linux-2.6.22.1/drivers/char/fusion/property.h ---- linux-2.6.22.1-0rig/drivers/char/fusion/property.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/property.h 2007-01-20 05:03:01.000000000 +0100 -@@ -0,0 +1,58 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifndef __FUSION__PROPERTY_H__ -+#define __FUSION__PROPERTY_H__ -+ -+#include "fusiondev.h" -+#include "types.h" -+ -+ -+/* module init/cleanup */ -+ -+int fusion_property_init (FusionDev *dev); -+void fusion_property_deinit (FusionDev *dev); -+ -+ -+/* public API */ -+ -+int fusion_property_new (FusionDev *dev, -+ int *ret_id); -+ -+int fusion_property_lease (FusionDev *dev, -+ int id, -+ int fusion_id); -+ -+int fusion_property_purchase (FusionDev *dev, -+ int id, -+ int fusion_id); -+ -+int fusion_property_cede (FusionDev *dev, -+ int id, -+ int fusion_id); -+ -+int fusion_property_holdup (FusionDev *dev, -+ int id, -+ Fusionee *fusionee); -+ -+int fusion_property_destroy (FusionDev *dev, -+ int id); -+ -+ -+/* internal functions */ -+ -+void fusion_property_cede_all (FusionDev *dev, -+ int fusion_id); -+ -+#endif -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/reactor.c linux-2.6.22.1/drivers/char/fusion/reactor.c ---- linux-2.6.22.1-0rig/drivers/char/fusion/reactor.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/reactor.c 2007-01-20 05:03:01.000000000 +0100 -@@ -0,0 +1,367 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifdef HAVE_LINUX_CONFIG_H -+#include <linux/config.h> -+#endif -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/smp_lock.h> -+#include <linux/sched.h> -+ -+#include <linux/fusion.h> -+ -+#include "fusiondev.h" -+#include "fusionee.h" -+#include "list.h" -+#include "reactor.h" -+ -+typedef struct { -+ FusionLink link; -+ -+ int fusion_id; -+ -+ int count; /* number of attach calls */ -+} ReactorNode; -+ -+typedef struct { -+ FusionEntry entry; -+ -+ FusionLink *nodes; -+ -+ int dispatch_count; -+ -+ bool destroyed; -+} FusionReactor; -+ -+/******************************************************************************/ -+ -+static int fork_node ( FusionReactor *reactor, -+ FusionID fusion_id, -+ FusionID from_id ); -+ -+static void free_all_nodes( FusionReactor *reactor ); -+ -+/******************************************************************************/ -+ -+static inline ReactorNode * -+get_node (FusionReactor *reactor, -+ FusionID fusion_id) -+{ -+ ReactorNode *node; -+ -+ fusion_list_foreach (node, reactor->nodes) { -+ if (node->fusion_id == fusion_id) -+ return node; -+ } -+ -+ return NULL; -+} -+ -+/******************************************************************************/ -+ -+static void -+fusion_reactor_destruct( FusionEntry *entry, -+ void *ctx ) -+{ -+ FusionReactor *reactor = (FusionReactor*) entry; -+ -+ free_all_nodes( reactor ); -+} -+ -+static int -+fusion_reactor_print( FusionEntry *entry, -+ void *ctx, -+ char *buf ) -+{ -+ int num = 0; -+ FusionReactor *reactor = (FusionReactor*) entry; -+ FusionLink *node = reactor->nodes; -+ -+ fusion_list_foreach (node, reactor->nodes) { -+ num++; -+ } -+ -+ return sprintf( buf, "%5dx dispatch, %d nodes%s\n", reactor->dispatch_count, num, -+ reactor->destroyed ? " DESTROYED" : "" ); -+} -+ -+ -+FUSION_ENTRY_CLASS( FusionReactor, reactor, NULL, -+ fusion_reactor_destruct, fusion_reactor_print ) -+ -+/******************************************************************************/ -+ -+int -+fusion_reactor_init (FusionDev *dev) -+{ -+ fusion_entries_init( &dev->reactor, &reactor_class, dev ); -+ -+ create_proc_read_entry( "reactors", 0, dev->proc_dir, -+ fusion_entries_read_proc, &dev->reactor ); -+ -+ return 0; -+} -+ -+void -+fusion_reactor_deinit (FusionDev *dev) -+{ -+ remove_proc_entry ("reactors", dev->proc_dir); -+ -+ fusion_entries_deinit( &dev->reactor ); -+} -+ -+/******************************************************************************/ -+ -+int -+fusion_reactor_new (FusionDev *dev, int *ret_id) -+{ -+ return fusion_entry_create( &dev->reactor, ret_id, NULL ); -+} -+ -+int -+fusion_reactor_attach (FusionDev *dev, int id, FusionID fusion_id) -+{ -+ int ret; -+ ReactorNode *node; -+ FusionReactor *reactor; -+ -+ ret = fusion_reactor_lock( &dev->reactor, id, false, &reactor ); -+ if (ret) -+ return ret; -+ -+ if (reactor->destroyed) { -+ fusion_reactor_unlock( reactor ); -+ return -EIDRM; -+ } -+ -+ dev->stat.reactor_attach++; -+ -+ node = get_node (reactor, fusion_id); -+ if (!node) { -+ node = kmalloc (sizeof(ReactorNode), GFP_KERNEL); -+ if (!node) { -+ fusion_reactor_unlock( reactor ); -+ return -ENOMEM; -+ } -+ -+ node->fusion_id = fusion_id; -+ node->count = 1; -+ -+ fusion_list_prepend (&reactor->nodes, &node->link); -+ } -+ else -+ node->count++; -+ -+ fusion_reactor_unlock( reactor ); -+ -+ return 0; -+} -+ -+int -+fusion_reactor_detach (FusionDev *dev, int id, FusionID fusion_id) -+{ -+ int ret; -+ ReactorNode *node; -+ FusionReactor *reactor; -+ -+ ret = fusion_reactor_lock( &dev->reactor, id, true, &reactor ); -+ if (ret) -+ return ret; -+ -+ dev->stat.reactor_detach++; -+ -+ node = get_node (reactor, fusion_id); -+ if (!node) { -+ fusion_reactor_unlock( reactor ); -+ up( &dev->reactor.lock ); -+ return -EIO; -+ } -+ -+ if (! --node->count) { -+ fusion_list_remove (&reactor->nodes, &node->link); -+ kfree (node); -+ } -+ -+ if (reactor->destroyed && !reactor->nodes) -+ fusion_entry_destroy_locked( &dev->reactor, &reactor->entry ); -+ else -+ fusion_reactor_unlock( reactor ); -+ -+ up( &dev->reactor.lock ); -+ -+ return 0; -+} -+ -+int -+fusion_reactor_dispatch (FusionDev *dev, int id, Fusionee *fusionee, -+ int msg_size, const void *msg_data) -+{ -+ int ret; -+ FusionLink *l; -+ FusionReactor *reactor; -+ FusionID fusion_id = fusionee ? fusionee_id( fusionee ) : 0; -+ -+ ret = fusion_reactor_lock( &dev->reactor, id, false, &reactor ); -+ if (ret) -+ return ret; -+ -+ if (reactor->destroyed) { -+ fusion_reactor_unlock( reactor ); -+ return -EIDRM; -+ } -+ -+ reactor->dispatch_count++; -+ -+ fusion_list_foreach (l, reactor->nodes) { -+ ReactorNode *node = (ReactorNode *) l; -+ -+ if (node->fusion_id == fusion_id) -+ continue; -+ -+ fusionee_send_message (dev, fusionee, node->fusion_id, FMT_REACTOR, -+ reactor->entry.id, msg_size, msg_data); -+ } -+ -+ fusion_reactor_unlock( reactor ); -+ -+ return 0; -+} -+ -+int -+fusion_reactor_destroy (FusionDev *dev, int id) -+{ -+ int ret; -+ FusionReactor *reactor; -+ -+ ret = fusion_reactor_lock( &dev->reactor, id, true, &reactor ); -+ if (ret) -+ return ret; -+ -+ if (reactor->destroyed) { -+ fusion_reactor_unlock( reactor ); -+ up( &dev->reactor.lock ); -+ return -EIDRM; -+ } -+ -+ reactor->destroyed = true; -+ -+ if (!reactor->nodes) -+ fusion_entry_destroy_locked( &dev->reactor, &reactor->entry ); -+ else -+ fusion_reactor_unlock( reactor ); -+ -+ up( &dev->reactor.lock ); -+ -+ return 0; -+} -+ -+void -+fusion_reactor_detach_all (FusionDev *dev, FusionID fusion_id) -+{ -+ FusionLink *l, *n; -+ -+ down (&dev->reactor.lock); -+ -+ fusion_list_foreach_safe (l, n, dev->reactor.list) { -+ ReactorNode *node; -+ FusionReactor *reactor = (FusionReactor *) l; -+ -+ down (&reactor->entry.lock); -+ -+ fusion_list_foreach (node, reactor->nodes) { -+ if (node->fusion_id == fusion_id) { -+ fusion_list_remove (&reactor->nodes, &node->link); -+ kfree (node); -+ break; -+ } -+ } -+ -+ if (reactor->destroyed && !reactor->nodes) -+ fusion_entry_destroy_locked( &dev->reactor, &reactor->entry ); -+ else -+ up (&reactor->entry.lock); -+ } -+ -+ up (&dev->reactor.lock); -+} -+ -+int -+fusion_reactor_fork_all (FusionDev *dev, FusionID fusion_id, FusionID from_id) -+{ -+ FusionLink *l; -+ int ret = 0; -+ -+ down (&dev->reactor.lock); -+ -+ fusion_list_foreach (l, dev->reactor.list) { -+ FusionReactor *reactor = (FusionReactor *) l; -+ -+ ret = fork_node (reactor, fusion_id, from_id); -+ if (ret) -+ break; -+ } -+ -+ up (&dev->reactor.lock); -+ -+ return ret; -+} -+ -+/******************************************************************************/ -+ -+static int -+fork_node (FusionReactor *reactor, FusionID fusion_id, FusionID from_id) -+{ -+ ReactorNode *node; -+ -+ down (&reactor->entry.lock); -+ -+ fusion_list_foreach (node, reactor->nodes) { -+ if (node->fusion_id == from_id) { -+ ReactorNode *new_node; -+ -+ new_node = kmalloc (sizeof(ReactorNode), GFP_KERNEL); -+ if (!new_node) { -+ up (&reactor->entry.lock); -+ return -ENOMEM; -+ } -+ -+ new_node->fusion_id = fusion_id; -+ new_node->count = node->count; -+ -+ fusion_list_prepend (&reactor->nodes, &new_node->link); -+ -+ break; -+ } -+ } -+ -+ up (&reactor->entry.lock); -+ -+ return 0; -+} -+ -+static void -+free_all_nodes (FusionReactor *reactor) -+ -+{ -+ FusionLink *n; -+ ReactorNode *node; -+ -+ fusion_list_foreach_safe (node, n, reactor->nodes) { -+ kfree (node); -+ } -+ -+ reactor->nodes = NULL; -+} -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/reactor.h linux-2.6.22.1/drivers/char/fusion/reactor.h ---- linux-2.6.22.1-0rig/drivers/char/fusion/reactor.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/reactor.h 2007-01-20 05:03:01.000000000 +0100 -@@ -0,0 +1,59 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifndef __FUSION__REACTOR_H__ -+#define __FUSION__REACTOR_H__ -+ -+#include "fusiondev.h" -+#include "types.h" -+ -+ -+/* module init/cleanup */ -+ -+int fusion_reactor_init (FusionDev *dev); -+void fusion_reactor_deinit (FusionDev *dev); -+ -+ -+/* public API */ -+ -+int fusion_reactor_new (FusionDev *dev, -+ int *id); -+ -+int fusion_reactor_attach (FusionDev *dev, -+ int id, -+ FusionID fusion_id); -+ -+int fusion_reactor_detach (FusionDev *dev, -+ int id, -+ FusionID fusion_id); -+ -+int fusion_reactor_dispatch (FusionDev *dev, -+ int id, -+ Fusionee *fusionee, -+ int msg_size, -+ const void *msg_data); -+ -+int fusion_reactor_destroy (FusionDev *dev, -+ int id); -+ -+ -+/* internal functions */ -+ -+void fusion_reactor_detach_all (FusionDev *dev, -+ FusionID fusion_id); -+ -+int fusion_reactor_fork_all (FusionDev *dev, -+ FusionID fusion_id, -+ FusionID from_id); -+#endif -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/ref.c linux-2.6.22.1/drivers/char/fusion/ref.c ---- linux-2.6.22.1-0rig/drivers/char/fusion/ref.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/ref.c 2007-01-06 14:09:45.000000000 +0100 -@@ -0,0 +1,680 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifdef HAVE_LINUX_CONFIG_H -+#include <linux/config.h> -+#endif -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/smp_lock.h> -+#include <linux/sched.h> -+ -+#include <linux/fusion.h> -+ -+#include "fusiondev.h" -+#include "list.h" -+#include "call.h" -+#include "ref.h" -+ -+typedef struct __Fusion_FusionRef FusionRef; -+ -+typedef struct { -+ FusionLink link; -+ FusionID fusion_id; -+ int refs; -+} LocalRef; -+ -+typedef struct { -+ FusionLink link; -+ FusionRef *ref; -+} Inheritor; -+ -+struct __Fusion_FusionRef { -+ FusionEntry entry; -+ -+ int global; -+ int local; -+ -+ int locked; /* non-zero fusion id of lock owner */ -+ -+ bool watched; /* true if watch has been installed */ -+ int call_id; /* id of call registered with a watch */ -+ int call_arg; /* optional call parameter */ -+ -+ FusionRef *inherited; -+ FusionLink *inheritors; -+ -+ FusionLink *local_refs; -+}; -+ -+/**********************************************************************************************************************/ -+ -+static int add_local ( FusionRef *ref, FusionID fusion_id, int add ); -+static void clear_local ( FusionDev *dev, FusionRef *ref, FusionID fusion_id ); -+static int fork_local ( FusionDev *dev, FusionRef *ref, FusionID fusion_id, FusionID from_id ); -+static void free_all_local ( FusionRef *ref ); -+ -+static int propagate_local ( FusionDev *dev, FusionRef *ref, int diff ); -+ -+static void notify_ref ( FusionDev *dev, FusionRef *ref ); -+ -+static int add_inheritor ( FusionRef *ref, FusionRef *from ); -+static void remove_inheritor( FusionRef *ref, FusionRef *from ); -+static void drop_inheritors ( FusionDev *dev, FusionRef *ref ); -+ -+/**********************************************************************************************************************/ -+ -+static void -+fusion_ref_destruct( FusionEntry *entry, -+ void *ctx ) -+{ -+ FusionRef *ref = (FusionRef*) entry; -+ FusionDev *dev = (FusionDev*) ctx; -+ -+ drop_inheritors( dev, ref ); -+ -+ if (ref->inherited) -+ remove_inheritor( ref, ref->inherited ); -+ -+ free_all_local( ref ); -+} -+ -+static int -+fusion_ref_print( FusionEntry *entry, -+ void *ctx, -+ char *buf ) -+{ -+ FusionRef *ref = (FusionRef*) entry; -+ -+ if (ref->locked) -+ return sprintf( buf, "%2d %2d (locked by %d)\n", ref->global, ref->local, ref->locked ); -+ -+ return sprintf( buf, "%2d %2d\n", ref->global, ref->local ); -+} -+ -+FUSION_ENTRY_CLASS( FusionRef, ref, NULL, -+ fusion_ref_destruct, fusion_ref_print ); -+ -+/**********************************************************************************************************************/ -+ -+int -+fusion_ref_init( FusionDev *dev ) -+{ -+ fusion_entries_init( &dev->ref, &ref_class, dev ); -+ -+ create_proc_read_entry( "refs", 0, dev->proc_dir, fusion_entries_read_proc, &dev->ref ); -+ -+ return 0; -+} -+ -+void -+fusion_ref_deinit( FusionDev *dev ) -+{ -+ remove_proc_entry( "refs", dev->proc_dir ); -+ -+ fusion_entries_deinit( &dev->ref ); -+} -+ -+/**********************************************************************************************************************/ -+ -+int -+fusion_ref_new( FusionDev *dev, int *ret_id ) -+{ -+ return fusion_entry_create( &dev->ref, ret_id, NULL ); -+} -+ -+int -+fusion_ref_up (FusionDev *dev, int id, FusionID fusion_id) -+{ -+ int ret; -+ FusionRef *ref; -+ -+ ret = fusion_ref_lock( &dev->ref, id, true, &ref ); -+ if (ret) -+ return ret; -+ -+ dev->stat.ref_up++; -+ -+ if (ref->locked) { -+ ret = -EAGAIN; -+ goto out; -+ } -+ -+ if (fusion_id) { -+ ret = add_local (ref, fusion_id, 1); -+ if (ret) -+ goto out; -+ -+ ret = propagate_local( dev, ref, 1 ); -+ } -+ else -+ ref->global++; -+ -+ -+out: -+ fusion_ref_unlock( ref ); -+ up( &dev->ref.lock ); -+ -+ return ret; -+} -+ -+int -+fusion_ref_down (FusionDev *dev, int id, FusionID fusion_id) -+{ -+ int ret; -+ FusionRef *ref; -+ -+ ret = fusion_ref_lock( &dev->ref, id, true, &ref ); -+ if (ret) -+ return ret; -+ -+ dev->stat.ref_down++; -+ -+ if (ref->locked) { -+ ret = -EAGAIN; -+ goto out; -+ } -+ -+ if (fusion_id) { -+ ret = -EIO; -+ if (!ref->local) -+ goto out; -+ -+ ret = add_local (ref, fusion_id, -1); -+ if (ret) -+ goto out; -+ -+ ret = propagate_local( dev, ref, -1 ); -+ } -+ else { -+ if (!ref->global) { -+ ret = -EIO; -+ goto out; -+ } -+ -+ ref->global--; -+ -+ if (ref->local + ref->global == 0) -+ notify_ref (dev, ref); -+ } -+ -+ -+out: -+ fusion_ref_unlock( ref ); -+ up( &dev->ref.lock ); -+ -+ return ret; -+} -+ -+int -+fusion_ref_zero_lock (FusionDev *dev, int id, FusionID fusion_id) -+{ -+ int ret; -+ FusionRef *ref; -+ -+ ret = fusion_ref_lock( &dev->ref, id, false, &ref ); -+ if (ret) -+ return ret; -+ -+ while (true) { -+ if (ref->watched) { -+ fusion_ref_unlock( ref ); -+ return -EACCES; -+ } -+ -+ if (ref->locked) { -+ fusion_ref_unlock( ref ); -+ return ref->locked == fusion_id ? -EIO : -EAGAIN; -+ } -+ -+ if (ref->global || ref->local) { -+ ret = fusion_ref_wait( ref, NULL ); -+ if (ret) -+ return ret; -+ } -+ else -+ break; -+ } -+ -+ ref->locked = fusion_id; -+ -+ fusion_ref_unlock( ref ); -+ -+ return 0; -+} -+ -+int -+fusion_ref_zero_trylock (FusionDev *dev, int id, FusionID fusion_id) -+{ -+ int ret; -+ FusionRef *ref; -+ -+ ret = fusion_ref_lock( &dev->ref, id, false, &ref ); -+ if (ret) -+ return ret; -+ -+ if (ref->locked) { -+ fusion_ref_unlock( ref ); -+ return ref->locked == fusion_id ? -EIO : -EAGAIN; -+ } -+ -+ if (ref->global || ref->local) -+ ret = -ETOOMANYREFS; -+ else -+ ref->locked = fusion_id; -+ -+ fusion_ref_unlock( ref ); -+ -+ return ret; -+} -+ -+int -+fusion_ref_zero_unlock (FusionDev *dev, int id, FusionID fusion_id) -+{ -+ int ret; -+ FusionRef *ref; -+ -+ ret = fusion_ref_lock( &dev->ref, id, false, &ref ); -+ if (ret) -+ return ret; -+ -+ if (ref->locked != fusion_id) { -+ fusion_ref_unlock( ref ); -+ return -EIO; -+ } -+ -+ ref->locked = 0; -+ -+ fusion_ref_unlock( ref ); -+ -+ return 0; -+} -+ -+int -+fusion_ref_stat (FusionDev *dev, int id, int *refs) -+{ -+ int ret; -+ FusionRef *ref; -+ -+ ret = fusion_ref_lock( &dev->ref, id, false, &ref ); -+ if (ret) -+ return ret; -+ -+ *refs = ref->global + ref->local; -+ -+ fusion_ref_unlock( ref ); -+ -+ return 0; -+} -+ -+int -+fusion_ref_watch (FusionDev *dev, -+ int id, -+ int call_id, -+ int call_arg) -+{ -+ int ret; -+ FusionRef *ref; -+ -+ ret = fusion_ref_lock( &dev->ref, id, false, &ref ); -+ if (ret) -+ return ret; -+ -+ if (ref->entry.pid != current->pid) { -+ fusion_ref_unlock( ref ); -+ return -EACCES; -+ } -+ -+ if (ref->global + ref->local == 0) { -+ fusion_ref_unlock( ref ); -+ return -EIO; -+ } -+ -+ if (ref->watched) { -+ fusion_ref_unlock( ref ); -+ return -EBUSY; -+ } -+ -+ ref->watched = true; -+ ref->call_id = call_id; -+ ref->call_arg = call_arg; -+ -+ fusion_ref_notify( ref, true ); -+ -+ fusion_ref_unlock( ref ); -+ -+ return 0; -+} -+ -+int -+fusion_ref_inherit (FusionDev *dev, -+ int id, -+ int from_id) -+{ -+ int ret; -+ FusionRef *ref; -+ FusionRef *from = NULL; -+ -+ ret = fusion_ref_lock( &dev->ref, id, true, &ref ); -+ if (ret) -+ return ret; -+ -+ ret = -EBUSY; -+ if (ref->inherited) -+ goto out; -+ -+ ret = -EINVAL; -+ fusion_list_foreach (from, dev->ref.list) { -+ if (from->entry.id == from_id) { -+ if (down_interruptible( &from->entry.lock )) { -+ ret = -EINTR; -+ from = NULL; -+ } -+ -+ break; -+ } -+ } -+ if (!from) -+ goto out; -+ -+ ret = add_inheritor( ref, from ); -+ if (ret) -+ goto out; -+ -+ ret = propagate_local( dev, ref, from->local ); -+ if (ret) -+ goto out; -+ -+ ref->inherited = from; -+ -+out: -+ if (from) -+ up( &from->entry.lock ); -+ -+ fusion_ref_unlock( ref ); -+ up ( &dev->ref.lock ); -+ -+ return ret; -+} -+ -+int -+fusion_ref_destroy (FusionDev *dev, int id) -+{ -+ return fusion_entry_destroy( &dev->ref, id ); -+} -+ -+void -+fusion_ref_clear_all_local( FusionDev *dev, FusionID fusion_id ) -+{ -+ FusionRef *ref; -+ -+ down( &dev->ref.lock ); -+ -+ fusion_list_foreach (ref, dev->ref.list) -+ clear_local( dev, ref, fusion_id ); -+ -+ up( &dev->ref.lock ); -+} -+ -+int -+fusion_ref_fork_all_local( FusionDev *dev, FusionID fusion_id, FusionID from_id ) -+{ -+ FusionRef *ref; -+ int ret = 0; -+ -+ down( &dev->ref.lock ); -+ -+ fusion_list_foreach (ref, dev->ref.list) { -+ ret = fork_local( dev, ref, fusion_id, from_id ); -+ if (ret) -+ break; -+ } -+ -+ up( &dev->ref.lock ); -+ -+ return ret; -+} -+ -+/**********************************************************************************************************************/ -+ -+static int -+add_local (FusionRef *ref, FusionID fusion_id, int add) -+{ -+ FusionLink *l; -+ LocalRef *local; -+ -+ fusion_list_foreach (l, ref->local_refs) { -+ local = (LocalRef *) l; -+ -+ if (local->fusion_id == fusion_id) { -+ fusion_list_move_to_front( &ref->local_refs, l ); -+ -+ if (local->refs + add < 0) -+ return -EIO; -+ -+ local->refs += add; -+ return 0; -+ } -+ } -+ -+ /* Can only create local node if value is positive. */ -+ if (add <= 0) -+ return -EIO; -+ -+ local = kmalloc (sizeof(LocalRef), GFP_KERNEL); -+ if (!local) -+ return -ENOMEM; -+ -+ local->fusion_id = fusion_id; -+ local->refs = add; -+ -+ fusion_list_prepend (&ref->local_refs, &local->link); -+ -+ return 0; -+} -+ -+static void -+clear_local (FusionDev *dev, FusionRef *ref, FusionID fusion_id) -+{ -+ FusionLink *l; -+ -+ down (&ref->entry.lock); -+ -+ if (ref->locked == fusion_id) { -+ ref->locked = 0; -+ wake_up_interruptible_all (&ref->entry.wait); -+ } -+ -+ fusion_list_foreach (l, ref->local_refs) { -+ LocalRef *local = (LocalRef *) l; -+ -+ if (local->fusion_id == fusion_id) { -+ if (local->refs) -+ propagate_local( dev, ref, - local->refs ); -+ -+ fusion_list_remove( &ref->local_refs, l ); -+ -+ kfree (l); -+ break; -+ } -+ } -+ -+ up (&ref->entry.lock); -+} -+ -+static int -+fork_local (FusionDev *dev, FusionRef *ref, FusionID fusion_id, FusionID from_id) -+{ -+ FusionLink *l; -+ int ret = 0; -+ -+ down (&ref->entry.lock); -+ -+ fusion_list_foreach (l, ref->local_refs) { -+ LocalRef *local = (LocalRef *) l; -+ -+ if (local->fusion_id == from_id) { -+ if (local->refs) { -+ LocalRef *new_local; -+ -+ new_local = kmalloc (sizeof(LocalRef), GFP_KERNEL); -+ if (!new_local) { -+ ret = -ENOMEM; -+ break; -+ } -+ -+ new_local->fusion_id = fusion_id; -+ new_local->refs = local->refs; -+ -+ fusion_list_prepend( &ref->local_refs, &new_local->link ); -+ -+ propagate_local( dev, ref, local->refs ); -+ } -+ break; -+ } -+ } -+ -+ up (&ref->entry.lock); -+ -+ return ret; -+} -+ -+static void -+free_all_local (FusionRef *ref) -+{ -+ FusionLink *l = ref->local_refs; -+ -+ while (l) { -+ FusionLink *next = l->next; -+ -+ kfree (l); -+ -+ l = next; -+ } -+ -+ ref->local_refs = NULL; -+} -+ -+static void -+notify_ref (FusionDev *dev, FusionRef *ref) -+{ -+ if (ref->watched) { -+ FusionCallExecute execute; -+ -+ execute.call_id = ref->call_id; -+ execute.call_arg = ref->call_arg; -+ execute.call_ptr = NULL; -+ -+ fusion_call_execute (dev, 0, &execute); -+ } -+ else -+ wake_up_interruptible_all (&ref->entry.wait); -+} -+ -+static int -+propagate_local( FusionDev *dev, FusionRef *ref, int diff ) -+{ -+ FusionLink *l; -+ -+ /* Recurse into inheritors. */ -+ fusion_list_foreach (l, ref->inheritors) { -+ FusionRef *inheritor = ((Inheritor*) l)->ref; -+ -+ if (down_interruptible( &inheritor->entry.lock )) { -+ printk( KERN_ERR "fusion_ref: propagate_local() interrupted!\n" ); -+ //return -EINTR; -+ } -+ -+ propagate_local( dev, inheritor, diff ); -+ -+ up( &inheritor->entry.lock ); -+ } -+ -+ /* Apply difference. */ -+ ref->local += diff; -+ -+ /* Notify zero count. */ -+ if (ref->local + ref->global == 0) -+ notify_ref( dev, ref ); -+ -+ return 0; -+} -+ -+static int -+add_inheritor(FusionRef *ref, FusionRef *from) -+{ -+ Inheritor *inheritor; -+ -+ inheritor = kmalloc (sizeof(Inheritor), GFP_KERNEL); -+ if (!inheritor) -+ return -ENOMEM; -+ -+ inheritor->ref = ref; -+ -+ fusion_list_prepend( &from->inheritors, &inheritor->link ); -+ -+ return 0; -+} -+ -+static void -+remove_inheritor(FusionRef *ref, FusionRef *from) -+{ -+ FusionLink *l; -+ -+ down( &from->entry.lock ); -+ -+ fusion_list_foreach (l, from->inheritors) { -+ Inheritor *inheritor = (Inheritor*) l; -+ -+ if (inheritor->ref == ref) { -+ fusion_list_remove( &from->inheritors, &inheritor->link ); -+ -+ kfree( l ); -+ break; -+ } -+ } -+ -+ up( &from->entry.lock ); -+} -+ -+static void -+drop_inheritors( FusionDev *dev, FusionRef *ref ) -+{ -+ FusionLink *l = ref->inheritors; -+ -+ while (l) { -+ FusionLink *next = l->next; -+ FusionRef *inheritor = ((Inheritor*) l)->ref; -+ -+ if (down_interruptible( &inheritor->entry.lock )) { -+ printk( KERN_ERR "fusion_ref: drop_inheritors() interrupted!\n" ); -+ //return; -+ } -+ -+ propagate_local( dev, inheritor, - ref->local ); -+ -+ inheritor->inherited = NULL; -+ -+ up( &inheritor->entry.lock ); -+ -+ -+ kfree (l); -+ -+ l = next; -+ } -+ -+ ref->inheritors = NULL; -+} -+ -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/ref.h linux-2.6.22.1/drivers/char/fusion/ref.h ---- linux-2.6.22.1-0rig/drivers/char/fusion/ref.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/ref.h 2006-08-14 11:16:54.000000000 +0200 -@@ -0,0 +1,79 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifndef __FUSION__REF_H__ -+#define __FUSION__REF_H__ -+ -+#include "fusiondev.h" -+#include "types.h" -+ -+ -+/* module init/cleanup */ -+ -+int fusion_ref_init (FusionDev *dev); -+void fusion_ref_deinit (FusionDev *dev); -+ -+ -+/* public API */ -+ -+int fusion_ref_new (FusionDev *dev, -+ int *id); -+ -+int fusion_ref_up (FusionDev *dev, -+ int id, -+ FusionID fusion_id); -+ -+int fusion_ref_down (FusionDev *dev, -+ int id, -+ FusionID fusion_id); -+ -+int fusion_ref_zero_lock (FusionDev *dev, -+ int id, -+ FusionID fusion_id); -+ -+int fusion_ref_zero_trylock (FusionDev *dev, -+ int id, -+ FusionID fusion_id); -+ -+int fusion_ref_zero_unlock (FusionDev *dev, -+ int id, -+ FusionID fusion_id); -+ -+int fusion_ref_stat (FusionDev *dev, -+ int id, -+ int *refs); -+ -+int fusion_ref_watch (FusionDev *dev, -+ int id, -+ int call_id, -+ int call_arg); -+ -+int fusion_ref_inherit (FusionDev *dev, -+ int id, -+ int from); -+ -+int fusion_ref_destroy (FusionDev *dev, -+ int id); -+ -+ -+/* internal functions */ -+ -+void fusion_ref_clear_all_local (FusionDev *dev, -+ FusionID fusion_id); -+ -+int fusion_ref_fork_all_local (FusionDev *dev, -+ FusionID fusion_id, -+ FusionID from_id); -+ -+#endif -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/shmpool.c linux-2.6.22.1/drivers/char/fusion/shmpool.c ---- linux-2.6.22.1-0rig/drivers/char/fusion/shmpool.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/shmpool.c 2007-01-20 05:03:01.000000000 +0100 -@@ -0,0 +1,444 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifdef HAVE_LINUX_CONFIG_H -+#include <linux/config.h> -+#endif -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/smp_lock.h> -+#include <linux/sched.h> -+ -+#include <linux/fusion.h> -+ -+#include "fusiondev.h" -+#include "fusionee.h" -+#include "list.h" -+#include "shmpool.h" -+ -+ -+#define SHM_BASE 0x20010000 /* virtual base address */ -+#define SHM_SIZE 0x1FFEF000 /* size of virtual address space */ -+ -+ -+typedef struct { -+ FusionLink link; -+ unsigned long next_base; -+} AddrEntry; -+ -+ -+typedef struct { -+ FusionLink link; -+ -+ FusionID fusion_id; -+ -+ int count; /* number of attach calls */ -+} SHMPoolNode; -+ -+typedef struct { -+ FusionEntry entry; -+ -+ int max_size; -+ -+ void *addr_base; -+ int size; -+ -+ AddrEntry *addr_entry; -+ -+ FusionLink *nodes; -+ -+ int dispatch_count; -+} FusionSHMPool; -+ -+/******************************************************************************/ -+ -+static SHMPoolNode *get_node ( FusionSHMPool *shmpool, -+ FusionID fusion_id ); -+ -+static void remove_node ( FusionSHMPool *shmpool, -+ FusionID fusion_id ); -+ -+static int fork_node ( FusionSHMPool *shmpool, -+ FusionID fusion_id, -+ FusionID from_id ); -+ -+static void free_all_nodes( FusionSHMPool *shmpool ); -+ -+/******************************************************************************/ -+ -+ -+static DECLARE_MUTEX (addr_lock); -+static FusionLink *addr_entries; -+static unsigned long addr_base = SHM_BASE; -+ -+/******************************************************************************/ -+ -+static AddrEntry * -+add_addr_entry( unsigned long next_base ) -+{ -+ AddrEntry *entry = kmalloc( sizeof(AddrEntry), GFP_KERNEL ); -+ -+ entry->next_base = next_base; -+ -+ fusion_list_prepend( &addr_entries, &entry->link ); -+ -+ return entry; -+} -+ -+/******************************************************************************/ -+ -+static int -+fusion_shmpool_construct( FusionEntry *entry, -+ void *ctx, -+ void *create_ctx ) -+{ -+ FusionSHMPool *shmpool = (FusionSHMPool*) entry; -+ FusionSHMPoolNew *poolnew = create_ctx; -+ -+ down( &addr_lock ); -+ -+ if (addr_base + poolnew->max_size >= SHM_BASE + SHM_SIZE) { -+ up( &addr_lock ); -+ printk( KERN_WARNING "%s: virtual address space exhausted! (FIXME)\n", __FUNCTION__ ); -+ return -ENOSPC; -+ } -+ -+ shmpool->max_size = poolnew->max_size; -+ shmpool->addr_base = poolnew->addr_base = (void*) addr_base; -+ -+ addr_base += PAGE_ALIGN(poolnew->max_size) + PAGE_SIZE; /* fence page */ -+ -+ shmpool->addr_entry = add_addr_entry( addr_base ); -+ -+ up( &addr_lock ); -+ -+ return 0; -+} -+ -+static void -+fusion_shmpool_destruct( FusionEntry *entry, -+ void *ctx ) -+{ -+ AddrEntry *addr_entry; -+ FusionSHMPool *shmpool = (FusionSHMPool*) entry; -+ -+ free_all_nodes( shmpool ); -+ -+ -+ down( &addr_lock ); -+ -+ fusion_list_remove( &addr_entries, &shmpool->addr_entry->link ); -+ -+ -+ /* -+ * free trailing address space -+ */ -+ -+ addr_base = SHM_BASE; -+ -+ fusion_list_foreach (addr_entry, addr_entries) { -+ if (addr_entry->next_base > addr_base) -+ addr_base = addr_entry->next_base; -+ } -+ -+ up( &addr_lock ); -+} -+ -+static int -+fusion_shmpool_print( FusionEntry *entry, -+ void *ctx, -+ char *buf ) -+{ -+ int num = 0; -+ FusionSHMPool *shmpool = (FusionSHMPool*) entry; -+ FusionLink *node = shmpool->nodes; -+ -+ fusion_list_foreach (node, shmpool->nodes) { -+ num++; -+ } -+ -+ return sprintf( buf, "0x%p [0x%x] - 0x%x, %dx dispatch, %d nodes\n", -+ shmpool->addr_base, shmpool->max_size, shmpool->size, -+ shmpool->dispatch_count, num ); -+} -+ -+ -+FUSION_ENTRY_CLASS( FusionSHMPool, shmpool, fusion_shmpool_construct, -+ fusion_shmpool_destruct, fusion_shmpool_print ) -+ -+/******************************************************************************/ -+ -+int -+fusion_shmpool_init (FusionDev *dev) -+{ -+ fusion_entries_init( &dev->shmpool, &shmpool_class, dev ); -+ -+ create_proc_read_entry( "shmpools", 0, dev->proc_dir, -+ fusion_entries_read_proc, &dev->shmpool ); -+ -+ return 0; -+} -+ -+void -+fusion_shmpool_deinit (FusionDev *dev) -+{ -+ remove_proc_entry ("shmpools", dev->proc_dir); -+ -+ fusion_entries_deinit( &dev->shmpool ); -+} -+ -+/******************************************************************************/ -+ -+int -+fusion_shmpool_new (FusionDev *dev, -+ FusionSHMPoolNew *pool) -+{ -+ if (pool->max_size <= 0) -+ return -EINVAL; -+ -+ return fusion_entry_create( &dev->shmpool, &pool->pool_id, pool ); -+} -+ -+int -+fusion_shmpool_attach (FusionDev *dev, -+ FusionSHMPoolAttach *attach, -+ FusionID fusion_id) -+{ -+ int ret; -+ SHMPoolNode *node; -+ FusionSHMPool *shmpool; -+ -+ ret = fusion_shmpool_lock( &dev->shmpool, attach->pool_id, false, &shmpool ); -+ if (ret) -+ return ret; -+ -+ dev->stat.shmpool_attach++; -+ -+ node = get_node (shmpool, fusion_id); -+ if (!node) { -+ node = kmalloc (sizeof(SHMPoolNode), GFP_KERNEL); -+ if (!node) { -+ fusion_shmpool_unlock( shmpool ); -+ return -ENOMEM; -+ } -+ -+ node->fusion_id = fusion_id; -+ node->count = 1; -+ -+ fusion_list_prepend (&shmpool->nodes, &node->link); -+ } -+ else -+ node->count++; -+ -+ attach->addr_base = shmpool->addr_base; -+ attach->size = shmpool->size; -+ -+ fusion_shmpool_unlock( shmpool ); -+ -+ return 0; -+} -+ -+int -+fusion_shmpool_detach (FusionDev *dev, int id, FusionID fusion_id) -+{ -+ int ret; -+ SHMPoolNode *node; -+ FusionSHMPool *shmpool; -+ -+ ret = fusion_shmpool_lock( &dev->shmpool, id, false, &shmpool ); -+ if (ret) -+ return ret; -+ -+ dev->stat.shmpool_detach++; -+ -+ node = get_node (shmpool, fusion_id); -+ if (!node) { -+ fusion_shmpool_unlock( shmpool ); -+ return -EIO; -+ } -+ -+ if (! --node->count) { -+ fusion_list_remove (&shmpool->nodes, &node->link); -+ kfree (node); -+ } -+ -+ fusion_shmpool_unlock( shmpool ); -+ -+ return 0; -+} -+ -+int -+fusion_shmpool_dispatch( FusionDev *dev, -+ FusionSHMPoolDispatch *dispatch, -+ Fusionee *fusionee ) -+{ -+ int ret; -+ FusionLink *l; -+ FusionSHMPool *shmpool; -+ FusionSHMPoolMessage message; -+ FusionID fusion_id = fusionee_id( fusionee ); -+ -+ if (dispatch->size <= 0) -+ return -EINVAL; -+ -+ ret = fusion_shmpool_lock( &dev->shmpool, dispatch->pool_id, false, &shmpool ); -+ if (ret) -+ return ret; -+ -+ message.type = FSMT_REMAP; -+ message.size = dispatch->size; -+ -+ shmpool->dispatch_count++; -+ -+ shmpool->size = dispatch->size; -+ -+ fusion_list_foreach (l, shmpool->nodes) { -+ SHMPoolNode *node = (SHMPoolNode *) l; -+ -+ if (node->fusion_id == fusion_id) -+ continue; -+ -+ fusionee_send_message (dev, fusionee, node->fusion_id, FMT_SHMPOOL, -+ shmpool->entry.id, sizeof(message), &message); -+ } -+ -+ fusion_shmpool_unlock( shmpool ); -+ -+ return 0; -+} -+ -+int -+fusion_shmpool_destroy (FusionDev *dev, int id) -+{ -+ return fusion_entry_destroy( &dev->shmpool, id ); -+} -+ -+void -+fusion_shmpool_detach_all (FusionDev *dev, FusionID fusion_id) -+{ -+ FusionLink *l; -+ -+ down (&dev->shmpool.lock); -+ -+ fusion_list_foreach (l, dev->shmpool.list) { -+ FusionSHMPool *shmpool = (FusionSHMPool *) l; -+ -+ remove_node (shmpool, fusion_id); -+ } -+ -+ up (&dev->shmpool.lock); -+} -+ -+int -+fusion_shmpool_fork_all( FusionDev *dev, -+ FusionID fusion_id, -+ FusionID from_id ) -+{ -+ FusionLink *l; -+ int ret = 0; -+ -+ down (&dev->shmpool.lock); -+ -+ fusion_list_foreach (l, dev->shmpool.list) { -+ FusionSHMPool *shmpool = (FusionSHMPool *) l; -+ -+ ret = fork_node( shmpool, fusion_id, from_id ); -+ if (ret) -+ break; -+ } -+ -+ up (&dev->shmpool.lock); -+ -+ return ret; -+} -+ -+/******************************************************************************/ -+ -+static SHMPoolNode * -+get_node (FusionSHMPool *shmpool, -+ FusionID fusion_id) -+{ -+ SHMPoolNode *node; -+ -+ fusion_list_foreach (node, shmpool->nodes) { -+ if (node->fusion_id == fusion_id) -+ return node; -+ } -+ -+ return NULL; -+} -+ -+static void -+remove_node (FusionSHMPool *shmpool, FusionID fusion_id) -+{ -+ SHMPoolNode *node; -+ -+ down (&shmpool->entry.lock); -+ -+ fusion_list_foreach (node, shmpool->nodes) { -+ if (node->fusion_id == fusion_id) { -+ fusion_list_remove (&shmpool->nodes, &node->link); -+ break; -+ } -+ } -+ -+ up (&shmpool->entry.lock); -+} -+ -+static int -+fork_node (FusionSHMPool *shmpool, FusionID fusion_id, FusionID from_id) -+{ -+ int ret = 0; -+ SHMPoolNode *node; -+ -+ down (&shmpool->entry.lock); -+ -+ fusion_list_foreach (node, shmpool->nodes) { -+ if (node->fusion_id == from_id) { -+ SHMPoolNode *new_node; -+ -+ new_node = kmalloc (sizeof(SHMPoolNode), GFP_KERNEL); -+ if (!new_node) { -+ ret = -ENOMEM; -+ break; -+ } -+ -+ new_node->fusion_id = fusion_id; -+ new_node->count = node->count; -+ -+ fusion_list_prepend (&shmpool->nodes, &new_node->link); -+ -+ break; -+ } -+ } -+ -+ up (&shmpool->entry.lock); -+ -+ return ret; -+} -+ -+static void -+free_all_nodes (FusionSHMPool *shmpool) -+ -+{ -+ FusionLink *n; -+ SHMPoolNode *node; -+ -+ fusion_list_foreach_safe (node, n, shmpool->nodes) { -+ kfree (node); -+ } -+ -+ shmpool->nodes = NULL; -+} -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/shmpool.h linux-2.6.22.1/drivers/char/fusion/shmpool.h ---- linux-2.6.22.1-0rig/drivers/char/fusion/shmpool.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/shmpool.h 2007-01-20 05:03:01.000000000 +0100 -@@ -0,0 +1,59 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifndef __FUSION__SHMPOOL_H__ -+#define __FUSION__SHMPOOL_H__ -+ -+#include "fusiondev.h" -+#include "types.h" -+ -+ -+/* module init/cleanup */ -+ -+int fusion_shmpool_init (FusionDev *dev); -+void fusion_shmpool_deinit (FusionDev *dev); -+ -+ -+/* public API */ -+ -+int fusion_shmpool_new (FusionDev *dev, -+ FusionSHMPoolNew *pool); -+ -+int fusion_shmpool_attach (FusionDev *dev, -+ FusionSHMPoolAttach *attach, -+ FusionID fusion_id); -+ -+int fusion_shmpool_detach (FusionDev *dev, -+ int id, -+ FusionID fusion_id); -+ -+int fusion_shmpool_dispatch (FusionDev *dev, -+ FusionSHMPoolDispatch *dispatch, -+ Fusionee *fusionee ); -+ -+int fusion_shmpool_destroy (FusionDev *dev, -+ int id); -+ -+ -+/* internal functions */ -+ -+void fusion_shmpool_detach_all (FusionDev *dev, -+ FusionID fusion_id); -+ -+int fusion_shmpool_fork_all (FusionDev *dev, -+ FusionID fusion_id, -+ FusionID from_id); -+ -+#endif -+ -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/skirmish.c linux-2.6.22.1/drivers/char/fusion/skirmish.c ---- linux-2.6.22.1-0rig/drivers/char/fusion/skirmish.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/skirmish.c 2007-01-06 14:09:45.000000000 +0100 -@@ -0,0 +1,397 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifdef HAVE_LINUX_CONFIG_H -+#include <linux/config.h> -+#endif -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/smp_lock.h> -+#include <linux/sched.h> -+ -+#include <linux/fusion.h> -+ -+#include "fusiondev.h" -+#include "fusionee.h" -+#include "list.h" -+#include "skirmish.h" -+ -+ -+#define MAX_PRE_ACQUISITIONS 32 -+ -+ -+typedef struct __FUSION_FusionSkirmish FusionSkirmish; -+ -+struct __FUSION_FusionSkirmish { -+ FusionEntry entry; -+ -+ int lock_fid; /* non-zero if locked */ -+ int lock_pid; -+ int lock_count; -+ -+ int lock_total; -+ -+#ifdef FUSION_DEBUG_SKIRMISH_DEADLOCK -+ int pre_acquis[MAX_PRE_ACQUISITIONS]; -+ -+ bool outer; -+#endif -+}; -+ -+static int -+fusion_skirmish_print( FusionEntry *entry, -+ void *ctx, -+ char *buf ) -+{ -+ int written = 0; -+ FusionSkirmish *skirmish = (FusionSkirmish*) entry; -+ -+#ifdef FUSION_DEBUG_SKIRMISH_DEADLOCK -+ int i, n; -+ -+ -+ for (i=0, n=0; i<MAX_PRE_ACQUISITIONS; i++) { -+ if (skirmish->pre_acquis[i]) { -+ n++; -+ } -+ } -+ -+ written += sprintf( buf + written, "[%2d]%s", n, skirmish->outer ? "." : " " ); -+ -+ for (i=0, n=0; i<MAX_PRE_ACQUISITIONS; i++) { -+ if (skirmish->pre_acquis[i]) { -+ written += sprintf( buf + written, "%s%02x", n ? "," : "", skirmish->pre_acquis[i] - 1 ); -+ -+ n++; -+ } -+ } -+#endif -+ -+ if (skirmish->lock_fid) { -+ if (skirmish->entry.waiters) -+ return sprintf( buf + written, " - %dx [0x%08x] (%d) %d WAITING\n", -+ skirmish->lock_count, skirmish->lock_fid, -+ skirmish->lock_pid, skirmish->entry.waiters ) + written; -+ else -+ return sprintf( buf + written, " - %dx [0x%08x] (%d)\n", -+ skirmish->lock_count, skirmish->lock_fid, -+ skirmish->lock_pid ) + written; -+ } -+ -+ return sprintf( buf + written, "\n" ) + written; -+} -+ -+FUSION_ENTRY_CLASS( FusionSkirmish, skirmish, NULL, NULL, fusion_skirmish_print ) -+ -+/******************************************************************************/ -+ -+int -+fusion_skirmish_init (FusionDev *dev) -+{ -+ fusion_entries_init( &dev->skirmish, &skirmish_class, dev ); -+ -+ create_proc_read_entry( "skirmishs", 0, dev->proc_dir, -+ fusion_entries_read_proc, &dev->skirmish ); -+ -+ return 0; -+} -+ -+void -+fusion_skirmish_deinit (FusionDev *dev) -+{ -+ remove_proc_entry ("skirmishs", dev->proc_dir); -+ -+ fusion_entries_deinit( &dev->skirmish ); -+} -+ -+/******************************************************************************/ -+ -+int -+fusion_skirmish_new (FusionDev *dev, int *ret_id) -+{ -+ return fusion_entry_create( &dev->skirmish, ret_id, NULL ); -+} -+ -+int -+fusion_skirmish_prevail (FusionDev *dev, int id, int fusion_id) -+{ -+ int ret; -+ FusionSkirmish *skirmish; -+#ifdef FUSION_DEBUG_SKIRMISH_DEADLOCK -+ FusionSkirmish *s; -+ int i; -+ bool outer = true; -+#endif -+ -+ dev->stat.skirmish_prevail_swoop++; -+ -+ ret = fusion_skirmish_lock( &dev->skirmish, id, true, &skirmish ); -+ if (ret) -+ return ret; -+ -+ if (skirmish->lock_pid == current->pid) { -+ skirmish->lock_count++; -+ skirmish->lock_total++; -+ fusion_skirmish_unlock( skirmish ); -+ up( &dev->skirmish.lock ); -+ return 0; -+ } -+ -+#ifdef FUSION_DEBUG_SKIRMISH_DEADLOCK -+ /* look in currently acquired skirmishs for this one being -+ a pre-acquisition, indicating a potential deadlock */ -+ fusion_list_foreach (s, dev->skirmish.list) { -+ if (s->lock_pid != current->pid) -+ continue; -+ -+ outer = false; -+ -+ for (i=0; i<MAX_PRE_ACQUISITIONS; i++) { -+ if (s->pre_acquis[i] == id + 1) { -+ printk( KERN_DEBUG "FusionSkirmish: Potential deadlock " -+ "between locked 0x%x and to be locked 0x%x in world %d!\n", -+ s->entry.id, skirmish->entry.id, dev->index ); -+ } -+ } -+ } -+ -+ if (outer) -+ skirmish->outer = true; -+ -+ /* remember all previously acquired skirmishs being pre-acquisitions for -+ this one, to detect potential deadlocks due to a lock order twist */ -+ fusion_list_foreach (s, dev->skirmish.list) { -+ int free = -1; -+ -+ if (s->lock_pid != current->pid) -+ continue; -+ -+ for (i=0; i<MAX_PRE_ACQUISITIONS; i++) { -+ if (skirmish->pre_acquis[i]) { -+ if (skirmish->pre_acquis[i] == s->entry.id + 1) { -+ break; -+ } -+ } -+ else -+ free = i; -+ } -+ -+ /* not found? */ -+ if (i == MAX_PRE_ACQUISITIONS) { -+ if (free != -1) { -+ skirmish->pre_acquis[free] = s->entry.id + 1; -+ } -+ else { -+ printk( KERN_DEBUG "FusionSkirmish: Too many pre-acquisitions to remember.\n" ); -+ -+ printk( KERN_DEBUG " [ '%s' ] <- ", skirmish->entry.name ); -+ -+ for (i=0; i<MAX_PRE_ACQUISITIONS; i++) -+ printk( "0x%03x ", skirmish->pre_acquis[i] - 1 ); -+ -+ printk( "\n" ); -+ } -+ } -+ } -+#endif -+ -+ up( &dev->skirmish.lock ); -+ -+ while (skirmish->lock_pid) { -+ ret = fusion_skirmish_wait( skirmish, NULL ); -+ if (ret) -+ return ret; -+ } -+ -+ skirmish->lock_fid = fusion_id; -+ skirmish->lock_pid = current->pid; -+ skirmish->lock_count = 1; -+ -+ skirmish->lock_total++; -+ -+ fusion_skirmish_unlock( skirmish ); -+ -+ return 0; -+} -+ -+int -+fusion_skirmish_swoop (FusionDev *dev, int id, int fusion_id) -+{ -+ int ret; -+ FusionSkirmish *skirmish; -+ -+ ret = fusion_skirmish_lock( &dev->skirmish, id, false, &skirmish ); -+ if (ret) -+ return ret; -+ -+ dev->stat.skirmish_prevail_swoop++; -+ -+ if (skirmish->lock_fid) { -+ if (skirmish->lock_pid == current->pid) { -+ skirmish->lock_count++; -+ skirmish->lock_total++; -+ fusion_skirmish_unlock( skirmish ); -+ return 0; -+ } -+ -+ fusion_skirmish_unlock( skirmish ); -+ -+ return -EAGAIN; -+ } -+ -+ skirmish->lock_fid = fusion_id; -+ skirmish->lock_pid = current->pid; -+ skirmish->lock_count = 1; -+ -+ skirmish->lock_total++; -+ -+ fusion_skirmish_unlock( skirmish ); -+ -+ return 0; -+} -+ -+int -+fusion_skirmish_lock_count (FusionDev *dev, int id, int fusion_id, int *ret_lock_count) -+{ -+ int ret; -+ FusionSkirmish *skirmish; -+ -+ ret = fusion_skirmish_lock( &dev->skirmish, id, false, &skirmish ); -+ if (ret) -+ return ret; -+ -+ if (skirmish->lock_fid == fusion_id && -+ skirmish->lock_pid == current->pid) -+ { -+ *ret_lock_count = skirmish->lock_count; -+ } -+ else -+ { -+ *ret_lock_count = 0; -+ } -+ -+ fusion_skirmish_unlock( skirmish ); -+ -+ return 0; -+} -+ -+int -+fusion_skirmish_dismiss (FusionDev *dev, int id, int fusion_id) -+{ -+ int ret; -+ FusionSkirmish *skirmish; -+ -+ ret = fusion_skirmish_lock( &dev->skirmish, id, false, &skirmish ); -+ if (ret) -+ return ret; -+ -+ dev->stat.skirmish_dismiss++; -+ -+ if (skirmish->lock_pid != current->pid) { -+ fusion_skirmish_unlock( skirmish ); -+ return -EIO; -+ } -+ -+ if (--skirmish->lock_count == 0) { -+ skirmish->lock_fid = 0; -+ skirmish->lock_pid = 0; -+ -+ fusion_skirmish_notify( skirmish, true ); -+ } -+ -+ fusion_skirmish_unlock( skirmish ); -+ -+ return 0; -+} -+ -+int -+fusion_skirmish_destroy (FusionDev *dev, int id) -+{ -+#ifdef FUSION_DEBUG_SKIRMISH_DEADLOCK -+ int i; -+ FusionSkirmish *s; -+ -+ /* Lock entries. */ -+ if (down_interruptible( &dev->skirmish.lock )) -+ return -EINTR; -+ -+ /* remove from all pre-acquisition lists */ -+ fusion_list_foreach (s, dev->skirmish.list) { -+ for (i=0; i<MAX_PRE_ACQUISITIONS; i++) { -+ if (s->pre_acquis[i] == id + 1) -+ s->pre_acquis[i] = 0; -+ } -+ } -+ -+ up( &dev->skirmish.lock ); -+ -+ /* FIXME: gap? */ -+#endif -+ -+ return fusion_entry_destroy( &dev->skirmish, id ); -+} -+ -+void -+fusion_skirmish_dismiss_all (FusionDev *dev, int fusion_id) -+{ -+ FusionLink *l; -+ -+ down (&dev->skirmish.lock); -+ -+ fusion_list_foreach (l, dev->skirmish.list) { -+ FusionSkirmish *skirmish = (FusionSkirmish *) l; -+ -+ down (&skirmish->entry.lock); -+ -+ if (skirmish->lock_fid == fusion_id) { -+ skirmish->lock_fid = 0; -+ skirmish->lock_pid = 0; -+ skirmish->lock_count = 0; -+ -+ wake_up_interruptible_all (&skirmish->entry.wait); -+ } -+ -+ up (&skirmish->entry.lock); -+ } -+ -+ up (&dev->skirmish.lock); -+} -+ -+void -+fusion_skirmish_dismiss_all_from_pid (FusionDev *dev, int pid) -+{ -+ FusionLink *l; -+ -+ down (&dev->skirmish.lock); -+ -+ fusion_list_foreach (l, dev->skirmish.list) { -+ FusionSkirmish *skirmish = (FusionSkirmish *) l; -+ -+ down (&skirmish->entry.lock); -+ -+ if (skirmish->lock_pid == pid) { -+ skirmish->lock_fid = 0; -+ skirmish->lock_pid = 0; -+ skirmish->lock_count = 0; -+ -+ wake_up_interruptible_all (&skirmish->entry.wait); -+ } -+ -+ up (&skirmish->entry.lock); -+ } -+ -+ up (&dev->skirmish.lock); -+} -+ -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/skirmish.h linux-2.6.22.1/drivers/char/fusion/skirmish.h ---- linux-2.6.22.1-0rig/drivers/char/fusion/skirmish.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/skirmish.h 2006-06-30 10:54:55.000000000 +0200 -@@ -0,0 +1,62 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002-2003 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifndef __FUSION__SKIRMISH_H__ -+#define __FUSION__SKIRMISH_H__ -+ -+#include "fusiondev.h" -+#include "types.h" -+ -+ -+/* module init/cleanup */ -+ -+int fusion_skirmish_init (FusionDev *dev); -+void fusion_skirmish_deinit (FusionDev *dev); -+ -+ -+/* public API */ -+ -+int fusion_skirmish_new (FusionDev *dev, -+ int *id); -+ -+int fusion_skirmish_prevail (FusionDev *dev, -+ int id, -+ int fusion_id); -+ -+int fusion_skirmish_swoop (FusionDev *dev, -+ int id, -+ int fusion_id); -+ -+int fusion_skirmish_lock_count (FusionDev *dev, -+ int id, -+ int fusion_id, -+ int *ret_lock_count); -+ -+int fusion_skirmish_dismiss (FusionDev *dev, -+ int id, -+ int fusion_id); -+ -+int fusion_skirmish_destroy (FusionDev *dev, -+ int id); -+ -+ -+/* internal functions */ -+ -+void fusion_skirmish_dismiss_all (FusionDev *dev, -+ int fusion_id); -+ -+void fusion_skirmish_dismiss_all_from_pid (FusionDev *dev, -+ int pid); -+ -+#endif -diff -urN linux-2.6.22.1-0rig/drivers/char/fusion/types.h linux-2.6.22.1/drivers/char/fusion/types.h ---- linux-2.6.22.1-0rig/drivers/char/fusion/types.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/drivers/char/fusion/types.h 2007-01-20 05:03:01.000000000 +0100 -@@ -0,0 +1,29 @@ -+/* -+ * Fusion Kernel Module -+ * -+ * (c) Copyright 2002 Convergence GmbH -+ * -+ * Written by Denis Oliver Kropp <dok@directfb.org> -+ * -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#ifndef __FUSION__TYPES_H__ -+#define __FUSION__TYPES_H__ -+ -+#include <linux/version.h> -+ -+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) -+typedef enum { -+ false = 0, -+ true = !false -+} bool; -+#endif -+ -+typedef struct __Fusion_Fusionee Fusionee; -+ -+#endif -diff -urN linux-2.6.22.1-0rig/drivers/char/Kconfig linux-2.6.22.1/drivers/char/Kconfig ---- linux-2.6.22.1-0rig/drivers/char/Kconfig 2007-07-10 20:56:30.000000000 +0200 -+++ linux-2.6.22.1/drivers/char/Kconfig 2007-08-12 19:30:42.000000000 +0200 -@@ -484,6 +484,8 @@ - All modern Linux systems use the Unix98 ptys. Say Y unless - you're on an embedded system and want to conserve memory. - -+source "drivers/char/fusion/Kconfig" -+ - config LEGACY_PTYS - bool "Legacy (BSD) PTY support" - default y -diff -urN linux-2.6.22.1-0rig/drivers/char/Makefile linux-2.6.22.1/drivers/char/Makefile ---- linux-2.6.22.1-0rig/drivers/char/Makefile 2007-07-10 20:56:30.000000000 +0200 -+++ linux-2.6.22.1/drivers/char/Makefile 2007-08-12 19:45:20.000000000 +0200 -@@ -100,6 +100,7 @@ - obj-$(CONFIG_DRM) += drm/ - obj-$(CONFIG_PCMCIA) += pcmcia/ - obj-$(CONFIG_IPMI_HANDLER) += ipmi/ -+obj-$(CONFIG_FUSION_DEVICE) += fusion/ - - obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o - obj-$(CONFIG_TCG_TPM) += tpm/ -diff -urN linux-2.6.22.1-0rig/include/linux/fusion.h linux-2.6.22.1/include/linux/fusion.h ---- linux-2.6.22.1-0rig/include/linux/fusion.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.22.1/include/linux/fusion.h 2007-01-29 01:43:50.000000000 +0100 -@@ -0,0 +1,277 @@ -+#ifndef __LINUX__FUSION_H__ -+#define __LINUX__FUSION_H__ -+ -+#include <asm/ioctl.h> -+ -+/* -+ * Fusion Kernel Device API Version -+ */ -+#define FUSION_API_MAJOR 3 /* Increased if backward compatibility is dropped. */ -+#define FUSION_API_MINOR 2 /* Increased if new features are added. */ -+ -+/* -+ * The Fusion ID is a unique identifier for one process consisting of threads. -+ */ -+typedef unsigned long FusionID; -+ -+#define FUSION_ID_MASTER 1 /* This is the fusion id of the master (first process). */ -+ -+/* -+ * Entering a world -+ */ -+typedef struct { -+ struct { -+ int major; /* Must be set to FUSION_API_MAJOR before entering. */ -+ int minor; /* Must be set to FUSION_API_MINOR before entering. */ -+ } api; -+ -+ FusionID fusion_id; /* Returns the fusion id of the entering process. */ -+} FusionEnter; -+ -+/* -+ * Forking in world -+ */ -+typedef struct { -+ FusionID fusion_id; /* Returns the fusion id of the new (forked) fusionee. */ -+} FusionFork; -+ -+/* -+ * Sending a message -+ */ -+typedef struct { -+ FusionID fusion_id; /* recipient */ -+ -+ int msg_id; /* optional message identifier */ -+ int msg_size; /* message size, must be greater than zero */ -+ const void *msg_data; /* message data, must not be NULL */ -+} FusionSendMessage; -+ -+/* -+ * Receiving a message -+ */ -+typedef enum { -+ FMT_SEND, /* msg_id is an optional custom id */ -+ FMT_CALL, /* msg_id is the call id */ -+ FMT_REACTOR, /* msg_id is the reactor id */ -+ FMT_SHMPOOL /* msg_id is the pool id */ -+} FusionMessageType; -+ -+typedef struct { -+ FusionMessageType msg_type; /* type (origin) of message */ -+ -+ int msg_id; /* message id (custom id or call/reactor/pool id) */ -+ int msg_size; /* size of the following message data */ -+ -+ /* message data follows */ -+} FusionReadMessage; -+ -+/* -+ * Dispatching a message via a reactor -+ */ -+typedef struct { -+ int reactor_id; -+ int self; -+ -+ int msg_size; /* message size, must be greater than zero */ -+ const void *msg_data; /* message data, must not be NULL */ -+} FusionReactorDispatch; -+ -+/* -+ * Calling (synchronous RPC) -+ */ -+typedef struct { -+ int call_id; /* new call id returned */ -+ -+ void *handler; /* function pointer of handler to install */ -+ void *ctx; /* optional handler context */ -+} FusionCallNew; -+ -+typedef enum { -+ FCEF_NONE = 0x00000000, -+ FCEF_ONEWAY = 0x00000001, -+ FCEF_ALL = 0x00000001 -+} FusionCallExecFlags; -+ -+typedef struct { -+ int ret_val; /* return value of the call */ -+ -+ int call_id; /* id of the requested call, each call has a fixed owner */ -+ -+ int call_arg; /* optional int argument */ -+ void *call_ptr; /* optional pointer argument (shared memory) */ -+ -+ FusionCallExecFlags flags; /* execution flags */ -+} FusionCallExecute; -+ -+typedef struct { -+ int call_id; /* id of currently executing call */ -+ -+ int val; /* value to return */ -+} FusionCallReturn; -+ -+typedef struct { -+ void *handler; /* function pointer of handler to call */ -+ void *ctx; /* optional handler context */ -+ -+ int caller; /* fusion id of the caller or zero if called from Fusion */ -+ int call_arg; /* optional call parameter */ -+ void *call_ptr; /* optional call parameter */ -+} FusionCallMessage; -+ -+/* -+ * Watching a reference -+ * -+ * This information is needed to have a specific call being executed if the -+ * reference count reaches zero. Currently one watch per reference is allowed. -+ * -+ * The call is made by Fusion and therefor has a caller id of zero. -+ * -+ */ -+typedef struct { -+ int id; /* id of the reference to watch */ -+ -+ int call_id; /* id of the call to execute */ -+ int call_arg; /* optional call parameter, e.g. the id of a user -+ space resource associated with that reference */ -+} FusionRefWatch; -+ -+/* -+ * Inheriting local count from other reference -+ */ -+typedef struct { -+ int id; /* own reference id */ -+ int from; /* id of the reference to inherit from */ -+} FusionRefInherit; -+ -+/* -+ * Killing other fusionees (experimental) -+ */ -+typedef struct { -+ FusionID fusion_id; /* fusionee to kill, zero means all but ourself */ -+ int signal; /* signal to be delivered, e.g. SIGTERM */ -+ int timeout_ms; /* -1 means no timeout, 0 means infinite, otherwise the -+ max. time to wait until the fusionee(s) terminated */ -+} FusionKill; -+ -+ -+/* -+ * Shared memory pools -+ */ -+typedef struct { -+ int max_size; /* Maximum size that this pool will be allowed to grow to. */ -+ -+ int pool_id; /* Returns the new pool id. */ -+ void *addr_base; /* Returns the base of the reserved virtual memory address space. */ -+} FusionSHMPoolNew; -+ -+typedef struct { -+ int pool_id; /* The id of the pool to attach to. */ -+ -+ void *addr_base; /* Returns the base of the reserved virtual memory address space. */ -+ int size; /* Returns the current size of the pool. */ -+} FusionSHMPoolAttach; -+ -+typedef struct { -+ int pool_id; /* The id of the pool to notify. */ -+ -+ int size; /* New size of the pool. */ -+} FusionSHMPoolDispatch; -+ -+typedef enum { -+ FSMT_REMAP, /* Remap the pool due to a change of its size. */ -+ FSMT_UNMAP /* Unmap the pool due to its destruction. */ -+} FusionSHMPoolMessageType; -+ -+typedef struct { -+ FusionSHMPoolMessageType type; /* Type of the message. */ -+ -+ int size; /* New size of the pool, if type is FSMT_REMAP. */ -+} FusionSHMPoolMessage; -+ -+ -+/* -+ * Fusion types -+ */ -+typedef enum { -+ FT_LOUNGE, -+ FT_MESSAGING, -+ FT_CALL, -+ FT_REF, -+ FT_SKIRMISH, -+ FT_PROPERTY, -+ FT_REACTOR, -+ FT_SHMPOOL -+} FusionType; -+ -+ -+/* -+ * Set attributes like 'name' for an entry of the specified type. -+ */ -+#define FUSION_ENTRY_INFO_NAME_LENGTH 24 -+ -+typedef struct { -+ FusionType type; -+ int id; -+ -+ char name[FUSION_ENTRY_INFO_NAME_LENGTH]; -+} FusionEntryInfo; -+ -+ -+ -+#define FUSION_ENTER _IOR(FT_LOUNGE, 0x00, FusionEnter) -+#define FUSION_UNBLOCK _IO (FT_LOUNGE, 0x01) -+#define FUSION_KILL _IOW(FT_LOUNGE, 0x02, FusionKill) -+ -+#define FUSION_ENTRY_SET_INFO _IOW(FT_LOUNGE, 0x03, FusionEntryInfo) -+#define FUSION_ENTRY_GET_INFO _IOW(FT_LOUNGE, 0x04, FusionEntryInfo) -+ -+#define FUSION_FORK _IOW(FT_LOUNGE, 0x05, FusionFork) -+ -+#define FUSION_SEND_MESSAGE _IOW(FT_MESSAGING, 0x00, FusionSendMessage) -+ -+#define FUSION_CALL_NEW _IOW(FT_CALL, 0x00, FusionCallNew) -+#define FUSION_CALL_EXECUTE _IOW(FT_CALL, 0x01, FusionCallExecute) -+#define FUSION_CALL_RETURN _IOW(FT_CALL, 0x02, FusionCallReturn) -+#define FUSION_CALL_DESTROY _IOW(FT_CALL, 0x03, int) -+ -+#define FUSION_REF_NEW _IOW(FT_REF, 0x00, int) -+#define FUSION_REF_UP _IOW(FT_REF, 0x01, int) -+#define FUSION_REF_UP_GLOBAL _IOW(FT_REF, 0x02, int) -+#define FUSION_REF_DOWN _IOW(FT_REF, 0x03, int) -+#define FUSION_REF_DOWN_GLOBAL _IOW(FT_REF, 0x04, int) -+#define FUSION_REF_ZERO_LOCK _IOW(FT_REF, 0x05, int) -+#define FUSION_REF_ZERO_TRYLOCK _IOW(FT_REF, 0x06, int) -+#define FUSION_REF_UNLOCK _IOW(FT_REF, 0x07, int) -+#define FUSION_REF_STAT _IOW(FT_REF, 0x08, int) -+#define FUSION_REF_WATCH _IOW(FT_REF, 0x09, FusionRefWatch) -+#define FUSION_REF_INHERIT _IOW(FT_REF, 0x0A, FusionRefInherit) -+#define FUSION_REF_DESTROY _IOW(FT_REF, 0x0B, int) -+ -+#define FUSION_SKIRMISH_NEW _IOW(FT_SKIRMISH, 0x00, int) -+#define FUSION_SKIRMISH_PREVAIL _IOW(FT_SKIRMISH, 0x01, int) -+#define FUSION_SKIRMISH_SWOOP _IOW(FT_SKIRMISH, 0x02, int) -+#define FUSION_SKIRMISH_DISMISS _IOW(FT_SKIRMISH, 0x03, int) -+#define FUSION_SKIRMISH_DESTROY _IOW(FT_SKIRMISH, 0x04, int) -+#define FUSION_SKIRMISH_LOCK_COUNT _IOW(FT_SKIRMISH, 0x05, int) -+ -+#define FUSION_PROPERTY_NEW _IOW(FT_PROPERTY, 0x00, int) -+#define FUSION_PROPERTY_LEASE _IOW(FT_PROPERTY, 0x01, int) -+#define FUSION_PROPERTY_PURCHASE _IOW(FT_PROPERTY, 0x02, int) -+#define FUSION_PROPERTY_CEDE _IOW(FT_PROPERTY, 0x03, int) -+#define FUSION_PROPERTY_HOLDUP _IOW(FT_PROPERTY, 0x04, int) -+#define FUSION_PROPERTY_DESTROY _IOW(FT_PROPERTY, 0x05, int) -+ -+#define FUSION_REACTOR_NEW _IOW(FT_REACTOR, 0x00, int) -+#define FUSION_REACTOR_ATTACH _IOW(FT_REACTOR, 0x01, int) -+#define FUSION_REACTOR_DETACH _IOW(FT_REACTOR, 0x02, int) -+#define FUSION_REACTOR_DISPATCH _IOW(FT_REACTOR, 0x03, FusionReactorDispatch) -+#define FUSION_REACTOR_DESTROY _IOW(FT_REACTOR, 0x04, int) -+ -+#define FUSION_SHMPOOL_NEW _IOW(FT_SHMPOOL, 0x00, FusionSHMPoolNew) -+#define FUSION_SHMPOOL_ATTACH _IOW(FT_SHMPOOL, 0x01, FusionSHMPoolAttach) -+#define FUSION_SHMPOOL_DETACH _IOW(FT_SHMPOOL, 0x02, int) -+#define FUSION_SHMPOOL_DISPATCH _IOW(FT_SHMPOOL, 0x03, FusionSHMPoolDispatch) -+#define FUSION_SHMPOOL_DESTROY _IOW(FT_SHMPOOL, 0x04, int) -+ -+#endif -+ diff --git a/package/fusion/40-fusion.rules b/package/linux-fusion/40-fusion.rules index dc7fca19c..dc7fca19c 100644 --- a/package/fusion/40-fusion.rules +++ b/package/linux-fusion/40-fusion.rules diff --git a/package/fusion/Config.in b/package/linux-fusion/Config.in index cd0bfc7c5..6fb526076 100644 --- a/package/fusion/Config.in +++ b/package/linux-fusion/Config.in @@ -1,6 +1,5 @@ config BR2_PACKAGE_LINUX_FUSION bool "linux-fusion communication layer for DirectFB multi" - depends on BR2_PACKAGE_DIRECTFB help DirectFB Communication Layer allowing multiple DirectFB applications to run concurrently diff --git a/package/linux-fusion/linux-fusion-8.0.2-cross-compile.patch b/package/linux-fusion/linux-fusion-8.0.2-cross-compile.patch new file mode 100644 index 000000000..110e66333 --- /dev/null +++ b/package/linux-fusion/linux-fusion-8.0.2-cross-compile.patch @@ -0,0 +1,100 @@ +diff -urN linux-fusion-8.0.2-0rig//linux/drivers/char/fusion/shmpool.c linux-fusion-8.0.2/linux/drivers/char/fusion/shmpool.c +--- linux-fusion-8.0.2-0rig//linux/drivers/char/fusion/shmpool.c 2008-09-29 12:20:44.000000000 +0200 ++++ linux-fusion-8.0.2/linux/drivers/char/fusion/shmpool.c 2009-01-11 17:00:19.000000000 +0100 +@@ -20,6 +20,8 @@ + #include <linux/slab.h> + #include <linux/smp_lock.h> + #include <linux/sched.h> ++#include <asm/page.h> ++#include <linux/mm.h> + + #include <linux/fusion.h> + +@@ -28,8 +30,6 @@ + #include "list.h" + #include "shmpool.h" + +- +- + typedef struct { + FusionLink link; + unsigned long next_base; +diff -urN linux-fusion-8.0.2-0rig//Makefile linux-fusion-8.0.2/Makefile +--- linux-fusion-8.0.2-0rig//Makefile 2008-09-29 12:20:44.000000000 +0200 ++++ linux-fusion-8.0.2/Makefile 2009-01-11 18:07:54.000000000 +0100 +@@ -17,13 +17,15 @@ + + + DESTDIR ?= $(SYSROOT) +- ++HEADERDIR ?= $(SYSROOT) ++# This location is valid for at least 2.6.27.10 ++KERNEL_FUSION_LIB=$(KERNEL_MODLIB)/kernel/drivers/char/fusion + + SUB = linux/drivers/char/fusion + + export CONFIG_FUSION_DEVICE=m + +- ++ARCH=avr32 + ifeq ($(DEBUG),yes) + CPPFLAGS += -DFUSION_DEBUG_SKIRMISH_DEADLOCK + endif +@@ -45,25 +47,41 @@ + ln -s Makefile-2.$(K_PATCHLEVEL) $(SUB)/Makefile + ifeq ($(call check-version,2,6,24),1) + $(MAKE) -C $(KERNEL_BUILD) \ +- KCPPFLAGS="$(CPPFLAGS) -I`pwd`/linux/include" \ ++ ARCH=avr32 \ ++ CC=$(CROSS_COMPILE)gcc \ ++ AS=$(CROSS_COMPILE)as \ ++ KCPPFLAGS="$(CPPFLAGS) \ ++ -I`pwd`/linux/include \ ++ -I$(KERNEL_SOURCE)/include \ ++ -I$(KERNEL_SOURCE)/arch/$(ARCH)/include" \ + SUBDIRS=`pwd`/$(SUB) modules + else + $(MAKE) -C $(KERNEL_BUILD) \ +- CPPFLAGS="$(CPPFLAGS) -D__KERNEL__ -I`pwd`/linux/include -I$(KERNEL_BUILD)/include -I$(KERNEL_SOURCE)/include $(AUTOCONF_H)" \ ++ ARCH=avr32 \ ++ CC=$(CROSS_COMPILE)gcc \ ++ AS=$(CROSS_COMPILE)as \ ++ CPPFLAGS="$(CPPFLAGS) \ ++ -I`pwd`/linux/include \ ++ -I$(KERNEL_BUILD)/include \ ++ -I$(KERNEL_SOURCE)/include \ ++ -I$(KERNEL_SOURCE)/arch/$(ARCH)/include \ ++ $(AUTOCONF_H)" \ + SUBDIRS=`pwd`/$(SUB) modules + endif + +-install: all ++#-D__KERNEL__ ++#-DHAVE_LINUX_CONFIG_H \ ++ ++install: all install-header + install -d $(DESTDIR)/usr/include/linux + install -m 644 linux/include/linux/fusion.h $(DESTDIR)/usr/include/linux +- +- install -d $(DESTDIR)$(KERNEL_MODLIB)/drivers/char/fusion ++ install -d $(DESTDIR)$(KERNEL_FUSION_LIB) + + ifeq ($(K_PATCHLEVEL),4) +- install -m 644 $(SUB)/fusion.o $(DESTDIR)$(KERNEL_MODLIB)/drivers/char/fusion ++ install -m 644 $(SUB)/fusion.o $(DESTDIR)$(KERNEL_FUSION_LIB) + rm -f $(DESTDIR)$(KERNEL_MODLIB)/fusion.o + else +- install -m 644 $(SUB)/fusion.ko $(DESTDIR)$(KERNEL_MODLIB)/drivers/char/fusion ++ install -m 644 $(SUB)/fusion.ko $(DESTDIR)$(KERNEL_FUSION_LIB) + rm -f $(DESTDIR)$(KERNEL_MODLIB)/fusion.ko + endif + ifneq ($(strip $(DESTDIR)),) +@@ -72,6 +90,8 @@ + /sbin/depmod -ae $(KERNEL_VERSION) + endif + ++install-header: ++ install -m 644 linux/include/linux/fusion.h $(HEADERDIR)/usr/include/linux + + + clean: diff --git a/package/linux-fusion/linux-fusion.mk b/package/linux-fusion/linux-fusion.mk new file mode 100644 index 000000000..8d863abb1 --- /dev/null +++ b/package/linux-fusion/linux-fusion.mk @@ -0,0 +1,83 @@ +############################################################# +# +# linux-fusion +# +############################################################# +LINUX_FUSION_VERSION = 8.0.2 +LINUX_FUSION_SOURCE = linux-fusion-$(LINUX_FUSION_VERSION).tar.gz +LINUX_FUSION_SITE = http://www.directfb.org/downloads/Core/ +LINUX_FUSION_AUTORECONF = NO +LINUX_FUSION_INSTALL_STAGING = YES +LINUX_FUSION_INSTALL_TARGET = YES + +LINUX_FUSION_CONF_OPT = + +LINUX_FUSION_DEPENDENCIES = uclibc + +# BR2_LINUX26_VERSION is not really dependable +# LINUX26_VERSION is not yet set. +# Retrieve REAL kernel version from file. +LINUX_FOR_FUSION=`cat $(PROJECT_BUILD_DIR)/.linux-version` + +LINUX_FUSION_DIR:=$(BUILD_DIR)/linux-fusion-$(LINUX_FUSION_VERSION) +LINUX_FUSION_ETC_DIR:=$(TARGET_DIR)/etc/udev/rules.d + +LINUX_FUSION_CAT:=$(ZCAT) + +LINUX_FUSION_MAKE_OPTS:= KERNEL_VERSION=$(LINUX_FOR_FUSION) +LINUX_FUSION_MAKE_OPTS += KERNEL_BUILD=$(PROJECT_BUILD_DIR)/linux-$(LINUX_FOR_FUSION) +LINUX_FUSION_MAKE_OPTS += KERNEL_SOURCE=$(PROJECT_BUILD_DIR)/linux-$(LINUX_FOR_FUSION) + +LINUX_FUSION_MAKE_OPTS += SYSROOT=$(STAGING_DIR) +LINUX_FUSION_MAKE_OPTS += ARCH=$(BR2_ARCH) +LINUX_FUSION_MAKE_OPTS += CROSS_COMPILE=$(TARGET_CROSS) +LINUX_FUSION_MAKE_OPTS += KERNEL_MODLIB=/lib/modules/$(LINUX_FOR_FUSION) +LINUX_FUSION_MAKE_OPTS += DESTDIR=$(PROJECT_BUILD_DIR)/root +LINUX_FUSION_MAKE_OPTS += HEADERDIR=$(STAGING_DIR) +#LINUX_FUSION_MAKE_OPTS += + +#LINUX_FUSION_MAKE_OPTS += __KERNEL__=$(LINUX26_VERSION) + +$(DL_DIR)/$(LINUX_FUSION_SOURCE): + $(WGET) -P $(DL_DIR) $(LINUX_FUSION_SITE)/$(LINUX_FUSION_SOURCE) + +$(LINUX_FUSION_DIR)/.unpacked: $(DL_DIR)/$(LINUX_FUSION_SOURCE) + $(LINUX_FUSION_CAT) $(DL_DIR)/$(LINUX_FUSION_SOURCE) | tar -C $(BUILD_DIR) $(TAR_OPTIONS) - + toolchain/patch-kernel.sh $(LINUX_FUSION_DIR) package/linux-fusion/ linux-fusion\*.patch + touch $@ + +$(LINUX_FUSION_DIR)/.install: $(LINUX_FUSION_DIR)/.unpacked + mkdir -p $(STAGING_DIR)/lib/modules/$(LINUX_FOR_FUSION)/source/include/linux + echo "LINUX=$(LINUX26_VERSION)" + $(MAKE) $(TARGET_CONFIGURE_OPTS) \ + $(LINUX_FUSION_MAKE_OPTS) \ + -C $(LINUX_FUSION_DIR) install + rm -f $(TARGET_DIR)/usr/include/linux/fusion.h + mkdir -p $(LINUX_FUSION_ETC_DIR) + cp -dpf package/linux-fusion/40-fusion.rules $(LINUX_FUSION_ETC_DIR) + touch $@ + + +linux-fusion-source: $(DL_DIR)/$(LINUX_FUSION_SOURCE) + +linux-fusion-unpacked: $(LINUX_FUSION_DIR)/.unpacked + +linux-fusion: uclibc linux26 $(LINUX_FUSION_DIR)/.install + +linux-fusion-clean: + -$(MAKE) -C $(LINUX_FUSION_DIR) clean + rm -f $(STAGING_DIR)/usr/include/linux/fusion.h + rm -rf $(TARGET_DIR)/lib/modules/$(LINUX_FOR_FUSION)/drivers/char/fusion + rm -f $(LINUX_FUSION_DIR)/.install + +linux-fusion-dirclean: + rm -rf $(LINUX_FUSION_DIR) +############################################################# +# +# Toplevel Makefile options +# +############################################################# +ifeq ($(BR2_PACKAGE_LINUX_FUSION),y) +TARGETS+=linux-fusion +endif + |