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,11 +1429,8 @@ VOID BiosHandleIrq(BYTE IrqNumber, LPWORD Stack)
BYTE ScanCode, VirtualKey; BYTE ScanCode, VirtualKey;
WORD Character; WORD Character;
/* Loop while there is a scancode available */
do
{
/* Get the scan code and virtual key code */ /* Get the scan code and virtual key code */
ScanCode = KeyboardReadData(); ScanCode = PS2ReadPort(PS2_DATA_PORT);
VirtualKey = MapVirtualKey(ScanCode & 0x7F, MAPVK_VSC_TO_VK); VirtualKey = MapVirtualKey(ScanCode & 0x7F, MAPVK_VSC_TO_VK);
/* Check if this is a key press or release */ /* Check if this is a key press or release */
@ -1468,8 +1465,6 @@ VOID BiosHandleIrq(BYTE IrqNumber, LPWORD Stack)
/* Key release, unset the highest bit */ /* Key release, unset the highest bit */
BiosKeyboardMap[VirtualKey] &= ~(1 << 7); BiosKeyboardMap[VirtualKey] &= ~(1 << 7);
} }
}
while (KeyboardReadStatus() & 1);
/* Clear the keyboard flags */ /* Clear the keyboard flags */
Bda->KeybdShiftFlags = 0; Bda->KeybdShiftFlags = 0;

View file

@ -78,6 +78,7 @@ INT wmain(INT argc, WCHAR *argv[])
DWORD LastVerticalRefresh; DWORD LastVerticalRefresh;
DWORD LastCyclePrintout; DWORD LastCyclePrintout;
DWORD Cycles = 0; DWORD Cycles = 0;
INT KeyboardIntCounter = 0;
/* Set the handler routine */ /* Set the handler routine */
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE); SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
@ -227,6 +228,13 @@ INT wmain(INT argc, WCHAR *argv[])
LastVerticalRefresh = CurrentTickCount; LastVerticalRefresh = CurrentTickCount;
} }
KeyboardIntCounter++;
if (KeyboardIntCounter == KBD_INT_CYCLES)
{
GenerateKeyboardInterrupts();
KeyboardIntCounter = 0;
}
/* Horizontal retrace occurs as fast as possible */ /* Horizontal retrace occurs as fast as possible */
VgaHorizontalRetrace(); VgaHorizontalRetrace();

View file

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

View file

@ -25,24 +25,17 @@ static BYTE KeyboardData = 0, KeyboardResponse = 0;
static BOOLEAN KeyboardReadResponse = FALSE, KeyboardWriteResponse = FALSE; static BOOLEAN KeyboardReadResponse = FALSE, KeyboardWriteResponse = FALSE;
static BYTE KeyboardConfig = PS2_DEFAULT_CONFIG; static BYTE KeyboardConfig = PS2_DEFAULT_CONFIG;
static HANDLE QueueMutex = NULL; static HANDLE QueueMutex = NULL;
static HANDLE InputThread = NULL; static HANDLE InputThread = NULL;
/* PRIVATE FUNCTIONS **********************************************************/ /* PRIVATE FUNCTIONS **********************************************************/
static BOOLEAN KeyboardQueuePush(BYTE ScanCode) static BOOLEAN KeyboardQueuePush(BYTE ScanCode)
{ {
BOOLEAN Result = TRUE; /* Check if the keyboard queue is full */
if (!KeyboardQueueEmpty && (KeyboardQueueStart == KeyboardQueueEnd)) return FALSE;
WaitForSingleObject(QueueMutex, INFINITE); WaitForSingleObject(QueueMutex, INFINITE);
/* Check if the keyboard queue is full */
if (!KeyboardQueueEmpty && (KeyboardQueueStart == KeyboardQueueEnd))
{
Result = FALSE;
goto Done;
}
/* Insert the value in the queue */ /* Insert the value in the queue */
KeyboardQueue[KeyboardQueueEnd] = ScanCode; KeyboardQueue[KeyboardQueueEnd] = ScanCode;
KeyboardQueueEnd++; KeyboardQueueEnd++;
@ -51,24 +44,17 @@ static BOOLEAN KeyboardQueuePush(BYTE ScanCode)
/* Since we inserted a value, it's not empty anymore */ /* Since we inserted a value, it's not empty anymore */
KeyboardQueueEmpty = FALSE; KeyboardQueueEmpty = FALSE;
Done:
ReleaseMutex(QueueMutex); ReleaseMutex(QueueMutex);
return Result; return TRUE;
} }
static BOOLEAN KeyboardQueuePop(BYTE *ScanCode) static BOOLEAN KeyboardQueuePop(BYTE *ScanCode)
{ {
BOOLEAN Result = TRUE; /* Make sure the keyboard queue is not empty */
if (KeyboardQueueEmpty) return FALSE;
WaitForSingleObject(QueueMutex, INFINITE); WaitForSingleObject(QueueMutex, INFINITE);
/* Make sure the keyboard queue is not empty */
if (KeyboardQueueEmpty)
{
Result = FALSE;
goto Done;
}
/* Get the scan code */ /* Get the scan code */
*ScanCode = KeyboardQueue[KeyboardQueueStart]; *ScanCode = KeyboardQueue[KeyboardQueueStart];
@ -82,24 +68,21 @@ static BOOLEAN KeyboardQueuePop(BYTE *ScanCode)
KeyboardQueueEmpty = TRUE; KeyboardQueueEmpty = TRUE;
} }
Done:
ReleaseMutex(QueueMutex); ReleaseMutex(QueueMutex);
return Result; return TRUE;
} }
/* PUBLIC FUNCTIONS ***********************************************************/ /* PUBLIC FUNCTIONS ***********************************************************/
BYTE KeyboardReadStatus() BYTE WINAPI PS2ReadPort(ULONG Port)
{
if (Port == PS2_CONTROL_PORT)
{ {
BYTE Status = 0; BYTE Status = 0;
WaitForSingleObject(QueueMutex, INFINITE);
/* Set the first bit if the data can be read */ /* Set the first bit if the data can be read */
if (KeyboardReadResponse || !KeyboardQueueEmpty) Status |= 1 << 0; if (KeyboardReadResponse || !KeyboardQueueEmpty) Status |= 1 << 0;
ReleaseMutex(QueueMutex);
/* Always set bit 2 */ /* Always set bit 2 */
Status |= 1 << 2; Status |= 1 << 2;
@ -108,10 +91,25 @@ BYTE KeyboardReadStatus()
return Status; return Status;
} }
else if (Port == PS2_DATA_PORT)
VOID KeyboardWriteCommand(BYTE Command)
{ {
switch (Command) /* 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)
{
switch (Data)
{ {
/* Read configuration byte */ /* Read configuration byte */
case 0x20: case 0x20:
@ -133,7 +131,7 @@ VOID KeyboardWriteCommand(BYTE Command)
case 0xD4: case 0xD4:
{ {
/* These commands require a response */ /* These commands require a response */
KeyboardResponse = Command; KeyboardResponse = Data;
KeyboardWriteResponse = TRUE; KeyboardWriteResponse = TRUE;
break; break;
} }
@ -205,25 +203,7 @@ VOID KeyboardWriteCommand(BYTE Command)
} }
} }
} }
else if (Port == PS2_DATA_PORT)
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 */ /* Check if the controller is waiting for a response */
if (KeyboardWriteResponse) if (KeyboardWriteResponse)
@ -281,23 +261,15 @@ VOID KeyboardWriteData(BYTE Data)
// TODO: Implement PS/2 device commands // TODO: Implement PS/2 device commands
} }
BYTE WINAPI PS2ReadPort(ULONG Port)
{
if (Port == PS2_CONTROL_PORT)
return KeyboardReadStatus();
else if (Port == PS2_DATA_PORT)
return KeyboardReadData();
else
return 0;
} }
VOID WINAPI PS2WritePort(ULONG Port, BYTE Data) VOID GenerateKeyboardInterrupts(VOID)
{ {
if (Port == PS2_CONTROL_PORT) if (KeyboardQueuePop(&KeyboardData))
KeyboardWriteCommand(Data); {
else if (Port == PS2_DATA_PORT) /* IRQ 1 */
KeyboardWriteData(Data); PicInterruptRequest(1);
}
} }
DWORD WINAPI InputThreadProc(LPVOID Parameter) DWORD WINAPI InputThreadProc(LPVOID Parameter)
@ -335,8 +307,6 @@ DWORD WINAPI InputThreadProc(LPVOID Parameter)
KeyboardQueuePush(ScanCode); KeyboardQueuePush(ScanCode);
} }
/* Keyboard IRQ */
PicInterruptRequest(1);
break; break;
} }

View file

@ -24,13 +24,11 @@
/* FUNCTIONS ******************************************************************/ /* FUNCTIONS ******************************************************************/
BYTE KeyboardReadStatus();
//VOID KeyboardWriteCommand(BYTE Command);
BYTE KeyboardReadData();
//VOID KeyboardWriteData(BYTE Data);
BOOLEAN PS2Initialize(HANDLE ConsoleInput); BOOLEAN PS2Initialize(HANDLE ConsoleInput);
VOID PS2Cleanup(VOID); VOID PS2Cleanup(VOID);
BYTE WINAPI PS2ReadPort(ULONG Port);
VOID WINAPI PS2WritePort(ULONG Port, BYTE Data);
VOID GenerateKeyboardInterrupts(VOID);
#endif // _PS2_H_ #endif // _PS2_H_