Improve the keyboard event handling.
Clean up the PS/2 code a bit.


svn path=/branches/ntvdm/; revision=61229
This commit is contained in:
Aleksandar Andrejevic 2013-12-06 04:35:58 +00:00
parent 6dde554aa8
commit 1b784a5b7b
5 changed files with 233 additions and 261 deletions

View file

@ -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;

View file

@ -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();

View file

@ -45,6 +45,7 @@
/* Processor speed */
#define STEPS_PER_CYCLE 256
#define KBD_INT_CYCLES 16
/* FUNCTIONS ******************************************************************/

View file

@ -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;
}

View file

@ -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_