{ -----------------------------------------------------------------------------}
{ Copyright 2000-2001, Zloba Alexander.  All Rights Reserved.                  }
{ This unit can be freely used and distributed in commercial and private       }
{ environments, provided this notice is not modified in any way.               }
{ -----------------------------------------------------------------------------}
{ Feel free to contact me if you have any questions, comments or suggestions at}
{   zal@specosoft.com (Zloba Alexander)                                        }
{ You can always find the latest version of this unit at:                      }
{   http://www.specosoft.com                                                   }

{ -----------------------------------------------------------------------------}
{ Date last modified:  08/10/2001                                              }
{ -----------------------------------------------------------------------------}
{ ZLPortIO driver interface unit v1.20                                         }
{ -----------------------------------------------------------------------------}
{ Description:                                                                 }
{   This unit allow your application direct access port input and output under }
{   all versions of Microsoft Windows�                                         }
{ Depends:                                                                     }
{   zlportio.sys ddkint.pas                                                    }
{   You must distribute zlportio.sys with your application                     }
{ Procedures and functions:                                                    }
{   procedure zlioportread( const Port,DataType:dword ):dword;                 }
{   procedure zlioportwrite( const Port,DataType,Data:dword );                 }
{                                                                              }
{  function portreadb( const Port:dword ):byte;                                }
{  function portreadw( const Port:dword ):word;                                }
{  function portreadl( const Port:dword ):dword;                               }
{                                                                              }
{  procedure portwriteb( const Port:Dword;const Data:byte );                   }
{  procedure portwritew( const Port:dword;const Data:word );                   }
{  procedure portwritel( const Port,Data:dword );                              }
{                                                                              }
{   Examples:                                                                  }
{    //  get data bits from LPT port                                           }
{      databits := portreadb( $378 )                                           }
{    //  set data bits from LPT port                                           }
{      portwriteb( $378, databits )                                            }
{    //  The second parameter determine the databus length for operation       }
{ -----------------------------------------------------------------------------}
{ Revision History:                                                            }
{ 1.00:  + First public release                                                }
{ 1.10:  + Added new functions (portreadX,portwriteX) for convenience of usage }
{ 1.20:  + Added new function (zliosetiopm) for enabling direct access to ports}
{ 1.30:  + added compiler directives for correct compilation                   }
{ 1.40:  + added opportunity to run multiply instances client to driver        }
{ 1.50:  - fixed bug with work under win98                                     }
{------------------------------------------------------------------------------}

{$A-,H-}
unit zlportio;

interface

uses windows,
     sysutils,
     ddkint;

Const
  ZLIO_BYTE  = 0;
  ZLIO_WORD  = 1;
  ZLIO_DWORD = 2;

var

// if TRUE then driver was started
// in other case something wrong
// We start driver in initialization section of unit.

  ZlIOStarted:boolean = false;

// if TRUE then we can use asm IN,OUT under NT/2000
// see zliosetiopm for more details
  ZlIODirect:boolean = false;

// handle to opened driver

  HZLIO:THandle;


function portreadb( const Port:dword ):byte;
function portreadw( const Port:dword ):word;
function portreadl( const Port:dword ):dword;

procedure portwriteb( const Port:Dword;const Data:byte );
procedure portwritew( const Port:dword;const Data:word );
procedure portwritel( const Port,Data:dword );


procedure zlioportwrite( const Port,DataType,Data:dword );
function zlioportread( const Port,DataType:dword ):dword;

// if you need the best perfomance for your IO operations
// call zliosetiopm(TRUE). This allow your application
// to use asm command IN,OUT directly in your code.

procedure zliosetiopm( const Direct:boolean );

// internal

function zliostart:boolean;
procedure zliostop;


implementation

const
  ZLIODriverName='zlportio';

var
  IOCTL_ZLUNI_PORT_READ:cardinal;
  IOCTL_ZLUNI_PORT_WRITE:cardinal;
  IOCTL_ZLUNI_IOPM_ON:cardinal;
  IOCTL_ZLUNI_IOPM_OFF:cardinal;

type
TzlIOData = record
  Port,DataType,Data:dword;
end;


procedure zlioportwrite( const Port,DataType,Data:dword );
var resdata:TZLIOData;
    cBR:cardinal;
begin
 if (not ZLIODirect) then begin
  resdata.Port := Port;
  resdata.Data :=  Data;
  resdata.DataType :=  DataType;
  if ZLIOStarted then
   DeviceIoControl(HZLIO,IOCTL_ZLUNI_PORT_WRITE,@resdata,sizeof(resdata),nil,0,cBR,nil );
 end
 else begin
   Case DataType of
    ZLIO_BYTE : asm mov edx,Port;mov eax,data;out dx,al; end;
    ZLIO_WORD : asm mov edx,Port;mov eax,data;out dx,ax; end;
    ZLIO_DWORD: asm mov edx,Port;mov eax,data;out dx,eax; end;
   end;
 end;
end;

function zlioportread(const Port,DataType:dword):dword;
var resdata:TZLIOData;
    cBR:cardinal;i:dword;
begin
 if (not ZLIODirect) then begin
   resdata.Port := Port;
   resdata.DataType :=  DataType;
   if ZLIOStarted then
    DeviceIoControl(HZLIO,IOCTL_ZLUNI_PORT_READ,@resdata,sizeof(resdata),@i,sizeof(dword),cBR,nil );
 end
 else begin
   Case DataType of
    ZLIO_BYTE : asm mov edx,Port;xor eax,eax;in al,dx;mov i,eax; end;
    ZLIO_WORD : asm mov edx,Port;xor eax,eax;in ax,dx;mov i,eax; end;
    ZLIO_DWORD: asm mov edx,Port;xor eax,eax;in eax,dx;mov i,eax end;
   end;
 end;
  result := i;
end;

function portreadb( const Port:dword ):byte;
begin
 Result := zlioportread(Port,ZLIO_BYTE);
end;

function portreadw( const Port:dword ):word;
begin
 Result := zlioportread(Port,ZLIO_WORD);
end;

function portreadl( const Port:dword ):dword;
begin
 Result := zlioportread(Port,ZLIO_DWORD);
end;

procedure portwriteb( const Port:Dword;const Data:byte );
begin
 zlioportwrite(Port,ZLIO_BYTE,Data);
end;

procedure portwritew( const Port:dword;const Data:word );
begin
 zlioportwrite(Port,ZLIO_WORD,Data);
end;

procedure portwritel( const Port,Data:dword );
begin
 zlioportwrite(Port,ZLIO_DWORD,Data);
end;

procedure zliosetiopm( const Direct:boolean );
var cBR:cardinal;
begin
 if Win32Platform=VER_PLATFORM_WIN32_NT then
  if ZLIOStarted then begin
   if Direct then
     DeviceIoControl(HZLIO,IOCTL_ZLUNI_IOPM_ON,nil,0,nil,0,cBR,nil )
   else
     DeviceIoControl(HZLIO,IOCTL_ZLUNI_IOPM_OFF,nil,0,nil,0,cBR,nil );
   ZLIODirect := Direct;
 end
end;




function zliostart;
var dir:shortstring;
begin
 if Win32Platform<>VER_PLATFORM_WIN32_NT then begin
  result := true;
  exit;
 end;
// Result := false;
 zliostop;
 dir := ExtractFileDir(ParamStr(0))+'\'+ZLIODriverName+'.sys'#0;
 driverinstall(pchar(@dir[1]),ZLIODriverName+#0);
 Result := driverstart(ZLIODriverName) = 0;
end;

procedure zliostop;
begin
 if Win32Platform<>VER_PLATFORM_WIN32_NT then
  exit;
 driverstop(ZLIODriverName);
 driverremove(ZLIODriverName);
end;

function zlioopen( var Handle:thandle):boolean;
var cERR:integer;
    s:string;
begin
 if Win32Platform<>VER_PLATFORM_WIN32_NT then begin
  result := true;
  exit;
 end;
 Result := false;
 Handle := THandle(-1);
 Handle := createFile('\\.\ZLPORTIO',
                  GENERIC_READ or GENERIC_WRITE,
                  0,
                  nil,
                  OPEN_EXISTING,
                  FILE_ATTRIBUTE_NORMAL,
                  0 );
 cERR := getlasterror;
 s := messagestring( cerr);
 if (cERR = ERROR_ALREADY_EXISTS)or(cERR = ERROR_SUCCESS) then Result := True;
end;

procedure zlioclose( const Handle:thandle);
begin
 if (Win32Platform=VER_PLATFORM_WIN32_NT) then
 closehandle(Handle);
end;


initialization

IOCTL_ZLUNI_PORT_READ := CTL_CODE(FILE_DEVICE_KRNLDRVR, 1, METHOD_BUFFERED, FILE_ANY_ACCESS);
IOCTL_ZLUNI_PORT_WRITE := CTL_CODE(FILE_DEVICE_KRNLDRVR, 2, METHOD_BUFFERED, FILE_ANY_ACCESS);
IOCTL_ZLUNI_IOPM_ON := CTL_CODE(FILE_DEVICE_KRNLDRVR, 3, METHOD_BUFFERED, FILE_ANY_ACCESS);
IOCTL_ZLUNI_IOPM_OFF := CTL_CODE(FILE_DEVICE_KRNLDRVR, 4, METHOD_BUFFERED, FILE_ANY_ACCESS);

 if Win32Platform<>VER_PLATFORM_WIN32_NT then begin
   zliostarted := true;
   zliodirect := true;
 end
 else begin
   if not zlioopen(HZLIO) then begin
    if zliostart then
     ZLIOStarted := zlioopen(HZLIO) or (Win32Platform<>VER_PLATFORM_WIN32_NT);
   end
   else
    ZLIOStarted := true;
 end;
finalization

if ZLIOStarted then
 zliostop;



end.