#define WANTVXDWRAPS #include #include #include #include #include #include #include "irqgen.h" #pragma VxD_LOCKED_CODE_SEG #pragma VxD_LOCKED_DATA_SEG DWORD cbIn, cbOut; // Sizes of input and output buffers LPOVERLAPPED lpo; // Pointer to overlapped structure BYTE myIRQ = 0; // holds irq sent by dll BOOL IRQ_Hooked = FALSE; BOOL IRQ_Occurred = FALSE; BOOL IRQ_Requested = FALSE; ULONG myBase = 0; // holds base address sent by dll USHORT myOffset = 0; // holds clear offset sent by dll UCHAR myOp = 0; // holds operation sent by dll HIRQ hIRQ; VID IRQGEN_IRQ_Desc = {0,0,0,0,0,0,0,0,0}; /**************************************************************************** IRQGEN_DeviceIOControl // Returning a positive value will cause the WIN32 DeviceIOControl // call to return FALSE, the error code can then be retrieved // via the WIN32 API GetLastError. ****************************************************************************/ DWORD _stdcall IRQGEN_DeviceIOControl(DWORD dwService, DWORD dwDDB, DWORD hDevice, LPDIOC lpDIOCParms) { DWORD dwRetVal = 0; switch(dwService) { case DIOC_OPEN: // same as DIOC_GETVERSION dwRetVal = 0; break; case DIOC_CLOSEHANDLE: dwRetVal = IRQGEN_CleanUp(); break; case InitGenDriver: dwRetVal = IRQGEN_InitGenDriver(dwDDB, hDevice, lpDIOCParms); break; case DetectIRQ: dwRetVal = IRQGEN_DetectIRQ(dwDDB, hDevice, lpDIOCParms); break; case SendEOI: dwRetVal = IRQGEN_SendEOI(dwDDB, hDevice, lpDIOCParms); break; case Abort: dwRetVal = IRQGEN_Abort(dwDDB, hDevice, lpDIOCParms); break; default: dwRetVal = ERROR_NOT_SUPPORTED; break; } return(dwRetVal); } DWORD _stdcall IRQGEN_SendEOI(DWORD dwDDB, DWORD hDevice, LPDIOC lpDIOCtl) { if (!IRQ_Hooked) return ERROR_NOT_SUPPORTED; VPICD_Phys_EOI(hIRQ); return(0); } DWORD _stdcall IRQGEN_Abort(DWORD dwDDB, DWORD hDevice, LPDIOC lpDIOCtl) { if (!IRQ_Requested) return ERROR_NOT_SUPPORTED; lpo->O_InternalHigh = 1; VWIN32_DIOCCompletionRoutine(lpo->O_Internal); MyPageUnlock((DWORD)lpo, sizeof(OVERLAPPED)); IRQ_Requested = FALSE; return(0); } DWORD _stdcall IRQGEN_InitGenDriver(DWORD dwDDB, DWORD hDevice, LPDIOC lpDIOCtl) { PIRQGEN_INIT_DATA pBuffer; pBuffer = (PIRQGEN_INIT_DATA)lpDIOCtl->lpvInBuffer; cbIn = lpDIOCtl->cbInBuffer; if (cbIn < sizeof(IRQGEN_INIT_DATA)) return ERROR_INVALID_PARAMETER; if (IRQ_Hooked) VPICD_Force_Default_Behavior(hIRQ); IRQ_Hooked = FALSE; myIRQ = pBuffer->IRQ; myBase = pBuffer->BaseAddress; myOffset = pBuffer->ClearOffset; myOp = pBuffer->Operation; IRQGEN_IRQ_Desc.VID_IRQ_Number = myIRQ; IRQGEN_IRQ_Desc.VID_Hw_Int_Proc = (ULONG)&IRQGEN_Event_Callback; hIRQ = VPICD_Virtualize_IRQ(&IRQGEN_IRQ_Desc); IRQ_Hooked = TRUE; VPICD_Physically_Unmask(hIRQ); return(0); } DWORD _stdcall IRQGEN_DetectIRQ(DWORD dwDDB, DWORD hDevice, LPDIOC lpDIOCtl) { *(PDWORD)(lpDIOCtl->lpcbBytesReturned) = 1; if (!lpDIOCtl->lpoOverlapped || !IRQ_Hooked || IRQ_Requested) return ERROR_NOT_SUPPORTED; cbIn = lpDIOCtl->cbInBuffer; cbOut = lpDIOCtl->cbOutBuffer; lpo = (LPOVERLAPPED)lpDIOCtl->lpoOverlapped; if (IRQ_Occurred) { IRQ_Occurred = FALSE; *(PDWORD)(lpDIOCtl->lpcbBytesReturned) = 0; return(0); // This will make DeviceIOControl return synchronously } IRQ_Requested = TRUE; lpo = (LPOVERLAPPED)MyPageLock((DWORD)lpo, sizeof(OVERLAPPED)); return(-1); // This will make DeviceIOControl return ERROR_IO_PENDING } void _cdecl IRQGEN_Event_Callback(void) { unsigned short port = myBase + myOffset; unsigned char val = 0; IRQ_Occurred = TRUE; switch (myOp) { case WRITE_TO_CLEAR: _asm { mov dx, port mov al, val out dx, al } break; case READ_TO_CLEAR: _asm { mov dx,port in al,dx } break; } _asm sti; if (IRQ_Requested) { lpo->O_InternalHigh = 0; VWIN32_DIOCCompletionRoutine(lpo->O_Internal); MyPageUnlock((DWORD)lpo, sizeof(OVERLAPPED)); IRQ_Occurred = FALSE; IRQ_Requested = FALSE; } } DWORD _stdcall IRQGEN_CleanUp(void) { if (IRQ_Hooked) VPICD_Force_Default_Behavior(hIRQ); if (IRQ_Requested) MyPageUnlock((DWORD)lpo, sizeof(OVERLAPPED)); return(VXD_SUCCESS); } DWORD _stdcall IRQGEN_Dynamic_Exit(void) { return(VXD_SUCCESS); } DWORD _stdcall MyPageLock(DWORD lpMem, DWORD cbSize) { DWORD LinPageNum, LinOffset, nPages; LinOffset = lpMem & 0xfff; // page offset of memory to map LinPageNum = lpMem >> 12; // generate page number // Calculate # of pages to map globally nPages = ((lpMem + cbSize) >> 12) - LinPageNum + 1; // // Return global mapping of passed in pointer, as this new pointer // is how the memory must be accessed out of context. // return (_LinPageLock(LinPageNum, nPages, PAGEMAPGLOBAL) + LinOffset); } void _stdcall MyPageUnlock(DWORD lpMem, DWORD cbSize) { DWORD LinPageNum, nPages; LinPageNum = lpMem >> 12; nPages = ((lpMem + cbSize) >> 12) - LinPageNum + 1; // Free globally mapped memory _LinPageUnlock(LinPageNum, nPages, PAGEMAPGLOBAL); } #pragma VxD_ICODE_SEG #pragma VxD_IDATA_SEG DWORD _stdcall IRQGEN_Dynamic_Init(void) { return(VXD_SUCCESS); }