mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
[FAST486]
Separate external interrupts from interrupt signals (which are interrupts whose number is not known until they can be serviced, just like hardware interrupts on a real CPU). [NTVDM] Improve the PIC emulation code (IRQ priorities, etc...). Instead of checking for interrupts in the main loop, move the PS/2 input parsing to a different thread. Improve BIOS keyboard IRQ handling. svn path=/branches/ntvdm/; revision=60761
This commit is contained in:
parent
fcbe98e6b6
commit
f5d3c9254c
11 changed files with 204 additions and 94 deletions
|
@ -145,6 +145,13 @@ typedef enum _FAST486_EXCEPTIONS
|
|||
FAST486_EXCEPTION_MC = 0x12
|
||||
} FAST486_EXCEPTIONS, *PFAST486_EXCEPTIONS;
|
||||
|
||||
typedef enum _FAST486_INT_STATUS
|
||||
{
|
||||
FAST486_INT_NONE = 0,
|
||||
FAST486_INT_EXECUTE = 1,
|
||||
FAST486_INT_SIGNAL = 2
|
||||
} FAST486_INT_STATUS, *PFAST486_INT_STATUS;
|
||||
|
||||
typedef
|
||||
BOOLEAN
|
||||
(NTAPI *FAST486_MEM_READ_PROC)
|
||||
|
@ -200,6 +207,13 @@ VOID
|
|||
USHORT BopCode
|
||||
);
|
||||
|
||||
typedef
|
||||
UCHAR
|
||||
(NTAPI *FAST486_INT_ACK_PROC)
|
||||
(
|
||||
PFAST486_STATE State
|
||||
);
|
||||
|
||||
typedef union _FAST486_REG
|
||||
{
|
||||
union
|
||||
|
@ -352,6 +366,7 @@ struct _FAST486_STATE
|
|||
FAST486_IO_WRITE_PROC IoWriteCallback;
|
||||
FAST486_IDLE_PROC IdleCallback;
|
||||
FAST486_BOP_PROC BopCallback;
|
||||
FAST486_INT_ACK_PROC IntAckCallback;
|
||||
FAST486_REG GeneralRegs[FAST486_NUM_GEN_REGS];
|
||||
FAST486_SEG_REG SegmentRegs[FAST486_NUM_SEG_REGS];
|
||||
FAST486_REG InstPtr, SavedInstPtr;
|
||||
|
@ -362,7 +377,7 @@ struct _FAST486_STATE
|
|||
ULONG ExceptionCount;
|
||||
ULONG PrefixFlags;
|
||||
FAST486_SEG_REGS SegmentOverride;
|
||||
BOOLEAN HardwareInt;
|
||||
FAST486_INT_STATUS IntStatus;
|
||||
UCHAR PendingIntNum;
|
||||
};
|
||||
|
||||
|
@ -396,6 +411,10 @@ VOID
|
|||
NTAPI
|
||||
Fast486Interrupt(PFAST486_STATE State, UCHAR Number);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486InterruptSignal(PFAST486_STATE State);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486ExecuteAt(PFAST486_STATE State, USHORT Segment, ULONG Offset);
|
||||
|
|
|
@ -61,11 +61,23 @@ Fast486ExecutionControl(PFAST486_STATE State, INT Command)
|
|||
{
|
||||
State->SavedInstPtr = State->InstPtr;
|
||||
|
||||
/* Check if interrupts are enabled and there is an interrupt pending */
|
||||
if (State->Flags.If && State->HardwareInt)
|
||||
/*
|
||||
* Check if there is an interrupt to execute, or a hardware interrupt signal
|
||||
* while interrupts are enabled.
|
||||
*/
|
||||
if ((State->IntStatus == FAST486_INT_EXECUTE)
|
||||
|| (State->Flags.If
|
||||
&& (State->IntAckCallback != NULL)
|
||||
&& (State->IntStatus == FAST486_INT_SIGNAL)))
|
||||
{
|
||||
FAST486_IDT_ENTRY IdtEntry;
|
||||
|
||||
if (State->IntStatus == FAST486_INT_SIGNAL)
|
||||
{
|
||||
/* Acknowledge the interrupt to get the number */
|
||||
State->PendingIntNum = State->IntAckCallback(State);
|
||||
}
|
||||
|
||||
/* Get the interrupt vector */
|
||||
if (Fast486GetIntVector(State, State->PendingIntNum, &IdtEntry))
|
||||
{
|
||||
|
@ -76,8 +88,8 @@ Fast486ExecutionControl(PFAST486_STATE State, INT Command)
|
|||
IdtEntry.Type);
|
||||
}
|
||||
|
||||
/* Clear the interrupt pending flag */
|
||||
State->HardwareInt = FALSE;
|
||||
/* Clear the interrupt status */
|
||||
State->IntStatus = FAST486_INT_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,6 +255,7 @@ Fast486Reset(PFAST486_STATE State)
|
|||
FAST486_IO_WRITE_PROC IoWriteCallback = State->IoWriteCallback;
|
||||
FAST486_IDLE_PROC IdleCallback = State->IdleCallback;
|
||||
FAST486_BOP_PROC BopCallback = State->BopCallback;
|
||||
FAST486_INT_ACK_PROC IntAckCallback = State->IntAckCallback;
|
||||
|
||||
/* Clear the entire structure */
|
||||
RtlZeroMemory(State, sizeof(*State));
|
||||
|
@ -278,17 +291,26 @@ Fast486Reset(PFAST486_STATE State)
|
|||
State->IoWriteCallback = IoWriteCallback;
|
||||
State->IdleCallback = IdleCallback;
|
||||
State->BopCallback = BopCallback;
|
||||
State->IntAckCallback = IntAckCallback;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486Interrupt(PFAST486_STATE State, UCHAR Number)
|
||||
{
|
||||
/* Set the hardware interrupt flag */
|
||||
State->HardwareInt = TRUE;
|
||||
/* Set the interrupt status and the number */
|
||||
State->IntStatus = FAST486_INT_EXECUTE;
|
||||
State->PendingIntNum = Number;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486InterruptSignal(PFAST486_STATE State)
|
||||
{
|
||||
/* Set the interrupt status */
|
||||
State->IntStatus = FAST486_INT_SIGNAL;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486ExecuteAt(PFAST486_STATE State, USHORT Segment, ULONG Offset)
|
||||
|
|
|
@ -876,7 +876,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeHalt)
|
|||
}
|
||||
|
||||
/* Halt */
|
||||
while (!State->HardwareInt) State->IdleCallback(State);
|
||||
while (State->IntStatus != FAST486_INT_SIGNAL) State->IdleCallback(State);
|
||||
|
||||
/* Return success */
|
||||
return TRUE;
|
||||
|
|
|
@ -1092,39 +1092,40 @@ VOID BiosHandleIrq(BYTE IrqNumber, LPWORD Stack)
|
|||
BYTE ScanCode, VirtualKey;
|
||||
WORD Character;
|
||||
|
||||
/* Check if there is a scancode available */
|
||||
if (!(KeyboardReadStatus() & 1)) break;
|
||||
|
||||
/* Get the scan code and virtual key code */
|
||||
ScanCode = KeyboardReadData();
|
||||
VirtualKey = MapVirtualKey(ScanCode & 0x7F, MAPVK_VSC_TO_VK);
|
||||
|
||||
/* Check if this is a key press or release */
|
||||
if (!(ScanCode & (1 << 7)))
|
||||
/* Loop while there is a scancode available */
|
||||
while (KeyboardReadStatus() & 1)
|
||||
{
|
||||
/* Key press */
|
||||
if (VirtualKey == VK_NUMLOCK
|
||||
|| VirtualKey == VK_CAPITAL
|
||||
|| VirtualKey == VK_SCROLL)
|
||||
{
|
||||
/* For toggle keys, toggle the lowest bit in the keyboard map */
|
||||
BiosKeyboardMap[VirtualKey] ^= ~(1 << 0);
|
||||
}
|
||||
/* Get the scan code and virtual key code */
|
||||
ScanCode = KeyboardReadData();
|
||||
VirtualKey = MapVirtualKey(ScanCode & 0x7F, MAPVK_VSC_TO_VK);
|
||||
|
||||
/* Set the highest bit */
|
||||
BiosKeyboardMap[VirtualKey] |= (1 << 7);
|
||||
|
||||
/* Find out which character this is */
|
||||
if (ToAscii(VirtualKey, ScanCode, BiosKeyboardMap, &Character, 0) > 0)
|
||||
/* Check if this is a key press or release */
|
||||
if (!(ScanCode & (1 << 7)))
|
||||
{
|
||||
/* Push it onto the BIOS keyboard queue */
|
||||
BiosKbdBufferPush((ScanCode << 8) | (Character & 0xFF));
|
||||
/* Key press */
|
||||
if (VirtualKey == VK_NUMLOCK
|
||||
|| VirtualKey == VK_CAPITAL
|
||||
|| VirtualKey == VK_SCROLL)
|
||||
{
|
||||
/* For toggle keys, toggle the lowest bit in the keyboard map */
|
||||
BiosKeyboardMap[VirtualKey] ^= ~(1 << 0);
|
||||
}
|
||||
|
||||
/* Set the highest bit */
|
||||
BiosKeyboardMap[VirtualKey] |= (1 << 7);
|
||||
|
||||
/* Find out which character this is */
|
||||
if (ToAscii(VirtualKey, ScanCode, BiosKeyboardMap, &Character, 0) > 0)
|
||||
{
|
||||
/* Push it onto the BIOS keyboard queue */
|
||||
BiosKbdBufferPush((ScanCode << 8) | (Character & 0xFF));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Key release, unset the highest bit */
|
||||
BiosKeyboardMap[VirtualKey] &= ~(1 << 7);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Key release, unset the highest bit */
|
||||
BiosKeyboardMap[VirtualKey] &= ~(1 << 7);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
@ -329,6 +329,14 @@ static VOID WINAPI EmulatorBiosOperation(PFAST486_STATE State, WORD Code)
|
|||
}
|
||||
}
|
||||
|
||||
static BYTE WINAPI EmulatorIntAcknowledge(PFAST486_STATE State)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(State);
|
||||
|
||||
/* Get the interrupt number from the PIC */
|
||||
return PicGetInterrupt();
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
BOOLEAN EmulatorInitialize()
|
||||
|
@ -342,7 +350,8 @@ BOOLEAN EmulatorInitialize()
|
|||
EmulatorContext.MemWriteCallback = (FAST486_MEM_WRITE_PROC)EmulatorWriteMemory;
|
||||
EmulatorContext.IoReadCallback = (FAST486_IO_READ_PROC)EmulatorReadIo;
|
||||
EmulatorContext.IoWriteCallback = (FAST486_IO_WRITE_PROC)EmulatorWriteIo;
|
||||
EmulatorContext.BopCallback = (FAST486_BOP_PROC)EmulatorBiosOperation;
|
||||
EmulatorContext.BopCallback = EmulatorBiosOperation;
|
||||
EmulatorContext.IntAckCallback = EmulatorIntAcknowledge;
|
||||
|
||||
/* Reset the CPU */
|
||||
Fast486Reset(&EmulatorContext);
|
||||
|
@ -371,10 +380,10 @@ VOID EmulatorInterrupt(BYTE Number)
|
|||
Fast486Interrupt(&EmulatorContext, Number);
|
||||
}
|
||||
|
||||
VOID EmulatorExternalInterrupt(BYTE Number)
|
||||
VOID EmulatorInterruptSignal(VOID)
|
||||
{
|
||||
/* Call the Fast486 API */
|
||||
Fast486Interrupt(&EmulatorContext, Number);
|
||||
Fast486InterruptSignal(&EmulatorContext);
|
||||
}
|
||||
|
||||
ULONG EmulatorGetRegister(ULONG Register)
|
||||
|
|
|
@ -88,7 +88,7 @@ BOOLEAN EmulatorInitialize();
|
|||
VOID EmulatorSetStack(WORD Segment, DWORD Offset);
|
||||
VOID EmulatorExecute(WORD Segment, WORD Offset);
|
||||
VOID EmulatorInterrupt(BYTE Number);
|
||||
VOID EmulatorExternalInterrupt(BYTE Number);
|
||||
VOID EmulatorInterruptSignal(VOID);
|
||||
ULONG EmulatorGetRegister(ULONG Register);
|
||||
ULONG EmulatorGetProgramCounter(VOID);
|
||||
VOID EmulatorSetRegister(ULONG Register, ULONG Value);
|
||||
|
|
|
@ -79,12 +79,12 @@ INT wmain(INT argc, WCHAR *argv[])
|
|||
INT i;
|
||||
CHAR CommandLine[DOS_CMDLINE_LENGTH];
|
||||
DWORD CurrentTickCount;
|
||||
DWORD LastTickCount = GetTickCount();
|
||||
DWORD Cycles = 0;
|
||||
DWORD LastCyclePrintout = GetTickCount();
|
||||
DWORD LastVerticalRefresh = GetTickCount();
|
||||
LARGE_INTEGER Frequency, LastTimerTick, Counter;
|
||||
LONGLONG TimerTicks;
|
||||
HANDLE InputThread = NULL;
|
||||
|
||||
/* Set the handler routine */
|
||||
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
|
||||
|
@ -141,6 +141,9 @@ INT wmain(INT argc, WCHAR *argv[])
|
|||
DisplayMessage(L"Could not start program: %S", CommandLine);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Start the input thread */
|
||||
InputThread = CreateThread(NULL, 0, &InputThreadProc, NULL, 0, NULL);
|
||||
|
||||
/* Set the last timer tick to the current time */
|
||||
QueryPerformanceCounter(&LastTimerTick);
|
||||
|
@ -162,13 +165,6 @@ INT wmain(INT argc, WCHAR *argv[])
|
|||
for (i = 0; i < TimerTicks; i++) PitDecrementCount();
|
||||
LastTimerTick = Counter;
|
||||
|
||||
/* Check for console input events every millisecond */
|
||||
if (CurrentTickCount != LastTickCount)
|
||||
{
|
||||
CheckForInputEvents();
|
||||
LastTickCount = CurrentTickCount;
|
||||
}
|
||||
|
||||
/* Check for vertical retrace */
|
||||
if ((CurrentTickCount - LastVerticalRefresh) >= 16)
|
||||
{
|
||||
|
@ -198,6 +194,7 @@ INT wmain(INT argc, WCHAR *argv[])
|
|||
VgaRefreshDisplay();
|
||||
|
||||
Cleanup:
|
||||
if (InputThread != NULL) CloseHandle(InputThread);
|
||||
BiosCleanup();
|
||||
EmulatorCleanup();
|
||||
|
||||
|
|
|
@ -35,8 +35,8 @@ BYTE PicReadCommand(BYTE Port)
|
|||
}
|
||||
else
|
||||
{
|
||||
/* The IRR is always 0, as the emulated CPU receives the interrupt instantly */
|
||||
return 0;
|
||||
/* Read the interrupt request register */
|
||||
return Pic->IntRequestRegister;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,9 +167,9 @@ VOID PicInterruptRequest(BYTE Number)
|
|||
/* Check if the interrupt is masked */
|
||||
if (MasterPic.MaskRegister & (1 << Number)) return;
|
||||
|
||||
/* Set the appropriate bit in the ISR and interrupt the CPU */
|
||||
if (!MasterPic.AutoEoi) MasterPic.InServiceRegister |= 1 << Number;
|
||||
EmulatorExternalInterrupt(MasterPic.IntOffset + Number);
|
||||
/* Set the appropriate bit in the IRR and interrupt the CPU */
|
||||
MasterPic.IntRequestRegister |= 1 << Number;
|
||||
EmulatorInterruptSignal();
|
||||
}
|
||||
else if (Number >= 8 && Number < 16)
|
||||
{
|
||||
|
@ -187,7 +187,7 @@ VOID PicInterruptRequest(BYTE Number)
|
|||
|
||||
/* Check if any of the higher-priorirty interrupts are busy */
|
||||
if (MasterPic.InServiceRegister != 0) return;
|
||||
for (i = 0; i <= Number ; i++)
|
||||
for (i = 0; i <= Number; i++)
|
||||
{
|
||||
if (SlavePic.InServiceRegister & (1 << Number)) return;
|
||||
}
|
||||
|
@ -196,12 +196,57 @@ VOID PicInterruptRequest(BYTE Number)
|
|||
if (SlavePic.MaskRegister & (1 << Number)) return;
|
||||
|
||||
/* Set the IRQ 2 bit in the master ISR */
|
||||
if (!MasterPic.AutoEoi) MasterPic.InServiceRegister |= 1 << 2;
|
||||
if (!MasterPic.AutoEoi) MasterPic.InServiceRegister |= (1 << 2);
|
||||
|
||||
/* Set the appropriate bit in the ISR and interrupt the CPU */
|
||||
if (!SlavePic.AutoEoi) SlavePic.InServiceRegister |= 1 << Number;
|
||||
EmulatorExternalInterrupt(SlavePic.IntOffset + Number);
|
||||
/* Set the appropriate bit in the IRR and interrupt the CPU */
|
||||
SlavePic.IntRequestRegister |= 1 << Number;
|
||||
EmulatorInterruptSignal();
|
||||
}
|
||||
}
|
||||
|
||||
BYTE PicGetInterrupt(VOID)
|
||||
{
|
||||
INT i, j;
|
||||
|
||||
/* Search interrupts by priority */
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
/* Check if this line is cascaded to the slave PIC */
|
||||
if ((i == 2)
|
||||
&& MasterPic.CascadeRegister & (1 << 2)
|
||||
&& SlavePic.Slave
|
||||
&& (SlavePic.CascadeRegister == 2))
|
||||
{
|
||||
/* Search the slave PIC interrupts by priority */
|
||||
for (j = 0; j < 8; j++) if ((j != 1) && SlavePic.IntRequestRegister & (1 << j))
|
||||
{
|
||||
/* Clear the IRR flag */
|
||||
SlavePic.IntRequestRegister &= ~(1 << j);
|
||||
|
||||
/* Set the ISR flag, unless AEOI is enabled */
|
||||
if (!SlavePic.AutoEoi) SlavePic.InServiceRegister |= (1 << j);
|
||||
|
||||
/* Return the interrupt number */
|
||||
return SlavePic.IntOffset + j;
|
||||
}
|
||||
}
|
||||
|
||||
if (MasterPic.IntRequestRegister & (1 << i))
|
||||
{
|
||||
/* Clear the IRR flag */
|
||||
MasterPic.IntRequestRegister &= ~(1 << i);
|
||||
|
||||
/* Set the ISR flag, unless AEOI is enabled */
|
||||
if (!MasterPic.AutoEoi) MasterPic.InServiceRegister |= (1 << i);
|
||||
|
||||
/* Return the interrupt number */
|
||||
return MasterPic.IntOffset + i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Spurious interrupt */
|
||||
if (MasterPic.InServiceRegister & (1 << 2)) return SlavePic.IntOffset + 7;
|
||||
else return MasterPic.IntOffset + 7;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -34,6 +34,7 @@ typedef struct _PIC
|
|||
{
|
||||
BOOLEAN Initialization;
|
||||
BYTE MaskRegister;
|
||||
BYTE IntRequestRegister;
|
||||
BYTE InServiceRegister;
|
||||
BYTE IntOffset;
|
||||
BYTE ConfigRegister;
|
||||
|
@ -51,6 +52,7 @@ VOID PicWriteCommand(BYTE Port, BYTE Value);
|
|||
BYTE PicReadData(BYTE Port);
|
||||
VOID PicWriteData(BYTE Port, BYTE Value);
|
||||
VOID PicInterruptRequest(BYTE Number);
|
||||
BYTE PicGetInterrupt(VOID);
|
||||
|
||||
#endif // _PIC_H_
|
||||
|
||||
|
|
|
@ -265,49 +265,64 @@ VOID KeyboardWriteData(BYTE Data)
|
|||
// TODO: Implement PS/2 device commands
|
||||
}
|
||||
|
||||
VOID CheckForInputEvents()
|
||||
DWORD WINAPI InputThreadProc(LPVOID Parameter)
|
||||
{
|
||||
PINPUT_RECORD Buffer;
|
||||
INT i;
|
||||
HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||
DWORD i, j, Count, TotalEvents;
|
||||
BYTE ScanCode;
|
||||
BOOLEAN Interrupt = FALSE;
|
||||
INPUT_RECORD InputRecord;
|
||||
DWORD Count;
|
||||
|
||||
/* Get the number of input events */
|
||||
if (!GetNumberOfConsoleInputEvents(ConsoleInput, &Count)) return;
|
||||
if (Count == 0) return;
|
||||
|
||||
/* Allocate the buffer */
|
||||
Buffer = (PINPUT_RECORD)HeapAlloc(GetProcessHeap(), 0, Count * sizeof(INPUT_RECORD));
|
||||
if (Buffer == NULL) return;
|
||||
|
||||
/* Peek the input events */
|
||||
if (!ReadConsoleInput(ConsoleInput, Buffer, Count, &TotalEvents)) goto Cleanup;
|
||||
|
||||
for (i = 0; i < TotalEvents; i++)
|
||||
while (VdmRunning)
|
||||
{
|
||||
/* Check if this is a key event */
|
||||
if (Buffer[i].EventType != KEY_EVENT) continue;
|
||||
|
||||
/* Get the scan code */
|
||||
ScanCode = (BYTE)Buffer[i].Event.KeyEvent.wVirtualScanCode;
|
||||
|
||||
/* If this is a key release, set the highest bit in the scan code */
|
||||
if (!Buffer[i].Event.KeyEvent.bKeyDown) ScanCode |= 0x80;
|
||||
|
||||
/* Push the scan code onto the keyboard queue */
|
||||
for (j = 0; j < Buffer[i].Event.KeyEvent.wRepeatCount; j++)
|
||||
/* Wait for an input record */
|
||||
if (!ReadConsoleInput(ConsoleInput, &InputRecord, 1, &Count))
|
||||
{
|
||||
KeyboardQueuePush(ScanCode);
|
||||
DPRINT1("Error reading console input\n");
|
||||
return GetLastError();
|
||||
|
||||
}
|
||||
|
||||
Interrupt = TRUE;
|
||||
ASSERT(Count != 0);
|
||||
|
||||
/* Check the event type */
|
||||
switch (InputRecord.EventType)
|
||||
{
|
||||
case KEY_EVENT:
|
||||
{
|
||||
BYTE ScanCode = (BYTE)InputRecord.Event.KeyEvent.wVirtualScanCode;
|
||||
|
||||
/* If this is a key release, set the highest bit in the scan code */
|
||||
if (!InputRecord.Event.KeyEvent.bKeyDown) ScanCode |= 0x80;
|
||||
|
||||
/* Push the scan code onto the keyboard queue */
|
||||
for (i = 0; i < InputRecord.Event.KeyEvent.wRepeatCount; i++)
|
||||
{
|
||||
KeyboardQueuePush(ScanCode);
|
||||
}
|
||||
|
||||
/* Keyboard IRQ */
|
||||
PicInterruptRequest(1);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MOUSE_EVENT:
|
||||
{
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
/* Ignored */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Interrupt) PicInterruptRequest(1);
|
||||
|
||||
Cleanup:
|
||||
HeapFree(GetProcessHeap(), 0, Buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -28,7 +28,7 @@ BYTE KeyboardReadStatus();
|
|||
VOID KeyboardWriteCommand(BYTE Command);
|
||||
BYTE KeyboardReadData();
|
||||
VOID KeyboardWriteData(BYTE Data);
|
||||
VOID CheckForInputEvents();
|
||||
DWORD WINAPI InputThreadProc(LPVOID Parameter);
|
||||
|
||||
#endif // _PS2_H_
|
||||
|
||||
|
|
Loading…
Reference in a new issue