wideman-one 
Last edit: 98-06-04 Graham Wideman

Delphi

Hardware I/O Port Programming with Delphi and NT
Article created: 98-06-01

Orientation

Engineers and others interested in using their PCs to manipulate external hardware have long been drawn to TurboPascal/Delphi, because of the combination of power, predictability and speedy compilation that it offers while avoiding some of the complexity of C++.  You can afford to be a specialist at something other than the programming language.  This was great under DOS, and even under W3.1 and W95 with Delphi 1.  But with Delphi 2 and 3, and Win NT, the direct hardware manipulation features are not so directly accessible.

This article covers these general topics:

Version applicability: This article applies to (and the software has been tested with) Windows NT 4 (SP3). It uses techniques that have applied certainly since 1986 (hence should work with NT 3.5x).  It has not been tried with NT 5.

The Port I/O Instructions

This is actually the easy part.  In Turbo/Borland Pascal and Delphi 1 there are Port arrays which you can read and write (like any other array). These are absent from Delphi 2 and 3, presumably because of the additional wrinkles added by Win32 and NT programming.  No matter, we can easily add PortIn and PortOut functions/procedures to call the CPU's I/O instructions.  These are in unit gwportio.pas, and are similar to other such functions floating around the web.   (Onno Kortmann authored a unit called simport.pas with a slightly cooler object-based implementation that looks like the old Port arrays. I decided to go for simplest implementation, so mine are just functions and procedures.)

Getting Permission From NT

Under NT, "user-mode" code (ie: applications written by mere mortals) is not allowed to access hardware directly, hence when your application attempts to execute an I/O instruction you get an exception.  The idea is, of course, that hardware resources are things that no application should just take over at will, instead it should be up to the operating system (and its drivers) to arbitrate between different apps requests to use those resources.

That's the theory.  Turns out that the NT kernel maintains a map of I/O port addresses that each process is allowed to access, and for your apps that's normally set to "none". But we can tell NT to use a different I/O Permissions Map (IOPM) for our process and thereby gain access to the ports.  This approach is of course very naughty from a disciplined OS standpoint, so not recommended for widely distributed commercial apps.  But for those times when you just need to hack on some hardware, who has time to write a proper NT device driver?

The only problem is that user-mode code is not allowed to execute the kernel functions to change the permissions map. The workaround for that problem is to create an NT driver (drivers have sufficient privileges) to twiddle the IOPM at the request of your app. Just such a driver, giveio.sys, has been floating around the net since '86, authored by Dale Roberts in conjunction with a May 96 Dr Dobbs article.

Improved Driver and Delphi Interface Unit

Giveio.sys demonstrates the concept and most importantly clues us in to the undocumented kernel functions, but it throws open access to all I/O ports.  So I decided to take a crack at an improved driver that would allow giving access only to selected ports, and would provide a few diagnostic functions in to the bargain. The result is gwiopm.sys (source code included if you want to browse).   A Delphi interface to gwiopm.sys is provided in gwiopm.pas.

If you too want to have a go at device driver development, be forewarned that the only known way to compile one is with the MS Device Driver Development Kit (DDK), which in turn needs the Win32 SDK, and relies on some pretty specific feature of the MS C environment (Visual Studio). (Oh, and supposedly you can't compile on a W95 machine either...)     This leads to the somewhat incongruous necessity to install about about 500 Meg of cra... er, I mean, "supporting code" in order to compile a couple of hundred lines of source code into a 4K executable.  Recommended: Art Baker's "The Windows NT Device Driver Book" (Prentice Hall '97) helps to smooth out the bumps.

Installing a Driver Without Hassle for Users

So now we have a driver that can give our application permission to use I/O instructions. To install this driver you could create an installation program, or you could manually edit the registry to have NT load up the driver on boot up.  But though you're not really going to distribute your hardware hack, there are just a couple of other people who'll need to install it, right? And making them hassle with installing a driver is tedious.

For this reason, gwiopm.pas includes functions that your Delphi app can call to transparently install the gwiopm driver on the fly, start it up and then later stop and uninstall it after you are done. (I first learned about the functions to do this from example loaddrv.c code written by Paula Tomlinson, associated with a Windows Dev Journal article.)

Copyright Status

Please feel free to distribute or publish this article and associated code, provided some note of credit for me remains attached. Thanks!


Go to:  wideman-one