library W32IRQM; uses SysUtils, Classes, Windows, WinSvc; {$R *.RES} type TInitData = record BaseAddress : DWORD; IRQ : WORD; BusType : SmallInt; BusNumber : WORD; ClearOffset : WORD; Operation : WORD; Reserved1 : DWORD; Reserved2 : DWORD; end; var hDevice : HWND; EnvBuf : array[0..31] of char; ManagerHandle, ServiceHandle : SC_HANDLE; OS : Byte; const ServiceExe: PChar = '%SystemRoot%\SYSTEM32\DRIVERS\IRQGENM.SYS'; // control codes created by CTL_CODE macro in winioctl.h dioInit = $80FF2004; dioDetectIRQ = $80FF2008; dioSendEOI = $80FF200C; dioDisconnect = $80FF2010; dioAbort = $80FF2014; DriverName : PChar = 'IRQGENM'; Args : PChar = NIL; kWin = 1; kNT = 2; // the following are defined in winnt.h SERVICE_AUTO_START = $02; SERVICE_DEMAND_START = $03; SERVICE_ERROR_NORMAL = $01; SERVICE_KERNEL_DRIVER = $01; function InitGenDriver(Base: DWORD; IRQ: Byte; BusType: SmallInt; BusNumber: BYTE; Off: WORD; Op: BYTE): ByteBool; cdecl; var cbRet : Integer; ret : Boolean; Data : TInitData; begin ret := false; if hDevice <> INVALID_HANDLE_VALUE then begin Data.BaseAddress := Base; Data.IRQ := IRQ; Data.BusType := BusType; Data.BusNumber := BusNumber; Data.ClearOffset := Off; Data.Operation := Op; ret := DeviceIOControl(hDevice, dioInit, @Data, sizeof(Data), nil, 0, cbRet, nil); end; InitGenDriver := ret; end; function DetectIRQ(IRQ: Byte): ByteBool; cdecl; var O : TOverlapped; hEvent, cbRet : Integer; LIRQ: DWORD; begin DetectIRQ := false; LIRQ := IRQ; if hDevice <> INVALID_HANDLE_VALUE then begin hEvent := CreateEvent(nil, true, false, ''); O.Internal := 0; O.InternalHigh := 0; O.Offset := 0; O.OffsetHigh := 0; O.hEvent := hEvent; if not DeviceIOControl(hDevice, dioDetectIRQ, @LIRQ, 4, nil, 0, cbRet, @O) then begin if GetLastError = ERROR_IO_PENDING then begin GetOverlappedResult(hDevice, O, cbRet, true); if cbRet <> 0 then begin CloseHandle(hEvent); Exit; // IRP was cancelled end; end else begin CloseHandle(hEvent); Exit; // some error occurred in the driver so return false end; end; CloseHandle(hEvent); DetectIRQ := true; end; end; function SendEOI(IRQ: Byte): ByteBool; cdecl; var cbRet : Integer; LIRQ: DWORD; begin SendEOI := false; LIRQ := IRQ; if hDevice <> INVALID_HANDLE_VALUE then SendEOI := DeviceIOControl(hDevice, dioSendEOI, @LIRQ, 4, nil, 0, cbRet, nil); end; function DisconnectIRQ(IRQ: Byte): ByteBool; cdecl; var cbRet : Integer; LIRQ: DWORD; begin DisconnectIRQ := false; LIRQ := IRQ; if hDevice <> INVALID_HANDLE_VALUE then DisconnectIRQ := DeviceIOControl(hDevice, dioDisconnect, @LIRQ, 4, nil, 0, cbRet, nil); end; function AbortRequest(IRQ: Byte): ByteBool; cdecl; var cbRet : Integer; LIRQ: DWORD; begin AbortRequest := false; LIRQ := IRQ; if hDevice <> INVALID_HANDLE_VALUE then AbortRequest := DeviceIOControl(hDevice, dioAbort, @LIRQ, 4, nil, 0, cbRet, nil); end; function VBInitGenDriver(Base: DWORD; IRQ: Byte; BusType: SmallInt; BusNumber: BYTE; Off: WORD; Op: BYTE): ByteBool; stdcall; begin Result := InitGenDriver(Base, IRQ, BusType, BusNumber, Off, Op); end; function VBDetectIRQ(IRQ: Byte): ByteBool; stdcall; begin Result := DetectIRQ(IRQ); end; function VBSendEOI(IRQ: Byte): ByteBool; stdcall; begin Result := SendEOI(IRQ); end; function VBDisconnectIRQ(IRQ: Byte): ByteBool; stdcall; begin Result := DisconnectIRQ(IRQ); end; function VBAbortRequest(IRQ: Byte): ByteBool; stdcall; begin Result := AbortRequest(IRQ); end; exports InitGenDriver, DetectIRQ, SendEOI, DisconnectIRQ, AbortRequest, InitGenDriver name '_InitGenDriver', DetectIRQ name '_DetectIRQ', SendEOI name '_SendEOI', DisconnectIRQ name '_DisconnectIRQ', AbortRequest name '_AbortRequest', VBInitGenDriver, VBDetectIRQ, VBSendEOI, VBDisconnectIRQ, VBAbortRequest; procedure DLLHandler(Reason: Integer); var ServiceStatus : TServiceStatus; begin if (Reason = DLL_PROCESS_DETACH) and (hDevice <> 0) then begin CloseHandle(hDevice); Exit; // if auto start if OS = kNT then begin ManagerHandle := OpenSCManager (NIL, NIL, SC_MANAGER_ALL_ACCESS); ServiceHandle := OpenService(ManagerHandle, DriverName, SERVICE_ALL_ACCESS); ControlService(ServiceHandle, SERVICE_CONTROL_STOP, ServiceStatus); CloseServiceHandle(ManagerHandle); CloseServiceHandle(ServiceHandle); end; end; end; // DLL Initialization begin DLLProc := @DLLHandler; if hDevice = 0 then begin OS := kWin; GetEnvironmentVariable('OS', EnvBuf, 32); if (StrIComp(EnvBuf, 'WINDOWS_NT') = 0) then begin OS := kNT; // open manager ManagerHandle := OpenSCManager (NIL, NIL, SC_MANAGER_ALL_ACCESS); // create service ServiceHandle := CreateService (ManagerHandle, // SCManager database DriverName, // name of service DriverName, // name to display SERVICE_ALL_ACCESS, // desired access SERVICE_KERNEL_DRIVER, // service type SERVICE_AUTO_START, // start type SERVICE_ERROR_NORMAL, // error control type ServiceExe, // service's binary NIL, // no load ordering group NIL, // no tag identifier NIL, // no dependencies NIL, // LocalSystem account NIL // no password ); // open if already created if (ServiceHandle = 0) then ServiceHandle := OpenService(ManagerHandle, DriverName, SERVICE_ALL_ACCESS); StartService (ServiceHandle, 0, Args); CloseServiceHandle (ServiceHandle); CloseServiceHandle (ManagerHandle); hDevice := CreateFile('\\.\IRQGENM', GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); IF HDEVICE = -1 THEN HDEVICE := -1; end else hDevice := CreateFile('\\.\irqgenm.vxd', GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE or FILE_FLAG_OVERLAPPED, 0); end; end.