diff --git a/subsystems/ntvdm/bios.c b/subsystems/ntvdm/bios.c index 25294bcae23..9670caf6824 100644 --- a/subsystems/ntvdm/bios.c +++ b/subsystems/ntvdm/bios.c @@ -1429,47 +1429,42 @@ VOID BiosHandleIrq(BYTE IrqNumber, LPWORD Stack) BYTE ScanCode, VirtualKey; WORD Character; - /* Loop while there is a scancode available */ - do + /* Get the scan code and virtual key code */ + ScanCode = PS2ReadPort(PS2_DATA_PORT); + VirtualKey = MapVirtualKey(ScanCode & 0x7F, MAPVK_VSC_TO_VK); + + /* Check if this is a key press or release */ + if (!(ScanCode & (1 << 7))) { - /* 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))) + /* Key press */ + if (VirtualKey == VK_NUMLOCK || + VirtualKey == VK_CAPITAL || + VirtualKey == VK_SCROLL || + VirtualKey == VK_INSERT) { - /* Key press */ - if (VirtualKey == VK_NUMLOCK || - VirtualKey == VK_CAPITAL || - VirtualKey == VK_SCROLL || - VirtualKey == VK_INSERT) - { - /* For toggle keys, toggle the lowest bit in the keyboard map */ - BiosKeyboardMap[VirtualKey] ^= ~(1 << 0); - } + /* For toggle keys, toggle the lowest bit in the keyboard map */ + BiosKeyboardMap[VirtualKey] ^= ~(1 << 0); + } - /* Set the highest bit */ - BiosKeyboardMap[VirtualKey] |= (1 << 7); + /* Set the highest bit */ + BiosKeyboardMap[VirtualKey] |= (1 << 7); - /* Find out which character this is */ + /* Find out which character this is */ + Character = 0; + if (ToAscii(VirtualKey, ScanCode, BiosKeyboardMap, &Character, 0) == 0) + { + /* Not ASCII */ Character = 0; - if (ToAscii(VirtualKey, ScanCode, BiosKeyboardMap, &Character, 0) == 0) - { - /* Not ASCII */ - Character = 0; - } + } - /* Push it onto the BIOS keyboard queue */ - BiosKbdBufferPush(MAKEWORD(Character, ScanCode)); - } - else - { - /* Key release, unset the highest bit */ - BiosKeyboardMap[VirtualKey] &= ~(1 << 7); - } + /* Push it onto the BIOS keyboard queue */ + BiosKbdBufferPush(MAKEWORD(Character, ScanCode)); + } + else + { + /* Key release, unset the highest bit */ + BiosKeyboardMap[VirtualKey] &= ~(1 << 7); } - while (KeyboardReadStatus() & 1); /* Clear the keyboard flags */ Bda->KeybdShiftFlags = 0; diff --git a/subsystems/ntvdm/ntvdm.c b/subsystems/ntvdm/ntvdm.c index fb8e738651f..4c0df1485e1 100644 --- a/subsystems/ntvdm/ntvdm.c +++ b/subsystems/ntvdm/ntvdm.c @@ -78,6 +78,7 @@ INT wmain(INT argc, WCHAR *argv[]) DWORD LastVerticalRefresh; DWORD LastCyclePrintout; DWORD Cycles = 0; + INT KeyboardIntCounter = 0; /* Set the handler routine */ SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE); @@ -227,6 +228,13 @@ INT wmain(INT argc, WCHAR *argv[]) LastVerticalRefresh = CurrentTickCount; } + KeyboardIntCounter++; + if (KeyboardIntCounter == KBD_INT_CYCLES) + { + GenerateKeyboardInterrupts(); + KeyboardIntCounter = 0; + } + /* Horizontal retrace occurs as fast as possible */ VgaHorizontalRetrace(); diff --git a/subsystems/ntvdm/ntvdm.h b/subsystems/ntvdm/ntvdm.h index c057413e4ce..96fe0f8f3b9 100644 --- a/subsystems/ntvdm/ntvdm.h +++ b/subsystems/ntvdm/ntvdm.h @@ -45,6 +45,7 @@ /* Processor speed */ #define STEPS_PER_CYCLE 256 +#define KBD_INT_CYCLES 16 /* FUNCTIONS ******************************************************************/ diff --git a/subsystems/ntvdm/ps2.c b/subsystems/ntvdm/ps2.c index 5138d0b887c..d2f9997bede 100644 --- a/subsystems/ntvdm/ps2.c +++ b/subsystems/ntvdm/ps2.c @@ -25,24 +25,17 @@ static BYTE KeyboardData = 0, KeyboardResponse = 0; static BOOLEAN KeyboardReadResponse = FALSE, KeyboardWriteResponse = FALSE; static BYTE KeyboardConfig = PS2_DEFAULT_CONFIG; static HANDLE QueueMutex = NULL; - static HANDLE InputThread = NULL; /* PRIVATE FUNCTIONS **********************************************************/ static BOOLEAN KeyboardQueuePush(BYTE ScanCode) { - BOOLEAN Result = TRUE; + /* Check if the keyboard queue is full */ + if (!KeyboardQueueEmpty && (KeyboardQueueStart == KeyboardQueueEnd)) return FALSE; WaitForSingleObject(QueueMutex, INFINITE); - /* Check if the keyboard queue is full */ - if (!KeyboardQueueEmpty && (KeyboardQueueStart == KeyboardQueueEnd)) - { - Result = FALSE; - goto Done; - } - /* Insert the value in the queue */ KeyboardQueue[KeyboardQueueEnd] = ScanCode; KeyboardQueueEnd++; @@ -51,24 +44,17 @@ static BOOLEAN KeyboardQueuePush(BYTE ScanCode) /* Since we inserted a value, it's not empty anymore */ KeyboardQueueEmpty = FALSE; -Done: ReleaseMutex(QueueMutex); - return Result; + return TRUE; } static BOOLEAN KeyboardQueuePop(BYTE *ScanCode) { - BOOLEAN Result = TRUE; + /* Make sure the keyboard queue is not empty */ + if (KeyboardQueueEmpty) return FALSE; WaitForSingleObject(QueueMutex, INFINITE); - /* Make sure the keyboard queue is not empty */ - if (KeyboardQueueEmpty) - { - Result = FALSE; - goto Done; - } - /* Get the scan code */ *ScanCode = KeyboardQueue[KeyboardQueueStart]; @@ -82,222 +68,208 @@ static BOOLEAN KeyboardQueuePop(BYTE *ScanCode) KeyboardQueueEmpty = TRUE; } -Done: ReleaseMutex(QueueMutex); - return Result; + return TRUE; } /* PUBLIC FUNCTIONS ***********************************************************/ -BYTE KeyboardReadStatus() -{ - BYTE Status = 0; - - WaitForSingleObject(QueueMutex, INFINITE); - - /* Set the first bit if the data can be read */ - if (KeyboardReadResponse || !KeyboardQueueEmpty) Status |= 1 << 0; - - ReleaseMutex(QueueMutex); - - /* Always set bit 2 */ - Status |= 1 << 2; - - /* Set bit 3 if the next byte goes to the controller */ - if (KeyboardWriteResponse) Status |= 1 << 3; - - return Status; -} - -VOID KeyboardWriteCommand(BYTE Command) -{ - switch (Command) - { - /* Read configuration byte */ - case 0x20: - { - KeyboardResponse = KeyboardConfig; - KeyboardReadResponse = TRUE; - break; - } - - /* Write configuration byte */ - case 0x60: - /* Write controller output port */ - case 0xD1: - /* Write keyboard output buffer */ - case 0xD2: - /* Write mouse output buffer */ - case 0xD3: - /* Write mouse input buffer */ - case 0xD4: - { - /* These commands require a response */ - KeyboardResponse = Command; - KeyboardWriteResponse = TRUE; - break; - } - - /* Disable mouse */ - case 0xA7: - { - // TODO: Mouse support - break; - } - - /* Enable mouse */ - case 0xA8: - { - // TODO: Mouse support - break; - } - - /* Test mouse port */ - case 0xA9: - { - KeyboardResponse = 0; - KeyboardReadResponse = TRUE; - break; - } - - /* Test PS/2 controller */ - case 0xAA: - { - KeyboardResponse = 0x55; - KeyboardReadResponse = TRUE; - break; - } - - /* Disable keyboard */ - case 0xAD: - { - // TODO: Not implemented - break; - } - - /* Enable keyboard */ - case 0xAE: - { - // TODO: Not implemented - break; - } - - /* Read controller output port */ - case 0xD0: - { - // TODO: Not implemented - break; - } - - /* CPU Reset */ - case 0xF0: - case 0xF2: - case 0xF4: - case 0xF6: - case 0xF8: - case 0xFA: - case 0xFC: - case 0xFE: - { - /* Stop the simulation */ - VdmRunning = FALSE; - break; - } - } -} - -BYTE KeyboardReadData() -{ - /* If there was a response byte from the controller, return it */ - if (KeyboardReadResponse) - { - KeyboardReadResponse = FALSE; - KeyboardData = KeyboardResponse; - } - else - { - /* Otherwise, read the data from the queue */ - KeyboardQueuePop(&KeyboardData); - } - - return KeyboardData; -} - -VOID KeyboardWriteData(BYTE Data) -{ - /* Check if the controller is waiting for a response */ - if (KeyboardWriteResponse) - { - KeyboardWriteResponse = FALSE; - - /* Check which command it was */ - switch (KeyboardResponse) - { - /* Write configuration byte */ - case 0x60: - { - KeyboardConfig = Data; - break; - } - - /* Write controller output */ - case 0xD1: - { - /* Check if bit 0 is unset */ - if (!(Data & (1 << 0))) - { - /* CPU disabled - end simulation */ - VdmRunning = FALSE; - } - - /* Update the A20 line setting */ - EmulatorSetA20(Data & (1 << 1)); - - break; - } - - case 0xD2: - { - /* Push the data byte to the keyboard queue */ - KeyboardQueuePush(Data); - break; - } - - case 0xD3: - { - // TODO: Mouse support - break; - } - - case 0xD4: - { - // TODO: Mouse support - break; - } - } - - return; - } - - // TODO: Implement PS/2 device commands -} - BYTE WINAPI PS2ReadPort(ULONG Port) { if (Port == PS2_CONTROL_PORT) - return KeyboardReadStatus(); + { + BYTE Status = 0; + + /* Set the first bit if the data can be read */ + if (KeyboardReadResponse || !KeyboardQueueEmpty) Status |= 1 << 0; + + /* Always set bit 2 */ + Status |= 1 << 2; + + /* Set bit 3 if the next byte goes to the controller */ + if (KeyboardWriteResponse) Status |= 1 << 3; + + return Status; + } else if (Port == PS2_DATA_PORT) - return KeyboardReadData(); - else - return 0; + { + /* If there was a response byte from the controller, return it */ + if (KeyboardReadResponse) + { + KeyboardReadResponse = FALSE; + KeyboardData = KeyboardResponse; + } + + return KeyboardData; + } + else return 0; } VOID WINAPI PS2WritePort(ULONG Port, BYTE Data) { if (Port == PS2_CONTROL_PORT) - KeyboardWriteCommand(Data); + { + switch (Data) + { + /* Read configuration byte */ + case 0x20: + { + KeyboardResponse = KeyboardConfig; + KeyboardReadResponse = TRUE; + break; + } + + /* Write configuration byte */ + case 0x60: + /* Write controller output port */ + case 0xD1: + /* Write keyboard output buffer */ + case 0xD2: + /* Write mouse output buffer */ + case 0xD3: + /* Write mouse input buffer */ + case 0xD4: + { + /* These commands require a response */ + KeyboardResponse = Data; + KeyboardWriteResponse = TRUE; + break; + } + + /* Disable mouse */ + case 0xA7: + { + // TODO: Mouse support + break; + } + + /* Enable mouse */ + case 0xA8: + { + // TODO: Mouse support + break; + } + + /* Test mouse port */ + case 0xA9: + { + KeyboardResponse = 0; + KeyboardReadResponse = TRUE; + break; + } + + /* Test PS/2 controller */ + case 0xAA: + { + KeyboardResponse = 0x55; + KeyboardReadResponse = TRUE; + break; + } + + /* Disable keyboard */ + case 0xAD: + { + // TODO: Not implemented + break; + } + + /* Enable keyboard */ + case 0xAE: + { + // TODO: Not implemented + break; + } + + /* Read controller output port */ + case 0xD0: + { + // TODO: Not implemented + break; + } + + /* CPU Reset */ + case 0xF0: + case 0xF2: + case 0xF4: + case 0xF6: + case 0xF8: + case 0xFA: + case 0xFC: + case 0xFE: + { + /* Stop the simulation */ + VdmRunning = FALSE; + break; + } + } + } else if (Port == PS2_DATA_PORT) - KeyboardWriteData(Data); + { + /* Check if the controller is waiting for a response */ + if (KeyboardWriteResponse) + { + KeyboardWriteResponse = FALSE; + + /* Check which command it was */ + switch (KeyboardResponse) + { + /* Write configuration byte */ + case 0x60: + { + KeyboardConfig = Data; + break; + } + + /* Write controller output */ + case 0xD1: + { + /* Check if bit 0 is unset */ + if (!(Data & (1 << 0))) + { + /* CPU disabled - end simulation */ + VdmRunning = FALSE; + } + + /* Update the A20 line setting */ + EmulatorSetA20(Data & (1 << 1)); + + break; + } + + case 0xD2: + { + /* Push the data byte to the keyboard queue */ + KeyboardQueuePush(Data); + break; + } + + case 0xD3: + { + // TODO: Mouse support + break; + } + + case 0xD4: + { + // TODO: Mouse support + break; + } + } + + return; + } + + // TODO: Implement PS/2 device commands + } +} + +VOID GenerateKeyboardInterrupts(VOID) +{ + if (KeyboardQueuePop(&KeyboardData)) + { + /* IRQ 1 */ + PicInterruptRequest(1); + } } DWORD WINAPI InputThreadProc(LPVOID Parameter) @@ -335,8 +307,6 @@ DWORD WINAPI InputThreadProc(LPVOID Parameter) KeyboardQueuePush(ScanCode); } - /* Keyboard IRQ */ - PicInterruptRequest(1); break; } diff --git a/subsystems/ntvdm/ps2.h b/subsystems/ntvdm/ps2.h index e152e2bd510..5d887d51e04 100644 --- a/subsystems/ntvdm/ps2.h +++ b/subsystems/ntvdm/ps2.h @@ -24,13 +24,11 @@ /* FUNCTIONS ******************************************************************/ -BYTE KeyboardReadStatus(); -//VOID KeyboardWriteCommand(BYTE Command); -BYTE KeyboardReadData(); -//VOID KeyboardWriteData(BYTE Data); - BOOLEAN PS2Initialize(HANDLE ConsoleInput); VOID PS2Cleanup(VOID); +BYTE WINAPI PS2ReadPort(ULONG Port); +VOID WINAPI PS2WritePort(ULONG Port, BYTE Data); +VOID GenerateKeyboardInterrupts(VOID); #endif // _PS2_H_