Author: hbelusca Date: Thu Aug 13 19:34:16 2015 New Revision: 68710
URL: http://svn.reactos.org/svn/reactos?rev=68710&view=rev Log: [NTVDM] - When we have few R/W IO port handlers, just register them directly instead of using a wrap-up function. - Remove hardcoded bit flag values.
Modified: trunk/reactos/subsystems/mvdm/ntvdm/hardware/ps2.c trunk/reactos/subsystems/mvdm/ntvdm/hardware/ps2.h
Modified: trunk/reactos/subsystems/mvdm/ntvdm/hardware/ps2.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/hardw... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/hardware/ps2.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/hardware/ps2.c [iso-8859-1] Thu Aug 13 19:34:16 2015 @@ -5,6 +5,10 @@ * PURPOSE: PS/2 controller emulation * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * Hermes Belusca-Maito (hermes.belusca@sfr.fr) + * + * DOCUMENTATION: IBM Personal System/2 Hardware Interface Technical Reference, May 1988 (Section 10) + * http://wiki.osdev.org/%228042%22_PS/2_Controller + * http://www.computer-engineering.org/ps2keyboard/ */
/* INCLUDES *******************************************************************/ @@ -45,286 +49,362 @@ #define PS2_PORTS 2 static PS2_PORT Ports[PS2_PORTS];
-static BYTE ControllerConfig = 0x00; -static BYTE ControllerCommand = 0x00; - -static BYTE StatusRegister = 0x00; +static BYTE Memory[0x20]; // PS/2 Controller internal memory +#define ControllerConfig Memory[0] // The configuration byte is byte 0 + +static BYTE StatusRegister = 0x00; // Controller status register // static BYTE InputBuffer = 0x00; // PS/2 Input Buffer static BYTE OutputBuffer = 0x00; // PS/2 Output Buffer
+static BYTE ControllerCommand = 0x00; + static PHARDWARE_TIMER IrqTimer = NULL;
/* PRIVATE FUNCTIONS **********************************************************/
-static VOID PS2SendCommand(PPS2_PORT Port, BYTE Command) -{ - if (!Port->IsEnabled) return; +static VOID PS2SendCommand(BYTE PS2Port, BYTE Command) +{ + PPS2_PORT Port; + + ASSERT(PS2Port < PS2_PORTS); + Port = &Ports[PS2Port]; + + /* + * According to http://www.win.tue.nl/~aeb/linux/kbd/scancodes-11.html#kccad + * any PS/2 command sent reenables the corresponding port. + */ + if (PS2Port == 0) + ControllerConfig &= ~PS2_CONFIG_KBD_DISABLE; + else // if (PS2Port == 1) + ControllerConfig &= ~PS2_CONFIG_AUX_DISABLE; + + Port->IsEnabled = TRUE;
/* Call the device command */ if (Port->DeviceCommand) Port->DeviceCommand(Port->Param, Command); }
-static BYTE WINAPI PS2ReadPort(USHORT Port) -{ - if (Port == PS2_CONTROL_PORT) + +static BYTE WINAPI PS2ReadControl(USHORT Port) +{ + UNREFERENCED_PARAMETER(Port); + + /* + * Be sure the "Keyboard enable" flag is always set. + * On IBM PC-ATs this is the state of the hardware keyboard + * lock mechanism. It is not widely used, but some programs + * still use it, see for example: + * http://www.os2museum.com/wp/the-dos-4-0-shell-mouse-mystery/ + */ + StatusRegister |= PS2_STAT_KBD_ENABLE; + + /* We do not have any timeouts nor parity errors */ + StatusRegister &= ~(PS2_STAT_PARITY_ERROR | PS2_STAT_GEN_TIMEOUT); + + return StatusRegister; +} + +static BYTE WINAPI PS2ReadData(USHORT Port) +{ + UNREFERENCED_PARAMETER(Port); + + /* + * If there is something to read (response byte from the + * controller or data from a PS/2 device), read it. + */ + StatusRegister &= ~PS2_STAT_OUT_BUF_FULL; + + // Keep the state of the "Auxiliary output buffer full" flag + // in order to remember from where the data came from. + // StatusRegister &= ~PS2_STAT_AUX_OUT_BUF_FULL; + + // FIXME: We may check there whether there is data latched in + // PS2 ports 1 or 2 (keyboard or mouse) and retrieve it there... + + /* Always return the available byte stored in the output buffer */ + return OutputBuffer; +} + +static VOID WINAPI PS2WriteControl(USHORT Port, BYTE Data) +{ + UNREFERENCED_PARAMETER(Port); + + switch (Data) { - /* - * Be sure bit 4 "Keyboard enable flag" is always set. - * Keyboard enable (or keyboard lock) flag values are: - * 0: Locked; 1: Not locked. - * On IBM PC-ATs this is the state of the hardware keyboard - * lock mechanism. It is not widely used, but some programs - * still use it: see for example: - * http://www.os2museum.com/wp/the-dos-4-0-shell-mouse-mystery/ - */ - StatusRegister |= (1 << 4); - - // FIXME: Should clear bits 6 and 7 because there are - // no timeouts and no parity errors. - - return StatusRegister; + /* Read configuration byte (byte 0 from internal memory) */ + case 0x20: + /* Read byte N from internal memory */ + case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2A: case 0x2B: + case 0x2C: case 0x2D: case 0x2E: case 0x2F: + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3A: case 0x3B: + case 0x3C: case 0x3D: case 0x3E: case 0x3F: + { + OutputBuffer = Memory[Data & 0x1F]; + StatusRegister |= PS2_STAT_OUT_BUF_FULL; + break; + } + + /* Write configuration byte (byte 0 from internal memory) */ + case 0x60: + /* Write to byte N of internal memory */ + case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6A: case 0x6B: + case 0x6C: case 0x6D: case 0x6E: case 0x6F: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7A: case 0x7B: + case 0x7C: case 0x7D: case 0x7E: case 0x7F: + + /* Write controller output port */ + case 0xD1: + /* Write to the first PS/2 port output buffer */ + case 0xD2: + /* Write to the second PS/2 port output buffer */ + case 0xD3: + /* Write to the second PS/2 port input buffer */ + case 0xD4: + { + /* These commands require a response */ + ControllerCommand = Data; + StatusRegister |= PS2_STAT_COMMAND; + break; + } + + /* Disable second PS/2 port */ + case 0xA7: + { + ControllerConfig |= PS2_CONFIG_AUX_DISABLE; + Ports[1].IsEnabled = FALSE; + break; + } + + /* Enable second PS/2 port */ + case 0xA8: + { + ControllerConfig &= ~PS2_CONFIG_AUX_DISABLE; + Ports[1].IsEnabled = TRUE; + break; + } + + /* Test second PS/2 port */ + case 0xA9: + { + OutputBuffer = 0x00; // Success code + StatusRegister |= PS2_STAT_OUT_BUF_FULL; + break; + } + + /* Test PS/2 controller */ + case 0xAA: + { + OutputBuffer = 0x55; // Success code + StatusRegister |= PS2_STAT_OUT_BUF_FULL; + break; + } + + /* Test first PS/2 port */ + case 0xAB: + { + OutputBuffer = 0x00; // Success code + StatusRegister |= PS2_STAT_OUT_BUF_FULL; + break; + } + + /* Disable first PS/2 port */ + case 0xAD: + { + ControllerConfig |= PS2_CONFIG_KBD_DISABLE; + Ports[0].IsEnabled = FALSE; + break; + } + + /* Enable first PS/2 port */ + case 0xAE: + { + ControllerConfig &= ~PS2_CONFIG_KBD_DISABLE; + Ports[0].IsEnabled = TRUE; + break; + } + + /* Read controller output port */ + case 0xD0: + { + /* Bit 0 always set, and bit 1 is the A20 gate state */ + OutputBuffer = (!!EmulatorGetA20() << 1) | PS2_OUT_CPU_NO_RESET; + + /* Set IRQ1 state */ + if (ControllerConfig & PS2_CONFIG_KBD_INT) + OutputBuffer |= PS2_OUT_IRQ01; + else + OutputBuffer &= ~PS2_OUT_IRQ01; + + /* Set IRQ12 state */ + if (ControllerConfig & PS2_CONFIG_AUX_INT) + OutputBuffer |= PS2_OUT_IRQ12; + else + OutputBuffer &= ~PS2_OUT_IRQ12; + + /* Check whether data is already present */ + if (StatusRegister & PS2_STAT_OUT_BUF_FULL) + { + if (StatusRegister & PS2_STAT_AUX_OUT_BUF_FULL) + OutputBuffer |= PS2_OUT_AUX_DATA; + else + OutputBuffer |= PS2_OUT_KBD_DATA; + } + + StatusRegister |= PS2_STAT_OUT_BUF_FULL; + break; + } + + /* CPU Reset */ + case 0xF0: case 0xF2: case 0xF4: case 0xF6: + case 0xF8: case 0xFA: case 0xFC: case 0xFE: + { + /* Stop the VDM */ + EmulatorTerminate(); + return; + } } - else if (Port == PS2_DATA_PORT) +} + +static VOID WINAPI PS2WriteData(USHORT Port, BYTE Data) +{ + /* Check if the controller is waiting for a response */ + if (StatusRegister & PS2_STAT_COMMAND) { - /* - * If there is something to read (response byte from the - * controller or data from a PS/2 device), read it. - */ - if (StatusRegister & (1 << 0)) // || StatusRegister & (1 << 5) for second PS/2 port - StatusRegister &= ~(1 << 0); // StatusRegister &= ~(1 << 5); - - // FIXME: We may check there whether there is data latched in - // PS2 ports 1 or 2 (keyboard or mouse) and retrieve it there... - - /* Always return the available byte stored in the output buffer */ - return OutputBuffer; + StatusRegister &= ~PS2_STAT_COMMAND; + + /* Check which command it was */ + switch (ControllerCommand) + { + /* Write configuration byte (byte 0 from internal memory) */ + case 0x60: + { + ControllerConfig = Data; + + /* + * Synchronize the enable state of the PS/2 ports + * with the flags in the configuration byte. + */ + Ports[0].IsEnabled = !(ControllerConfig & PS2_CONFIG_KBD_DISABLE); + Ports[1].IsEnabled = !(ControllerConfig & PS2_CONFIG_AUX_DISABLE); + + /* + * Update the "System enabled" flag of the status register + * with bit 2 of the controller configuration byte. + * See: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-11.html#kccb2 + * for more details. + */ + if (ControllerConfig & PS2_CONFIG_SYSTEM) + StatusRegister |= PS2_STAT_SYSTEM; + else + StatusRegister &= ~PS2_STAT_SYSTEM; + + /* + * Update the "Keyboard enable" flag of the status register + * with the "Ignore keyboard lock" flag of the controller + * configuration byte (if set), then reset the latter one. + * See: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-11.html#kccb3 + * for more details. + */ + if (ControllerConfig & PS2_CONFIG_NO_KEYLOCK) + { + ControllerConfig &= ~PS2_CONFIG_NO_KEYLOCK; + StatusRegister |= PS2_STAT_KBD_ENABLE; + } + + break; + } + + /* Write to byte N of internal memory */ + case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6A: case 0x6B: + case 0x6C: case 0x6D: case 0x6E: case 0x6F: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7A: case 0x7B: + case 0x7C: case 0x7D: case 0x7E: case 0x7F: + { + Memory[ControllerCommand & 0x1F] = Data; + break; + } + + /* Write controller output */ + case 0xD1: + { + /* Check if bit 0 is unset */ + if (!(Data & PS2_OUT_CPU_NO_RESET)) + { + /* CPU disabled - Stop the VDM */ + EmulatorTerminate(); + return; + } + + /* Update the A20 line setting */ + EmulatorSetA20(Data & PS2_OUT_A20_SET); + + // FIXME: Should we need to add the status of IRQ1 and IRQ12?? + + break; + } + + /* Push the data byte into the first PS/2 port queue */ + case 0xD2: + { + PS2QueuePush(0, Data); + break; + } + + /* Push the data byte into the second PS/2 port queue */ + case 0xD3: + { + PS2QueuePush(1, Data); + break; + } + + /* + * Send a command to the second PS/2 port (by default + * it is a command for the first PS/2 port) + */ + case 0xD4: + { + PS2SendCommand(1, Data); + break; + } + } + + return; }
- return 0x00; -} - -static VOID WINAPI PS2WritePort(USHORT Port, BYTE Data) -{ - if (Port == PS2_CONTROL_PORT) - { - switch (Data) - { - /* Read configuration byte */ - case 0x20: - { - OutputBuffer = ControllerConfig; - StatusRegister |= (1 << 0); // There is something to read - break; - } - - /* Write configuration byte */ - case 0x60: - /* Write controller output port */ - case 0xD1: - /* Write to the first PS/2 port output buffer */ - case 0xD2: - /* Write to the second PS/2 port output buffer */ - case 0xD3: - /* Write to the second PS/2 port input buffer */ - case 0xD4: - { - /* These commands require a response */ - ControllerCommand = Data; - StatusRegister |= (1 << 3); // This is a controller command - break; - } - - /* Disable second PS/2 port */ - case 0xA7: - { - Ports[1].IsEnabled = FALSE; - break; - } - - /* Enable second PS/2 port */ - case 0xA8: - { - Ports[1].IsEnabled = TRUE; - break; - } - - /* Test second PS/2 port */ - case 0xA9: - { - OutputBuffer = 0x00; // Success code - StatusRegister |= (1 << 0); // There is something to read - break; - } - - /* Test PS/2 controller */ - case 0xAA: - { - OutputBuffer = 0x55; // Success code - StatusRegister |= (1 << 0); // There is something to read - break; - } - - /* Test first PS/2 port */ - case 0xAB: - { - OutputBuffer = 0x00; // Success code - StatusRegister |= (1 << 0); // There is something to read - break; - } - - /* Disable first PS/2 port */ - case 0xAD: - { - Ports[0].IsEnabled = FALSE; - break; - } - - /* Enable first PS/2 port */ - case 0xAE: - { - Ports[0].IsEnabled = TRUE; - break; - } - - /* Read controller output port */ - case 0xD0: - { - /* Bit 0 always set, and bit 1 is the A20 gate state */ - OutputBuffer = (!!EmulatorGetA20() << 1) | 0x01; - // FIXME: Set the status of IRQ1 and IRQ12 - - StatusRegister |= (1 << 0); // There is something to read - break; - } - - /* CPU Reset */ - case 0xF0: - case 0xF2: - case 0xF4: - case 0xF6: - case 0xF8: - case 0xFA: - case 0xFC: - case 0xFE: - { - /* Stop the VDM */ - EmulatorTerminate(); - return; - } - } - } - else if (Port == PS2_DATA_PORT) - { - /* Check if the controller is waiting for a response */ - if (StatusRegister & (1 << 3)) // If we have data for the controller - { - StatusRegister &= ~(1 << 3); - - /* Check which command it was */ - switch (ControllerCommand) - { - /* Write configuration byte */ - case 0x60: - { - ControllerConfig = Data; - - /* - * Update bit 2 "System flag" of the status register - * with bit 2 of the controller configuration byte. - * See: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-11.html#kccb2 - * for more details. - */ - if (ControllerConfig & (1 << 2)) - StatusRegister |= (1 << 2); - else - StatusRegister &= ~(1 << 2); - - /* - * Update bit 4 "Keyboard enable flag" of the status register - * with bit 3 "Ignore keyboard lock" of the controller - * configuration byte (if set), then reset the latter one. - * See: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-11.html#kccb3 - * for more details. - */ - if (ControllerConfig & (1 << 3)) - { - StatusRegister |= (1 << 4); - ControllerConfig &= ~(1 << 3); - } - - break; - } - - /* Write controller output */ - case 0xD1: - { - /* Check if bit 0 is unset */ - if (!(Data & (1 << 0))) - { - /* CPU disabled - Stop the VDM */ - EmulatorTerminate(); - return; - } - - /* Update the A20 line setting */ - EmulatorSetA20(Data & (1 << 1)); - - // FIXME: Add the status of IRQ1 and IRQ12 - - break; - } - - /* Push the data byte into the first PS/2 port queue */ - case 0xD2: - { - PS2QueuePush(0, Data); - break; - } - - /* Push the data byte into the second PS/2 port queue */ - case 0xD3: - { - PS2QueuePush(1, Data); - break; - } - - /* - * Send a command to the second PS/2 port (by default - * it is a command for the first PS/2 port) - */ - case 0xD4: - { - PS2SendCommand(&Ports[1], Data); - break; - } - } - - return; - } - - /* By default, send a command to the first PS/2 port */ - PS2SendCommand(&Ports[0], Data); - } + /* By default, send a command to the first PS/2 port */ + PS2SendCommand(0, Data); }
static VOID FASTCALL GeneratePS2Irq(ULONGLONG ElapsedTime) { UNREFERENCED_PARAMETER(ElapsedTime);
- /* Generate an IRQ 1 if there is data ready in the output queue */ + /* + * Pop out fresh new data from the PS/2 port output queues, and only + * in case there is data ready, generate an IRQ1 or IRQ12 depending + * on whether interrupts are enabled for the given port. + * + * NOTE: The first PS/2 port (keyboard) has priority over the second one (mouse). + */ if (PS2PortQueueRead(0)) { - /* Generate an interrupt if interrupts for the first PS/2 port are enabled */ - if (ControllerConfig & 0x01) PicInterruptRequest(1); - return; + if (ControllerConfig & PS2_CONFIG_KBD_INT) PicInterruptRequest(1); } - - /* Generate an IRQ 12 if there is data ready in the output queue */ - if (PS2PortQueueRead(1)) + else if (PS2PortQueueRead(1)) { - /* Generate an interrupt if interrupts for the second PS/2 port are enabled */ - if (ControllerConfig & 0x02) PicInterruptRequest(12); - return; + if (ControllerConfig & PS2_CONFIG_AUX_INT) PicInterruptRequest(12); } }
@@ -332,10 +412,11 @@
BOOLEAN PS2PortQueueRead(BYTE PS2Port) { - BOOLEAN Result = TRUE; + BOOLEAN Result = FALSE; PPS2_PORT Port;
- if (PS2Port >= PS2_PORTS) return FALSE; + // NOTE: The first PS/2 port (keyboard) has priority over the second one (mouse). + Port = &Ports[PS2Port];
if (!Port->IsEnabled) return FALSE; @@ -344,11 +425,12 @@ if (Port->QueueEmpty) { /* Only the keyboard should have its last data latched */ - // FIXME: Alternatively this can be done in PS2ReadPort when + // FIXME: Alternatively this can be done in PS2ReadData when // we read PS2_DATA_PORT. What is the best solution?? if (PS2Port == 0) { OutputBuffer = Port->Queue[(Port->QueueStart - 1) % BUFFER_SIZE]; + StatusRegister &= ~PS2_STAT_AUX_OUT_BUF_FULL; // Clear flag: keyboard data }
return FALSE; @@ -360,16 +442,21 @@ * Recheck whether the queue is not empty (it may * have changed after having grabbed the mutex). */ - if (Port->QueueEmpty) - { - Result = FALSE; - goto Done; - } + if (Port->QueueEmpty) goto Done;
/* Get the data */ OutputBuffer = Port->Queue[Port->QueueStart]; - StatusRegister |= (1 << 0); // There is something to read - // Sometimes StatusRegister |= (1 << 5); for the second PS/2 port + + // StatusRegister &= ~(PS2_STAT_AUX_OUT_BUF_FULL | PS2_STAT_OUT_BUF_FULL); + + /* Always set the "Output buffer full" flag */ + StatusRegister |= PS2_STAT_OUT_BUF_FULL; + + /* Set the "Auxiliary output buffer full" flag according to where the data came from */ + if (PS2Port == 0) + StatusRegister &= ~PS2_STAT_AUX_OUT_BUF_FULL; // Clear flag: keyboard data + else // if (PS2Port == 1) + StatusRegister |= PS2_STAT_AUX_OUT_BUF_FULL; // Set flag: mouse data
/* Remove the value from the queue */ Port->QueueStart++; @@ -379,6 +466,8 @@ if (Port->QueueStart == Port->QueueEnd) Port->QueueEmpty = TRUE;
+ Result = TRUE; + Done: ReleaseMutex(Port->QueueMutex); return Result; @@ -386,8 +475,7 @@
VOID PS2SetDeviceCmdProc(BYTE PS2Port, LPVOID Param, PS2_DEVICE_CMDPROC DeviceCommand) { - if (PS2Port >= PS2_PORTS) return; - + ASSERT(PS2Port < PS2_PORTS); Ports[PS2Port].Param = Param; Ports[PS2Port].DeviceCommand = DeviceCommand; } @@ -395,10 +483,10 @@ // PS2SendToPort BOOLEAN PS2QueuePush(BYTE PS2Port, BYTE Data) { - BOOLEAN Result = TRUE; + BOOLEAN Result = FALSE; PPS2_PORT Port;
- if (PS2Port >= PS2_PORTS) return FALSE; + ASSERT(PS2Port < PS2_PORTS); Port = &Ports[PS2Port];
if (!Port->IsEnabled) return FALSE; @@ -407,10 +495,7 @@
/* Check if the queue is full */ if (!Port->QueueEmpty && (Port->QueueStart == Port->QueueEnd)) - { - Result = FALSE; goto Done; - }
/* Insert the value in the queue */ Port->Queue[Port->QueueEnd] = Data; @@ -422,6 +507,8 @@
/* Schedule the IRQ */ EnableHardwareTimer(IrqTimer); + + Result = TRUE;
Done: ReleaseMutex(Port->QueueMutex); @@ -444,8 +531,8 @@ Ports[1].QueueMutex = CreateMutex(NULL, FALSE, NULL);
/* Register the I/O Ports */ - RegisterIoPort(PS2_CONTROL_PORT, PS2ReadPort, PS2WritePort); - RegisterIoPort(PS2_DATA_PORT , PS2ReadPort, PS2WritePort); + RegisterIoPort(PS2_CONTROL_PORT, PS2ReadControl, PS2WriteControl); + RegisterIoPort(PS2_DATA_PORT , PS2ReadData , PS2WriteData );
IrqTimer = CreateHardwareTimer(HARDWARE_TIMER_ONESHOT, HZ_TO_NS(100),
Modified: trunk/reactos/subsystems/mvdm/ntvdm/hardware/ps2.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/hardw... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/hardware/ps2.h [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/hardware/ps2.h [iso-8859-1] Thu Aug 13 19:34:16 2015 @@ -12,8 +12,38 @@
/* DEFINES ********************************************************************/
+/* I/O Ports */ #define PS2_DATA_PORT 0x60 #define PS2_CONTROL_PORT 0x64 + +/* Controller Status Register flags */ +#define PS2_STAT_OUT_BUF_FULL (1 << 0) +// #define PS2_STAT_IN_BUF_FULL (1 << 1) +#define PS2_STAT_SYSTEM (1 << 2) +#define PS2_STAT_COMMAND (1 << 3) +#define PS2_STAT_KBD_ENABLE (1 << 4) // 0: Locked; 1: Not locked +#define PS2_STAT_AUX_OUT_BUF_FULL (1 << 5) +#define PS2_STAT_GEN_TIMEOUT (1 << 6) +#define PS2_STAT_PARITY_ERROR (1 << 7) + +/* Controller Configuration Byte flags */ +#define PS2_CONFIG_KBD_INT (1 << 0) +#define PS2_CONFIG_AUX_INT (1 << 1) +#define PS2_CONFIG_SYSTEM (1 << 2) +#define PS2_CONFIG_NO_KEYLOCK (1 << 3) +#define PS2_CONFIG_KBD_DISABLE (1 << 4) +#define PS2_CONFIG_AUX_DISABLE (1 << 5) +// #define PS2_CONFIG_KBD_XLAT (1 << 6) + +/* Output Port flags */ +#define PS2_OUT_CPU_NO_RESET (1 << 0) +#define PS2_OUT_A20_SET (1 << 1) +#define PS2_OUT_AUX_DATA (1 << 2) +// #define PS2_OUT_AUX_CLOCK (1 << 3) +#define PS2_OUT_IRQ01 (1 << 4) +#define PS2_OUT_IRQ12 (1 << 5) +// #define PS2_OUT_KBD_CLOCK (1 << 6) +#define PS2_OUT_KBD_DATA (1 << 7)
typedef VOID (WINAPI *PS2_DEVICE_CMDPROC)(LPVOID Param, BYTE Command);