Index: .cvsignore
===================================================================
--- .cvsignore	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
+++ .cvsignore	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
@@ -0,0 +1,1 @@
+o-optimize
Index: pcmmio/ChangeLog
===================================================================
--- pcmmio/ChangeLog	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
+++ pcmmio/ChangeLog	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
@@ -0,0 +1,213 @@
+2009-12-14	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* mio_io_rtems.c: Make internal routines static.
+
+2009-12-14	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* Makefile, README, mio_io_rtems.c, pcmmio_commands.h: Add command to
+	benchmark discrete input including message queue send and receive.
+	* main_pcmmio_benchmark.c: New file.
+
+2009-12-11	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* mio_io_rtems.c: Ensure mio_error_code is properly initialized to
+	MIO_SUCCESS.
+
+2009-12-11	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* main_pcmmio_din.c, main_pcmmio_irq.c, pcmmio_shell.c: Report time
+	between discrete in interrupts in microseconds.
+
+2009-12-11	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* README: Add section on RTEMS Configuration needed by driver.
+	* mio_io_rtems.c: Switch to using a message queue for transmitting
+	discrete interrupt changes to the task level.
+	* pcmmio_shell.c: Modify application configuration to take into
+	account one less barrier and the new message queue.
+
+2009-12-11	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* README: Add list of new methods.
+	* mio_io.h, mio_io_rtems.c: Add dio_get_missed_interrupts() with
+	no tracking of missed interrupts since will switch to message queues.
+
+2009-10-21	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* main_pcmmio_din.c, main_pcmmio_irq.c: Adjust bit numbering
+	difference.
+
+2009-10-13	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* main_pcmmio_dac.c: Fix help message.
+
+2009-08-13	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* main_pcmmio_dout.c: Fix mismatch in numbering between our view of
+	0-47 and driver's 1-48 view.
+
+2009-08-13	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* main_pcmmio_irq.c, mio_io.h, mio_io_rtems.c: Add ADCs confirmed to
+	work using the dac command. Both single voltages and a pattern were
+	written.
+
+2009-08-12	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* Makefile, README, main_pcmmio_adc.c, main_pcmmio_dac.c,
+	main_pcmmio_din.c, main_pcmmio_dout.c, mio_io_rtems.c,
+	pcmmio_shell.c: Discrete input polled and interrupt now works.
+
+2009-07-23	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* main_pcmmio_irq.c: Add code to report interrupts.
+
+2009-07-23	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* main_pcmmio_adc.c, main_pcmmio_dac.c, main_pcmmio_din.c,
+	main_pcmmio_dout.c, main_pcmmio_irq.c: Update checks of return status
+	from rtems_string_to_XXX to reflect change to rtems_status_code.
+
+2009-07-22	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* Makefile, README, main_pcmmio_dac.c, mio_io.h, mio_io_rtems.c,
+	pcmmio_commands.h, pcmmio_shell.c, rtems_config.c: Add pcmmio_irq
+	command and do some cleanup as noticed on other files.
+	* main_pcmmio_irq.c: New file.
+
+2009-07-22	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* README: Fix typo.
+
+2009-07-22	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* README, main_pcmmio_dac.c, rtems_config.c: Add mode to pcmmio_dac
+	command where it can write a pattern.
+
+2009-07-22	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* README, main_pcmmio_adc.c, main_pcmmio_dac.c, main_pcmmio_din.c,
+	main_pcmmio_dout.c, pcmmio_commands.h: Switch to rtems/string2.h
+	methods. Verify negative voltages are allowed as input.
+
+2009-07-21	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* Makefile, README, main_pcmmio_dac.c, main_pcmmio_dout.c: Added
+	string2XXX routines to RTEMS so we have ability to do heavy error
+	checking on numeric inputs.
+
+2009-07-21	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* Makefile, README, mio_io.h, pcmmio_commands.h: Add pcmmio_dac
+	command.
+	* main_pcmmio_dac.c: New file.
+
+2009-07-20	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* Makefile, README, main_pcmmio_din.c, main_pcmmio_dout.c,
+	pcmmio_commands.h: Add initial command to monitor analog inputs.
+	Clean up help and usage.
+	* main_pcmmio_adc.c: New file.
+
+2009-07-20	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* README: Add description of commands.
+	* main_pcmmio_din.c, main_pcmmio_dout.c: Fix usage.
+
+2009-07-20	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* Makefile, main_pcmmio_din.c, pcmmio_commands.h, pcmmio_shell.c: Add
+	dout command.
+	* main_pcmmio_dout.c: New file.
+
+2009-07-20	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* Makefile: Put each command in its own file.
+	* main_pcmmio_din.c: New file.
+	* pcmmio_commands.c: Removed.
+
+2009-07-20	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* pcmmio_commands.c: Clean up command.
+
+2009-07-17	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* Makefile: Add dependencies so .exe's are relinked.
+	* mio_io.c: Typo.
+	* pcmmio_commands.c: Basic shell of command works.
+
+2009-07-17	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* Makefile: Shell appplication configured with a dummy pcmmio command.
+	* pcmmio_commands.c, pcmmio_commands.h, pcmmio_shell.c: New files.
+
+2009-07-16	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* Makefile, rtems_config.c: Simple RTEMS Application runs polled. Does
+	not report errors and reports all zeroes on input discretes.
+
+2009-07-10	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* rtems_config.c: Bump POSIX threads.
+
+2009-06-17	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* Status: New file.
+
+2009-06-17	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* buffered.c, dacbuff.c, dacout.c, flash.c, getall.c, getvolt.c,
+	kbhit.c, mio_io.c, mio_io_linux.c, mio_io_rtems.c, pcmmio.c, poll.c,
+	repeat.c, rtems_config.c: Clean up. Worked on RTEMS IRQ support code.
+
+2009-06-10	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* mio_io.h, mio_io_rtems.c: Add timestamps to buffered interrupts.
+	* rtems_config.c: Switch to POSIX Initialization thread and up
+	configured pthreads so application can create one.
+
+2009-06-10	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* rtems_config.c: Needs 4 barriers.
+
+2009-06-10	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* README: Document state of the driver.
+	* mio_io.h, mio_io_rtems.c: Move to shared interrupts when possible.
+	* rtems_config.c: Implement the RTEMS configuration and initialization.
+
+2009-06-10	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* mio_io_rtems.c: Initial interrupt support added. Should now be on
+	functional parity with Linux driver but not debugged.
+
+2009-06-10	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* mio_io_rtems.c: All Linux functionality should be implemented now
+	EXCEPT hooking the interrupt.
+
+2009-06-10	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* mio_io_rtems.c: Add checking for interrupt status.
+
+2009-06-08	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* Makefile, flash.c, mio_io.h: All programs now compile with the copied
+	RTEMS specific porting layer file.
+	* .cvsignore, mio_io_rtems.c: New files.
+
+2009-06-08	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* Makefile, mio_io.c, mio_io.h: Linux code split to porting file.
+	* mio_io_linux.c: New file.
+
+2009-06-08	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* Makefile, kbhit.c, mio_io.c, mio_io.h: First successful compilation
+	under RTEMS. Added some Linux ifdef's.
+	* rtems_config.c: New file.
+
+2009-06-08	Joel Sherrill <joel.sherrill@oarcorp.com>
+
+	* ChangeLog, Makefile.linux, README: New files.
+
Index: pcmmio/README
===================================================================
--- pcmmio/README	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
+++ pcmmio/README	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
@@ -0,0 +1,110 @@
+#
+#  $Id$
+#
+
+This is a port of the Winsystems Linux driver to RTEMS.
+
+In general, the goal was to minimize changes to the user level
+library and only replace Linux IO calls to the device driver
+with direct access functions. 
+
+The driver uses 4 Classic API Barriers.
+
+--joel sherrill
+
+Issues
+======
++ The library is not reentrant. The GNU/Linux version uses global variables
+  to track the state of certain variables and access to these is not protected.
+  This design flaw is carried over into the RTEMS version.
+
++ We want to timestamp samples and the initial code did not do that.  I
+  added this.
+
+New Methods
+===========
+  void pcmmio_initialize(
+    unsigned short _base_port,
+    unsigned short _irq
+  );
+
+  void flush_buffered_ints(void);
+
+  int wait_adc_int_with_timeout(int adc_num, int milliseconds);
+
+  int wait_dac_int_with_timeout(int dac_num, int milliseconds);
+
+  int wait_dio_int_with_timeout(int milliseconds);
+
+  int wait_dio_int_with_timestamp(
+    int                 milliseconds,
+    unsigned long long *timestamp
+  );
+  int dio_get_missed_interrupts(void);
+
+RTEMS Configuration
+===================
+The driver needs:
+
++ 3 Classic API Barriers
++ 1 Classic API Message Queue
+  - 1024 buffers of sizeof(din_messsage_t) (should be 12 bytes)
+
+The pcmmio_shell example is probably over configured but is a
+working guide.
+
+RTEMS Shell Commands
+====================
+The following RTEMS Shell configuration aids are defined to assist in
+adding PCMMIO related commands to your shell.
+  CONFIGURE_PCMMIO_ALIASES
+  CONFIGURE_PCMMIO_COMMANDS
+
+pcmmio_din - Read Discrete Inputs
+    pcmmio_din [-i iterations] [-p period] [-v]
+    Where: maximum iterations defaults to 1
+           the period is in milliseconds and defaults to 1000
+
+pcmmio_dout - Write a Discrete Output
+    pcmmio_dout bit value
+    Where: bit must be 0-47
+           value must be 0 or 1
+
+pcmmio_adc - Read Analog Inputs
+    pcmmio_adc [-i iterations] [-p period] [-v]
+    Where: maximum iterations defaults to 1
+           the period is in milliseconds and defaults to 1000
+
+pcmmio_dac - Write Analog Output
+    pcmmio_dac dac voltage
+    pcmmio_dac dac low high step time_per_step maximum_time
+
+    Where: dac must be 0-7
+           voltages and step must be -10V to +10V
+           times are in milliseconds
+
+    First form is a single write.
+    Second form writes a pattern.
+
+pcmmio_irq - Wait for PCMMIO IRQs
+  pcmmio_irq [-i iterations] [-p period] [-v] [-d|-D DAC|-a ADC]
+
+  Where: maximum iterations defaults to 1
+         the period is in milliseconds and defaults to 1000
+         -d enables discrete input irq monitoring
+         -D DAC enables irq monitoring on the DAC channel "DAC"
+         -a ADC enables irq monitoring on the ADC channel "ADC"
+
+  You select one of the three IRQ sources to monitor.
+
+pcmmio_benchmark - Benchmark Discrete Input Interrupt Performance
+
+  pcmmio_benchmarks [-i interrupts] [-v]
+
+  Where: maximum interrupts must be >= 1
+
+Aliases
+  + adc  - alias for pcmmio_adc 
+  + dac  - alias for pcmmio_dac 
+  + din  - alias for pcmmio_din 
+  + dout - alias for pcmmio_dout 
Index: pcmmio/Status
===================================================================
--- pcmmio/Status	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
+++ pcmmio/Status	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
@@ -0,0 +1,16 @@
+#
+#  $Id$
+#
+
+Questions
+=========
++ IO Base Address has to be selected and jumpered
+
++ Interrupt is software programmed but must be selected
+
+Debug Issues
+============
++ RTEMS specific interrupt code and initialization is the main
+  area of risk in this driver.  The rest of the code is massaged
+  versions of the GNU/Linux driver.
+
Index: pcmmio/buffered.c
===================================================================
--- pcmmio/buffered.c	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
+++ pcmmio/buffered.c	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
@@ -0,0 +1,138 @@
+/* buffered.c Demonstration program for WinSystems PCM-MIO Driver */
+
+/*
+*
+* $Id$
+*
+* Compile for GNU/Linux with:
+*
+*   gcc buffered.c kbhit.c mio_io.o -o buffered -lpthread
+*
+*
+*  This program demonstrates the adc_buffered_channel_conversions function
+*  which allows for a programmed sequence of conversions to be accomplished
+*  with a single call.
+*/
+
+/* Our IOCTL definitions and all function prototypes */
+
+#include "mio_io.h"    
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* This array will hold 2000 channel numbers plus a terminating 0xff charcter */
+
+unsigned char to_do_channels[2001];
+
+/* This array will store the results of 2000 conversions */
+
+unsigned short values[2000];
+
+/* Keyboard support function prototypes */
+
+void init_keyboard(void);
+void close_keyboard(void);
+int kbhit(void);
+int readch(void);
+
+
+int main(int argc, char* argv[])
+{
+int channel = 0;
+unsigned short result;
+float current;
+unsigned long count = 0;
+int x;
+
+	/* Set up all 16 channels for the +/- 10 Volt range */
+
+	for(channel =0; channel < 16; channel ++)
+	{
+		adc_set_channel_mode(channel,ADC_SINGLE_ENDED,ADC_BIPOLAR,ADC_TOP_10V);
+		if(mio_error_code)
+		{
+			printf("\nError occured - %s\n",mio_error_string);
+			exit(1);
+		}
+	}
+
+	/* We'll fill the to_do list with the four different channels 500
+	  each successively.
+    */
+
+	for(x=0; x < 500; x++)
+	{
+		to_do_channels[x] = 0;
+		to_do_channels[x+500] = 1;
+		to_do_channels[x+1000] = 2;
+		to_do_channels[x+1500] = 3;
+
+	}
+
+	/* Load the "terminator" into the last position */ 
+
+	to_do_channels[2000] = 0xff;
+
+	/*  We'll keep going until a key is pressed */
+
+	init_keyboard();
+
+	while(!kbhit())
+	{
+		/* Start up the conversions. This function returns when all 2000 of
+	     our conversions are complete.
+	    */
+
+		adc_buffered_channel_conversions(to_do_channels,values);
+		
+		count += 2000;
+
+		if(mio_error_code)
+		{
+			printf("\nError occured - %s\n",mio_error_string);
+			exit(1);
+		}
+
+		/* We'll extract our data from the "values" array. In order to make the
+		 display more readable, we'll take a value from each channel display them,
+		 and move to the next result.
+		*/
+
+		for(x=0; x < 500; x++)
+		{
+			printf("%08ld  ",count);
+
+			/* Get the raw data */
+
+			result = values[x];
+
+			/* Convert to voltage */
+
+			current = adc_convert_to_volts(0, result);
+
+			/* Display the value */
+
+			printf("CH0 %9.5f ",current);
+
+			/* Repeat for channels 1 - 3  */
+
+			result = values[x+500];
+			current = adc_convert_to_volts(1, result);
+			printf("CH1 %9.5f ",current);
+
+			result = values[x+1000];
+			current = adc_convert_to_volts(2, result);
+			printf("CH2 %9.5f ",current);
+			
+			result = values[x+1500];
+			current = adc_convert_to_volts(3, result);
+			printf("CH3 %9.5f ",current);
+			printf("\r");
+		}
+	}
+	readch();
+	printf("\n\n");
+	close_keyboard();
+	return 0;
+}
Index: pcmmio/j.diff
===================================================================
--- pcmmio/j.diff	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
+++ pcmmio/j.diff	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
@@ -0,0 +1,56 @@
+Index: mio_io_rtems.c
+===================================================================
+RCS file: /home/CVS-Mitre/pcmmio-rtems/mio_io_rtems.c,v
+retrieving revision 1.10
+diff -u -r1.10 mio_io_rtems.c
+--- mio_io_rtems.c	13 Aug 2009 20:49:38 -0000	1.10
++++ mio_io_rtems.c	11 Dec 2009 15:12:44 -0000
+@@ -663,24 +681,34 @@
+       #endif
+ 
+       /*
+-       * Buffer the interrupt
+-       *
+-       * NOTE: No need to worry about disabling interrupts,
+-       *       we are in interrupts.
++       * Ensure there is space to buffer the interrupt
+        */
++      if ( inptr == (outptr-1) || ((inptr == MAX_INTS) && outptr == 0)) {
++        pcmmio_dio_missed_interrupts++;
+ 
+-      int_buffer[inptr].timestamp = rdtsc();
+-      int_buffer[inptr].line = int_num;
+-      inptr++;
+-      if (inptr == MAX_INTS)
+-        inptr = 0;
++	/* Clear the interrupt */
++	clr_int(int_num);
++        /* at last slot */
++      } else {
++        /*
++         * Buffer the interrupt
++         *
++         * NOTE: No need to worry about disabling interrupts,
++         *       we are in interrupts.
++         */
++	int_buffer[inptr].timestamp = rdtsc();
++	int_buffer[inptr].line = int_num;
++	inptr++;
++	if (inptr == MAX_INTS)
++	  inptr = 0;
+ 
+-      /* Clear the interrupt */
+-      clr_int(int_num);
+-    }
++	/* Clear the interrupt */
++	clr_int(int_num);
+ 
+-    /* Wake up anybody waiting for a DIO interrupt */
+-    wake_up_interruptible(&wq_dio);
++        /* Wake up anybody waiting for a DIO interrupt */
++        wake_up_interruptible(&wq_dio);
++      }
++    }
+   }
+ 
+   if (status & 0x10) {
Index: pcmmio/mio_io.c
===================================================================
--- pcmmio/mio_io.c	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
+++ pcmmio/mio_io.c	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
@@ -0,0 +1,1497 @@
+/* mio_io.c
+ * WinSystems support module file for the PCM-MIO Linux and RTEMS drivers
+ *
+ *  $Id$
+ *
+ *  This file implements all of the supported 'C' language functions.
+ *  Where necessary calls are made into a porting layer to access the
+ *  actual hardware.
+ */
+
+#define LIB_DEFINED
+
+/* #define DEBUG 1 */
+
+#include "mio_io.h"    
+
+#include <stdio.h>
+
+/* These image variable help out where a register is not
+   capable of a read/modify/write operation
+*/
+
+unsigned char dio_port_images[8];
+unsigned char adc1_port_image =0;
+unsigned char adc2_port_image =0;
+unsigned char dac1_port_image =0;
+unsigned char dac2_port_image =0;
+
+
+/* The channel selects on the ADC are non contigous. In order to avoid shifting and such
+   with each channel select, we simple bild an array for selection.
+*/
+
+unsigned char adc_channel_select[16] = {ADC_CH0_SELECT, ADC_CH1_SELECT, ADC_CH2_SELECT,
+	ADC_CH3_SELECT, ADC_CH4_SELECT, ADC_CH5_SELECT, ADC_CH6_SELECT, ADC_CH7_SELECT,
+	ADC_CH0_SELECT, ADC_CH1_SELECT, ADC_CH2_SELECT, ADC_CH3_SELECT, ADC_CH4_SELECT,
+	ADC_CH5_SELECT, ADC_CH6_SELECT, ADC_CH7_SELECT };
+
+/* Mode selection can also be time consuming and we'd also like the mode to "Stick" from
+   call to call. This array will eventually hold the actual command byte to send to the
+   ADC controller for each channel according to the mode set with adc_set_channel_mode
+*/
+
+unsigned char adc_channel_mode[16] = {ADC_CH0_SELECT, ADC_CH1_SELECT, ADC_CH2_SELECT,
+	ADC_CH3_SELECT, ADC_CH4_SELECT, ADC_CH5_SELECT, ADC_CH6_SELECT, ADC_CH7_SELECT,
+	ADC_CH0_SELECT, ADC_CH1_SELECT, ADC_CH2_SELECT, ADC_CH3_SELECT, ADC_CH4_SELECT,
+	ADC_CH5_SELECT, ADC_CH6_SELECT, ADC_CH7_SELECT };
+
+
+/* This array and the index value are used internally for the adc_convert_all_channels
+  and for the adc_buffered_conversion routines.
+*/
+unsigned char adc_channel_buff[18] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,0xff,0xff};
+unsigned char *adc_input_buffer;
+unsigned short *adc_user_buffer;
+
+/* Becaues of the nature of the ADC beast. It's necessary to keep track of the last
+  channel and the previous channel in order to retrieve the data amd know who it belongs to
+*/
+
+int adc_last_channel, adc_current_channel;
+
+/* Various index pointers for the above arrays and misc globals */
+
+int adc_ch_index =0;
+int adc_out_index=0;
+int adc_repeat_channel;
+int adc_repeat_count;
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		DISABLE_DIO_INTERRUPT
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int disable_dio_interrupt(void)
+{
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	adc1_port_image = adc1_port_image | 0x10;
+	mio_write_reg(0x03, adc1_port_image);	// Access the int enable register
+	mio_write_reg(0x02, 0);
+	adc1_port_image = adc1_port_image & 0xef;
+	mio_write_reg(0x03,adc1_port_image );	// Disable the interrupt
+	
+	return(0);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		ENABLE_DIO_INTERRUPT
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int enable_dio_interrupt(void)
+{
+unsigned char vector;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	/* We read the assign IRQ from the driver, so we can program the hardware to
+	   match,  but only if an aaplication desires such.
+    */
+
+	vector = mio_read_irq_assigned();
+
+	if(vector == 0)
+	{
+		mio_error_code = MIO_MISSING_IRQ;
+		sprintf(mio_error_string,"MIO(DIO) : enable_dio_interrupt - No IRQ assigned");
+		return(1);
+	}
+
+	adc1_port_image = adc1_port_image | 0x10;
+	mio_write_reg(0x03, adc1_port_image);	// Access the int enable register
+	mio_write_reg(0x02, vector);
+	adc1_port_image = adc1_port_image & 0xef;
+	mio_write_reg(0x03, adc1_port_image);	// Enable the interrupt
+
+	return(0);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		DISABLE_DAC_INTERRUPT
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int disable_dac_interrupt(int dac_num)
+{
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	if(dac_num)
+	{
+		dac2_port_image = dac2_port_image & 0xfe;
+		dac2_port_image = dac2_port_image | 0x08;
+		mio_write_reg(0x0f, dac2_port_image);	// Access the int enable register
+		mio_write_reg(0x0e, 0);
+		dac2_port_image = dac2_port_image & 0xf7;
+		mio_write_reg(0x0f, dac2_port_image);	// Disable the interrupt
+	}
+	else
+	{
+		dac1_port_image = dac1_port_image & 0xfe;
+		dac1_port_image = dac1_port_image | 0x08;
+		mio_write_reg(0x0b, dac1_port_image);	// Access the int enable register
+	
+		mio_write_reg(0x0a, 0);
+
+		dac1_port_image = dac1_port_image & 0xf7;
+		mio_write_reg(0x0b, dac1_port_image);	// Disable the interrupt
+	}
+	return(0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		ENABLE_DAC_INTERRUPT
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int enable_dac_interrupt(int dac_num)
+{
+unsigned char vector;
+
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	/* We read the assign IRQ from the driver, so we can program the hardware to
+	   match,  but only if an aaplication desires such.
+    */
+
+	vector = mio_read_irq_assigned();
+
+	if(vector == 0)
+	{
+		mio_error_code = MIO_MISSING_IRQ;
+		sprintf(mio_error_string,"MIO(DAC) : enable_dac_interrupt - No IRQ assigned");
+		return(1);
+	}
+
+
+	if(dac_num)
+	{
+		dac2_port_image = dac2_port_image & 0xfe;
+		dac2_port_image = dac2_port_image | 0x08;
+		mio_write_reg(0x0f, dac2_port_image);	// Access the int enable register
+
+		mio_write_reg(0x0e, vector);
+
+		dac2_port_image = dac2_port_image & 0xf7;
+		dac2_port_image = dac2_port_image | 0x01;
+		mio_write_reg(0x0f, dac2_port_image);	// Enable the interrupt
+	}
+	else
+	{
+		dac1_port_image = dac1_port_image & 0xfe;
+		dac1_port_image = dac1_port_image | 0x08;
+		mio_write_reg(0x0b, dac1_port_image);	// Access the int enable register
+
+		mio_write_reg(0x0a, vector);
+
+		dac1_port_image = dac1_port_image & 0xf7;
+		dac1_port_image = dac1_port_image | 0x01;
+		mio_write_reg(0x0b, dac1_port_image);	// Enable the interrupt
+	}
+	return(0);
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		DISABLE_ADC_INTERRUPT
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int disable_adc_interrupt(int adc_num)
+{
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	if(adc_num)
+	{
+		adc2_port_image = adc2_port_image & 0xfe;
+		adc2_port_image = adc2_port_image | 0x08;
+		mio_write_reg(0x07, adc2_port_image);	// Access the int enable register
+
+		mio_write_reg(0x06, 0);
+
+		adc2_port_image = adc2_port_image & 0xf7;
+		mio_write_reg(0x07, adc2_port_image);	// Disable the interrupt
+	}
+	else
+	{
+		adc1_port_image = adc1_port_image & 0xfe;
+		adc1_port_image = adc1_port_image | 0x08;
+		mio_write_reg(0x03, adc1_port_image);	// Access the int enable register
+
+		mio_write_reg(0x02, 0);
+
+		adc1_port_image = adc1_port_image & 0xf7;
+		mio_write_reg(0x03, adc1_port_image);	// Disable the interrupt
+	}
+	return(0);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		ENABLE_ADC_INTERRUPT
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int enable_adc_interrupt(int adc_num)
+{
+unsigned char vector;
+
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	/* We read the assign IRQ from the driver, so we can program the hardware to
+	   match,  but only if an aaplication desires such.
+    */
+
+	vector = mio_read_irq_assigned();
+
+	if(vector == 0)
+	{
+		mio_error_code = MIO_MISSING_IRQ;
+		sprintf(mio_error_string,"MIO(ADC) : enable_adc_interrupt - No IRQ assigned");
+
+		return(1);
+	}
+
+	if(adc_num)
+	{
+		adc2_port_image = adc2_port_image & 0xfe;
+		adc2_port_image = adc2_port_image | 0x08;
+		mio_write_reg(0x07, adc2_port_image);	// Access the int enable register
+
+		mio_write_reg(0x06, vector);
+
+		adc2_port_image = adc2_port_image & 0xf7;
+		adc2_port_image = adc2_port_image | 0x01;
+		mio_write_reg(0x07, adc2_port_image);	// Enable the interrupt
+	}
+	else
+	{
+		adc1_port_image = adc1_port_image & 0xfe;
+		adc1_port_image = adc1_port_image | 0x08;
+		mio_write_reg(0x03, adc1_port_image);	// Access the int enable register
+
+		mio_write_reg(0x02, vector);
+
+		adc1_port_image = adc1_port_image & 0xf7;
+		adc1_port_image = adc1_port_image | 0x01;
+		mio_write_reg(0x03, adc1_port_image);	// Enable the interrupt
+	}
+	return(0);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		SET_DAC_SPAN
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int set_dac_span(int channel, unsigned char span_value)
+{
+unsigned char select_val;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	if((channel < 0) || (channel > 7))
+	{
+		mio_error_code = MIO_BAD_CHANNEL_NUMBER;
+		sprintf(mio_error_string,"MIO(DAC) : Set_dac_span - bad channel number %d",channel);
+		return(1);
+	}
+
+
+	/* This function sets up the output range for the DAC channel */
+
+	select_val = (channel % 4) << 1;
+
+	write_dac_data(channel / 4, span_value);
+	if(mio_error_code)
+		return 1;
+
+	write_dac_command(channel / 4, 0x60 | select_val);
+	if(mio_error_code)
+		return(1);
+
+	if(wait_dac_ready(channel))
+		return 1;
+
+	return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		WAIT_DAC_READY
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int wait_dac_ready(int channel)
+{
+unsigned long retry;
+
+	retry = 100000L;
+
+	/* This may seem like an absurd way to handle waiting and violates the
+	"no busy waiting" policy. The fact is that the hardware is normally so fast that we
+	usually only need one time through the loop anyway. The longer timeout is for rare
+	occasions and for detecting non-existant hardware.
+	*/
+
+	while(retry--)
+	{
+		if(dac_read_status(channel / 4) & DAC_BUSY)
+			return 0;
+
+	}
+	return 1;
+
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		SET_DAC_OUTPUT
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int set_dac_output(int channel, unsigned short dac_value)
+{
+unsigned char select_val;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	select_val = (channel % 4) << 1;
+	write_dac_data(channel / 4, dac_value);
+	if(mio_error_code)
+		return(1);
+	write_dac_command(channel / 4, 0x70 | select_val);
+	if(mio_error_code)
+		return(1);
+
+	if(wait_dac_ready(channel))
+		return 1;
+
+	return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		SET_DAC_VOLTAGE
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int set_dac_voltage(int channel, float voltage)
+{
+unsigned short  value = 0;
+float bit_val;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	/* This output function is auto-ranging in that it picks the span that will
+	give the most precision for the voltage specified. This has one side-effect that
+	may be objectionable to some applications. When call to set_dac_span completes the
+	new range is set and the output will respond immediately using whatever value was last
+	in the output registers. This may cause a spike (up or down) in the DAC output until the
+	new output value is sent to the controller.
+	*/
+
+	if((voltage < -10.0) || (voltage > 10.0))
+	{
+		mio_error_code = MIO_ILLEGAL_VOLTAGE;
+		sprintf(mio_error_string,"MIO(DAC) :Set DAC Voltage - Illegal Voltage %9.5f",voltage);
+		return 1;
+	}
+
+	if((voltage >= 0.0) && (voltage < 5.0))
+	{
+		set_dac_span(channel,DAC_SPAN_UNI5);
+		if(mio_error_code)
+			return(1);
+		bit_val = 5.0 / 65536;
+		value = (unsigned short) (voltage / bit_val);
+	}
+
+	if(voltage >= 5.0)
+	{
+		set_dac_span(channel,DAC_SPAN_UNI10);
+		if(mio_error_code)
+			return(1);
+		bit_val = 10.0 / 65536;
+		value = (unsigned short) (voltage / bit_val);
+	}
+
+	if((voltage < 0.0) && (voltage > -5.0))
+	{
+		set_dac_span(channel, DAC_SPAN_BI5);
+		if(mio_error_code)
+			return(1);
+		bit_val = 10.0 / 65536;
+		value = (unsigned short) ((voltage + 5.0) / bit_val);
+	}
+
+	if(voltage <= -5.0)
+	{
+		set_dac_span(channel, DAC_SPAN_BI10);
+		if(mio_error_code)
+			return(1);
+		bit_val = 20.0 / 65536;
+		value  = (unsigned short) ((voltage + 10.0) / bit_val);
+	}
+
+	if(wait_dac_ready(channel))
+		return 1;
+
+	set_dac_output(channel,value);
+	if(mio_error_code)
+		return(1);
+
+	return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		ADC_START_CONVERSION
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int adc_start_conversion(int channel)
+{
+	mio_error_code = MIO_SUCCESS;
+
+	if((channel <0) || (channel > 15))
+	{
+		mio_error_code = MIO_BAD_CHANNEL_NUMBER;
+		sprintf(mio_error_string,"MIO(ADC) : Start conversion bad channel number %d",channel);
+		return(1);
+	}
+
+	adc_last_channel = adc_current_channel;
+	adc_current_channel = channel;
+
+	write_adc_command(channel / 8,adc_channel_mode[channel]);
+	
+	if(mio_error_code)
+		return(1);
+
+	return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		ADC_GET_CHANNEL_VOLTAGE
+//
+//////////////////////////////////////////////////////////////////////////////
+
+float adc_get_channel_voltage(int channel)
+{
+unsigned short value;
+float result;
+
+	mio_error_code = MIO_SUCCESS;
+
+	// Start two conversions so that we can have current data
+
+	adc_start_conversion(channel);
+	if(mio_error_code)
+		return(0.0);
+
+	adc_wait_ready(channel);
+	if(mio_error_code)
+		return(0.0);
+
+	adc_start_conversion(channel);
+	if(mio_error_code)
+		return(0.0);
+
+	adc_wait_ready(channel);
+	if(mio_error_code)
+		return(0.0);
+
+	// Read out the conversion's raw data
+
+	value = adc_read_conversion_data(channel);
+	if(mio_error_code)
+		return(0.0);
+
+	// Convert the raw data to a voltage 
+
+	value = value + adc_adjust[channel];
+	result = value * adc_bitval[channel];
+	result = result + adc_offset[channel];
+
+	return(result);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		ADC_CONVERT_ALL_CHANNELS
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int adc_convert_all_channels(unsigned short *buffer)
+{
+int x;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	// Initialize global variables including transferinng the
+	// address of the user's ouput buffer to an internal buffer pointer
+
+	adc_user_buffer = buffer;
+	adc_input_buffer = adc_channel_buff;
+	adc_ch_index =0;
+	adc_out_index = 0;
+
+	adc_start_conversion(0);
+	if(mio_error_code)
+		return(1);
+
+	adc_wait_ready(0);
+	if(mio_error_code)
+		return(1);
+
+	// This is old data throw it out
+
+	adc_read_conversion_data(0);
+	if(mio_error_code)
+		return(1);
+
+	// Finish the rest of the channels
+
+	for(x=1; x<8; x++)
+	{
+		adc_start_conversion(x);
+		if(mio_error_code)
+			return(1);
+
+		adc_wait_ready(x);
+		if(mio_error_code)
+			return(1);
+
+		// Store the results in the user's buffer
+
+		adc_user_buffer[adc_out_index++] = adc_read_conversion_data(x);
+		if(mio_error_code)
+			return(1);
+	}
+
+	// A final dummy conversion is required to get out the last data
+
+	adc_start_conversion(7);
+	if(mio_error_code)
+		return(1);
+
+	adc_wait_ready(7);
+	if(mio_error_code)
+		return(1);
+
+	adc_user_buffer[adc_out_index++] = adc_read_conversion_data(7);
+	if(mio_error_code)
+		return(1);
+
+	// Now start on the second controller
+
+	adc_start_conversion(8);
+	if(mio_error_code)
+		return(1);
+
+	adc_wait_ready(8);
+	if(mio_error_code)
+		return(1);
+
+	// This data is old - Throw it out
+
+	adc_read_conversion_data(8);
+	if(mio_error_code)
+		return(1);
+
+	for(x=9; x<16; x++)
+	{
+		adc_start_conversion(x);
+		if(mio_error_code)
+			return(1);
+
+		adc_wait_ready(x);
+		if(mio_error_code)
+			return(1);
+
+		adc_user_buffer[adc_out_index++] = adc_read_conversion_data(x);
+		if(mio_error_code)
+			return(1);
+	}
+
+	// A final dummy conversion is required to get the last data
+
+	adc_start_conversion(15);
+	if(mio_error_code)
+		return(1);
+
+	adc_wait_ready(15);
+	if(mio_error_code)
+		return(1);
+
+	adc_user_buffer[adc_out_index++] = adc_read_conversion_data(15);
+	if(mio_error_code)
+		return(1);
+
+	return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		ADC_CONVERT_TO_VOLTS
+//
+//////////////////////////////////////////////////////////////////////////////
+
+float adc_convert_to_volts(int channel, unsigned short value)
+{
+float result;
+
+		if((channel < 0) || (channel > 15))
+			return(0.0);
+
+		value = value + adc_adjust[channel];
+		result = value * adc_bitval[channel];
+		result = result + adc_offset[channel];
+		return result;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		ADC_CONVERT_SINGLE_REPEATED
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int adc_convert_single_repeated(int channel, unsigned short count, unsigned short *buffer)
+{
+	int x;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	// Setup global variables including transferring the address of the
+	// user's output buffer to a global variable the ISR knows about.
+
+	adc_user_buffer = buffer;
+	adc_out_index = 0;
+	adc_repeat_channel = channel;
+	adc_repeat_count = count;
+
+	adc_start_conversion(adc_repeat_channel);
+	if(mio_error_code)
+		return(1);
+
+	adc_wait_ready(adc_repeat_channel);
+	if(mio_error_code)
+		return(1);
+
+	// This data is old, we don't want it
+
+	adc_read_conversion_data(adc_repeat_channel);
+	if(mio_error_code)
+		return(1);
+
+	// Perform the requested number of conversions. Place the results into
+	// the user's buffer.
+
+	for(x=0; x<=adc_repeat_count; x++)
+	{
+		adc_start_conversion(adc_repeat_channel);
+		if(mio_error_code)
+			return(1);
+
+		adc_wait_ready(adc_repeat_channel);
+		if(mio_error_code)
+			return(1);
+
+		adc_user_buffer[adc_out_index++] = adc_read_conversion_data(adc_repeat_channel);
+		if(mio_error_code)
+			return(1);
+	}
+
+	// One last dummy conversion to retrieve our last data
+
+	adc_start_conversion(adc_repeat_channel);
+	if(mio_error_code)
+		return(1);
+
+	adc_wait_ready(adc_repeat_channel);
+	if(mio_error_code)
+		return(1);
+
+	adc_user_buffer[adc_out_index++] = adc_read_conversion_data(adc_repeat_channel);
+	if(mio_error_code)
+		return(1);
+
+	return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		ADC_BUFFERED_CHANNEL_CONVERSIONS
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int adc_buffered_channel_conversions(unsigned char *input_channel_buffer,unsigned short *buffer)
+{
+int adc_next_channel;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+
+	adc_ch_index = 0;
+	adc_out_index = 0;
+	
+	adc_user_buffer = buffer;
+	adc_input_buffer = input_channel_buffer;
+
+	// Reset all of the array index pointers
+
+	adc_start_conversion(adc_input_buffer[adc_ch_index]);
+
+	if(mio_error_code)
+		return(1);
+
+	adc_wait_ready(adc_input_buffer[adc_ch_index++]);
+
+	if(mio_error_code)
+		return(1);
+
+	// While there are channel numbers in the buffer (1= 0xff)
+	// convert the requested channel and place the result in the
+	// user's output buffer
+
+	while(adc_input_buffer[adc_ch_index] != 0xff)
+	{
+		adc_next_channel = adc_input_buffer[adc_ch_index];
+
+
+		/* This function is particularly tricky because of the
+		fact that the data is delayed by one conversion and if
+		we switch back and forth between the two controllers
+		we'll need to run an extra conversion in order to get the
+		last data offering from the previous controller. The
+		conditional code in the next several lines handles the
+		switches from one controller to the other.
+		*/
+
+		if(adc_current_channel < 8 && adc_next_channel > 7)
+		{
+			adc_start_conversion(adc_current_channel);
+			if(mio_error_code)
+				return(1);
+
+			adc_wait_ready(adc_current_channel);
+			if(mio_error_code)
+				return(1);
+
+			adc_user_buffer[adc_out_index++] = adc_read_conversion_data(adc_current_channel);
+			if(mio_error_code)
+				return(1);
+
+			adc_start_conversion(adc_input_buffer[adc_ch_index]);
+			if(mio_error_code)
+				return(1);
+
+			adc_wait_ready(adc_input_buffer[adc_ch_index++]);
+			if(mio_error_code)
+				return(1);
+		}
+		else if(adc_current_channel > 7 && adc_next_channel < 8)
+		{
+			adc_start_conversion(adc_current_channel);
+			if(mio_error_code)
+				return(1);
+
+			adc_wait_ready(adc_current_channel);
+			if(mio_error_code)
+				return(1);
+
+			adc_user_buffer[adc_out_index++] = adc_read_conversion_data(adc_current_channel);
+			if(mio_error_code)
+				return(1);
+
+			adc_start_conversion(adc_input_buffer[adc_ch_index]);
+			if(mio_error_code)
+				return(1);
+
+			adc_wait_ready(adc_input_buffer[adc_ch_index++]);
+			if(mio_error_code)
+				return(1);
+		}
+		adc_start_conversion(adc_input_buffer[adc_ch_index]);
+		if(mio_error_code)
+			return(1);
+
+		adc_wait_ready(adc_input_buffer[adc_ch_index++]);
+		if(mio_error_code)
+			return(1);
+
+		adc_user_buffer[adc_out_index++] = adc_read_conversion_data(adc_current_channel);
+		if(mio_error_code)
+			return(1);
+	}
+
+	// One last conversion allows us to retrieve our real last data
+
+	adc_start_conversion(adc_input_buffer[--adc_ch_index]);
+	if(mio_error_code)
+		return(1);
+	adc_wait_ready(adc_input_buffer[adc_ch_index]);
+	if(mio_error_code)
+		return(1);
+
+	adc_user_buffer[adc_out_index++] = adc_read_conversion_data(adc_last_channel);
+	if(mio_error_code)
+		return(1);
+
+	return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		ADC_WAIT_READY
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int adc_wait_ready(int channel)
+{
+long retry;
+	
+	mio_error_code = MIO_SUCCESS;
+	retry = 100000l;
+
+	/* Like with the DAC timeout routine, under normal circumstances we'll
+	barely make it through the loop one time beacuse the hadrware is plenty
+	fast. We have the delay for the rare occasion and when the hadrware is not
+	responding properly.
+	*/
+
+	while(retry--)
+	{
+		if(adc_read_status(channel / 8) & 0x80)
+			return 0;
+	}
+
+	mio_error_code = MIO_TIMEOUT_ERROR;
+	sprintf(mio_error_string,"MIO(ADC) : Wait ready - Device timeout error");
+	return(1);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		BUFFERED_DAC_OUTPUT
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int buffered_dac_output(unsigned char *cmd_buff,unsigned short *data_buff)
+{
+int x= 0;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	while(1)
+	{
+		if(cmd_buff[x] == 0xff)
+			return 0;
+
+		if(set_dac_output(cmd_buff[x], data_buff[x]))
+			return 1;
+
+		x++;
+	}
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		ADC_SET_CHANNEL_MODE
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int adc_set_channel_mode(int channel, int input_mode,int duplex,int range)
+{
+unsigned char command_byte;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(channel < 0 || channel > 15)
+	{
+		mio_error_code = MIO_BAD_CHANNEL_NUMBER;
+		sprintf(mio_error_string,"MIO(ADC) : Set Channel Mode - Bad Channel Number %d",channel);
+		return(1);
+	}
+
+	// Check for illegal modes
+
+	if((input_mode != ADC_SINGLE_ENDED) && (input_mode != ADC_DIFFERENTIAL))
+	{
+		mio_error_code = MIO_BAD_MODE_NUMBER;
+		sprintf(mio_error_string,"MIO(ADC) : Set Channel Mode - Bad Mode Number");
+		return(1);
+	}
+
+	if((duplex != ADC_UNIPOLAR) && (duplex != ADC_BIPOLAR))
+	{
+		mio_error_code = MIO_BAD_MODE_NUMBER;
+		sprintf(mio_error_string,"MIO(ADC) : Set Channel Mode - Bad Mode Number");
+		return(1);
+	}
+
+	if((range != ADC_TOP_5V) && (range != ADC_TOP_10V))
+	{
+		mio_error_code = MIO_BAD_RANGE;
+		sprintf(mio_error_string,"MIO(ADC) : Set Channel Mode - Bad Range Value");
+		return(1);
+	}
+
+	command_byte = adc_channel_select[channel];
+	command_byte = command_byte | input_mode | duplex | range;
+
+	/* Building these four arrays at mode set time is critical for speed
+	   as we don't need to calculate anything when we want to start an ADC
+	   conversion. WE simply retrieve the command byte from the array
+	   and send it to the controller.
+
+	   Likewise, when doing conversion from raw 16-bit values to a voltage
+	   the mode controls the worth of each individual bit as well as binary
+	   bias and offset values.
+   */
+
+	adc_channel_mode[channel] = command_byte;
+
+	/* Calculate bit values, offset, and adjustment values */
+
+	if((range == ADC_TOP_5V) && (duplex == ADC_UNIPOLAR))
+	{
+		adc_bitval[channel] = 5.00 / 65536.0;
+		adc_adjust[channel] = 0;
+		adc_offset[channel] = 0.0;
+	}
+
+	if((range == ADC_TOP_5V) && (duplex == ADC_BIPOLAR))
+	{
+		adc_bitval[channel] = 10.0 / 65536.0;
+		adc_adjust[channel] = 0x8000;
+		adc_offset[channel] = -5.000;
+	}
+
+	if((range == ADC_TOP_10V) && (duplex == ADC_UNIPOLAR))
+	{
+		adc_bitval[channel] = 10.0 / 65536.0;
+		adc_adjust[channel] = 0;
+		adc_offset[channel] = 0.0;
+	}
+
+	if((range == ADC_TOP_10V) && (duplex == ADC_BIPOLAR))
+	{
+		adc_bitval[channel] = 20.0 / 65536.0;
+		adc_adjust[channel] = 0x8000;
+		adc_offset[channel] = -10.0;
+	}
+
+	return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+//		ADC_AUTO_GET_CHANNEL_VOLTAGE
+//
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+float adc_auto_get_channel_voltage(int channel)
+{
+unsigned short value;
+float result;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	// Start out on a +/-10 Volt scale
+
+	adc_set_channel_mode(channel,ADC_SINGLE_ENDED,ADC_BIPOLAR,ADC_TOP_10V);
+	if(mio_error_code)
+		return(0.0);
+
+	adc_start_conversion(channel);
+	if(mio_error_code)
+		return(0.0);
+
+	adc_wait_ready(channel);
+	if(mio_error_code)
+		return(0.0);
+
+	adc_start_conversion(channel);
+	if(mio_error_code)
+		return(0.0);
+
+	adc_wait_ready(channel);
+	if(mio_error_code)
+		return(0.0);
+
+	value = adc_read_conversion_data(channel);
+	if(mio_error_code)
+		return(0.0);
+
+	// Convert the raw data to voltage
+
+	value = value + adc_adjust[channel];
+	result = value * adc_bitval[channel];
+	result = result + adc_offset[channel];
+
+#ifdef DEBUG
+	printf("auto_get_channel_voltage : Raw = %04x, adjust = %d, bitval = %9.5f, offset = %9.5f,  result = %9.5f\n",
+		                                value - adc_adjust[channel],adc_adjust[channel],adc_bitval[channel],adc_offset[channel],result);
+#endif
+
+	// If the voltage is less than -5.00 volts, we're as precise as we can get
+
+	if(result <= -5.00)
+		return(result);
+
+	// If the result is between -4.99 and 0.0 we can  to the +/- 5V scale.
+
+	if(result < 0.0)
+		adc_set_channel_mode(channel,ADC_SINGLE_ENDED,ADC_BIPOLAR,ADC_TOP_5V);
+
+	if(mio_error_code)
+		return(0.0);
+
+	// If the result is above 5 volts a 0 - 10V range will work best
+
+	if(result >= 5.00)
+		adc_set_channel_mode(channel,ADC_SINGLE_ENDED,ADC_UNIPOLAR,ADC_TOP_10V);
+
+	if(mio_error_code)
+		return(0.0);
+
+	// Lastly if we're greater than 0 and less than 5 volts the 0-5V scale is best
+
+	if((result >= 0.0) && (result < 5.00))
+		adc_set_channel_mode(channel, ADC_SINGLE_ENDED, ADC_UNIPOLAR,ADC_TOP_5V);
+
+	if(mio_error_code)
+		return(0.0);
+
+	// Now that the values is properly ranged, we take two more samples
+	// to get a current reading at the new scale.
+
+	adc_start_conversion(channel);
+
+	if(mio_error_code)
+		return(0.0);
+
+	adc_wait_ready(channel);
+
+	if(mio_error_code)
+		return(0.0);
+
+	adc_start_conversion(channel);
+
+	if(mio_error_code)
+		return(0.0);
+
+	adc_wait_ready(channel);
+
+	if(mio_error_code)
+		return(0.0);
+
+	value = adc_read_conversion_data(channel);
+	if(mio_error_code)
+		return(0.0);
+
+	// Convert the raw data to voltage
+
+	value = value + adc_adjust[channel];
+	result = value * adc_bitval[channel];
+	result = result + adc_offset[channel];
+
+#ifdef DEBUG
+	printf("auto_get_channel_voltage : Raw = %04x, adjust = %d, bitval = %9.5f, offset = %9.5f,  result = %9.5f\n",
+		                                value - adc_adjust[channel],adc_adjust[channel],adc_bitval[channel],adc_offset[channel],result);
+#endif
+
+	return(result);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+//		DIO_READ_BIT
+//
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+int dio_read_bit(int bit_number)
+{
+unsigned char port;
+int val;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	// Adjust for 0 - 47 bit numbering
+
+	--bit_number;
+
+	port = bit_number / 8;
+
+	val = read_dio_byte(port);
+
+	// Get just the bit we specified
+
+	val = val & (1 << (bit_number % 8));
+
+	// adjust the return for a 0 or 1 value
+
+	if(val)
+		return 1;
+
+	return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+//		DIO_WRITE_BIT
+//
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+int dio_write_bit(int bit_number, int val)
+{
+unsigned char port;
+unsigned char temp;
+unsigned char mask;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	// Adjust bit numbering for 0 based numbering
+
+	--bit_number;
+
+	// Calculate the address of the port based on bit number
+
+	port = bit_number / 8;
+
+	// Use the image value to avoid having to read from the port first
+
+	temp = dio_port_images[bit_number / 8];
+
+	// Calculate the bit mask for the specifed bit
+
+	mask = (1 << (bit_number %8));
+
+	// Check whether the request was to set or clear the bit
+
+	if(val)
+		temp = temp | mask;
+	else
+		temp = temp & ~mask;
+
+	// Update the image value with the value we're about to write
+
+	dio_port_images[bit_number / 8] = temp;
+
+	write_dio_byte(port, temp);
+
+	return 0;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+//		DIO_SET_BIT
+//
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+int dio_set_bit(int bit_number)
+{
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	dio_write_bit(bit_number,1);
+
+	return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+//		DIO_CLR_BIT
+//
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+int dio_clr_bit(int bit_number)
+{
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	dio_write_bit(bit_number,0);
+
+	return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+//		DIO_ENAB_BIT_INT
+//
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+int dio_enab_bit_int(int bit_number, int polarity)
+{
+unsigned char port;
+unsigned char temp;
+unsigned char mask;
+
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	// Adjust the bit number for 0 based numbering
+
+	--bit_number;
+
+	// Calculate the offset for the enable port
+
+	port = (bit_number / 8) + 8;
+
+	// Calculate the proper bit mask for this bit number
+
+	mask = (1 << (bit_number % 8));
+
+	// Turn on access to page 2 registers
+
+	write_dio_byte(0x07,0x80);
+
+	// Get the current state of the enable register
+
+	temp = read_dio_byte(port);
+
+	// Set the enable bit for our bit number
+
+	temp = temp | mask;
+
+	// Now update the interrupt enable register
+
+	write_dio_byte(port, temp);
+
+	// Turn on access to page 1 for polarity control
+
+	write_dio_byte(0x07,0x40);
+
+	temp = read_dio_byte(port);
+
+	// Set the polarity according to the argument value
+
+	if(polarity)
+		temp = temp | mask;
+	else
+		temp = temp & ~mask;
+
+	write_dio_byte(port, temp);
+
+	// Set access back to page 0
+
+	write_dio_byte(0x07,0);
+
+	return 0;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+//		DIO_DISAB_BIT_INT
+//
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+int dio_disab_bit_int(int bit_number)
+{
+unsigned char port;
+unsigned char temp;
+unsigned char mask;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	// Adjust the bit number for 0 based numbering
+
+	--bit_number;
+
+	// Calculate the offset for the enable port
+
+	port = (bit_number / 8) + 8;
+
+	// Calculate the proper bit mask for this bit number
+
+	mask = (1 << (bit_number % 8));
+
+	// Turn on access to page 2 registers
+
+	write_dio_byte(0x07,0x80);
+
+	// Get the current state of the enable register
+
+	temp = read_dio_byte(port);
+
+	// Clear the enable bit for the our bit
+
+	temp = temp & ~mask;
+
+	// Update the enable register with the new data
+
+	write_dio_byte(port,temp);
+
+	// Set access back to page 0
+
+	write_dio_byte(0x07,0);
+
+	return 0;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+//		DIO_CLR_INT
+//
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+int dio_clr_int(int bit_number)
+{
+unsigned short port;
+unsigned short temp;
+unsigned short mask;
+
+	// Adjust for 0 based numbering
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	--bit_number;
+
+	// Calculate the correct offset for our enable register
+
+	port = (bit_number / 8) + 8;
+
+	// Calculate the bit mask for this bit
+
+	mask = (1 << (bit_number % 8));
+
+	// Set access to page 2 for the enable register
+
+	write_dio_byte(0x07,0x80);
+
+	// Get the current state of the register
+
+	temp = read_dio_byte(port);
+
+	// Temporarily clear only our enable. This clears the interrupt
+
+	temp = temp & ~mask;
+
+	// Write out the temporary value
+
+	write_dio_byte(port, temp);
+
+	temp = temp | mask;
+
+	write_dio_byte(port, temp);
+
+	// Set access back to page 0
+
+	write_dio_byte(0x07,0);
+
+	return 0;
+}
+
Index: pcmmio/mio_io.h
===================================================================
--- pcmmio/mio_io.h	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
+++ pcmmio/mio_io.h	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
@@ -0,0 +1,210 @@
+/* Filename : $RCSfile$
+ *
+ * The declarations here have to be in a header file, 
+ * because they need to be known both to the kernel 
+ * module (in chardev.c) and the process calling ioctl 
+ * (ioctl.c)
+ */
+
+/* $Id$ */
+
+#ifndef CHARDEV_H
+#define CHARDEV_H
+
+#if defined(__linux__)
+#include <linux/ioctl.h> 
+
+
+/* These are the IOCTL value the pcmmio driver recognizes */
+
+#define WRITE_DAC_DATA 		_IOWR(MAJOR_NUM, 0, int)
+
+#define READ_DAC_STATUS 	_IOWR(MAJOR_NUM, 1, int)
+
+#define WRITE_DAC_COMMAND 	_IOWR(MAJOR_NUM, 2, int)
+
+#define WRITE_ADC_COMMAND	_IOWR(MAJOR_NUM, 3, int)
+
+#define READ_ADC_DATA 		_IOWR(MAJOR_NUM, 4, int)
+
+#define READ_ADC_STATUS		_IOWR(MAJOR_NUM, 5, int)
+
+#define WRITE_DIO_BYTE 		_IOWR(MAJOR_NUM, 6, int)
+
+#define READ_DIO_BYTE 		_IOWR(MAJOR_NUM, 7, int)
+
+#define MIO_WRITE_REG 		_IOWR(MAJOR_NUM, 8, int)
+
+#define MIO_READ_REG 		_IOWR(MAJOR_NUM, 9, int)
+
+#define WAIT_A2D_INT_1 		_IOWR(MAJOR_NUM, 10, int)
+
+#define WAIT_A2D_INT_2 		_IOWR(MAJOR_NUM, 11, int)
+
+#define WAIT_DAC_INT_1 		_IOWR(MAJOR_NUM, 12, int)
+
+#define WAIT_DAC_INT_2 		_IOWR(MAJOR_NUM, 13, int)
+
+#define WAIT_DIO_INT 		_IOWR(MAJOR_NUM, 14, int)
+
+#define READ_IRQ_ASSIGNED	_IOWR(MAJOR_NUM, 15, int)
+
+#define DIO_GET_INT			_IOWR(MAJOR_NUM, 16, int)
+
+
+/* The name of the device file */
+
+#define DEVICE_FILE_NAME "pcmmio"
+
+#endif
+
+#endif
+
+/* These are the error codes for mio_error_code */
+
+#define MIO_SUCCESS 0
+#define MIO_OPEN_ERROR 1
+#define MIO_TIMEOUT_ERROR 2
+#define MIO_BAD_CHANNEL_NUMBER 3
+#define MIO_BAD_MODE_NUMBER 4
+#define MIO_BAD_RANGE 5
+#define MIO_COMMAND_WRITE_FAILURE 6
+#define MIO_READ_DATA_FAILURE 7
+#define MIO_MISSING_IRQ 8
+#define MIO_ILLEGAL_VOLTAGE 9
+
+
+/* These are DAC specific defines */
+
+#define DAC_BUSY 0x80
+
+#define DAC_SPAN_UNI5  0
+#define DAC_SPAN_UNI10 1
+#define DAC_SPAN_BI5   2
+#define DAC_SPAN_BI10  3
+#define DAC_SPAN_BI2   4
+#define DAC_SPAN_BI7   5
+
+/* These are ADC specific defines */
+
+#define	ADC_SINGLE_ENDED 0x80
+#define ADC_DIFFERENTIAL 0x00
+
+#define ADC_UNIPOLAR  0x08
+#define ADC_BIPOLAR   0x00
+
+#define ADC_TOP_5V	  0x00
+#define ADC_TOP_10V	  0x04
+
+#define ADC_CH0_SELECT 0x00
+#define ADC_CH1_SELECT 0x40
+#define ADC_CH2_SELECT 0x10
+#define ADC_CH3_SELECT 0x50
+#define ADC_CH4_SELECT 0x20
+#define ADC_CH5_SELECT 0x60
+#define ADC_CH6_SELECT 0x30
+#define ADC_CH7_SELECT 0x70
+
+/* These are DIO specific defines */
+
+#define FALLING 1
+#define RISING  0
+
+#ifdef LIB_DEFINED
+
+/* These are used by the library functions */
+
+int mio_error_code;
+char mio_error_string[128];
+float adc_bitval[16] = {.00, .00, .00, .00, .00, .00, 00, .00,
+		        .00, .00, .00, .00, .00, .00, .00, .00 };
+
+unsigned short adc_adjust[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
+float adc_offset[16] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+			 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
+
+#else
+
+
+/* The rest of this file is made up of global variables available to application
+   code and the function prototypes for all available functions
+*/
+
+
+extern int mio_error_code;
+extern char mio_error_string[128];
+extern float adc_bitval[16];
+
+extern unsigned short adc_adjust[16];
+
+extern float adc_offset[16];
+
+#endif
+
+/* part of the porting layer */
+int check_handle(void);
+int mio_read_irq_assigned(void);
+
+int disable_dio_interrupt(void);
+int enable_dio_interrupt(void);
+int disable_dac_interrupt(int dac_num);
+int enable_dac_interrupt(int dac_num);
+int disable_adc_interrupt(int adc_num);
+int enable_adc_interrupt(int adc_num);
+int set_dac_span(int channel, unsigned char span_value);
+int wait_dac_ready(int channel);
+int set_dac_output(int channel, unsigned short dac_value);
+int set_dac_voltage(int channel, float voltage);
+unsigned char read_dio_byte(int offset);
+unsigned char mio_read_reg(int offset);
+int mio_write_reg(int offset, unsigned char value);
+int write_dio_byte(int offset, unsigned char value);
+int write_dac_command(int dac_num,unsigned char value);
+int adc_start_conversion(int channel);
+float adc_get_channel_voltage(int channel);
+int adc_convert_all_channels(unsigned short *buffer);
+float adc_convert_to_volts(int channel, unsigned short value);
+int adc_convert_single_repeated(int channel, unsigned short count, unsigned short *buffer);
+int adc_buffered_channel_conversions(unsigned char *input_channel_buffer,unsigned short *buffer);
+int adc_wait_ready(int channel);
+int write_adc_command(int adc_num,unsigned char value);
+int buffered_dac_output(unsigned char *cmd_buff,unsigned short *data_buff);
+int write_dac_data(int dac_num, unsigned short value);
+unsigned char dac_read_status(int dac_num);
+unsigned char adc_read_status(int adc_num);
+int adc_set_channel_mode(int channel, int input_mode,int duplex,int range);
+unsigned short adc_read_conversion_data(int channel);
+float adc_auto_get_channel_voltage(int channel);
+int dio_read_bit(int bit_number);
+int dio_write_bit(int bit_number, int val);
+int dio_set_bit(int bit_number);
+int dio_clr_bit(int bit_number);
+int dio_enab_bit_int(int bit_number, int polarity);
+int dio_disab_bit_int(int bit_number);
+int dio_clr_int(int bit_number);
+int dio_get_int(void);
+int dio_get_int_with_timestamp(
+  unsigned long long *timestamp
+);
+int wait_adc_int(int adc_num);
+int wait_dac_int(int dac_num);
+int wait_dio_int(void);
+
+#if defined(__rtems__)
+  void pcmmio_initialize(
+    unsigned short _base_port,
+    unsigned short _irq
+  );
+
+  void flush_buffered_ints(void);
+  int wait_adc_int_with_timeout(int adc_num, int milliseconds);
+  int wait_dac_int_with_timeout(int dac_num, int milliseconds);
+  int wait_dio_int_with_timeout(int milliseconds);
+  int wait_dio_int_with_timestamp(
+    int                 milliseconds,
+    unsigned long long *timestamp
+  );
+  int dio_get_missed_interrupts(void);
+#endif
+
Index: pcmmio/mio_io_linux.c
===================================================================
--- pcmmio/mio_io_linux.c	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
+++ pcmmio/mio_io_linux.c	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
@@ -0,0 +1,405 @@
+/* mio_io.c
+ * WinSystems support module file for the  PCM-MIO Linux driver
+ *
+ *
+ *  $Id$
+ *
+ *
+ *  This file implements all of the supported 'C' language functions.
+ *  Where necessary ioctl calls are made into the kernel driver to access
+ *  the actual hardware.
+ */
+
+/* #define DEBUG 1 */
+
+#include "mio_io.h"    
+
+#include <stdio.h>
+#include <fcntl.h>      /* open */ 
+#include <unistd.h>     /* exit */
+#include <sys/ioctl.h>  /* ioctl */
+
+/**************************************************************************
+*
+*		USER LIBRARY FUNCTIONS
+*
+***************************************************************************
+*/
+
+int handle = 0;
+char *device_id ="pcmmio";
+char *dev_id    = "/dev/pcmmio";
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		MIO_READ_IRQ_ASSIGNED
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int mio_read_irq_assigned(void)
+{
+unsigned char val;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+
+	/* All of our programming of the hardware is handled at this level so that 
+	   all of the routines that need to shove and IRQ value into hardware will 
+	   use this call.
+   */
+
+    val = ioctl(handle,READ_IRQ_ASSIGNED,NULL);
+
+	return val & 0xff;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		READ_DIO_BYTE
+//
+//////////////////////////////////////////////////////////////////////////////
+
+unsigned char read_dio_byte(int offset)
+{
+int val;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	/* All bit operations are handled at this level so we need only
+	read and write bytes from the actual hardware using the driver
+	to handle our ioctl call for it.
+	*/
+
+    val = ioctl(handle,READ_DIO_BYTE,offset);
+
+	return (unsigned char) (val & 0xff);;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		MIO_READ_REG
+//
+//////////////////////////////////////////////////////////////////////////////
+
+unsigned char mio_read_reg(int offset)
+{
+int val;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+
+	/* This is a catchall register read routine that allows reading of
+	   ANY of the registers on the PCM-MIO. It is used primarily for
+	   retreiving control and access values in the hardware.
+   */
+
+     val = ioctl(handle,MIO_READ_REG,offset);
+
+	return (unsigned char) (val & 0xff);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		MIO_WRITE_REG
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int mio_write_reg(int offset, unsigned char value)
+{
+unsigned short param;
+int val;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	param = offset & 0xff;
+
+	param = param | (value << 8);
+    
+	/* This function like the previous allow unlimited
+	   write access to ALL of the registers on the PCM-MIO
+   */
+
+	val = ioctl(handle,MIO_WRITE_REG,param);
+	
+	return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		WRITE_DIO_BYTE
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int write_dio_byte(int offset, unsigned char value)
+{
+unsigned short param;
+int val;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	param = offset & 0xff;
+
+	param = param | (value << 8);
+    
+	/* All bit operations for the DIO are handled at this level
+	   and we need the driver to allow access to the actual
+	   DIO registers to update the value.
+    */
+
+	val = ioctl(handle,WRITE_DIO_BYTE,param);
+	
+	return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		WRITE_DAC_COMMAND
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int write_dac_command(int dac_num,unsigned char value)
+{
+unsigned short param;
+int val;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	param = dac_num & 0xff;
+
+	param = param | (value << 8);
+
+	val = ioctl(handle,WRITE_DAC_COMMAND,param);
+
+	return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		WRITE_ADC_COMMAND
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int write_adc_command(int adc_num,unsigned char value)
+{
+unsigned short param;
+int ret_val;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	param = adc_num & 0xff;
+
+	param = param | (value << 8);
+
+    ret_val = ioctl(handle,WRITE_ADC_COMMAND,param);
+
+	return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		WRITE_DAC_DATA
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int write_dac_data(int dac_num, unsigned short value)
+{
+int ret_val;
+unsigned char buffer[3];
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	buffer[0] = dac_num;
+	buffer[1] = value & 0xff;
+	buffer[2] = value >> 8;
+
+    ret_val = ioctl(handle,WRITE_DAC_DATA,buffer);
+	
+	return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		DAC_READ_STATUS
+//
+//////////////////////////////////////////////////////////////////////////////
+
+unsigned char dac_read_status(int dac_num)
+{
+int ret_val;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+    ret_val = ioctl(handle,READ_DAC_STATUS,dac_num);
+
+	return ret_val & 0xff;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		ADC_READ_STATUS
+//
+//////////////////////////////////////////////////////////////////////////////
+
+unsigned char adc_read_status(int adc_num)
+{
+int ret_val;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+    ret_val = ioctl(handle,READ_ADC_STATUS,adc_num);
+
+	return (ret_val & 0xff);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//		ADC_READ_CONVERSION_DATA
+//
+//////////////////////////////////////////////////////////////////////////////
+
+unsigned short adc_read_conversion_data(int channel)
+{
+int ret_val;
+int adc_num;
+
+	mio_error_code = MIO_SUCCESS;
+
+	if(check_handle())   /* Check for chip available */
+		return -1;
+
+	if(channel > 7)
+		adc_num = 1;
+	else
+		adc_num = 0;
+
+    ret_val = ioctl(handle,READ_ADC_DATA,adc_num);
+	
+	return (ret_val & 0xffff);
+}
+
+
+int dio_get_int(void)
+{
+int c;
+
+    c=ioctl(handle,DIO_GET_INT,NULL);
+
+    return (c & 0xff);
+
+}
+
+
+int wait_adc_int(int adc_num)
+{
+int c;
+
+
+    if(check_handle())   /* Check for chip available */
+		return -1;
+
+	if(adc_num)
+	    c=ioctl(handle,WAIT_A2D_INT_1,NULL);
+	else
+	    c=ioctl(handle,WAIT_A2D_INT_2,NULL);
+
+
+    return (c & 0xff);
+
+}
+
+
+int wait_dac_int(int dac_num)
+{
+int c;
+
+    if(check_handle())   /* Check for chip available */
+		return -1;
+
+	if(dac_num)
+	    c=ioctl(handle,WAIT_DAC_INT_1,NULL);
+	else
+	    c=ioctl(handle,WAIT_DAC_INT_2,NULL);
+
+    return (c & 0xff);
+
+}
+
+
+int wait_dio_int(void)
+{
+int c;
+
+
+    if(check_handle())   /* Check for chip available */
+		return -1;
+
+    c=ioctl(handle,WAIT_DIO_INT,NULL);
+
+    return (c & 0xff);
+
+}
+
+
+
+int check_handle(void)
+{
+    if(handle > 0)	/* If it's already a valid handle */
+		return 0;
+
+    if(handle == -1)	/* If it's already been tried */
+	{
+		mio_error_code = MIO_OPEN_ERROR;
+		sprintf(mio_error_string,"MIO - Unable to open device PCMMIO");
+		return -1;
+	}
+
+    /* Try opening the device file, in case it hasn't been opened yet */
+
+    handle = open(device_id,0);
+
+	/* Try an alternate open at /dev */
+
+	if(handle < 0)
+		handle = open(dev_id,0);
+
+    if(handle > 0)	/* If it's now a valid handle */
+		return 0;
+
+	mio_error_code = MIO_OPEN_ERROR;
+	sprintf(mio_error_string,"MIO - Unable to open device PCMMIO");
+    handle = -1;
+	return -1;
+}
+
Index: pcmmio/mio_io_rtems.c
===================================================================
--- pcmmio/mio_io_rtems.c	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
+++ pcmmio/mio_io_rtems.c	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
@@ -0,0 +1,909 @@
+/* mio_io.c WinSystems support module file for the  PCM-MIO RTEMS driver
+ *
+ *  $Id$
+ *
+ *  This file implements the hardware access routines as implemented for RTEMS.
+ *  This is very likely close to what is required with no OS.
+ */
+
+/* #define DEBUG 1 */
+
+#include "mio_io.h"    
+
+#include <stdio.h>
+#include <fcntl.h>      /* open */ 
+#include <unistd.h>     /* exit */
+#include <sys/ioctl.h>  /* ioctl */
+#include <stdlib.h>     /* for exit */
+
+#include <rtems.h>
+#include <i386_io.h>
+#include <bsp/irq.h>
+
+/*
+ *  These are configured by the initialization call.
+ */
+
+/* IRQ source or 0 ==> polled */
+static unsigned short irq = 0;
+/* This holds the base addresses of the board */
+static unsigned short base_port = 0;
+
+/* Function prototypes for local functions */
+static int get_buffered_int(
+  unsigned long long *timestamp
+);
+static void init_io(unsigned short io_address);
+static void clr_int(int bit_number);
+static int get_int(void);
+
+/* RTEMS Ids for Wait Queues */
+rtems_id wq_a2d_1;
+rtems_id wq_a2d_2;
+rtems_id wq_dac_1;
+rtems_id wq_dac_2;
+rtems_id wq_dio;
+
+/*
+ *  Limits on number of buffered discrete input interrupts in
+ *  the message queue.
+ */
+#define MAXIMUM_BUFFERED_DISCRETE_INTERRUPTS 1024
+
+///////////////////////////////////////////////////////////////////////////////
+typedef struct {
+  unsigned long long timestamp;
+  int                pin;
+} din_message_t;
+
+unsigned int pcmmio_dio_missed_interrupts;
+
+int interruptible_sleep_on(
+  rtems_id *id,
+  int       milliseconds
+);
+void wake_up_interruptible(
+  rtems_id *id
+);
+
+//
+//    MIO_READ_IRQ_ASSIGNED
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int mio_read_irq_assigned(void)
+{
+  mio_error_code = MIO_SUCCESS;
+
+  if (check_handle())   /* Check for chip available */
+    return -1;
+
+  /* All of our programming of the hardware is handled at this level so that 
+     all of the routines that need to shove and IRQ value into hardware will 
+     use this call.
+  */
+
+  return (irq & 0xff);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//    READ_DIO_BYTE
+//
+//////////////////////////////////////////////////////////////////////////////
+
+unsigned char read_dio_byte(int offset)
+{
+  unsigned char byte_val;
+  unsigned char offset_val;
+
+  mio_error_code = MIO_SUCCESS;
+
+  if (check_handle())   /* Check for chip available */
+    return -1;
+
+  /* All bit operations are handled at this level so we need only
+     read and write bytes from the actual hardware.
+  */
+
+  offset_val = offset & 0xff;
+  byte_val = inb(base_port + 0x10 + offset_val);
+  return (byte_val & 0xff);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//    MIO_READ_REG
+//
+//////////////////////////////////////////////////////////////////////////////
+
+unsigned char mio_read_reg(int offset)
+{
+  unsigned char byte_val;
+  unsigned char offset_val;
+
+  mio_error_code = MIO_SUCCESS;
+
+  if (check_handle())   /* Check for chip available */
+    return -1;
+
+
+  /* This is a catchall register read routine that allows reading of
+     ANY of the registers on the PCM-MIO. It is used primarily for
+     retreiving control and access values in the hardware.
+   */
+
+  offset_val = offset & 0xff;
+  byte_val = inb(base_port + offset_val);
+  return (byte_val & 0xff);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//    MIO_WRITE_REG
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int mio_write_reg(int offset, unsigned char value)
+{
+  unsigned char byte_val;
+  unsigned char offset_val;
+
+  mio_error_code = MIO_SUCCESS;
+
+  if (check_handle())   /* Check for chip available */
+    return -1;
+
+  /* This function like the previous allow unlimited
+     write access to ALL of the registers on the PCM-MIO
+   */
+
+  offset_val = offset & 0xff;
+  byte_val = value;
+  outb(byte_val, base_port + offset_val);
+  
+  return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//    WRITE_DIO_BYTE
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int write_dio_byte(int offset, unsigned char value)
+{
+  unsigned char byte_val;
+  unsigned char offset_val;
+
+  mio_error_code = MIO_SUCCESS;
+
+  if (check_handle())   /* Check for chip available */
+    return -1;
+
+  /* All bit operations for the DIO are handled at this level
+     and we need the driver to allow access to the actual
+     DIO registers to update the value.
+  */
+
+  offset_val = offset & 0xff;
+  byte_val = value;
+  outb(byte_val, base_port + 0x10 + offset_val);
+
+  return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//    WRITE_DAC_COMMAND
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int write_dac_command(int dac_num,unsigned char value)
+{
+  unsigned char  byte_val;
+  unsigned char  offset_val;
+
+  mio_error_code = MIO_SUCCESS;
+
+  if (check_handle())   /* Check for chip available */
+    return -1;
+
+  byte_val = dac_num & 0xff;		/* This is the DAC number */
+  offset_val = value;		        /* This is the data value */
+  if (byte_val)
+    outb(offset_val,base_port + 0x0e);
+  else
+    outb(offset_val,base_port + 0x0a);
+
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//    WRITE_ADC_COMMAND
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int write_adc_command(int adc_num,unsigned char value)
+{
+  unsigned char byte_val;
+  unsigned char offset_val;
+
+  mio_error_code = MIO_SUCCESS;
+
+  if (check_handle())   /* Check for chip available */
+    return -1;
+
+  byte_val = adc_num & 0xff;		/* This is the ADC number */
+  offset_val = value;		        /* This is the data value */
+
+  if(byte_val)
+    outb(offset_val,base_port + 0x06);
+  else
+    outb(offset_val,base_port + 0x02);
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//    WRITE_DAC_DATA
+//
+//////////////////////////////////////////////////////////////////////////////
+
+int write_dac_data(int dac_num, unsigned short value)
+{
+  unsigned short word_val;
+  unsigned char byte_val;
+
+  mio_error_code = MIO_SUCCESS;
+
+  if (check_handle())   /* Check for chip available */
+    return -1;
+
+  byte_val = dac_num;
+  word_val = value;
+
+  if(byte_val)		/* DAC 1 */
+    outw(word_val,base_port+0x0c);
+  else
+    outw(word_val,base_port+8);
+  
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//    DAC_READ_STATUS
+//
+//////////////////////////////////////////////////////////////////////////////
+
+unsigned char dac_read_status(int dac_num)
+{
+  mio_error_code = MIO_SUCCESS;
+
+  if (check_handle())   /* Check for chip available */
+    return -1;
+
+  if (dac_num)
+    return inb(base_port + 0x0f);
+
+  return inb(base_port + 0x0b);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//    ADC_READ_STATUS
+//
+//////////////////////////////////////////////////////////////////////////////
+
+unsigned char adc_read_status(int adc_num)
+{
+  mio_error_code = MIO_SUCCESS;
+
+  if (check_handle())   /* Check for chip available */
+    return -1;
+
+  if (adc_num)
+    return inb(base_port + 7);
+  return inb(base_port + 3);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//    ADC_READ_CONVERSION_DATA
+//
+//////////////////////////////////////////////////////////////////////////////
+
+unsigned short adc_read_conversion_data(int channel)
+{
+  int adc_num;
+
+  mio_error_code = MIO_SUCCESS;
+
+  if (check_handle())   /* Check for chip available */
+    return -1;
+
+  if (channel > 7)
+    adc_num = 1;
+  else
+    adc_num = 0;
+
+  if (adc_num)
+    return inw(base_port + 4);
+
+  return inw(base_port);
+}
+
+
+int dio_get_int_with_timestamp(
+  unsigned long long *timestamp
+)
+{
+  mio_error_code = MIO_SUCCESS;
+
+  if (check_handle())   /* Check for chip available */
+    return -1;
+
+  return get_buffered_int(timestamp) & 0xff;
+}
+
+int dio_get_int(void)
+{
+  mio_error_code = MIO_SUCCESS;
+
+  return dio_get_int_with_timestamp(NULL);
+}
+
+int wait_adc_int_with_timeout(int adc_num, int milliseconds)
+{
+  int sc;
+
+  mio_error_code = MIO_SUCCESS;
+
+  if (check_handle())   /* Check for chip available */
+    return -1;
+
+  if (adc_num) {
+    sc = interruptible_sleep_on(&wq_a2d_1, milliseconds);
+  } else {
+    sc = interruptible_sleep_on(&wq_a2d_2, milliseconds);
+  }
+
+  return sc;
+}
+
+int wait_adc_int(int adc_num)
+{
+  return wait_adc_int_with_timeout(adc_num, 0);
+}
+
+int wait_dac_int_with_timeout(int dac_num, int milliseconds)
+{
+  int sc;
+
+  mio_error_code = MIO_SUCCESS;
+
+  if (check_handle())   /* Check for chip available */
+    return -1;
+
+  if (dac_num) {
+    sc = interruptible_sleep_on(&wq_dac_1, milliseconds);
+  } else {
+    sc = interruptible_sleep_on(&wq_dac_2, milliseconds);
+  }
+
+  return sc;
+}
+
+int wait_dac_int(int dac_num)
+{
+  return wait_dac_int_with_timeout(dac_num, 0);
+}
+
+int wait_dio_int_with_timestamp(
+  int                 milliseconds,
+  unsigned long long *timestamp
+)
+{
+  rtems_status_code  rc;
+  din_message_t      din;
+  size_t             received;
+
+  mio_error_code = MIO_SUCCESS;
+
+  if (check_handle())   /* Check for chip available */
+    return -1;
+
+  rc = rtems_message_queue_receive(
+    wq_dio,
+    &din,
+    &received,
+    RTEMS_DEFAULT_OPTIONS,
+    RTEMS_MILLISECONDS_TO_TICKS(milliseconds)
+  );
+  if ( rc == RTEMS_UNSATISFIED ) {
+    mio_error_code = MIO_READ_DATA_FAILURE;
+    return -1;
+  }
+
+  if ( rc == RTEMS_TIMEOUT ) {
+    mio_error_code = MIO_TIMEOUT_ERROR;
+    return -1;
+  }
+
+  if ( rc != RTEMS_SUCCESSFUL ) {
+    printk( "wait_dio_int_with_timestamp - error %d\n", rc );
+    exit( 0 );
+  }
+
+  if (timestamp)
+    *timestamp = din.timestamp;
+  return din.pin;
+}
+
+int wait_dio_int_with_timeout(int milliseconds)
+{
+  return wait_dio_int_with_timestamp(milliseconds, NULL);
+}
+
+int wait_dio_int(void)
+{
+  return wait_dio_int_with_timestamp(0, NULL);
+}
+
+static int handle = 0; /* XXX move to lower */
+
+int check_handle(void)
+{
+  if (handle > 0)  /* If it's already a valid handle */
+    return 0;
+
+  if (handle == -1)  /* If it's already been tried */
+  {
+    mio_error_code = MIO_OPEN_ERROR;
+    sprintf(mio_error_string,"MIO - Unable to open device PCMMIO");
+    return -1;
+  }
+
+  /*
+   * 0  ==> not initialized
+   * 1+ ==> valid file handle, thus initialized
+   * -1 ==> already attempted to open
+   */
+  handle = 1;
+  return 0;
+
+  /* if an error happens, go here */
+  mio_error_code = MIO_OPEN_ERROR;
+  sprintf(mio_error_string,"MIO - Unable to open device PCMMIO");
+  handle = -1;
+  return -1;
+}
+
+/*
+ *  RTEMS barrier create helper
+ */
+void pcmmio_barrier_create(
+  rtems_name  name,
+  rtems_id   *id
+)
+{
+  rtems_status_code rc;
+
+  rc = rtems_barrier_create( name, RTEMS_BARRIER_MANUAL_RELEASE, 0, id );
+  if ( rc == RTEMS_SUCCESSFUL )
+    return;
+
+ printk( "Unable to create PCMMIO Barrier\n" );
+ exit(1);
+}
+
+/*
+ *  RTEMS barrier create helper
+ */
+void pcmmio_din_queue_create(
+  rtems_name  name,
+  rtems_id   *id
+)
+{
+  rtems_status_code rc;
+
+  rc = rtems_message_queue_create(
+    name,
+    MAXIMUM_BUFFERED_DISCRETE_INTERRUPTS,
+    sizeof(din_message_t),
+    RTEMS_DEFAULT_ATTRIBUTES,
+    id
+  );
+  if ( rc == RTEMS_SUCCESSFUL )
+    return;
+
+  printk( "Unable to create PCMMIO DIN IRQ Message Queue\n" );
+  exit(1);
+}
+
+int interruptible_sleep_on(
+  rtems_id *id,
+  int       milliseconds
+)
+{
+  rtems_status_code rc;
+
+  rc = rtems_barrier_wait(*id, RTEMS_MILLISECONDS_TO_TICKS(milliseconds));
+  if ( rc == RTEMS_SUCCESSFUL )
+    return 0;
+
+  mio_error_code = MIO_TIMEOUT_ERROR;
+  return -1;
+}
+
+void wake_up_interruptible(
+  rtems_id *id
+)
+{
+  uint32_t  unblocked;
+
+  (void) rtems_barrier_release(*id, &unblocked);
+}
+
+/*
+ *  RTEMS specific interrupt handler
+ */
+#include <bsp/irq.h>
+
+void common_handler(void);
+
+void pcmmio_irq_handler(
+  rtems_irq_hdl_param param
+)
+{
+  common_handler();
+}
+
+static void pcmmio_irq_disable(const rtems_irq_connect_data *irq)
+{
+  BSP_irq_disable_at_i8259s(irq->name);
+}
+static void pcmmio_irq_enable(const rtems_irq_connect_data *irq)
+{
+  BSP_irq_enable_at_i8259s(irq->name);
+}
+
+static int pcmmio_irq_is_on(const rtems_irq_connect_data *irq)
+{
+  return BSP_irq_enabled_at_i8259s( irq->name );
+}
+
+rtems_irq_connect_data pcmmio_irq = {
+  0,                            // name
+  pcmmio_irq_handler,           // handler
+  NULL,                         // parameter
+  pcmmio_irq_enable,            // enable IRQ
+  pcmmio_irq_disable,           // disable IRQ
+  pcmmio_irq_is_on,             // is IRQ enabled
+};
+
+/* from pcmmio.c - GNU/Linux driver */
+void init_io(unsigned short io_address)
+{
+  int x;
+  unsigned short port;
+
+  /* save the address for later use */
+  port = io_address + 0X10;
+
+  /* Clear all of the I/O ports. This also makes them inputs */
+  for(x=0; x < 7; x++)
+    outb(0,port+x);
+
+  /* Set page 2 access, for interrupt enables */
+  outb(0x80,port+7);
+
+  /* Clear all interrupt enables */
+  outb(0,port+8);
+  outb(0,port+9);
+  outb(0,port+0x0a);
+
+  /* Restore page 0 register access */
+  outb(0,port+7);
+}
+
+/*
+ * RTEMS specific initialization routine
+ */
+void pcmmio_initialize(
+  unsigned short _base_port,
+  unsigned short _irq
+)
+{
+  /* hardware configuration information */
+  base_port                    = _base_port;
+  irq                          = _irq;
+  pcmmio_dio_missed_interrupts = 0;
+
+  /* Create RTEMS Objects */
+  pcmmio_barrier_create( rtems_build_name( 'a', '2', 'd', '1' ), &wq_a2d_1 );
+  pcmmio_barrier_create( rtems_build_name( 'd', 'a', 'c', '1' ), &wq_dac_1 );
+  pcmmio_barrier_create( rtems_build_name( 'd', 'a', 'c', '2' ), &wq_dac_2 );
+  pcmmio_din_queue_create( rtems_build_name( 'd', 'i', 'o', ' ' ), &wq_dio );
+
+  if ( base_port )
+    init_io( base_port );
+
+  /* install IRQ handler */
+  if ( base_port && irq ) {
+    int status = 0;
+    pcmmio_irq.name = irq;
+    #if defined(BSP_SHARED_HANDLER_SUPPORT)
+      printk( "PCMMIO Installing IRQ handler as shared\n" );
+      status = BSP_install_rtems_shared_irq_handler( &pcmmio_irq );
+    #else
+      printk( "PCMMIO Installing IRQ handler as non-shared\n" );
+      status = BSP_install_rtems_irq_handler( &pcmmio_irq );
+    #endif
+    if ( !status ) {
+      printk("Error installing PCMMIO interrupt handler! status=%d\n", status );
+    }
+  }
+}
+
+#include <libcpu/cpuModel.h> /* for rdtsc */
+
+/*
+ *  From this point down, we should be able to share easily with the Linux
+ *  driver but I haven't gone to the trouble to do surgery on it.  I have
+ *  no way to test it.
+ */
+
+/* real copy is in mio_io.c */
+extern unsigned char adc2_port_image;
+
+/* This is the common interrupt handler. It is called by the
+ * actual hardware ISR.
+ */
+
+void common_handler(void)
+{
+  unsigned char status;
+  unsigned char int_num;
+
+  /* Read the interrupt ID register from ADC2 */
+
+  adc2_port_image = adc2_port_image | 0x20;
+  outb(adc2_port_image,base_port + 0x0f);
+
+  status = inb(base_port + 0x0f);
+  if (status & 1) {
+    /* Clear ADC1 interrupt */
+    inb(base_port+1);      /* Clear interrupt */
+
+    /* Wake up any holding processes */
+    wake_up_interruptible(&wq_a2d_1);
+  }
+
+  if (status & 2) {
+    /* Clear ADC1 interrupt */
+    inb(base_port+5);      /* Clear interrupt */
+
+    /* Wake up anybody waiting for ADC1 */
+    wake_up_interruptible(&wq_a2d_2);
+  }
+
+  if (status & 4) {
+    /* Clear DAC1 interrupt */
+    inb(base_port+9);    /* Clear interrupt */
+
+    /* Wake up if you're waiting on DAC1 */
+    wake_up_interruptible(&wq_dac_1);
+  }
+
+  if (status & 8) {
+
+    /* DIO interrupt. Find out which bit */
+    int_num = get_int();
+    if (int_num) {
+      rtems_status_code  rc;
+      din_message_t      din;
+
+      din.timestamp = rdtsc(); 
+      din.pin       = int_num; 
+
+      rc = rtems_message_queue_send( wq_dio, &din, sizeof(din_message_t) );
+      if ( rc != RTEMS_SUCCESSFUL ) {
+        pcmmio_dio_missed_interrupts++;
+        #ifdef DEBUG
+          printk("<1>Missed DIO interrupt\n" );
+        #endif
+     }
+     #ifdef DEBUG
+       printk("<1>Buffering DIO interrupt on bit %d\n",int_num);
+     #endif
+
+      /* Clear the interrupt */
+      clr_int(int_num);
+    }
+  }
+
+  if (status & 0x10) {
+    /* Clear DAC2 Interrupt */
+    inb(base_port+0x0d);    /* Clear interrupt */
+
+    /* Wake up DAC2 holding processes */
+    wake_up_interruptible(&wq_dac_2);
+  }
+
+  /* Reset the access to the interrupt ID register */
+  adc2_port_image = adc2_port_image & 0xdf;
+  outb(adc2_port_image,base_port+0x0f);
+}
+
+
+void clr_int(int bit_number)
+{
+  unsigned short port;
+  unsigned short temp;
+  unsigned short mask;
+  unsigned short dio_port;
+
+  dio_port = base_port + 0x10;
+
+  /* Also adjust bit number */
+  --bit_number;
+
+  /* Calculate the I/O address based upon bit number */
+  port = (bit_number / 8) + dio_port + 8;
+
+  /* Calculate a bit mask based upon the specified bit number */
+  mask = (1 << (bit_number % 8));
+
+  /* Turn on page 2 access */
+  outb(0x80,dio_port+7);
+
+  /* Get the current state of the interrupt enable register */
+  temp = inb(port);
+
+  /* Temporarily clear only our enable. This clears the interrupt */
+  temp = temp & ~mask;    /* Clear the enable for this bit */
+
+  /* Now update the interrupt enable register */
+  outb(temp,port);
+
+  /* Re-enable our interrupt bit */
+  temp = temp | mask;
+  outb(temp,port);
+
+  /* Set access back to page 0 */
+  outb(0x00,dio_port+7);
+}
+
+int get_int(void)
+{
+  int temp;
+  int x;
+  unsigned short dio_port;
+
+  dio_port = base_port + 0x10;
+
+  /* Read the master interrupt pending register,
+           mask off undefined bits */
+  temp = inb(dio_port+6) & 0x07;
+
+  /* If there are no pending interrupts, return 0 */
+  if ((temp & 7) == 0)
+    return 0;
+
+  /* There is something pending, now we need to identify it */
+
+  /* Set access to page 3 for interrupt id register */
+  outb(0xc0, dio_port + 7);
+
+  /* Read the interrupt ID register for port 0 */
+  temp = inb(dio_port+8);
+
+  /* See if any bit set, if so return the bit number */
+  if (temp != 0) {
+    for (x=0; x<=7; x++) {
+      if (temp & (1 << x)) {
+        outb(0,dio_port+7);
+        return(x+1);
+       }
+    }
+  }
+
+  /* None in port 0, read port 1 interrupt ID register */
+  temp = inb(dio_port+9);
+
+  /* See if any bit set, if so return the bit number */
+  if (temp != 0) {
+    for (x=0; x<=7; x++) {
+      if (temp & (1 << x)) {
+        outb(0,dio_port+7);
+        return(x+9);
+      }
+    }
+  }
+
+  /* Lastly, read the status of port 2 interrupt ID register */
+  temp = inb(dio_port+0x0a);
+
+  /* If any pending, return the appropriate bit number */
+  if (temp != 0) {
+    for (x=0; x<=7; x++) {
+      if (temp & (1 << x)) {
+         outb(0,dio_port+7);
+         return(x+17);
+      }
+    }
+  }
+
+  /* We should never get here unless the hardware is seriously
+     misbehaving, but just to be sure, we'll turn the page access
+     back to 0 and return a 0 for no interrupt found
+  */
+  outb(0,dio_port+7);
+  return 0;
+}
+
+void flush_buffered_ints(void)
+{
+  rtems_status_code  rc;
+  size_t             flushed;
+
+  rc = rtems_message_queue_flush( wq_dio, &flushed );
+  if ( rc != RTEMS_SUCCESSFUL ) {
+    printk( "flushed_buffered_int - error %d\n", rc );
+    exit( 0 );
+  }
+}
+
+int get_buffered_int(
+  unsigned long long *timestamp
+)
+{
+  rtems_status_code  rc;
+  din_message_t      din;
+  int                line;
+  size_t             received;
+
+  if (irq == 0) {
+    line = get_int();
+    if (line)
+      clr_int(line);
+    return line;
+  }
+
+  rc = rtems_message_queue_receive(
+    wq_dio,
+    &din,
+    &received,
+    RTEMS_NO_WAIT,
+    0
+  );
+  if ( rc == RTEMS_UNSATISFIED ) {
+    mio_error_code = MIO_READ_DATA_FAILURE;
+    return 0;
+  }
+
+  if ( rc != RTEMS_SUCCESSFUL ) {
+    printk( "get_buffered_int - error %d\n", rc );
+    exit( 0 );
+  }
+
+  if (timestamp)
+    *timestamp = din.timestamp;
+  return din.pin;
+}
+
+int dio_get_missed_interrupts(void)
+{
+  int isrs;
+
+  isrs = pcmmio_dio_missed_interrupts;
+
+  pcmmio_dio_missed_interrupts = 0;
+
+  return isrs;
+}
Index: pcmmio/pcmmio.c
===================================================================
--- pcmmio/pcmmio.c	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
+++ pcmmio/pcmmio.c	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
@@ -0,0 +1,1018 @@
+/*
+ * WinSystems PCM-MIO Linux Device Driver
+ * 
+ * $Id$
+ */
+
+ static char *RCSInfo = "$Id$";
+
+/* Portions of original code Copyright (C) 1998-99 by Ori Pomerantz */
+
+
+/* #define DEBUG 1 */
+
+#ifndef __KERNEL__
+#  define __KERNEL__
+#endif
+
+#ifndef MODULE
+#  define MODULE
+#endif
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+
+MODULE_LICENSE("GPL");
+
+/* Our own ioctl numbers */
+
+#include "mio_io.h"
+
+#define SUCCESS 0
+
+#define MAX_INTS 1024
+
+/* Function prototypes for local functions */
+
+int get_buffered_int(void);
+void init_io(unsigned short io_address);
+void clr_int(int bit_number);
+int get_int(void);
+
+
+/* Interrupt handler */
+
+irqreturn_t mio_handler(int, void *, struct pt_regs *);
+
+void common_handler(void);
+
+
+/* This holds the base addresses of the board */
+
+unsigned short base_port = 0;
+
+/* The name for our device, as it will appear in 
+ * /proc/devices */
+
+#define MAJOR_NUM 115
+#define DEVICE_NAME "pcmmio"
+
+/* The maximum length of the message for the device */
+
+#define BUF_LEN 40
+
+/* The message the device will give when asked */
+
+static char Message[BUF_LEN];
+
+/* A message pointer for the device */
+
+int Message_Ptr = 0;
+
+/* Our insmod command line arguments */
+
+MODULE_PARM(io,"1-6i");
+MODULE_PARM(irq,"1-6i");
+
+static unsigned short io = 0;
+static unsigned short irq = 0;
+
+
+/* We will buffer up the transition interrupts and will pass them on
+   to waiting applications
+*/
+
+unsigned char int_buffer[MAX_INTS];
+int inptr = 0;
+int outptr = 0;
+
+
+/* These declarations create the wait queues. One for each supported
+   device.
+*/
+
+DECLARE_WAIT_QUEUE_HEAD(wq_a2d_1);
+DECLARE_WAIT_QUEUE_HEAD(wq_a2d_2);
+DECLARE_WAIT_QUEUE_HEAD(wq_dac_1);
+DECLARE_WAIT_QUEUE_HEAD(wq_dac_2);
+DECLARE_WAIT_QUEUE_HEAD(wq_dio);
+
+unsigned char adc2_port_image = 0;
+
+/* This is the common interrupt handler. It is called by the hctual hardware ISR.
+*/
+
+void common_handler()
+{
+unsigned char status;
+unsigned char int_num;
+
+
+			/* Read the interrupt ID register from ADC2 */
+
+			adc2_port_image = adc2_port_image | 0x20;
+			outb(adc2_port_image,base_port + 0x0f);	
+
+			status = inb(base_port + 0x0f);
+
+			if(status & 1)
+			{
+				/* Clear ADC1 interrupt */
+				inb(base_port+1);			/* Clear interrupt */
+
+				/* Wake up any holding processes */
+
+				wake_up_interruptible(&wq_a2d_1);
+			}
+
+			if(status & 2)
+			{			
+				/* Clear ADC1 interrupt */
+
+				inb(base_port+5);			/* Clear interrupt */
+
+				/* Wake up anybody waiting for ADC1 */
+
+				wake_up_interruptible(&wq_a2d_2);
+			}
+
+			if(status & 4)
+			{
+				/* Clear DAC1 interrupt */
+
+				inb(base_port+9);		/* Clear interrupt */
+
+				/* Wake up if you're waiting on DAC1 */
+
+				wake_up_interruptible(&wq_dac_1);
+			}
+
+			if(status & 8)
+			{
+
+				/* DIO interrupt. Find out which bit */
+
+				int_num = get_int();
+				if(int_num)
+				{
+#ifdef DEBUG
+					printk("<1>Buffering DIO interrupt on bit %d\n",int_num);
+#endif
+
+					/* Buffer the interrupt */
+
+					int_buffer[inptr++] = int_num;
+					if(inptr == MAX_INTS)
+						inptr = 0;
+				
+					/* Clear the interrupt */
+
+					clr_int(int_num);
+				}
+
+				/* Wake up anybody waiting for a DIO interrupt */
+
+				wake_up_interruptible(&wq_dio);
+			}
+
+			if(status & 0x10)
+			{
+				/* Clear DAC2 Interrupt */
+
+				inb(base_port+0x0d);		/* Clear interrupt */
+
+				/* Wake up DAC2 holding processes */
+
+				wake_up_interruptible(&wq_dac_2);
+			}
+
+
+			/* Reset the access to the interrupt ID register */
+
+			adc2_port_image = adc2_port_image & 0xdf;
+			outb(adc2_port_image,base_port+0x0f);	
+
+}
+
+
+
+/* This is the actual hadrware interrupt handler. It defers to another
+   functon for handling.
+*/
+
+irqreturn_t mio_handler(int pirq, void *dev_id, struct pt_regs *regs)
+{
+
+#ifdef DEBUG
+	printk("<1>MIO Interrupt received\n");
+#endif
+
+	common_handler();
+	return IRQ_HANDLED;
+}
+
+
+
+/***********************************************************************
+*
+*
+*			DEVICE OPEN
+*
+*
+************************************************************************
+*/
+
+
+/* This function is called whenever a process attempts 
+ * to open the device file */
+
+static int device_open(struct inode *inode, struct file *file)
+{
+
+  if(base_port == 0)
+  {
+	printk("<1>**** OPEN ATTEMPT on uninitialized port *****\n");
+	return -1;
+  }
+
+#ifdef DEBUG
+  printk ("device_open(%p)\n", file);
+#endif
+
+  /* Rewind the message pointer for this device on a new open.
+
+     This could cause problems for applications that use file I/O
+     for talking to the device as we do not limit the number of
+     applications that can open the device. The solution is to use
+     IOCTL functions to control the device rather than file I/O
+     calls.
+  */
+
+  Message_Ptr = 0;
+
+
+  return SUCCESS;
+}
+
+
+/*************************************************************************
+*
+*
+*			DEVICE CLOSE
+*
+*
+**************************************************************************
+*/
+
+
+int device_release(struct inode *inode, struct file *file)
+{
+
+#ifdef DEBUG
+  printk ("device_release(%p,%p)\n", inode, file);
+#endif 
+
+
+  return 0;
+
+}
+
+
+/****************************************************************************
+*
+*			DEVICE READ
+*
+*
+*
+*****************************************************************************
+*/
+
+ssize_t device_read(struct file *file,char *buffer,size_t length,loff_t *offset)
+{
+unsigned short port;
+int bytes_read;
+int x;
+
+   /* We only allow reading of the 32 valid ports in the device. Beyond
+      that we return EOF.
+   */
+
+   if(Message_Ptr == 32)
+ 	return 0;	/* EOF Condition */
+
+   port = base_port;
+
+   // Do a fresh read of the ports */
+
+   for(x=0; x<32; x++)
+       Message[x] = inb(port+x);
+
+
+  /* Number of bytes actually written to the buffer */
+
+   bytes_read = 0;
+
+#ifdef DEBUG
+  printk("device_read(%p,%p,%d)\n",file, buffer, length);
+#endif
+
+
+  /* Actually put the data into the buffer */
+
+  while (length && (Message_Ptr < 32))
+  {
+    /* Because the buffer is in the user data segment, 
+     * not the kernel data segment, assignment wouldn't 
+     * work. Instead, we have to use put_user which 
+     * copies data from the kernel data segment to the 
+     * user data segment. */
+
+    put_user((Message[Message_Ptr++]), buffer++);
+    length --;
+    bytes_read ++;
+  }
+
+#ifdef DEBUG
+   printk ("Read %d bytes, %d left\n",bytes_read, length);
+#endif
+
+   /* Read functions are supposed to return the number 
+    * of bytes actually inserted into the buffer */
+
+
+  /* By updating file->f_pos we can allow seeking of our Messge_Ptr
+     which will allow random access to the ports using file I/O
+  */
+
+  file->f_pos = (loff_t)Message_Ptr;
+
+  return bytes_read;
+}
+
+
+/****************************************************************************
+*
+*
+*				DEVICE WRITE
+*
+*****************************************************************************
+*/
+
+ssize_t device_write(struct file *file,const char *buffer,size_t length,loff_t *offset)
+{
+int i;
+unsigned short port;
+
+    port = base_port;
+
+#ifdef DEBUG
+  printk ("device_write(%p,%s,%d)",file, buffer, length);
+#endif
+
+  /* Read in the bytes to write, one at a time */
+
+  for(i=0; i<length && i<BUF_LEN; i++)
+  {
+    get_user(Message[i], buffer+i);
+
+    /* We output each byte to it's appropriate port as it comes in */
+
+	if(Message_Ptr == 32)
+	{
+         file->f_pos = (loff_t) Message_Ptr;
+	     return i;
+	}
+
+
+    outb(Message[i],port + Message_Ptr++);
+
+  }
+
+  /* As with device_read if we update the file position. Seeking will
+     work as expected.
+  */
+
+  file->f_pos = (loff_t) Message_Ptr;
+
+
+  /* Again, return the number of input characters used */
+
+    return i;
+}
+
+
+/****************************************************************************
+*
+*
+*
+*			DEVICE IOCTL
+*
+*
+*****************************************************************************
+*/
+
+
+int device_ioctl(struct inode *inode,struct file *file,
+     unsigned int ioctl_num, unsigned long ioctl_param)
+{
+int i;
+unsigned short word_val;
+unsigned char byte_val;
+unsigned char offset_val;
+unsigned char *arguments;
+
+#ifdef DEBUG
+//  printk("PCMMIO - IOCTL call IOCTL CODE %04X\n",ioctl_num);
+#endif
+
+
+  /* Switch according to the ioctl called */
+
+  switch (ioctl_num)
+	{
+
+	case WRITE_DAC_DATA:
+
+		arguments = (char *) ioctl_param;
+
+		if(!access_ok(VERIFY_WRITE,arguments,3))
+		{
+		    printk("<1>pcmmio : Unable to access IOCTL argument memory\n");
+		    return -EFAULT;
+		}
+
+		byte_val = arguments[0];
+
+		word_val = arguments[2];
+		word_val = word_val << 8;
+		word_val = word_val | arguments[1];
+
+		if(byte_val)		/* DAC 1 */
+			outw(word_val,base_port+0x0c);
+		else
+			outw(word_val,base_port+8);
+
+		break;
+
+
+	case	READ_DAC_STATUS:
+
+		byte_val = ioctl_param & 0xff;		/* This is the dac number */
+
+		if(byte_val)
+			i = inb(base_port + 0x0f);
+		else
+			i = inb(base_port + 0x0b);
+
+		return i;
+
+		break;
+
+
+	case	WRITE_DAC_COMMAND:
+
+		byte_val = ioctl_param & 0xff;		/* This is the DAC number */
+		offset_val = ioctl_param >> 8;		/* This is the data value */
+
+		if(byte_val)
+			outb(offset_val,base_port + 0x0e);
+		else
+			outb(offset_val,base_port + 0x0a);
+
+		break;
+
+
+	case	WRITE_ADC_COMMAND:
+
+		byte_val = ioctl_param & 0xff;		/* This is the ADC number */
+		offset_val = ioctl_param >> 8;		/* This is the data value */
+
+		if(byte_val)
+			outb(offset_val,base_port + 0x06);
+		else
+			outb(offset_val,base_port + 0x02);
+
+		break;
+
+
+
+	case	READ_ADC_DATA:
+
+		byte_val = ioctl_param & 0xff;	/* This is the ADC number */
+
+		if(byte_val)
+			word_val = inw(base_port + 4);
+		else
+			word_val = inw(base_port);
+
+		return word_val;
+
+		break;
+
+
+	case	READ_ADC_STATUS:
+
+		byte_val = ioctl_param & 0xff;		/* This is the ADC number */
+        
+		if(byte_val)
+			i = inb(base_port + 7);
+		else
+			i = inb(base_port + 3);
+
+		return i;
+
+		break;
+
+
+	case	WRITE_DIO_BYTE:
+
+		offset_val = ioctl_param & 0xff;
+		byte_val = ioctl_param >> 8;
+		outb(byte_val, base_port + 0x10 + offset_val);
+
+		break;
+
+
+	case	READ_DIO_BYTE:
+
+		offset_val = ioctl_param & 0xff;
+		byte_val = inb(base_port + 0x10 + offset_val);
+		return (byte_val & 0xff);
+
+		break;
+
+
+	case	MIO_WRITE_REG:
+
+		offset_val = ioctl_param & 0xff;
+		byte_val = ioctl_param >> 8;
+		outb(byte_val, base_port + offset_val);
+
+		break;
+
+
+	case	MIO_READ_REG:
+
+		offset_val = ioctl_param & 0xff;
+		byte_val = inb(base_port + offset_val);
+		return (byte_val & 0xff);
+
+		break;
+
+
+	case	WAIT_A2D_INT_1:
+
+#ifdef DEBUG
+		printk("<1>PCMMIO - IOCTL wait_ad1_int \n");
+		printk("<1>PCMMIO : current process %i (%s) going to sleep\n",
+		current->pid,current->comm);
+#endif
+
+		interruptible_sleep_on(&wq_a2d_1);
+		break;
+
+	case	WAIT_A2D_INT_2:
+
+
+#ifdef DEBUG
+		printk("<1>PCMMIO - IOCTL wait_ad2_int \n");
+		printk("<1>PCMMIO : current process %i (%s) going to sleep\n",
+		current->pid,current->comm);
+#endif
+
+		interruptible_sleep_on(&wq_a2d_2);
+		break;
+
+	case	WAIT_DAC_INT_1:
+
+#ifdef DEBUG
+		printk("<1>PCMMIO - IOCTL wait_dac1_int \n");
+		printk("<1>PCMMIO : current process %i (%s) going to sleep\n",
+		current->pid,current->comm);
+#endif
+		interruptible_sleep_on(&wq_dac_1);
+		break;
+
+	case	WAIT_DAC_INT_2:
+
+#ifdef DEBUG
+		printk("<1>PCMMIO - IOCTL wait_dac2_int \n");
+		printk("<1>PCMMIO : current process %i (%s) going to sleep\n",
+		current->pid,current->comm);
+#endif
+		interruptible_sleep_on(&wq_dac_2);
+		break;
+
+	case	WAIT_DIO_INT:
+
+		if((i = get_buffered_int()))
+			return i;
+
+#ifdef DEBUG
+		printk("<1>PCMMIO - IOCTL wait_dio_int \n");
+		printk("<1>PCMMIO : current process %i (%s) going to sleep\n",
+		current->pid,current->comm);
+#endif
+		interruptible_sleep_on(&wq_dio);
+
+		i = get_buffered_int();
+
+		return i;
+		break;
+
+	case READ_IRQ_ASSIGNED:
+
+		return(irq & 0xff);
+		break;
+
+	case DIO_GET_INT:
+
+		i = get_buffered_int();
+		return(i & 0xff);
+		break;
+
+
+	 }
+
+  return SUCCESS;
+}
+
+/***************************** DEVICE_LSEEK ***************************/
+
+loff_t device_lseek(struct file *filp, loff_t off, int whence)
+{
+unsigned short offset;
+
+    /* Convert the offset value to a more familiar size. After all
+       our device is a fixed size of 10 bytes.
+    */
+
+    offset = (unsigned short)off;
+
+#ifdef DEBUG
+    printk("<1>PCMMIO:lseek - offset %d mode %d\n",offset,whence);
+#endif
+
+    switch(whence)
+    {
+	case 0:   /* Seek set */
+	    Message_Ptr = offset;
+		if(Message_Ptr > 32)
+			Message_Ptr = 32;
+		break;
+
+	case 1:   /* Seek from Current */
+	    Message_Ptr += offset;
+		if(Message_Ptr > 32)
+			Message_Ptr = 32;
+
+		break;
+	
+	default:	  /* Seek from End */
+	    return -EINVAL;
+	    break;
+    }
+
+	if(Message_Ptr < 0)
+	{
+	    Message_Ptr = 0;
+	    filp->f_pos = (loff_t)Message_Ptr;
+	    return -EINVAL;
+	}
+
+	if(Message_Ptr > 32)
+	{
+	    Message_Ptr = 32;
+	    filp->f_pos = (loff_t)Message_Ptr;
+	    return -EINVAL;
+	}
+
+	filp->f_pos = (loff_t)Message_Ptr;
+	return (loff_t)Message_Ptr;
+}
+
+/* ******************* Module Declarations *************************** */
+
+
+/* This structure will hold the functions to be called 
+ * when a process does something to the our device 
+*/
+
+struct file_operations Fops = {
+
+  owner:	THIS_MODULE,
+  llseek:	device_lseek,
+  read:		device_read, 
+  write:	device_write,
+  ioctl:	device_ioctl,
+  open:		device_open,
+  release:	device_release,
+};
+
+/****************************************************************************
+*
+*			INIT_MODULE
+*
+*
+*****************************************************************************
+*/
+
+/* Initialize the module - Register the character device */
+
+int init_module()
+{
+int ret_val;
+
+  /* Sign-on */
+
+   printk("<1>\nWinSystems PCM-MIO Driver. Copyright 2006. All rights reserved\n");
+   printk("<1>%s\n",RCSInfo);
+
+
+  /* Check and Map our I/O region requests */
+
+	if(io != 0)
+    {
+		if(request_region(io,0x20,"PCMMIO") == NULL)
+		{
+			printk("<1>PCMMIO - Unable to use I/O Address %04X\n",io);
+           	io = 0;
+		}
+  	/* Register the character device */
+
+  		ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops);
+
+  		/* Negative values signify an error */
+ 
+ 		if (ret_val < 0)
+		{
+    		printk (" %s failed with %d\n",",registering the character device PCMMIO ", ret_val);
+    		return ret_val;
+  		}
+	
+		printk ("\nPCMMIO : The Base I/O Address = %04X\n",io);
+		base_port = io;
+		init_io(io);
+	}
+
+      if((io != 0) && (irq != 0))
+      {
+			if(request_irq(irq,mio_handler,SA_SHIRQ,"PCMMIO",RCSInfo))
+			printk("<1>PCMMIO - Unable to register IRQ %d\n",irq);
+		else
+			printk("<1>PCMMIO - IRQ %d registered ok Chip 1\n",irq);
+
+	  }
+ 
+	return 0;
+}
+
+/***************************************************************************
+*
+*			CLEANUP_MODULE
+*
+****************************************************************************
+*/
+
+/* Cleanup - unregister the appropriate file from /proc */
+
+void cleanup_module()
+{
+  /* Unregister I/O Port usage */
+
+   	if(irq)
+		free_irq(irq,RCSInfo);
+     
+	if(io)
+      	release_region(io,0x20);
+
+  /* Unregister the device */
+
+	unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
+ 
+}  
+
+
+/* start of device subroutines */
+
+
+
+/* This array holds the image values of the last write to each I/O
+   port. This allows bit manipulation routines to work without having to actually do
+   a read-modify-write to the I/O port.
+*/
+
+unsigned char port_images[6];
+
+
+void init_io(unsigned short io_address)
+{
+int x;
+unsigned short port;
+
+	/* save the address for later use */
+
+	port = io_address + 0X10;
+
+	/* Clear all of the I/O ports. This also makes them inputs */
+
+	for(x=0; x < 7; x++)
+		outb(0,port+x);
+
+	/* Clear the image values as well */
+
+	for(x=0; x < 6; x++)
+		port_images[x] = 0;
+
+	/* Set page 2 access, for interrupt enables */
+
+	outb(0x80,port+7);
+
+	/* Clear all interrupt enables */
+
+	outb(0,port+8);
+	outb(0,port+9);
+	outb(0,port+0x0a);
+
+	/* Restore page 0 register access */
+
+	outb(0,port+7);
+}
+
+
+
+
+void clr_int(int bit_number)
+{
+unsigned short port;
+unsigned short temp;
+unsigned short mask;
+unsigned short dio_port;
+
+
+	dio_port = base_port + 0x10;
+
+	/* Also adjust bit number */
+
+	--bit_number;
+
+	/* Calculate the I/O address based upon bit number */
+
+	port = (bit_number / 8) + dio_port + 8;
+
+	/* Calculate a bit mask based upon the specified bit number */
+
+	mask = (1 << (bit_number % 8));
+
+	/* Turn on page 2 access */
+
+	outb(0x80,dio_port+7);
+
+	/* Get the current state of the interrupt enable register */
+
+	temp = inb(port);
+
+	/* Temporarily clear only our enable. This clears the interrupt */
+
+	temp = temp & ~mask;    /* Clear the enable for this bit */
+
+	/* Now update the interrupt enable register */
+
+	outb(temp,port);
+
+	/* Re-enable our interrupt bit */
+
+	temp = temp | mask;
+
+	outb(temp,port);
+
+	/* Set access back to page 0 */
+
+	outb(0x00,dio_port+7);
+}
+
+
+int get_int(void)
+{
+int temp;
+int x;
+unsigned short dio_port;
+
+	dio_port = base_port + 0x10;
+
+	/* Read the master interrupt pending register,
+           mask off undefined bits */
+
+	temp = inb(dio_port+6) & 0x07;
+
+	/* If there are no pending interrupts, return 0 */
+
+	if((temp & 7) == 0)
+	    return 0;
+
+	/* There is something pending, now we need to identify it */
+
+	/* Set access to page 3 for interrupt id register */
+
+	outb(0xc0, dio_port + 7);
+
+	/* Read the interrupt ID register for port 0 */
+
+	temp = inb(dio_port+8);
+
+	/* See if any bit set, if so return the bit number */
+
+	if(temp != 0)
+	{
+	    for(x=0; x<=7; x++)
+	    {
+            if(temp & (1 << x))
+	     	{
+		    outb(0,dio_port+7);
+		    return(x+1);
+            }
+         }
+     }
+
+	/* None in port 0, read port 1 interrupt ID register */
+
+	temp = inb(dio_port+9);
+
+	/* See if any bit set, if so return the bit number */
+
+	if(temp != 0)
+	{
+	    for(x=0; x<=7; x++)
+	    {
+		if(temp & (1 << x))
+		{
+		    outb(0,dio_port+7);
+		    return(x+9);
+		}
+	    }
+	}
+
+	/* Lastly, read the statur of port 2 interrupt ID register */
+
+	temp = inb(dio_port+0x0a);
+
+	/* If any pending, return the appropriate bit number */
+
+	if(temp != 0)
+	{
+	    for(x=0; x<=7; x++)
+	    {
+			if(temp & (1 << x))
+			{
+			   outb(0,dio_port+7);
+			   return(x+17);
+			}
+	    }
+	}
+
+	/* We should never get here unless the hardware is seriously
+	   misbehaving, but just to be sure, we'll turn the page access
+	   back to 0 and return a 0 for no interrupt found
+	*/
+
+	outb(0,dio_port+7);
+	return 0;
+}
+
+
+int get_buffered_int(void)
+{
+int temp;
+
+	if(irq == 0)
+	{
+	    temp = get_int();
+	    if(temp)
+			clr_int(temp);
+	    return temp;
+	}
+
+	if(outptr != inptr)
+	{
+	    temp = int_buffer[outptr++];
+	    if(outptr == MAX_INTS)
+			outptr = 0;
+	    return temp;
+	}
+
+	return 0;
+}
+
Index: pcmmio/pcmmio_shell.c
===================================================================
--- pcmmio/pcmmio_shell.c	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
+++ pcmmio/pcmmio_shell.c	(revision 13bdbeed67cf12d296b0fac1eecc248a1f960537)
@@ -0,0 +1,94 @@
+/*
+ *  COPYRIGHT (c) 1989-2009.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ *
+ *  $Id$
+ */
+
+#include "pcmmio_commands.h"
+
+rtems_task Init(
+  rtems_task_argument ignored
+)
+{
+  /*
+   *  Initialize the PCMMIO module to use IRQ6.  Ours is jumpered for 0x300
+   *  base address.  We use discrete input interrupts so enable all of the
+   *  as edge triggered on 1.
+   */
+  pcmmio_initialize(0x300, 6);
+  enable_dio_interrupt();
+  { int i;
+    for (i=1 ; i<=48 ; i++ )
+      dio_enab_bit_int(i, 1);
+  }
+
+  /*
+   *  Display a herald with some hints on usage
+   */
+  printf(
+    "\n"
+    "\n"
+    "*** Shell Configured with WinSystems PCMMIO Commands ***\n"
+    "Type \"help pcmmio\" for more information\n"
+    "\n"
+  );
+  rtems_shell_init(
+    "SHLL",                          /* task_name */
+    RTEMS_MINIMUM_STACK_SIZE * 4,    /* task_stacksize */
+    100,                             /* task_priority */
+    "/dev/console",                  /* devname */
+    false,                           /* forever */
+    true,                            /* wait */
+    NULL                             /* login */
+  );
+}
+
+/* RTEMS configuration */
+
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#ifdef RTEMS_BSP_HAS_IDE_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_IDE_DRIVER
+#endif
+#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK
+#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
+
+#define CONFIGURE_MICROSECONDS_PER_TICK     1000
+
+#define CONFIGURE_MAXIMUM_TASKS                  20
+#define CONFIGURE_MAXIMUM_SEMAPHORES             20
+#define CONFIGURE_MAXIMUM_BARRIERS                3
+#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES          1
+#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 20
+
+/*
+ * discrete in messages are 12 bytes and there are 1024 of them 
+ */
+#define CONFIGURE_MESSAGE_BUFFER_MEMORY \
+        CONFIGURE_MESSAGE_BUFFERS_FOR_QUEUE(1024, 12)
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+#define CONFIGURE_EXTRA_TASK_STACKS         (6 * RTEMS_MINIMUM_STACK_SIZE)
+#define CONFIGURE_INIT_TASK_ATTRIBUTES      RTEMS_FLOATING_POINT
+
+#define CONFIGURE_STACK_CHECKER_ENABLED
+#define CONFIGURE_MALLOC_STATISTICS
+
+#define CONFIGURE_INIT
+#include <rtems/confdefs.h>
+
+#define CONFIGURE_SHELL_USER_COMMANDS \
+  CONFIGURE_PCMMIO_COMMANDS
+#define CONFIGURE_SHELL_USER_ALIASES \
+  CONFIGURE_PCMMIO_ALIASES
+
+#define CONFIGURE_SHELL_COMMANDS_INIT
+#define CONFIGURE_SHELL_COMMANDS_ALL
+
+#include <rtems/shellconfig.h>
+
