   The RAWIO i386/486 Port I/O Driver for Microsoft Windows NT
                         Version 1.0
                       January 16, 1993

/* ***************************************************************** */

Copyright information:

		RAWIO.SYS and RAWIOVDD.DLL
		Copyright c. 1993
		The University of New Hampshire
		ALL RIGHTS RESERVED

The RAWIO.SYS kernel mode device driver and RAWIOVDD.DLL virtual
device driver for Windows NT were developed at the University of
New Hampshire for our own use. Anyone else can use them without
paying a fee, but if you are trying to sell them, it is illegal, 
and if you paid for them, you got ripped off! 

The following document describes how we think they work, but we take
no responsibility for errors in the document or the code. These files
were built and tested using the October, 1992 release of the
Microsoft Windows NT DDK and SDK. We would be glad to hear about problems 
(other than execution speed, which is beyond our control) or 
suggestions. Send any mail to:

		Compuserve:	70651,2770
		Internet:	t_miller@unhh.unh.edu

/* ***************************************************************** */

    The RAWIO driver for Windows NT provides the following
functionality:

1. User mode WIN32 processes can read and write i386/486 ports 
   using 8, 16, or 32 bit port I/O operations. Thus, custom
   hardware can be controlled via polled I/O without developing 
   a special device driver.

2. Existing DOS or Windows 3.x ".exe" files which do polled I/O
   to custom hardware can be run without modification, and 
   without developing device specific "Virtual Device Drivers".

    The "upside" of this is that you can talk to custom
hardware easily and conveniently. The "downside" is that this
port I/O is very inefficient, since each port I/O call must
endure the overhead imposed by the Windows NT I/O Manager. As a
result, the RAWIO driver is not particularly useful for 
transferring large amounts of data to/from a device. However,
it does allow DOS and Windows 3.x ".exe" files to work unmodified
and is useful for relatively low bandwidth devices. Our measurements
indicate that each call to the driver requires about 300 microseconds
on a 33 MHz 80486 and about 700 microseconds on a 25 MHz 80386.
Note that these times were measured using the October, 1992 beta
release of Windows NT, and might shorten (or lengthen!) on future 
releases (since the time is largely I/O Manager overhead).

/* ***************************************************************** */

          Installing the RAWIO i386/486 Port I/O Driver
	  
(these examples assume that the root directory for Windows NT is c:\winnt)

1. copy RAWIO.SYS to c:\winnt\system\drivers

2. copy RAWIOVDD.DLL to c:\winnt\system

3. use REGEDIT.EXE (supplied with the Windows NT distribution) to edit
   your system's registry file as follows. In each case, the key
   values are shown as they should look in the REGEDIT window after
   you have added them. Use the <Add Key> and <Add Value> options
   of the <Edit> menu to add the necessary keys and values.

	a. add a key named "Rawio" under the existing key path
	   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services

	b. add the following values to the new key (created in "a")
	   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Rawio

		Type:REG_DWORD_0x1
		Start:REG_DWORD:0x1
		ErrorControl:REG_DWORD:0x1
		Group:REG_SZ:Extended base
		ImagePath:REG_EXPAND_SZ:\SystemRoot\system\drivers\rawio.sys

	c. add the following value to the existing key
	   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\DOS Devices

		RAWIO:REG_SZ:\Device\RawIO0

	d. add the following value to the existing key
	   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\VirtualDeviceDrivers

		VDD:REG_MULTI_SZ:c:\winnt\system\rawiovdd.dll

	   (note: the VDD value might already exist on your system. If
	    so, just add the "c"\winnt\system\rawiovdd.dll" string
	    as an additional string of the "multi-string" value)

	e. add a key named "Parameters" under the path (created in "a")
	   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Rawio


	f. add the following values to the new key (created in "e") 
	   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Rawio\Parameters
	
		Ports:REG_MULTI_SZ:0x280-0x29f 0x300-0x30f ...

	   Each hex range such as "0x280-0x29f" is a separate string
	   of the "multi-string" value. This represents a range of
	   16 bit i386/486 port addresses that the driver will be able 
	   to access (usually occupied by a custom device). The format 
	   of the range specification is strict: "0xnnnn-0xmmmm" where 
	   "nnnn" and "mmmm" are hex values (using lower case a-f) of 
	   one to four hex digits in length. Each range can be as large 
	   as desired and can include unused port addresses, but should 
	   NOT include port addresses used by standard devices. Up to
	   eight range specifications will be used by the RAWIO driver.

4. Shutdown and reboot your Windows NT system.

/* ***************************************************************** */

	Performing Port I/O From WIN32 User Mode Processes

The file PORTIO.C contains simple procedure calls (similar
to Microsoft C for DOS and Windows port I/O calls). This file should
be compiled and linked to your WIN32 code. Function prototypes are 
declared in PORTIO.H. These procedures are self-explanatory and can
be used with no special initialization or termination code:

	// i386/486 port output (8, 16, or 32 bits)

	outp(port, byte_value);
	outpw(port, word_value);
	outpl(port, dword_value);

	// i386/486 port input (8, 16, or 32 bits)

	byte_value = inp(port);
	word_value = inpw(port);
	dword_value = inpl(port);

You can also use a procedure in PORTIO.C to get a file handle
for the RAWIO device:

	// get file handle for RAWIO logical device

	HANDLE hPorts;
	if ((hPorts = GetRawIoHandle(void)) == INVALID_HANDLE_VALUE)
		{ Error! - RAWIO driver probably not loaded correctly }
	...

You can use this handle to access the RAWIO driver through calls
to the WIN32 API procedure DeviceIoControl(). The file PORTIO.H
defines six legal control function codes which can be used in
DeviceIoControl():

	IOCTL_RAWIO_OUT_BYTE
	IOCTL_RAWIO_OUT_WORD
	IOCTL_RAWIO_OUT_DWORD

	IOCTL_RAWIO_IN_BYTE
	IOCTL_RAWIO_IN_WORD
	IOCTL_RAWIO_IN_DWORD

Regardless of the data size (BYTE, WORD or DWORD) the output and 
input buffers in the DeviceIoControl() call must be DWORD arrays.
For the port output operations, the output buffer is assumed to 
contain any number of alternating port addresses and data values:

	DWORD OutputBuffer[#_of_transfers * 2];
	OutputBuffer[0] = port_1_address;
	OutputBuffer[1] = port_1_value;
	OutputBuffer[2] = port_2_address;
	OutputBuffer[3] = port_2_value;
	...
	DeviceIoControl(
	    hPorts,
	    IOCTL_RAWIO_OUT_xxxx,
	    OutputBuffer,
	    #_of_transfers * 2 * sizeof(DWORD),
	    NULL,
	    0,
	    &i,
	    NULL
	    );

Thus, multiple port outputs can occur in response to a single 
DeviceIoControl() call (this is much more efficient than doing
sequential outp() calls). 

For port input functions, the output buffer is assumed to contain 
a list of addresses of ports to be read into corresponding positions 
of the input buffer:

	DWORD OutputBuffer[#_of_transfers];
	DWORD InputBuffer[#_of_transfers];
	OutputBuffer[0] = port_1_address;
	OutputBuffer[1] = port_2_address;
	...
	DeviceIoControl(
	    hPorts,
	    IOCTL_RAWIO_IN_xxxx,
	    OutputBuffer,
	    #_of_transfers * sizeof(DWORD),
	    InputBuffer,
	    #_of_transfers * sizeof(DWORD),
	    &i,
	    NULL
	    );

	port_1_value = InputBuffer[0];
	port_2_value = InputBuffer[1];
	...

Again, multiple port inputs can occur in response to a single 
DeviceIoControl() call (this is much more efficient than doing
sequential inp() calls). 

The RAWIO driver is a "nonexclusive" device driver, so multiple
threads and processes can access it without interference.

/* ***************************************************************** */

	Performing Port I/O From DOS and/or Windows 3.x

The RAWIO.SYS and RAWIOVDD.DLL pair provide DOS and Windows 3.x ".exe" 
files with apparent direct access to the i386/486 I/O ports listed in the 
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Rawio\Parameters
registry key (see installation instructions). Nothing else needs
to be done. Actually, the access isn't direct at all. When 
DOS or Windows programs attempt to execute an "in" or "out"
instruction to one of the enabled port addresses, a privileged 
instruction trap occurs. The trap handler redirects the I/O operation 
request to the RAWIOVDD.DLL virtual device driver, which in turn passes 
it on to the RAWIO.SYS kernel mode device driver (via the Windows NT
I/O Manager), which finally performs the I/O operation. Thus, the
DOS or Windows program will run much slower under Windows NT if it 
does a lot of I/O operations, but unless it is timing sensitive it 
should at least work (which it wouldn't otherwise do).
