IO.DLL

Synopsis

   IO.DLL allows seamless port I/O operations for Windows
   95/98/NT/2000/XP using the same library.
   
Introduction

   In the pre-Windows days, it was a relatively simple matter to access
   I/O ports on a typical PC. Indeed, nearly every language sported a
   special command for doing so. As Windows emerged and gradually
   evolved, this flapping in the wind behaviour could no longer be
   tolerated because of operating system's ability to virtualize
   hardware.
   
   Virtualizing hardware means that an application (typically a DOS box
   in Windows) believes it is talking directly to a physical device, but
   in reality it is talking to a driver that emulates the hardware,
   passing data back and forth as appropriate. This is how you are able
   to open dozens of DOS boxes in your Windows session, each one with the
   strange notion that it has exclusive access to peripherals such as the
   video adapter, keyboard, sound card and printer.
   
   If one were to rudely bang out data to an I/O port that Windows
   thought it was in full control of, the "official bad thing" could
   occur, the severity of which depending upon the exact hardware that
   was being accessed. Actually, with the virtualization just mentioned,
   it is quite improbable that Windows would permit anything too nasty
   from occuring.
   
   Windows 95/98 actually does allow I/O operations be executed at the
   application level, although you'd be hard pressed to find a language
   that supports this directly. Typically the programmer will have to
   resort to assembly language for this kind of low-level control. If you
   know what you are doing, this can be a quick and easy way to access
   I/O ports. Of course, not everyone knows, or desires to learn 80x86
   assembly programming just because they want to turn on a lamp from
   their computer. However, the unwillingness to learn assembly language
   becomes rather trivial when faced with 9x's big brother.
   
   Windows NT/2000/XP, being the secure operating system that it is, does
   not permit port I/O operations at the application level at all.
   Period. A program with inline IN and OUT assembly instructions that
   runs perfectly on Windows 95/98 will fail horribly when it comes to
   Windows NT/2000/XP.
   
   Windows NT/2000/XP does, however, allow I/O instructions in its kernel
   mode drivers. A kernel mode driver runs at the most priviledged level
   of the processor and can do whatever it pleases, including screwing up
   the system beyond repair, thus writing a kernel mode driver is not for
   the feint of heart.
   
   If you were to take it upon yourself to wade through the documentation
   of the Windows NT/2000/XP ddk and piece together a driver that was
   callable by your application to do the I/O instructions on behalf of
   your application, you'd probably notice something not too
   pleasant--this sort of access is painfully slow. The call from
   application level to system level typically takes about one
   millisecond. Compare this to the one microsecond that a normal I/O
   access takes. To further the insult, you are at the whim of the
   operating system. If it has tasks which it believes are of higher
   priority than your lowly call to your driver, it will perform them,
   making precise timing nearly impossible.
   
   Obviously, writing a driver that does acts a proxy for the I/O calls
   isn't the most ideal solution. There is, however, a solution for
   NT/2000/XP that allows the same convienience of inline assembly
   language that 95/98 does.
   
   As mentioned, a kernel mode driver can do whatever it wants. The
   implication here is that if another kernel mode driver shut off
   application access to the I/O ports, it should be possible for another
   kernel mode driver to turn it back on. This is where IO.DLL enters the
   picture.
   
Licensing

   IO.DLL is completely free! However, you may not:
     * Charge others for it in any way. For example, you cannot sell it
       as a stand alone product.
     * Charge for an IO.DLL wrapper, such as an OCX or Delphi control
       whose purpose is just to put a fancy interface on IO.DLL. I
       consider these to be "derived works" and they must be provided
       free of charge.
     * Claim that it is your property.
       
   Also, the author (that's me) cannot be held liable due to io.dll's
   failure to perform. As with most free stuff, you are on your own.
   
Source Code and Special Modifications

   The source code is available for $1,000 US.
   
   I'm willing to work with people should they require a special
   modification to IO.DLL. For example, you might have a strict timing
   requirement of some sort that can only be done in kernel mode. For a
   fee, I will modify IO.DLL and/or the embedded kernel mode driver for
   the task at hand.
   
Description of IO.DLL

   IO.DLL provides a useful set of commands for reading and writing to
   the I/O ports. These commands are consistent between 95/98 and
   NT/2000/XP. Furthermore, there is no need for the programmer to learn
   assembly language or muck with kernel mode drivers. Simply link to the
   DLL and call the functions. It's that easy.
   
   Windows NT/2000/XP is accomodated through the use of a small kernel
   mode driver that releases the ports as needed to the application. This
   driver is embedded in the DLL and is installed if Windows NT/2000/XP
   is determined to be the underlying operating system.
   
   Due to the very minor overhead involved in dynamically linking to
   IO.DLL, and the optimized functions contained within, access to I/O
   ports is nearly as fast as if it was written in raw assembler and
   inlined in your application. This holds true for both Windows 95/98
   and Windows NT/2000/XP.
   
   Before moving on, it is probably prudent to mention that the technique
   employed in IO.DLL for releasing the ports to the application level
   isn't, strictly speaking, the proper way to do things. The proper way
   is to have a virtual device driver for Windows 95/98 and a kernel mode
   driver for Windows NT/2000/XP. This isn't very practical for many
   people though, nor is it really necessary. There are several
   successful commercial products on the market that do exactly what
   IO.DLL does. Let it be noted though that some of them are shady with
   their explanation of how their product works, meanwhile charging $500
   or more for it.
   
Download

   [64]io.dll 49k
   
   The following two files are for C++ users. There is more info on these
   in the prototypes section.
   
   [65]io.cpp 1k
   [66]io.h 1k
   
C/C++ Prototypes

void WINAPI PortOut(short int Port, char Data);
void WINAPI PortWordOut(short int Port, short int Data);
void WINAPI PortDWordOut(short int Port, int Data);
char WINAPI PortIn(short int Port);
short int WINAPI PortWordIn(short int Port);
int WINAPI PortDWordIn(short int Port);
void WINAPI SetPortBit(short int Port, char Bit);
void WINAPI ClrPortBit(short int Port, char Bit);
void WINAPI NotPortBit(short int Port, char Bit);
short int WINAPI GetPortBit(short int Port, char Bit);
short int WINAPI RightPortShift(short int Port, short int Val);
short int WINAPI LeftPortShift(short int Port, short int Val);
short int WINAPI IsDriverInstalled();

   To use IO.DLL with Visual C++/ Borland C++, etc, you'll need to use
   LoadLibrary and GetProcAddress. Yes, it's more of a pain than using a
   .lib file, but because of name mangling, it's the only reliable way of
   calling the functions in IO.DLL. I've gone ahead and done the dirty
   work for you:
   
   [67]io.cpp
   [68]io.h
   
   Just save these two files and include them in your project. For a
   Visual C++, you may need to add #include "StdAfx.h" at the top of
   io.cpp otherwise the compiler will whine at you.
   
   These two files take care of calling LoadLibrary and all the
   neccessary calls to GetProcAddress, making your life happy once again.
   
   The only step you are required to do is call LoadIODLL somewhere at
   the beginning of your program. Make sure you do this or you will find
   yourself faced with all sorts of interesting crashes.
   
   Please let me know if you find any errors in the above two files. They
   are new and haven't been tested all that much.
   
Delphi Prototypes

procedure PortOut(Port : Word; Data : Byte);
procedure PortWordOut(Port : Word; Data : Word);
procedure PortDWordOut(Port : Word; Data : DWord);
function PortIn(Port : Word) : Byte;
function PortWordIn(Port : Word) : Word;
function PortDWordIn(Port : Word) : DWord;
procedure SetPortBit(Port : Word; Bit : Byte);
procedure ClrPortBit(Port : Word; Bit : Byte);
procedure NotPortBit(Port : Word; Bit : Byte);
function GetPortBit(Port : Word; Bit : Byte) : WordBool;
function RightPortShift(Port : Word; Val : WordBool) : WordBool;
function LeftPortShift(Port : Word; Val : WordBool) : WordBool;
function IsDriverInstalled : Boolean;

Visual Basic Prototypes

   Private Declare Sub PortOut Lib "IO.DLL" (ByVal Port As Integer, ByVal
   Data As Byte)
   Private Declare Sub PortWordOut Lib "IO.DLL" (ByVal Port As Integer,
   ByVal Data As Integer)
   Private Declare Sub PortDWordOut Lib "IO.DLL" (ByVal Port As Integer,
   ByVal Data As Long)
   Private Declare Function PortIn Lib "IO.DLL" (ByVal Port As Integer)
   As Byte
   Private Declare Function PortWordIn Lib "IO.DLL" (ByVal Port As
   Integer) As Integer
   Private Declare Function PortDWordIn Lib "IO.DLL" (ByVal Port As
   Integer) As Long
   Private Declare Sub SetPortBit Lib "IO.DLL" (ByVal Port As Integer,
   ByVal Bit As Byte)
   Private Declare Sub ClrPortBit Lib "IO.DLL" (ByVal Port As Integer,
   ByVal Bit As Byte)
   Private Declare Sub NotPortBit Lib "IO.DLL" (ByVal Port As Integer,
   ByVal Bit As Byte)
   Private Declare Function GetPortBit Lib "IO.DLL" (ByVal Port As
   Integer, ByVal Bit As Byte) As Boolean
   Private Declare Function RightPortShift Lib "IO.DLL" (ByVal Port As
   Integer, ByVal Val As Boolean) As Boolean
   Private Declare Function LeftPortShift Lib "IO.DLL" (ByVal Port As
   Integer, ByVal Val As Boolean) As Boolean
   Private Declare Function IsDriverInstalled Lib "IO.DLL" As Boolean
   
Function Descriptions

   Please refer to the prototype for the particular language you are
   using.
   
   PortOut
   Outputs a byte to the specified port.
   
   PortWordOut
   Outputs a word (16-bits) to the specified port.
   
   PortDWordOut
   Outputs a double word (32-bits) to the specified port.
   
   PortIn
   Reads a byte from the specified port.
   
   PortWordIn
   Reads a word (16-bits) from the specified port.
   
   PortDWordIn
   Reads a double word (32-bits) from the specified port.
   
   SetPortBit
   Sets the bit of the specified port.
   
   ClrPortBit
   Clears the bit of the specified port.
   
   NotPortBit
   Nots (inverts) the bit of the specified port.
   
   GetPortBit
   Returns the state of the specified bit.
   
   RightPortShift
   Shifts the specified port to the right. The LSB is returned, and the
   value passed becomes the MSB.
   
   LeftPortShift
   Shifts the specified port to the left. The MSB is returned, and the
   value passed becomes the LSB.
   
   IsDriverInstalled
   Returns non-zero if io.dll is installed and functioning. The primary
   purpose of this function is to ensure that the kernel mode driver for
   NT/2000/XP has been installed and is accessible.
   
Notes

     * When installing a new io.dll, it may be necessary to first shut
       off the existing io.sys kernel mode driver for NT/2000/XP. To do
       this, open up a Command Prompt and enter the command "net stop
       io.sys".