Index: emc2/src/configure.in
===================================================================
--- emc2.orig/src/configure.in	2009-10-02 19:50:22.000000000 +0200
+++ emc2/src/configure.in	2009-10-11 21:19:51.000000000 +0200
@@ -80,6 +80,7 @@
 RTPREFIX=""
 KERNELDIR=""
 RTFLAGS=""
+LINUX_REALTIME=no
 
 RTAI3_MOD=""
 RTAI_MOD=""
@@ -113,17 +114,27 @@
 AC_SUBST(SIMULATOR)
 
 AC_ARG_WITH(realtime,
-    [  --with-realtime=<path to realtime>     Path where RTAI or RTlinux is installed],
+    [  --with-realtime=<path to realtime>     Path where RTAI or RTlinux is installed or 'linux' for linux-rt],
     [   case "$withval" in
 	"" | y | ye | yes | n | no)
 	    AC_MSG_ERROR([You must supply a path for --with-rtai.]) ;;
+	linux)
+		LINUX_REALTIME=yes
+		BUILD_SYS=linux
+		RTPREFIX=linux
+		MODEXT=.so
+                MODULE_DIR=${prefix}/lib/emc2/modules
+                AC_MSG_RESULT([configuring for Realtime-Linux])
+		;;
 	*)
-		case "$SIMULATOR" in
-		yes) AC_MSG_ERROR([--with-realtime and --enable-simulator are mutually exclusive]) ;;
-		*) RTDIR="$withval" ;;
-		esac
-	;;
+		RTDIR="$withval" ;;
         esac])
+if test x$RTDIR != x; then
+  case "$SIMULATOR" in
+    yes) AC_MSG_ERROR([--with-realtime and --enable-simulator are mutually exclusive]) ;;
+  esac
+fi
+
 
 ##############################################################################
 # Subsection 2.2                                                             #
@@ -140,13 +151,8 @@
 ##############################################################################
 
 #at this point if RTDIR is empty, we need to find RT ourselves
-if test $SIMULATOR = yes; then
-  RTS=sim
-  AC_PATH_PROG(PTH_CONFIG,pth-config,"")
-  if test "$PTH_CONFIG" = ""; then
-    AC_MSG_ERROR([GNU PTH library is required: get it with apt-get install libpth-dev])
-  fi
-else
+if test $SIMULATOR != yes -a $LINUX_REALTIME != yes; then
+  # Using realtime hypervisor
   if test -z "$RTDIR"; then
     DIRS="/usr/realtime-`uname -r` /usr/realtime /usr/realtime* /usr /usr/src/rtai*"
   else
@@ -172,6 +178,20 @@
   AC_MSG_RESULT([Using $RTS as the RT signature])
 fi
 
+if test $LINUX_REALTIME = yes; then
+  # Using realtime capable linux
+  RTS=linux
+fi
+
+if test $SIMULATOR = yes; then
+  # Using simulator
+  RTS=sim
+  AC_PATH_PROG(PTH_CONFIG,pth-config,"")
+  if test "$PTH_CONFIG" = ""; then
+    AC_MSG_ERROR([GNU PTH library is required: get it with apt-get install libpth-dev])
+  fi
+fi
+
 
 ##############################################################################
 # Subsection 2.3                                                             #
@@ -243,7 +263,7 @@
     RTFLAGS=-DSIMULATOR
 esac
 
-if test $RTS != sim; then
+if test $RTS != sim -a $RTS != linux; then
     AC_MSG_CHECKING([for location of kernel headers])
     AC_ARG_WITH(kernel-headers,
 	[  --with-kernel-headers=<directory>       Location for kernel headers],
@@ -271,6 +291,8 @@
     AC_DEFINE(RTAPI_RTAI, [], [Realtime system is RTAI])
 elif test $RTPREFIX = rtl; then
     AC_DEFINE(RTAPI_RTL, [], [Realtime system is RTL])
+elif test $RTPREFIX = linux; then
+    AC_DEFINE(RTAPI_LINUX, [], [Realtime capable Linux])
 fi
 
 
@@ -362,7 +384,7 @@
 # compiled against.                                                          #
 ##############################################################################
 
-if test $RTS '!=' sim; then
+if test $RTS '!=' sim -a $RTS != linux; then
 AC_CHECK_HEADERS([$KERNELDIR/include/linux/version.h],[],[AC_MSG_ERROR([version.h not found - Is the kernel headers package installed ?])])
 
 # Unfortunately, many distributions (redhat, mandrake) have #defines
@@ -1390,13 +1412,16 @@
 else
 echo "#   This means that RT is properly installed                         #"
 fi
+if test $LINUX_REALTIME = yes; then
+echo "#   Using realtime capable Linux.                                    #"
+fi
 echo "#   If things don't work check config.log for errors & warnings      #"
 echo "#                                                                    #"
 
 if test "xyes" = "x$RUN_IN_PLACE"; then
 echo "#   Next compile by typing                                           #"
 echo "#         make                                                       #"
-if test $SIMULATOR != yes; then
+if test $SIMULATOR != yes -a $LINUX_REALTIME != yes; then
 echo "#         sudo make setuid                                           #"
 fi
 echo "#                                                                    #"
Index: emc2/src/rtapi/Submakefile
===================================================================
--- emc2.orig/src/rtapi/Submakefile	2009-10-02 20:17:00.000000000 +0200
+++ emc2/src/rtapi/Submakefile	2009-10-02 20:32:07.000000000 +0200
@@ -6,6 +6,7 @@
 	cp $^ $@
 
 ifeq ($(BUILD_SYS),sim)
+# Simulator
 
 RTAPI_APP_SRCS := \
 	rtapi/sim_rtapi_app.cc \
@@ -21,3 +22,19 @@
 	@$(CXX) -rdynamic $(LDFLAGS) -o $@ $^ -ldl $(PTH_LINK)
 TARGETS += ../bin/rtapi_app
 endif
+
+
+ifeq ($(BUILD_SYS),linux)
+# Realtime capable linux
+
+RTAPI_APP_SRCS := \
+	rtapi/linux_rtapi_app.cc \
+	rtapi/linux_rtapi.c
+USERSRCS += $(RTAPI_APP_SRCS)
+
+$(call TOOBJSDEPS, $(RTAPI_APP_SRCS)): EXTRAFLAGS += -DLINUX_REALTIME
+../bin/rtapi_app: $(call TOOBJS, $(RTAPI_APP_SRCS))
+	$(ECHO) Linking $(notdir $@)
+	@$(CXX) -rdynamic $(LDFLAGS) -o $@ $^ -ldl -lpthread -lrt
+TARGETS += ../bin/rtapi_app
+endif
Index: emc2/src/rtapi/linux_rtapi.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ emc2/src/rtapi/linux_rtapi.c	2009-10-11 21:21:34.000000000 +0200
@@ -0,0 +1,593 @@
+/********************************************************************
+* Description:  linux_rtapi.c
+*               This file, 'linux_rtapi.c', implements the RT API
+*               functions for machines with Linux-realtime
+*
+* Author: John Kasunich, Paul Corner
+* Copyright (c) 2004 All rights reserved.
+*
+* Copyright (c) 2009 Michael Buesch <mb@bu3sch.de>
+*
+* License: GPL Version 2
+*
+********************************************************************/
+
+#define _GNU_SOURCE
+#include <stdio.h>		/* vprintf() */
+#include <stdlib.h>		/* malloc(), sizeof() */
+#include <stdarg.h>		/* va_* */
+#include <unistd.h>		/* usleep() */
+#include <sys/ipc.h>		/* IPC_* */
+#include <sys/shm.h>		/* shmget() */
+#include <sys/io.h>		/* shmget() */
+#include <time.h>		/* clock_gettime etc */
+#include "rtapi.h"		/* these decls */
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+/* These structs hold data associated with objects like tasks, etc. */
+/* Task handles are pointers to these structs.                      */
+
+struct rtapi_module {
+	int magic;
+};
+
+struct rtapi_task {
+	int magic;		/* to check for valid handle */
+	int owner;
+	int deleted;
+
+	/* The realtime thread. */
+	pthread_t thread;
+	pthread_barrier_t thread_init_barrier;
+	void *stackaddr;
+	size_t stacksize;
+
+	int prio;
+	int period;
+	int ratio;
+	int destroyed;
+	struct timespec next_time;
+	void *arg;
+	void (*taskcode)(void *);	/* pointer to task function */
+};
+
+#define MODULE_MAGIC		30812
+#define TASK_MAGIC		21979	/* random numbers used as signatures */
+
+#define MAX_TASKS		64
+#define MAX_MODULES		64
+#define MODULE_OFFSET		32768
+
+#ifndef max
+# define max(a, b)	((a) > (b) ? (a) : (b))
+#endif
+
+
+/* data for all tasks */
+static struct rtapi_task task_array[MAX_TASKS];
+static struct rtapi_module module_array[MAX_MODULES];
+/* Lock for task_array and module_array allocations. */
+static pthread_mutex_t array_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* local functions and data */
+
+static pthread_key_t task_key;
+static pthread_once_t task_key_once = PTHREAD_ONCE_INIT;
+
+static int period;
+
+static unsigned long minfault_base;
+static unsigned long majfault_base;
+static pthread_mutex_t fault_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+static unsigned long rtapi_get_pagefault_count(void)
+{
+	struct rusage rusage;
+	unsigned long minor, major;
+
+	getrusage(RUSAGE_SELF, &rusage);
+	pthread_mutex_lock(&fault_mutex);
+	minor = rusage.ru_minflt;
+	major = rusage.ru_majflt;
+	if (minor < minfault_base || major < majfault_base) {
+		pthread_mutex_unlock(&fault_mutex);
+		rtapi_print_msg(RTAPI_MSG_ERR, "Got invalid fault counts.\n");
+		return 0;
+	}
+	minor -= minfault_base;
+	major -= majfault_base;
+	pthread_mutex_unlock(&fault_mutex);
+
+	return minor + major;
+}
+
+static void rtapi_reset_pagefault_count(void)
+{
+	struct rusage rusage;
+
+	getrusage(RUSAGE_SELF, &rusage);
+	pthread_mutex_lock(&fault_mutex);
+	if (minfault_base != rusage.ru_minflt ||
+	    majfault_base != rusage.ru_majflt) {
+		minfault_base = rusage.ru_minflt;
+		majfault_base = rusage.ru_majflt;
+		rtapi_print_msg(RTAPI_MSG_INFO, "Reset pagefault counter\n");
+	}
+	pthread_mutex_unlock(&fault_mutex);
+}
+
+static void rtapi_advance_time(struct timespec *tv, unsigned long ns,
+			       unsigned long s)
+{
+	ns += tv->tv_nsec;
+	while (ns > 1000000000) {
+		s++;
+		ns -= 1000000000;
+	}
+	tv->tv_nsec = ns;
+	tv->tv_sec += s;
+}
+
+static void rtapi_key_alloc()
+{
+	pthread_key_create(&task_key, NULL);
+}
+
+static void rtapi_set_task(struct rtapi_task *t)
+{
+	pthread_once(&task_key_once, rtapi_key_alloc);
+	pthread_setspecific(task_key, (void *)t);
+}
+
+static struct rtapi_task *rtapi_this_task()
+{
+	pthread_once(&task_key_once, rtapi_key_alloc);
+	return (struct rtapi_task *)pthread_getspecific(task_key);
+}
+
+int rtapi_prio_highest(void)
+{
+	return sched_get_priority_max(SCHED_FIFO);
+}
+
+int rtapi_prio_lowest(void)
+{
+	return sched_get_priority_min(SCHED_FIFO);
+}
+
+int rtapi_prio_next_higher(int prio)
+{
+	/* return a valid priority for out of range arg */
+	if (prio >= rtapi_prio_highest())
+		return rtapi_prio_highest();
+	if (prio < rtapi_prio_lowest())
+		return rtapi_prio_lowest();
+
+	/* return next higher priority for in-range arg */
+	return prio + 1;
+}
+
+int rtapi_prio_next_lower(int prio)
+{
+	/* return a valid priority for out of range arg */
+	if (prio <= rtapi_prio_lowest())
+		return rtapi_prio_lowest();
+	if (prio > rtapi_prio_highest())
+		return rtapi_prio_highest();
+
+	/* return next lower priority for in-range arg */
+	return prio - 1;
+}
+
+int rtapi_init(const char *modname)
+{
+	int n, result = -ENOMEM;
+
+	pthread_mutex_lock(&array_mutex);
+	for (n = 0; n < MAX_MODULES; n++) {
+		if (module_array[n].magic != MODULE_MAGIC) {
+			result = n + MODULE_OFFSET;
+			module_array[n].magic = MODULE_MAGIC;
+			break;
+		}
+	}
+	pthread_mutex_unlock(&array_mutex);
+
+	rtapi_reset_pagefault_count();
+
+	return result;
+}
+
+int rtapi_exit(int id)
+{
+	int n = id - MODULE_OFFSET;
+
+	if (n < 0 || n >= MAX_MODULES)
+		return -1;
+	/* Remove the module from the module_array. */
+	pthread_mutex_lock(&array_mutex);
+	module_array[n].magic = 0;
+	pthread_mutex_unlock(&array_mutex);
+
+	return 0;
+}
+
+int rtapi_clock_set_period(unsigned long int nsecs)
+{
+	struct timespec res = { 0, 0 };
+
+	if (nsecs == 0)
+		return period;
+	if (period != 0) {
+		rtapi_print_msg(RTAPI_MSG_ERR, "attempt to set period twice\n");
+		return -EINVAL;
+	}
+	clock_getres(CLOCK_MONOTONIC, &res);
+	period = (nsecs / res.tv_nsec) * res.tv_nsec;
+	if (period < 1)
+		period = res.tv_nsec;
+	rtapi_print_msg(RTAPI_MSG_INFO,
+			"rtapi_clock_set_period (res=%ld) -> %d\n", res.tv_nsec,
+			period);
+
+	return period;
+}
+
+int rtapi_task_new(void (*taskcode)(void *), void *arg,
+		   int prio, int owner, unsigned long int stacksize,
+		   int uses_fp)
+{
+	int n;
+	struct rtapi_task *task;
+	void *stackaddr;
+
+	stacksize = max(stacksize, 16384);
+	stackaddr = malloc(stacksize);
+	if (!stackaddr) {
+		rtapi_print_msg(RTAPI_MSG_ERR,
+				"Failed to allocate realtime thread stack\n");
+		return -ENOMEM;
+	}
+	memset(stackaddr, 0, stacksize);
+
+	/* find an empty entry in the task array */
+	pthread_mutex_lock(&array_mutex);
+	n = 0;
+	while ((n < MAX_TASKS) && (task_array[n].magic == TASK_MAGIC))
+		n++;
+	if (n == MAX_TASKS) {
+		pthread_mutex_unlock(&array_mutex);
+		free(stackaddr);
+		return -ENOMEM;
+	}
+	task = &(task_array[n]);
+	task->magic = TASK_MAGIC;
+	pthread_mutex_unlock(&array_mutex);
+
+	/* check requested priority */
+	{
+		int highest = rtapi_prio_highest();
+		int lowest = rtapi_prio_lowest();
+		if (prio < lowest || prio > highest) {
+			rtapi_print_msg(RTAPI_MSG_ERR,
+					"New task invalid priority %d (highest=%d lowest=%d)\n",
+					prio, highest, lowest);
+			free(stackaddr);
+			return -EINVAL;
+		}
+		rtapi_print_msg(RTAPI_MSG_INFO,
+				"Creating new task with requested priority %d (highest=%d lowest=%d)\n",
+				prio, highest, lowest);
+	}
+
+	task->owner = owner;
+	task->arg = arg;
+	task->stacksize = stacksize;
+	task->stackaddr = stackaddr;
+	task->destroyed = 0;
+	task->taskcode = taskcode;
+	task->prio = prio;
+
+	/* and return handle to the caller */
+
+	return n;
+}
+
+int rtapi_task_delete(int id)
+{
+	struct rtapi_task *task;
+	void *returncode;
+	int err;
+
+	if (id < 0 || id >= MAX_TASKS)
+		return -EINVAL;
+
+	task = &(task_array[id]);
+	/* validate task handle */
+	if (task->magic != TASK_MAGIC)
+		return -EINVAL;
+
+	/* Signal thread termination and wait for the thread to exit. */
+	if (!task->deleted) {
+		task->deleted = 1;
+		err = pthread_join(task->thread, &returncode);
+		if (err)
+			rtapi_print_msg(RTAPI_MSG_ERR, "pthread_join() on realtime thread failed\n");
+	}
+	/* Free the thread stack. */
+	free(task->stackaddr);
+	task->stackaddr = NULL;
+	/* Remove the task from the task_array. */
+	pthread_mutex_lock(&array_mutex);
+	task->magic = 0;
+	pthread_mutex_unlock(&array_mutex);
+
+	return 0;
+}
+
+#ifndef CPU_SETSIZE
+#define CPU_SETSIZE (8*sizeof(cpu_set_t))
+#endif
+
+static int realtime_set_affinity(struct rtapi_task *task)
+{
+	cpu_set_t set;
+	int err, cpu_nr, use_cpu = -1;
+
+	pthread_getaffinity_np(task->thread, sizeof(set), &set);
+	for (cpu_nr = CPU_SETSIZE - 1; cpu_nr >= 0; cpu_nr--) {
+		if (CPU_ISSET(cpu_nr, &set)) {
+			use_cpu = cpu_nr;
+			break;
+		}
+	}
+	if (use_cpu < 0) {
+		rtapi_print_msg(RTAPI_MSG_ERR, "Unable to get ID of the last CPU\n");
+		return -1;
+	}
+	rtapi_print_msg(RTAPI_MSG_INFO, "Using CPU %d\n", use_cpu);
+	CPU_ZERO(&set);
+	CPU_SET(use_cpu, &set);
+	err = pthread_setaffinity_np(task->thread, sizeof(set), &set);
+	if (err) {
+		rtapi_print_msg(RTAPI_MSG_ERR, "Failed to set CPU affinity to CPU %d (%s)\n",
+				use_cpu, strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
+static int realtime_set_priority(struct rtapi_task *task)
+{
+	struct sched_param schedp;
+
+	memset(&schedp, 0, sizeof(schedp));
+	schedp.sched_priority = task->prio;
+	if (sched_setscheduler(0, SCHED_FIFO, &schedp)) {
+		rtapi_print_msg(RTAPI_MSG_ERR, "Unable to set FIFO scheduling policy: %s",
+				strerror(errno));
+		return 1;
+	}
+
+	return 0;
+}
+
+static void *realtime_thread(void *arg)
+{
+	struct rtapi_task *task = arg;
+
+	rtapi_set_task(task);
+
+	if (task->period < period)
+		task->period = period;
+	task->ratio = task->period / period;
+	rtapi_print_msg(RTAPI_MSG_INFO, "task %p period = %d ratio=%d\n",
+			task, task->period, task->ratio);
+
+	if (realtime_set_priority(task))
+		goto error;
+	if (realtime_set_affinity(task))
+		goto error;
+
+	/* We're done initializing. Open the barrier. */
+	pthread_barrier_wait(&task->thread_init_barrier);
+
+	clock_gettime(CLOCK_MONOTONIC, &task->next_time);
+	rtapi_advance_time(&task->next_time, task->period, 0);
+
+	/* call the task function with the task argument */
+	task->taskcode(task->arg);
+
+	rtapi_print_msg(RTAPI_MSG_ERR, "ERROR: reached end of realtime thread for task %d\n",
+			(int)(task - task_array));
+	task->deleted = 1;
+
+	return NULL;
+error:
+	/* Signal that we're dead and open the barrier. */
+	task->deleted = 1;
+	pthread_barrier_wait(&task->thread_init_barrier);
+	return NULL;
+}
+
+int rtapi_task_start(int task_id, unsigned long int period_nsec)
+{
+	struct rtapi_task *task;
+	pthread_attr_t attr;
+	int retval;
+
+	if (task_id < 0 || task_id >= MAX_TASKS)
+		return -EINVAL;
+
+	task = &task_array[task_id];
+
+	/* validate task handle */
+	if (task->magic != TASK_MAGIC)
+		return -EINVAL;
+
+	if (period_nsec < period)
+		period_nsec = period;
+	task->period = period_nsec;
+	task->ratio = period_nsec / period;
+	task->deleted = 0;
+
+	/* create the thread - use the wrapper function, pass it a pointer
+	   to the task structure so it can call the actual task function */
+
+	pthread_barrier_init(&task->thread_init_barrier, NULL, 2);
+	pthread_attr_init(&attr);
+	pthread_attr_setstack(&attr, task->stackaddr, task->stacksize);
+	retval = pthread_create(&task->thread, &attr, realtime_thread, (void *)task);
+	pthread_attr_destroy(&attr);
+	if (retval) {
+		pthread_barrier_destroy(&task->thread_init_barrier);
+		rtapi_print_msg(RTAPI_MSG_ERR, "Failed to create realtime thread\n");
+		return -ENOMEM;
+	}
+	/* Wait for the thread to do basic initialization. */
+	pthread_barrier_wait(&task->thread_init_barrier);
+	pthread_barrier_destroy(&task->thread_init_barrier);
+	if (task->deleted) { /* The thread died in the init phase. */
+		rtapi_print_msg(RTAPI_MSG_ERR, "Realtime thread initialization failed\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+int rtapi_task_stop(int task_id)
+{
+	struct rtapi_task *task;
+
+	if (task_id < 0 || task_id >= MAX_TASKS)
+		return -EINVAL;
+
+	task = &task_array[task_id];
+
+	/* validate task handle */
+	if (task->magic != TASK_MAGIC)
+		return -EINVAL;
+
+	task->destroyed = 1;
+
+	return 0;
+}
+
+int rtapi_task_pause(int task_id)
+{
+	struct rtapi_task *task;
+
+	if (task_id < 0 || task_id >= MAX_TASKS)
+		return -EINVAL;
+
+	task = &task_array[task_id];
+
+	/* validate task handle */
+	if (task->magic != TASK_MAGIC)
+		return -EINVAL;
+
+	return -ENOSYS;
+}
+
+int rtapi_task_resume(int task_id)
+{
+	struct rtapi_task *task;
+
+	if (task_id < 0 || task_id >= MAX_TASKS)
+		return -EINVAL;
+
+	task = &task_array[task_id];
+
+	/* validate task handle */
+	if (task->magic != TASK_MAGIC)
+		return -EINVAL;
+
+	return -ENOSYS;
+}
+
+int rtapi_task_set_period(int task_id, unsigned long int period_nsec)
+{
+	struct rtapi_task *task;
+
+	if (task_id < 0 || task_id >= MAX_TASKS)
+		return -EINVAL;
+
+	task = &task_array[task_id];
+
+	/* validate task handle */
+	if (task->magic != TASK_MAGIC)
+		return -EINVAL;
+
+	task->period = period_nsec;
+
+	return 0;
+}
+
+int rtapi_wait(void)
+{
+	struct timespec ts;
+	struct rtapi_task *task = rtapi_this_task();
+
+	if (task->deleted)
+		pthread_exit(0);
+
+	clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &task->next_time, NULL);
+	rtapi_advance_time(&task->next_time, task->period, 0);
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+	if (ts.tv_sec > task->next_time.tv_sec
+	    || (ts.tv_sec == task->next_time.tv_sec
+		&& ts.tv_nsec > task->next_time.tv_nsec)) {
+		static int failures = 0;
+		int msglevel = RTAPI_MSG_NONE;
+
+		failures++;
+		if (failures == 1)
+			msglevel = RTAPI_MSG_ERR;
+		else if (failures < 10 || (failures % 10000 == 0))
+			msglevel = RTAPI_MSG_WARN;
+
+		if (msglevel != RTAPI_MSG_NONE) {
+			rtapi_print_msg(msglevel,
+					"ERROR: Missed scheduling deadline for task %d [%d times]\n"
+					"Now is %ld.%09ld, deadline was %ld.%09ld\n"
+					"Absolute number of pagefaults in realtime context: %lu\n",
+					(int)(task - task_array), failures,
+					(long)ts.tv_sec, (long)ts.tv_nsec,
+					(long)task->next_time.tv_sec,
+					(long)task->next_time.tv_nsec,
+					rtapi_get_pagefault_count());
+		}
+	}
+
+	return 0;
+}
+
+void rtapi_outb(unsigned char byte, unsigned int port)
+{
+	outb(byte, port);
+}
+
+unsigned char rtapi_inb(unsigned int port)
+{
+	return inb(port);
+}
+
+long int simple_strtol(const char *nptr, char **endptr, int base)
+{
+	return strtol(nptr, endptr, base);
+}
+
+long long rtapi_get_time(void)
+{
+	struct timespec ts;
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+	return ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+}
+
+#include "rtapi/linux_common.h"
Index: emc2/src/rtapi/linux_rtapi_app.cc
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ emc2/src/rtapi/linux_rtapi_app.cc	2009-10-11 19:16:15.000000000 +0200
@@ -0,0 +1,531 @@
+/* Copyright (C) 2006-2008 Jeff Epler <jepler@unpythonic.net>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <iostream>
+#include <vector>
+#include <string>
+#include <map>
+#include <algorithm>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <linux/capability.h>
+#include <sys/io.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <malloc.h>
+
+#include "config.h"
+
+#include "rtapi.h"
+#include "hal.h"
+#include "hal/hal_priv.h"
+
+extern "C" {
+	int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
+	int capget(cap_user_header_t hdrp, cap_user_data_t datap);
+}
+
+using namespace std;
+
+#define SOCKET_PATH "\0/tmp/rtapi_fifo"
+
+template <class T> T DLSYM(void *handle, const string & name)
+{
+	return (T) (dlsym(handle, name.c_str()));
+}
+
+template <class T> T DLSYM(void *handle, const char *name)
+{
+	return (T) (dlsym(handle, name));
+}
+
+static map<string, void *> modules;
+
+extern "C" int schedule(void)
+{
+	return sched_yield();
+}
+
+static int instance_count = 0;
+static int force_exit = 0;
+
+static int do_newinst_cmd(string type, string name, string arg)
+{
+	void *module = modules["hal_lib"];
+	if (!module) {
+		rtapi_print_msg(RTAPI_MSG_ERR,
+				"newinst: hal_lib is required, but not loaded\n");
+		return -1;
+	}
+
+	hal_comp_t *(*find_comp_by_name) (char *) =
+	    DLSYM <hal_comp_t * (*)(char *)>(module,
+					      "halpr_find_comp_by_name");
+	if (!find_comp_by_name) {
+		rtapi_print_msg(RTAPI_MSG_ERR,
+				"newinst: halpr_find_comp_by_name not found\n");
+		return -1;
+	}
+
+	hal_comp_t *comp = find_comp_by_name((char *)type.c_str());
+	if (!comp) {
+		rtapi_print_msg(RTAPI_MSG_ERR,
+				"newinst: component %s not found\n",
+				type.c_str());
+		return -1;
+	}
+
+	return comp->make((char *)name.c_str(), (char *)arg.c_str());
+}
+
+static int do_one_item(char item_type_char, const string & param_name,
+		       const string & param_value, void *vitem, int idx = 0)
+{
+	char *endp;
+	switch (item_type_char) {
+	case 'l':{
+			long *litem = *(long **)vitem;
+			litem[idx] = strtol(param_value.c_str(), &endp, 0);
+			if (*endp) {
+				rtapi_print_msg(RTAPI_MSG_ERR,
+						"`%s' invalid for parameter `%s'",
+						param_value.c_str(),
+						param_name.c_str());
+				return -1;
+			}
+			return 0;
+		}
+	case 'i':{
+			int *iitem = *(int **)vitem;
+			iitem[idx] = strtol(param_value.c_str(), &endp, 0);
+			if (*endp) {
+				rtapi_print_msg(RTAPI_MSG_ERR,
+						"`%s' invalid for parameter `%s'",
+						param_value.c_str(),
+						param_name.c_str());
+				return -1;
+			}
+			return 0;
+		}
+	case 's':{
+			char **sitem = *(char ***)vitem;
+			sitem[idx] = strdup(param_value.c_str());
+			return 0;
+		}
+	default:
+		rtapi_print_msg(RTAPI_MSG_ERR,
+				"%s: Invalid type character `%c'\n",
+				param_name.c_str(), item_type_char);
+		return -1;
+	}
+	return 0;
+}
+
+void remove_quotes(string & s)
+{
+	s.erase(remove_copy(s.begin(), s.end(), s.begin(), '"'), s.end());
+}
+
+static int do_comp_args(void *module, vector<string> args)
+{
+	for (unsigned i = 1; i < args.size(); i++) {
+		string & s = args[i];
+		remove_quotes(s);
+		size_t idx = s.find('=');
+		if (idx == string::npos) {
+			rtapi_print_msg(RTAPI_MSG_ERR,
+					"Invalid paramter `%s'\n", s.c_str());
+			return -1;
+		}
+		string param_name(s, 0, idx);
+		string param_value(s, idx + 1);
+		void *item =
+		    DLSYM < void *>(module, "rtapi_info_address_" + param_name);
+		if (!item) {
+			rtapi_print_msg(RTAPI_MSG_ERR,
+					"Unknown parameter `%s'\n", s.c_str());
+			return -1;
+		}
+		char **item_type =
+		    DLSYM < char **>(module, "rtapi_info_type_" + param_name);
+		if (!item_type || !*item_type) {
+			rtapi_print_msg(RTAPI_MSG_ERR,
+					"Unknown parameter `%s' (type information missing)\n",
+					s.c_str());
+			return -1;
+		}
+		string item_type_string = *item_type;
+
+		if (item_type_string.size() > 1) {
+			int a, b;
+			char item_type_char;
+			int r = sscanf(item_type_string.c_str(), "%d-%d%c",
+				       &a, &b, &item_type_char);
+			if (r != 3) {
+				rtapi_print_msg(RTAPI_MSG_ERR,
+						"Unknown parameter `%s' (corrupt array type information)\n",
+						s.c_str());
+				return -1;
+			}
+			size_t idx = 0;
+			int i = 0;
+			while (idx != string::npos) {
+				if (i == b) {
+					rtapi_print_msg(RTAPI_MSG_ERR,
+							"%s: can only take %d arguments\n",
+							s.c_str(), b);
+					return -1;
+				}
+				size_t idx1 = param_value.find(",", idx);
+				string substr(param_value, idx, idx1 - idx);
+				int result =
+				    do_one_item(item_type_char, s, substr, item,
+						i);
+				if (result != 0)
+					return result;
+				i++;
+				idx = idx1 == string::npos ? idx1 : idx1 + 1;
+			}
+		} else {
+			char item_type_char = item_type_string[0];
+			int result =
+			    do_one_item(item_type_char, s, param_value, item);
+			if (result != 0)
+				return result;
+		}
+	}
+	return 0;
+}
+
+static int do_load_cmd(string name, vector<string> args)
+{
+	void *w = modules[name];
+	if (w == NULL) {
+		char what[LINELEN + 1];
+		snprintf(what, LINELEN, "%s/%s.so", EMC2_RTLIB_DIR,
+			 name.c_str());
+		void *module = modules[name] =
+		    dlopen(what, RTLD_GLOBAL | RTLD_LAZY);
+		if (!module) {
+			rtapi_print_msg(RTAPI_MSG_ERR, "%s: dlopen: %s\n",
+					name.c_str(), dlerror());
+			return -1;
+		}
+		/// XXX handle arguments
+		int (*start) (void) =
+		    DLSYM<int (*) (void)>(module, "rtapi_app_main");
+		if (!start) {
+			rtapi_print_msg(RTAPI_MSG_ERR, "%s: dlsym: %s\n",
+					name.c_str(), dlerror());
+			return -1;
+		}
+		int result;
+
+		result = do_comp_args(module, args);
+		if (result < 0) {
+			dlclose(module);
+			return -1;
+		}
+
+		if ((result = start()) < 0) {
+			rtapi_print_msg(RTAPI_MSG_ERR,
+					"%s: rtapi_app_main: %d\n",
+					name.c_str(), result);
+			return result;
+		} else {
+			instance_count++;
+			return 0;
+		}
+	} else {
+		rtapi_print_msg(RTAPI_MSG_ERR, "%s: already exists\n",
+				name.c_str());
+		return -1;
+	}
+}
+
+static int do_unload_cmd(string name)
+{
+	void *w = modules[name];
+	if (w == NULL) {
+		rtapi_print_msg(RTAPI_MSG_ERR, "%s: not loaded\n",
+				name.c_str());
+		return -1;
+	} else {
+		int (*stop) (void) =
+		    DLSYM<int (*) (void)>(w, "rtapi_app_exit");
+		if (stop)
+			stop();
+		modules.erase(modules.find(name));
+		dlclose(w);
+		instance_count--;
+	}
+	return 0;
+}
+
+static int read_number(int fd)
+{
+	int r = 0, neg = 1;
+	char ch;
+
+	while (1) {
+		int res = read(fd, &ch, 1);
+		if (res != 1)
+			return -1;
+		if (ch == '-')
+			neg = -1;
+		else if (ch == ' ')
+			return r * neg;
+		else
+			r = 10 * r + ch - '0';
+	}
+}
+
+static string read_string(int fd)
+{
+	int len = read_number(fd);
+	char buf[len];
+	read(fd, buf, len);
+	return string(buf, len);
+}
+
+static vector<string> read_strings(int fd)
+{
+	vector<string> result;
+	int count = read_number(fd);
+	for (int i = 0; i < count; i++) {
+		result.push_back(read_string(fd));
+	}
+	return result;
+}
+
+static void write_number(string &buf, int num)
+{
+	char numbuf[10];
+	sprintf(numbuf, "%d ", num);
+	buf = buf + numbuf;
+}
+
+static void write_string(string &buf, string s)
+{
+	write_number(buf, s.size());
+	buf += s;
+}
+
+static void write_strings(int fd, vector<string> strings)
+{
+	string buf;
+	write_number(buf, strings.size());
+	for (unsigned int i = 0; i < strings.size(); i++) {
+		write_string(buf, strings[i]);
+	}
+	write(fd, buf.data(), buf.size());
+}
+
+static int handle_command(vector<string> args)
+{
+	if (args.size() == 0) {
+		return 0;
+	}
+	if (args.size() == 1 && args[0] == "exit") {
+		force_exit = 1;
+		return 0;
+	} else if (args.size() >= 2 && args[0] == "load") {
+		string name = args[1];
+		args.erase(args.begin());
+		return do_load_cmd(name, args);
+	} else if (args.size() == 2 && args[0] == "unload") {
+		return do_unload_cmd(args[1]);
+	} else if (args.size() == 3 && args[0] == "newinst") {
+		return do_newinst_cmd(args[1], args[2], "");
+	} else if (args.size() == 4 && args[0] == "newinst") {
+		return do_newinst_cmd(args[1], args[2], args[3]);
+	} else {
+		rtapi_print_msg(RTAPI_MSG_ERR,
+				"Unrecognized command starting with %s\n",
+				args[0].c_str());
+		return -1;
+	}
+}
+
+static int slave(int fd, vector<string> args)
+{
+	write_strings(fd, args);
+	int result = read_number(fd);
+	return result;
+}
+
+static int master(int fd, vector<string> args)
+{
+	dlopen(NULL, RTLD_GLOBAL);
+	do_load_cmd("hal_lib", vector<string>());
+	instance_count = 0;
+	if (args.size()) {
+		int result = handle_command(args);
+		if (result != 0)
+			return result;
+		if (force_exit || instance_count == 0)
+			return 0;
+	}
+	do {
+		struct sockaddr_un client_addr;
+		memset(&client_addr, 0, sizeof(client_addr));
+		socklen_t len = sizeof(client_addr);
+
+		int fd1 = accept(fd, (sockaddr *) & client_addr, &len);
+		if (fd1 < 0) {
+			perror("accept");
+			return -1;
+		} else {
+			int result = handle_command(read_strings(fd1));
+			string buf;
+			write_number(buf, result);
+			write(fd1, buf.data(), buf.size());
+			close(fd1);
+		}
+	} while (!force_exit && instance_count > 0);
+
+	return 0;
+}
+
+/* Pre-allocation size. */
+#define PRE_ALLOC_SIZE		(30 * 1024 * 1024)
+
+static int configure_memory(void)
+{
+	unsigned int i, pagesize;
+	char *buf;
+
+	/* Lock all memory. This includes all current allocations (BSS/data)
+	 * and future allocations. */
+	if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
+		perror("Failed to lock memory (mlockall)");
+		return 1;
+	}
+   	/* Turn off malloc trimming.*/
+	mallopt(M_TRIM_THRESHOLD, -1);
+	/* Turn off mmap usage. */
+	mallopt(M_MMAP_MAX, 0);
+
+	buf = static_cast<char *>(malloc(PRE_ALLOC_SIZE));
+	pagesize = sysconf(_SC_PAGESIZE);
+	/* Touch each page in this piece of memory to get it mapped into RAM */
+	for (i = 0; i < PRE_ALLOC_SIZE; i += pagesize) {
+		/* Each write to this buffer will generate a pagefault.
+		 * Once the pagefault is handled a page will be locked in
+		 * memory and never given back to the system. */
+		buf[i] = 0;
+	}
+	/* buffer will now be released. As Glibc is configured such that it
+	 * never gives back memory to the kernel, the memory allocated above is
+	 * locked for this process. All malloc() and new() calls come from
+	 * the memory pool reserved and locked above. Issuing free() and
+	 * delete() does NOT make this locking undone. So, with this locking
+	 * mechanism we can build C++ applications that will never run into
+	 * a major/minor pagefault, even with swapping enabled. */
+	free(buf);
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	/* Request RAW-I/O */
+	if (iopl(3)) {
+		perror("Failed to request RAW-I/O permissions (iopl)");
+		return 1;
+	}
+	if (configure_memory())
+		return 1;
+
+#if 0
+	cap_user_header_t header;
+	cap_user_data_t data;
+	capget(header, data);
+	data->effective |= CAP_SYS_NICE | CAP_SYS_RAWIO;
+	if (capset(header, data) != 0) {
+		perror("capset");
+	}
+	seteuid(getuid());
+#endif
+
+	vector<string> args;
+	for (int i = 1; i < argc; i++) {
+		args.push_back(string(argv[i]));
+	}
+
+become_master:
+	int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+	if (fd == -1) {
+		perror("socket");
+		exit(1);
+	}
+
+	int enable = 1;
+	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
+	struct sockaddr_un addr = { AF_UNIX, SOCKET_PATH };
+	int result = bind(fd, (sockaddr *)&addr, sizeof(addr));
+
+	if (result == 0) {
+		int result = listen(fd, 10);
+		if (result != 0) {
+			perror("listen");
+			exit(1);
+		}
+		result = master(fd, args);
+		unlink(SOCKET_PATH);
+		return result;
+	} else if (errno == EADDRINUSE) {
+		struct timeval t0, t1;
+		gettimeofday(&t0, NULL);
+		gettimeofday(&t1, NULL);
+		for (int i = 0; i < 3 || (t1.tv_sec < 3 + t0.tv_sec); i++) {
+			result = connect(fd, (sockaddr *)&addr, sizeof(addr));
+			if (result == 0)
+				break;
+			if (i == 0)
+				srand48(t0.tv_sec ^ t0.tv_usec);
+			usleep(lrand48() % 100000);
+			gettimeofday(&t1, NULL);
+		}
+		if (result < 0 && errno == ECONNREFUSED) {
+			unlink(SOCKET_PATH);
+			fprintf(stderr,
+				"Waited 3 seconds for master.  giving up.\n");
+			close(fd);
+			goto become_master;
+		}
+		if (result < 0) {
+			perror("connect");
+			exit(1);
+		}
+		return slave(fd, args);
+	} else {
+		perror("bind");
+		exit(1);
+	}
+}
Index: emc2/src/rtapi/linux_ulapi.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ emc2/src/rtapi/linux_ulapi.c	2009-10-11 00:08:37.000000000 +0200
@@ -0,0 +1,63 @@
+/********************************************************************
+* Description:  linux_ulapi.c
+*               This file, 'linux_ulapi.c', implements the user-level
+*               API functions for machines with Linux-realtime
+*
+* Author: John Kasunich, Paul Corner
+* Copyright (c) 2004 All rights reserved.
+*
+* License: LGPL Version 2
+*
+********************************************************************/
+
+#include <stddef.h>		/* NULL */
+#include <stdio.h>		/* printf */
+#include <malloc.h>		/* malloc(), free() */
+#include <sys/time.h>
+#include <time.h>
+#include <string.h>
+#include "rtapi.h"
+#include <unistd.h>
+
+int rtapi_init(const char *modname)
+{
+	/* does nothing, for now */
+	return getpid();
+}
+
+int rtapi_exit(int module_id)
+{
+	/* does nothing, for now */
+	return 0;
+}
+
+/* FIXME - no support for fifos */
+
+int rtapi_fifo_new(int key, int module_id, unsigned long int size, char mode)
+{
+	return -ENOSYS;
+}
+
+int rtapi_fifo_delete(int fifo_id, int module_id)
+{
+	return -ENOSYS;
+}
+
+int rtapi_fifo_read(int fifo_id, char *buf, unsigned long size)
+{
+	return -ENOSYS;
+}
+
+int rtapi_fifo_write(int fifo_id, char *buf, unsigned long int size)
+{
+	return -ENOSYS;
+}
+
+long long rtapi_get_time(void)
+{
+	struct timeval tv;
+	gettimeofday(&tv, 0);
+	return tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000;
+}
+
+#include "rtapi/linux_common.h"
Index: emc2/src/rtapi/linux_common.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ emc2/src/rtapi/linux_common.h	2009-10-11 19:02:15.000000000 +0200
@@ -0,0 +1,240 @@
+#include <sys/time.h>
+#include <time.h>
+#include <stdio.h>
+
+static int msg_level = RTAPI_MSG_INFO;	/* message printing level */ //XXX
+
+#include <sys/ipc.h>		/* IPC_* */
+#include <sys/shm.h>		/* shmget() */
+#include <pthread.h>
+
+/* These structs hold data associated with objects like tasks, etc. */
+/* Task handles are pointers to these structs.                      */
+
+typedef struct {
+	int magic;		/* to check for valid handle */
+	int key;		/* key to shared memory area */
+	int id;			/* OS identifier for shmem */
+	int count;		/* count of maps in this process */
+	unsigned long int size;	/* size of shared memory area */
+	void *mem;		/* pointer to the memory */
+} rtapi_shmem_handle;
+
+#define MAX_SHM		64
+
+#define SHMEM_MAGIC	25453	/* random numbers used as signatures */
+
+
+static rtapi_shmem_handle shmem_array[MAX_SHM];
+static pthread_mutex_t shmem_array_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+int rtapi_shmem_new(int key, int module_id, unsigned long int size)
+{
+	rtapi_shmem_handle *shmem;
+	int i;
+
+	pthread_mutex_lock(&shmem_array_mutex);
+	for (i = 0; i < MAX_SHM; i++) {
+		if (shmem_array[i].magic == SHMEM_MAGIC
+		    && shmem_array[i].key == key) {
+			shmem_array[i].count++;
+			pthread_mutex_unlock(&shmem_array_mutex);
+			return i;
+		}
+		if (shmem_array[i].magic != SHMEM_MAGIC)
+			break;
+	}
+	if (i == MAX_SHM) {
+		pthread_mutex_unlock(&shmem_array_mutex);
+		return -ENOMEM;
+	}
+	shmem = &shmem_array[i];
+
+	/* now get shared memory block from OS */
+	shmem->id = shmget((key_t) key, (int)size, IPC_CREAT | 0666);
+	if (shmem->id == -1) {
+		pthread_mutex_unlock(&shmem_array_mutex);
+		return -ENOMEM;
+	}
+	/* and map it into process space */
+	shmem->mem = shmat(shmem->id, 0, 0);
+	if ((ssize_t) (shmem->mem) == -1) {
+		pthread_mutex_unlock(&shmem_array_mutex);
+		return -ENOMEM;
+	}
+
+	/* label as a valid shmem structure */
+	shmem->magic = SHMEM_MAGIC;
+	/* fill in the other fields */
+	shmem->size = size;
+	shmem->key = key;
+	shmem->count = 1;
+
+	pthread_mutex_unlock(&shmem_array_mutex);
+
+	/* return handle to the caller */
+	return i;
+}
+
+int rtapi_shmem_getptr(int handle, void **ptr)
+{
+	rtapi_shmem_handle *shmem;
+
+	if (handle < 0 || handle >= MAX_SHM)
+		return -EINVAL;
+
+	shmem = &shmem_array[handle];
+
+	/* validate shmem handle */
+	if (shmem->magic != SHMEM_MAGIC)
+		return -EINVAL;
+
+	/* pass memory address back to caller */
+	*ptr = shmem->mem;
+
+	return 0;
+}
+
+int rtapi_shmem_delete(int handle, int module_id)
+{
+	struct shmid_ds d;
+	int r1, r2;
+	rtapi_shmem_handle *shmem;
+
+	if (handle < 0 || handle >= MAX_SHM)
+		return -EINVAL;
+
+	pthread_mutex_lock(&shmem_array_mutex);
+	shmem = &shmem_array[handle];
+
+	/* validate shmem handle */
+	if (shmem->magic != SHMEM_MAGIC) {
+		pthread_mutex_unlock(&shmem_array_mutex);
+		return -EINVAL;
+	}
+
+	shmem->count--;
+	if (shmem->count) {
+		pthread_mutex_unlock(&shmem_array_mutex);
+		return 0;
+	}
+
+	/* unmap the shared memory */
+	r1 = shmdt(shmem->mem);
+
+	/* destroy the shared memory */
+	r2 = shmctl(shmem->id, IPC_STAT, &d);
+	if (r2 == 0 && d.shm_nattch == 0) {
+		r2 = shmctl(shmem->id, IPC_RMID, &d);
+	}
+
+	/* free the shmem structure */
+	shmem->magic = 0;
+
+	pthread_mutex_unlock(&shmem_array_mutex);
+
+	if ((r1 != 0) || (r2 != 0))
+		return -EINVAL;
+	return 0;
+}
+
+#define BUFFERLEN 1024
+
+void default_rtapi_msg_handler(msg_level_t level, const char *buffer)
+{
+	if (level == RTAPI_MSG_ALL)
+		fputs(buffer, stdout);
+	else
+		fputs(buffer, stderr);
+}
+
+static rtapi_msg_handler_t rtapi_msg_handler = default_rtapi_msg_handler;
+
+rtapi_msg_handler_t rtapi_get_msg_handler(void)
+{
+	return rtapi_msg_handler;
+}
+
+void rtapi_set_msg_handler(rtapi_msg_handler_t handler)
+{
+	if (handler == NULL)
+		rtapi_msg_handler = default_rtapi_msg_handler;
+	else
+		rtapi_msg_handler = handler;
+}
+
+void rtapi_print(const char *fmt, ...)
+{
+	char buffer[BUFFERLEN + 1];
+	va_list args;
+
+	va_start(args, fmt);
+	/* call the normal library vnsprintf() */
+	vsnprintf(buffer, BUFFERLEN, fmt, args);
+	rtapi_msg_handler(RTAPI_MSG_ALL, buffer);
+	va_end(args);
+}
+
+void rtapi_print_msg(int level, const char *fmt, ...)
+{
+	char buffer[BUFFERLEN + 1];
+	va_list args;
+
+	if ((level <= msg_level) && (msg_level != RTAPI_MSG_NONE)) {
+		va_start(args, fmt);
+		/* call the normal library vnsprintf() */
+		vsnprintf(buffer, BUFFERLEN, fmt, args);
+		rtapi_msg_handler(level, buffer);
+		va_end(args);
+	}
+}
+
+int rtapi_snprintf(char *buffer, unsigned long int size, const char *msg, ...)
+{
+	va_list args;
+	int result;
+
+	va_start(args, msg);
+	/* call the normal library vnsprintf() */
+	result = vsnprintf(buffer, size, msg, args);
+	va_end(args);
+
+	return result;
+}
+
+int rtapi_vsnprintf(char *buffer, unsigned long int size, const char *fmt,
+		    va_list args)
+{
+	return vsnprintf(buffer, size, fmt, args);
+}
+
+int rtapi_set_msg_level(int level)
+{
+	msg_level = level;
+	return 0;
+}
+
+int rtapi_get_msg_level()
+{
+	return msg_level;
+}
+
+#ifdef MSR_H_USABLE
+#include <asm/msr.h>
+#elif defined(__i386__) || defined(__x86_64__)
+#define rdtscll(val) \
+         __asm__ __volatile__("rdtsc" : "=A" (val))
+#else
+#warning No implementation of rtapi_get_clocks available
+#define rdtscll(val) (val)=0
+#endif
+
+long long rtapi_get_clocks(void)
+{
+	long long int retval;
+
+	rdtscll(retval);
+
+	return retval;
+}
Index: emc2/scripts/realtime.in
===================================================================
--- emc2.orig/scripts/realtime.in	2009-10-02 21:02:33.000000000 +0200
+++ emc2/scripts/realtime.in	2009-10-02 21:03:04.000000000 +0200
@@ -66,7 +66,7 @@
     MODULES_LOAD=
     MODULES_UNLOAD=
     case $RTPREFIX in
-    sim) SHM_DEV=/dev/zero;;
+    sim|linux) SHM_DEV=/dev/zero;;
     *)
         for  MOD in $MODULES ; do
             eval MOD=\${MODPATH_$MOD}
@@ -94,7 +94,7 @@
 
 CheckStatus(){
     case $RTPREFIX in
-    sim)
+    sim|linux)
         if [ -z "$($PIDOF rtapi_app)" ]; then
             exit 1
         else
@@ -142,7 +142,7 @@
 
 Load(){
     case $RTPREFIX in
-    sim)
+    sim|linux)
     ;;
     *)
         for MOD in $MODULES_LOAD ; do
@@ -170,7 +170,7 @@
 
 Unload(){
     case $RTPREFIX in
-    sim)
+    sim|linux)
         rtapi_app exit 
         ipcrm -M 0x48414c32 2>/dev/null
         ;;
Index: emc2/src/module_helper/Submakefile
===================================================================
--- emc2.orig/src/module_helper/Submakefile	2009-10-02 21:13:58.000000000 +0200
+++ emc2/src/module_helper/Submakefile	2009-10-10 23:46:43.000000000 +0200
@@ -1,4 +1,4 @@
-ifneq ("$(RTPREFIX)","sim")
+ifeq "$(filter sim linux,$(RTPREFIX))" ""
 MODULE_HELPERSRCS := \
 	module_helper/module_helper.c
 USERSRCS += $(MODULE_HELPERSRCS)
Index: emc2/src/hal/utils/halcmd_commands.c
===================================================================
--- emc2.orig/src/hal/utils/halcmd_commands.c	2009-10-02 21:25:13.000000000 +0200
+++ emc2/src/hal/utils/halcmd_commands.c	2009-10-02 21:26:09.000000000 +0200
@@ -512,7 +512,7 @@
         return -EINVAL;
     }	
 
-#if defined(RTAPI_SIM)
+#if defined(RTAPI_SIM) || defined(RTAPI_LINUX)
     {
         char *argv[MAX_TOK];
         int m = 0, result;
@@ -1056,7 +1056,7 @@
     hal_comp_t *comp;
     char *argv[MAX_TOK+3];
     char *cp1;
-#if defined(RTAPI_SIM)
+#if defined(RTAPI_SIM) || defined(RTAPI_LINUX)
     argv[m++] = "-Wn";
     argv[m++] = mod_name;
     argv[m++] = EMC2_BIN_DIR "/rtapi_app";
@@ -1110,7 +1110,7 @@
 
     if ( retval != 0 ) {
 	halcmd_error("insmod failed, returned %d\n"
-#if !defined(RTAPI_SIM)
+#if !defined(RTAPI_SIM) && !defined(RTAPI_LINUX)
             "See the output of 'dmesg' for more information.\n"
 #endif
         , retval );
@@ -1301,7 +1301,7 @@
     int retval;
     char *argv[4];
 
-#if defined(RTAPI_SIM)
+#if defined(RTAPI_SIM) || defined(RTAPI_LINUX)
     argv[0] = EMC2_BIN_DIR "/rtapi_app";
     argv[1] = "unload";
 #else
Index: emc2/src/hal/utils/halrmt.c
===================================================================
--- emc2.orig/src/hal/utils/halrmt.c	2009-10-02 21:24:37.000000000 +0200
+++ emc2/src/hal/utils/halrmt.c	2009-10-02 21:25:03.000000000 +0200
@@ -1125,7 +1125,7 @@
     char *cp1;
     const char *nakStr = "SET LOADRT NAK";
 
-#if defined(RTAPI_SIM)
+#if defined(RTAPI_SIM) || defined(RTAPI_LINUX)
     argv[m++] = "-Wn";
     argv[m++] = mod_name;
     argv[m++] = EMC2_BIN_DIR "/rtapi_app";
Index: emc2/src/Makefile
===================================================================
--- emc2.orig/src/Makefile	2009-10-02 20:05:26.000000000 +0200
+++ emc2/src/Makefile	2009-10-11 21:19:51.000000000 +0200
@@ -52,7 +52,7 @@
 # The "modules" target is the gateway to the kernel module build.
 default: configs userspace modules
 ifeq ($(RUN_IN_PLACE),yes)
-ifneq ($(BUILD_SYS),sim)
+ifeq "$(filter sim linux,$(BUILD_SYS))" ""
 	@if [ -f ../bin/emc_module_helper ]; then if ! [ `stat -c %u ../bin/emc_module_helper` -eq 0 -a -u ../bin/emc_module_helper ]; then $(VECHO) "You now need to run 'sudo make setuid' in order to run in place."; fi; fi
 endif
 endif
@@ -361,9 +361,9 @@
 # So that nothing is built as root, this rule does not depend on the touched
 # files (Note that files in depends/ might be rebuilt, and there's little that
 # can be done about it)
-ifeq ($(BUILD_SYS),sim)
+ifneq "$(filter sim linux,$(BUILD_SYS))" ""
 setuid:
-	@echo "'make setuid' is not needed for the simulator"
+	@echo "'make setuid' is not needed for the simulator/linux-rt"
 else
 setuid:
 	chown root ../bin/emc_module_helper
@@ -484,7 +484,7 @@
 	$(FILE) ../share/emc/pncconf.glade $(DESTDIR)$(prefix)/share/emc
 	$(FILE) ../configs/common/emc.nml $(DESTDIR)$(prefix)/share/emc
 
-ifneq ($(BUILD_SYS),sim)
+ifeq "$(filter sim linux,$(BUILD_SYS))" ""
 	@for B in ${HM2_BOARDS}; do  \
 		echo copying files for $$B firmware package;  \
 		$(FILE) hal/drivers/mesa-hostmot2/firmware/$$B/*.BIT $(DESTDIR)/lib/firmware/hm2/$$B/;  \
@@ -512,7 +512,7 @@
 		$(DESTDIR)$(bindir) \
 		$(DESTDIR)$(sysconfdir)/emc2
 	$(FILE) ../rtlib/*$(MODULE_EXT) $(DESTDIR)$(EMC2_RTLIB_DIR)
-ifneq "$(BUILD_SYS)" "sim"
+ifeq "$(filter sim linux,$(BUILD_SYS))" ""
 	$(SETUID) ../bin/emc_module_helper $(DESTDIR)$(bindir)
 	$(SETUID) ../bin/bfload $(DESTDIR)$(bindir)
 	$(SETUID) ../bin/pci_write $(DESTDIR)$(bindir)
@@ -580,7 +580,7 @@
 # find a way around it.
 
 # Subdirectory:  rtapi
-ifneq ($(BUILD_SYS),sim)
+ifeq "$(filter sim linux,$(BUILD_SYS))" ""
 obj-$(CONFIG_RTAPI) += rtapi.o
 rtapi-objs := rtapi/$(RTPREFIX)_rtapi.o
 endif
@@ -626,7 +626,7 @@
 sampler-objs := hal/components/sampler.o $(MATHSTUB)
 
 # Subdirectory: hal/drivers
-ifneq ($(BUILD_SYS),sim)
+ifeq "$(filter sim linux,$(BUILD_SYS))" ""
 obj-$(CONFIG_HAL_PARPORT) += hal_parport.o
 hal_parport-objs := hal/drivers/hal_parport.o $(MATHSTUB)
 obj-$(CONFIG_PCI_8255) += pci_8255.o
@@ -749,7 +749,7 @@
 motmod-objs += libnml/posemath/sincos.o $(MATHSTUB)
 
 TORTOBJS = $(foreach file,$($(patsubst %.o,%,$(1))-objs), objects/rt$(file))
-ifeq ($(BUILD_SYS),sim)
+ifneq "$(filter sim linux,$(BUILD_SYS))" ""
 EXTRA_CFLAGS += -fPIC -Os
 RTOBJS := $(sort $(foreach mod,$(obj-m),$(call TORTOBJS,$(mod))))
 
@@ -797,8 +797,8 @@
 	@ld -r -static -S -Os -o $@ $^ $(EXTRALINK) $(MATHLIB)
 endif
 
-ifneq "$(filter normal sim,$(BUILD_SYS))" ""
-ifneq "$(BUILD_SYS)" "sim"
+ifneq "$(filter normal sim linux,$(BUILD_SYS))" ""
+ifeq "$(filter sim linux,$(BUILD_SYS))" ""
 ../rtlib/rtapi$(MODULE_EXT): $(addprefix objects/rt,$(rtapi-objs))
 endif
 ../rtlib/classicladder_rt$(MODULE_EXT): $(addprefix objects/rt,$(classicladder_rt-objs))
Index: emc2/src/Makefile.modinc
===================================================================
--- emc2.orig/src/Makefile.modinc	2009-10-10 22:47:35.000000000 +0200
+++ emc2/src/Makefile.modinc	2009-10-11 21:22:21.000000000 +0200
@@ -66,7 +66,7 @@
 	cp $(patsubst %.o,%.ko,$(obj-m)) $(DESTDIR)$(RTLIBDIR)/
 endif
 
-ifeq ($(BUILDSYS),sim)
+ifneq "$(filter sim linux,$(BUILDSYS))" ""
 EXTRA_CFLAGS += -DSIM -fPIC
 allmodules = $(patsubst %.o,%.so,$(obj-m))
 modules: $(allmodules)
Index: emc2/src/Makefile.modinc.in
===================================================================
--- emc2.orig/src/Makefile.modinc.in	2009-10-02 22:03:49.000000000 +0200
+++ emc2/src/Makefile.modinc.in	2009-10-10 23:05:46.000000000 +0200
@@ -66,7 +66,7 @@
 	cp $(patsubst %.o,%.ko,$(obj-m)) $(DESTDIR)$(RTLIBDIR)/
 endif
 
-ifeq ($(BUILDSYS),sim)
+ifneq "$(filter sim linux,$(BUILDSYS))" ""
 EXTRA_CFLAGS += -DSIM -fPIC
 allmodules = $(patsubst %.o,%.so,$(obj-m))
 modules: $(allmodules)
Index: emc2/src/hal/drivers/Submakefile
===================================================================
--- emc2.orig/src/hal/drivers/Submakefile	2009-10-02 22:02:08.000000000 +0200
+++ emc2/src/hal/drivers/Submakefile	2009-10-10 23:51:13.000000000 +0200
@@ -37,7 +37,7 @@
 
 # The kernel's build system won't know how to rebuild generated files
 # so modules must depend on them explicitly
-ifneq ($(BUILD_SYS),sim)
+ifeq "$(filter sim linux,$(BUILD_SYS))" ""
 modules:                                                         \
     hal/drivers/pluto_servo_rbf.h                                \
     hal/drivers/m5i20_HM5-4E.h                                   \
Index: emc2/src/hal/utils/Submakefile
===================================================================
--- emc2.orig/src/hal/utils/Submakefile	2009-10-02 22:01:13.000000000 +0200
+++ emc2/src/hal/utils/Submakefile	2009-10-10 23:49:36.000000000 +0200
@@ -67,7 +67,7 @@
 $(call TOOBJS, $(HALGTKSRCS)): Makefile.inc
 endif
 
-ifneq ($(BUILD_SYS),sim)
+ifeq "$(filter sim linux,$(BUILD_SYS))" ""
 M5I20CFGSRCS := hal/utils/m5i20cfg.c
 USERSRCS += $(M5I20CFGSRCS)
 ../bin/m5i20cfg: $(call TOOBJS, $(M5I20CFGSRCS))
Index: emc2/tests/hm2-idrom/skip
===================================================================
--- emc2.orig/tests/hm2-idrom/skip	2009-10-10 23:13:41.000000000 +0200
+++ emc2/tests/hm2-idrom/skip	2009-10-10 23:14:26.000000000 +0200
@@ -1,3 +1,3 @@
 #!/bin/sh
 . rtapi.conf
-! [ "$RTPREFIX" = sim ]
+! [ "$RTPREFIX" = sim -o "$RTPREFIX" = linux ]
