diff options
Diffstat (limited to 'src/VBox/Devices/Input/PS2K.cpp')
-rw-r--r-- | src/VBox/Devices/Input/PS2K.cpp | 615 |
1 files changed, 348 insertions, 267 deletions
diff --git a/src/VBox/Devices/Input/PS2K.cpp b/src/VBox/Devices/Input/PS2K.cpp index 1df1ddb2..e933fbc4 100644 --- a/src/VBox/Devices/Input/PS2K.cpp +++ b/src/VBox/Devices/Input/PS2K.cpp @@ -74,7 +74,7 @@ #define KRSP_ID1 0xAB #define KRSP_ID2 0x83 #define KRSP_BAT_OK 0xAA -#define KRSP_BAT_FAIL 0xFC +#define KRSP_BAT_FAIL 0xFC /* Also a 'release keys' signal. */ #define KRSP_ECHO 0xEE #define KRSP_ACK 0xFA #define KRSP_RESEND 0xFE @@ -187,22 +187,26 @@ typedef struct PS2K #if HC_ARCH_BITS == 32 uint32_t Alignment0; #endif - /** Critical section protecting the state. */ - PDMCRITSECT KbdCritSect; + /** Command delay timer - RC Ptr. */ PTMTIMERRC pKbdDelayTimerRC; /** Typematic timer - RC Ptr. */ PTMTIMERRC pKbdTypematicTimerRC; + + /** The device critical section protecting everything - R3 Ptr */ + R3PTRTYPE(PPDMCRITSECT) pCritSectR3; /** Command delay timer - R3 Ptr. */ PTMTIMERR3 pKbdDelayTimerR3; /** Typematic timer - R3 Ptr. */ PTMTIMERR3 pKbdTypematicTimerR3; + RTR3PTR Alignment2; + /** Command delay timer - R0 Ptr. */ PTMTIMERR0 pKbdDelayTimerR0; /** Typematic timer - R0 Ptr. */ PTMTIMERR0 pKbdTypematicTimerR0; - scan_state_t XlatState; //@todo: temporary + scan_state_t XlatState; ///@todo: temporary uint32_t Alignment1; /** @@ -415,7 +419,7 @@ static const key_def aPS2Keys[] = { /* 97 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Lang 8 */ /* 98 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Lang 9 */ /* 99 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Alternate Erase */ - /* 9A */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard SysReq/Attention */ + /* 9A */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard SysReq/Attention (Note 3) */ /* 9B */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Cancel */ /* 9C */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Clear */ /* 9D */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Prior */ @@ -428,6 +432,19 @@ static const key_def aPS2Keys[] = { /* A4 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard ExSel */ }; +/* + * Note 1: The behavior of these keys depends on the state of modifier keys + * at the time the key was pressed. + * + * Note 2: The key label depends on the national version of the keyboard. + * + * Note 3: Certain keys which have their own PS/2 scancodes do not exist on + * USB keyboards; the SysReq key is an example. The SysReq key scancode needs + * to be translated to the Print Screen HID usage code. The HID usage to PS/2 + * scancode conversion then generates the correct sequence depending on the + * keyboard state. + */ + /* USB to PS/2 conversion table for modifier keys. */ static const key_def aPS2ModKeys[] = { /* E0 */ {0x1D, 0x14, 0x11, 0, T_B }, /* Key 58: Left Control */ @@ -467,7 +484,7 @@ static uint8_t aScancode2Hid[] = 0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, /* 38-3F */ 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f, /* 40-47 */ 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59, /* 48-4F */ - 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x64, 0x44, /* 50-57 */ + 0x5a, 0x5b, 0x62, 0x63, 0x46, 0x00, 0x64, 0x44, /* 50-57 */ 0x45, 0x67, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, /* 58-5F */ 0x00, 0x00, 0x00, 0x00, 0x68, 0x69, 0x6a, 0x6b, /* 60-67 */ 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x00, /* 68-6F */ @@ -560,7 +577,7 @@ static scan_state_t ScancodeToHidUsage(scan_state_t state, uint8_t scanCode, uin * * @param pQ Pointer to the queue. */ -static void PS2ClearQueue(GeneriQ *pQ) +static void ps2kClearQueue(GeneriQ *pQ) { LogFlowFunc(("Clearing queue %p\n", pQ)); pQ->wpos = pQ->rpos; @@ -574,7 +591,7 @@ static void PS2ClearQueue(GeneriQ *pQ) * @param pQ Pointer to the queue. * @param val The byte to store. */ -static void PS2InsertQueue(GeneriQ *pQ, uint8_t val) +static void ps2kInsertQueue(GeneriQ *pQ, uint8_t val) { /* Check if queue is full. */ if (pQ->cUsed >= pQ->cSize) @@ -598,7 +615,7 @@ static void PS2InsertQueue(GeneriQ *pQ, uint8_t val) * @param pSSM SSM handle to write the state to. * @param pQ Pointer to the queue. */ -static void PS2SaveQueue(PSSMHANDLE pSSM, GeneriQ *pQ) +static void ps2kSaveQueue(PSSMHANDLE pSSM, GeneriQ *pQ) { uint32_t cItems = pQ->cUsed; int i; @@ -623,7 +640,7 @@ static void PS2SaveQueue(PSSMHANDLE pSSM, GeneriQ *pQ) * * @return int VBox status/error code. */ -static int PS2LoadQueue(PSSMHANDLE pSSM, GeneriQ *pQ) +static int ps2kLoadQueue(PSSMHANDLE pSSM, GeneriQ *pQ) { int rc; @@ -646,7 +663,7 @@ static int PS2LoadQueue(PSSMHANDLE pSSM, GeneriQ *pQ) return rc; } -#endif +#endif /* IN_RING3 */ /** * Retrieve a byte from a queue. @@ -657,7 +674,7 @@ static int PS2LoadQueue(PSSMHANDLE pSSM, GeneriQ *pQ) * @return int VINF_TRY_AGAIN if queue is empty, * VINF_SUCCESS if a byte was read. */ -int PS2RemoveQueue(GeneriQ *pQ, uint8_t *pVal) +static int ps2kRemoveQueue(GeneriQ *pQ, uint8_t *pVal) { int rc = VINF_TRY_AGAIN; @@ -678,7 +695,7 @@ int PS2RemoveQueue(GeneriQ *pQ, uint8_t *pVal) /* Convert encoded typematic value to milliseconds. Note that the values are rated * with +/- 20% accuracy, so there's no need for high precision. */ -static void PS2KSetupTypematic(PPS2K pThis, uint8_t val) +static void ps2kSetupTypematic(PPS2K pThis, uint8_t val) { int A, B; unsigned period; @@ -692,23 +709,23 @@ static void PS2KSetupTypematic(PPS2K pThis, uint8_t val) period = (8 + A) * (1 << B) * 417 / 100; pThis->uTypematicRepeat = period; Log(("Typematic delay %u ms, repeat period %u ms\n", - pThis->uTypematicDelay, pThis->uTypematicRepeat)); + pThis->uTypematicDelay, pThis->uTypematicRepeat)); } -static void PS2KSetDefaults(PPS2K pThis) +static void ps2kSetDefaults(PPS2K pThis) { LogFlowFunc(("Set keyboard defaults\n")); - PS2ClearQueue((GeneriQ *)&pThis->keyQ); + ps2kClearQueue((GeneriQ *)&pThis->keyQ); /* Set default Scan Set 3 typematic values. */ /* Set default typematic rate/delay. */ - PS2KSetupTypematic(pThis, KBD_DFL_RATE_DELAY); + ps2kSetupTypematic(pThis, KBD_DFL_RATE_DELAY); /* Clear last typematic key?? */ } /** * Receive and process a byte sent by the keyboard controller. * - * @param pThis The keyboard. + * @param pThis The PS/2 keyboard instance data. * @param cmd The command (or data) byte. */ int PS2KByteToKbd(PPS2K pThis, uint8_t cmd) @@ -717,118 +734,120 @@ int PS2KByteToKbd(PPS2K pThis, uint8_t cmd) LogFlowFunc(("new cmd=0x%02X, active cmd=0x%02X\n", cmd, pThis->u8CurrCmd)); - switch (cmd) { - case KCMD_ECHO: - PS2InsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ECHO); - pThis->u8CurrCmd = 0; - break; - case KCMD_READ_ID: - PS2InsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); - PS2InsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ID1); - PS2InsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ID2); - pThis->u8CurrCmd = 0; - break; - case KCMD_ENABLE: - pThis->fScanning = true; - PS2ClearQueue((GeneriQ *)&pThis->keyQ); - /* Clear last typematic key?? */ - PS2InsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); - pThis->u8CurrCmd = 0; - break; - case KCMD_DFLT_DISABLE: - pThis->fScanning = false; - PS2KSetDefaults(pThis); - PS2InsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); - pThis->u8CurrCmd = 0; - break; - case KCMD_SET_DEFAULT: - PS2KSetDefaults(pThis); - PS2InsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); - pThis->u8CurrCmd = 0; - break; - case KCMD_ALL_TYPEMATIC: - case KCMD_ALL_MK_BRK: - case KCMD_ALL_MAKE: - case KCMD_ALL_TMB: - //@todo: Set the key types here. - PS2InsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); - pThis->u8CurrCmd = 0; - break; - case KCMD_RESEND: - pThis->u8CurrCmd = 0; - break; - case KCMD_RESET: - pThis->u8ScanSet = 2; - PS2KSetDefaults(pThis); - //@todo: reset more? - PS2InsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); - pThis->u8CurrCmd = cmd; - /* Delay BAT completion; the test may take hundreds of ms. */ - TMTimerSetMillies(pThis->CTX_SUFF(pKbdDelayTimer), 2); - break; - /* The following commands need a parameter. */ - case KCMD_LEDS: - case KCMD_SCANSET: - case KCMD_RATE_DELAY: - case KCMD_TYPE_MATIC: - case KCMD_TYPE_MK_BRK: - case KCMD_TYPE_MAKE: - PS2InsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); - pThis->u8CurrCmd = cmd; - break; - default: - /* Sending a command instead of a parameter starts the new command. */ - switch (pThis->u8CurrCmd) { - case KCMD_LEDS: -#ifndef IN_RING3 - return VINF_IOM_R3_IOPORT_WRITE; -#else - { - PDMKEYBLEDS enmLeds = PDMKEYBLEDS_NONE; - - if (cmd & 0x01) - enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_SCROLLLOCK); - if (cmd & 0x02) - enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_NUMLOCK); - if (cmd & 0x04) - enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_CAPSLOCK); - pThis->Keyboard.pDrv->pfnLedStatusChange(pThis->Keyboard.pDrv, enmLeds); - pThis->fNumLockOn = !!(cmd & 0x02); /* Sync internal Num Lock state. */ - PS2InsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); - pThis->u8LEDs = cmd; - pThis->u8CurrCmd = 0; - } -#endif + switch (cmd) + { + case KCMD_ECHO: + ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ECHO); + pThis->u8CurrCmd = 0; break; - case KCMD_SCANSET: - PS2InsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); - if (cmd == 0) - PS2InsertQueue((GeneriQ *)&pThis->cmdQ, pThis->u8ScanSet); - else if (cmd < 4) - { - pThis->u8ScanSet = cmd; - LogRel(("PS2K: Selected scan set %d.\n", cmd)); - } - /* Other values are simply ignored. */ + case KCMD_READ_ID: + ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); + ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ID1); + ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ID2); pThis->u8CurrCmd = 0; break; - case KCMD_RATE_DELAY: - PS2KSetupTypematic(pThis, cmd); - PS2InsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); + case KCMD_ENABLE: + pThis->fScanning = true; + ps2kClearQueue((GeneriQ *)&pThis->keyQ); + /* Clear last typematic key?? */ + ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); pThis->u8CurrCmd = 0; break; - default: - fHandled = false; - } - /* Fall through only to handle unrecognized commands. */ - if (fHandled) + case KCMD_DFLT_DISABLE: + pThis->fScanning = false; + ps2kSetDefaults(pThis); + ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); + pThis->u8CurrCmd = 0; + break; + case KCMD_SET_DEFAULT: + ps2kSetDefaults(pThis); + ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); + pThis->u8CurrCmd = 0; + break; + case KCMD_ALL_TYPEMATIC: + case KCMD_ALL_MK_BRK: + case KCMD_ALL_MAKE: + case KCMD_ALL_TMB: + ///@todo Set the key types here. + ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); + pThis->u8CurrCmd = 0; break; + case KCMD_RESEND: + pThis->u8CurrCmd = 0; + break; + case KCMD_RESET: + pThis->u8ScanSet = 2; + ps2kSetDefaults(pThis); + ///@todo reset more? + ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); + pThis->u8CurrCmd = cmd; + /* Delay BAT completion; the test may take hundreds of ms. */ + TMTimerSetMillies(pThis->CTX_SUFF(pKbdDelayTimer), 2); + break; + /* The following commands need a parameter. */ + case KCMD_LEDS: + case KCMD_SCANSET: + case KCMD_RATE_DELAY: + case KCMD_TYPE_MATIC: + case KCMD_TYPE_MK_BRK: + case KCMD_TYPE_MAKE: + ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); + pThis->u8CurrCmd = cmd; + break; + default: + /* Sending a command instead of a parameter starts the new command. */ + switch (pThis->u8CurrCmd) + { + case KCMD_LEDS: +#ifndef IN_RING3 + return VINF_IOM_R3_IOPORT_WRITE; +#else + { + PDMKEYBLEDS enmLeds = PDMKEYBLEDS_NONE; + + if (cmd & 0x01) + enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_SCROLLLOCK); + if (cmd & 0x02) + enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_NUMLOCK); + if (cmd & 0x04) + enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_CAPSLOCK); + pThis->Keyboard.pDrv->pfnLedStatusChange(pThis->Keyboard.pDrv, enmLeds); + pThis->fNumLockOn = !!(cmd & 0x02); /* Sync internal Num Lock state. */ + ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); + pThis->u8LEDs = cmd; + pThis->u8CurrCmd = 0; + } +#endif + break; + case KCMD_SCANSET: + ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); + if (cmd == 0) + ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, pThis->u8ScanSet); + else if (cmd < 4) + { + pThis->u8ScanSet = cmd; + LogRel(("PS2K: Selected scan set %d.\n", cmd)); + } + /* Other values are simply ignored. */ + pThis->u8CurrCmd = 0; + break; + case KCMD_RATE_DELAY: + ps2kSetupTypematic(pThis, cmd); + ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK); + pThis->u8CurrCmd = 0; + break; + default: + fHandled = false; + } + /* Fall through only to handle unrecognized commands. */ + if (fHandled) + break; - case KCMD_INVALID_1: - case KCMD_INVALID_2: - PS2InsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_RESEND); - pThis->u8CurrCmd = 0; - break; + case KCMD_INVALID_1: + case KCMD_INVALID_2: + ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_RESEND); + pThis->u8CurrCmd = 0; + break; } LogFlowFunc(("Active cmd now 0x%02X; updating interrupts\n", pThis->u8CurrCmd)); // KBCUpdateInterrupts(pThis->pParent); @@ -838,34 +857,38 @@ int PS2KByteToKbd(PPS2K pThis, uint8_t cmd) /** * Send a byte (keystroke or command response) to the keyboard controller. * - * @param pThis The keyboard. + * @returns VINF_SUCCESS or VINF_TRY_AGAIN. + * @param pThis The PS/2 keyboard instance data. + * @param pb Where to return the byte we've read. + * @remarks Caller must have entered the device critical section. */ -int PS2KByteFromKbd(PPS2K pThis, uint8_t *pVal) +int PS2KByteFromKbd(PPS2K pThis, uint8_t *pb) { int rc; - Assert(pVal); + AssertPtr(pb); /* Anything in the command queue has priority over data * in the keystroke queue. Additionally, keystrokes are * blocked if a command is currently in progress, even if * the command queue is empty. */ - rc = PS2RemoveQueue((GeneriQ *)&pThis->cmdQ, pVal); + rc = ps2kRemoveQueue((GeneriQ *)&pThis->cmdQ, pb); if (rc != VINF_SUCCESS && !pThis->u8CurrCmd && pThis->fScanning) - rc = PS2RemoveQueue((GeneriQ *)&pThis->keyQ, pVal); + rc = ps2kRemoveQueue((GeneriQ *)&pThis->keyQ, pb); - LogFlowFunc(("keyboard sends 0x%02x (%svalid data)\n", *pVal, rc == VINF_SUCCESS ? "" : "not ")); + LogFlowFunc(("keyboard sends 0x%02x (%svalid data)\n", *pb, rc == VINF_SUCCESS ? "" : "not ")); return rc; } #ifdef IN_RING3 -static int PS2KProcessKeyEvent(PPS2K pThis, uint8_t u8HidCode, bool fKeyDown) +static int psk2ProcessKeyEvent(PPS2K pThis, uint8_t u8HidCode, bool fKeyDown) { unsigned int i = 0; key_def const *pKeyDef; uint8_t abCodes[16]; + uint8_t u8MakeCode; LogFlowFunc(("key %s: 0x%02x (set %d)\n", fKeyDown ? "down" : "up", u8HidCode, pThis->u8ScanSet)); @@ -897,9 +920,11 @@ static int PS2KProcessKeyEvent(PPS2K pThis, uint8_t u8HidCode, bool fKeyDown) if ((pKeyDef->keyFlags & KF_NL) && fKeyDown) pThis->fNumLockOn ^= true; - if (pThis->u8ScanSet == 2) + if (pThis->u8ScanSet == 1 || pThis->u8ScanSet == 2) { - /* Handle Scan Set 2 - used almost all the time. */ + /* The basic scan set 1 and 2 logic is the same, only the scan codes differ. + * Since scan set 2 is used almost all the time, that case is handled first. + */ abCodes[0] = 0; if (fKeyDown) { @@ -908,47 +933,63 @@ static int PS2KProcessKeyEvent(PPS2K pThis, uint8_t u8HidCode, bool fKeyDown) { /* Pause/Break sends different data if either Ctrl is held. */ if (pThis->u8Modifiers & (MOD_LCTRL | MOD_RCTRL)) - strcpy((char *)abCodes, "\xE0\x7E\xE0\xF0\x7E"); + strcpy((char *)abCodes, pThis->u8ScanSet == 2 ? + "\xE0\x7E\xE0\xF0\x7E" : "\xE0\x46\xE0\xC6"); else - strcpy((char *)abCodes, "\xE1\x14\x77\xE1\xF0\x14\xF0\x77"); + strcpy((char *)abCodes, pThis->u8ScanSet == 2 ? + "\xE1\x14\x77\xE1\xF0\x14\xF0\x77" : "\xE1\x1D\x45\xE1\x9D\xC5"); } else if (pKeyDef->keyFlags & KF_PS) { - /* Print Screen depends on all Ctrl, Shift, *and* Alt! */ + /* Print Screen depends on all of Ctrl, Shift, *and* Alt! */ if (pThis->u8Modifiers & (MOD_LALT | MOD_RALT)) - strcpy((char *)abCodes, "\x84"); + strcpy((char *)abCodes, pThis->u8ScanSet == 2 ? + "\x84" : "\x54"); else if (pThis->u8Modifiers & (MOD_LSHIFT | MOD_RSHIFT)) - strcpy((char *)abCodes, "\xE0\x7C"); + strcpy((char *)abCodes, pThis->u8ScanSet == 2 ? + "\xE0\x7C" : "\xE0\x37"); else - strcpy((char *)abCodes, "\xE0\x12\xE0\x7C"); + strcpy((char *)abCodes, pThis->u8ScanSet == 2 ? + "\xE0\x12\xE0\x7C" : "\xE0\x2A\xE0\x37"); } - else if (pKeyDef->keyFlags & KF_GK) + else if (pKeyDef->keyFlags & (KF_GK | KF_NS)) { - if (pThis->fNumLockOn) + /* The numeric pad keys fake Shift presses or releases + * depending on Num Lock and Shift key state. The '/' + * key behaves in a similar manner but does not depend on + * the Num Lock state. + */ + if (!pThis->fNumLockOn || (pKeyDef->keyFlags & KF_NS)) { - if ((pThis->u8Modifiers & (MOD_LSHIFT | MOD_RSHIFT)) == 0) - strcpy((char *)abCodes, "\xE0\x12"); + if (pThis->u8Modifiers & MOD_LSHIFT) + strcat((char *)abCodes, pThis->u8ScanSet == 2 ? + "\xE0\xF0\x12" : "\xE0\xAA"); + if (pThis->u8Modifiers & MOD_RSHIFT) + strcat((char *)abCodes, pThis->u8ScanSet == 2 ? + "\xE0\xF0\x59" : "\xE0\xB6"); } else { - if (pThis->u8Modifiers & MOD_LSHIFT) - strcat((char *)abCodes, "\xE0\xF0\x12"); - if (pThis->u8Modifiers & MOD_RSHIFT) - strcat((char *)abCodes, "\xE0\xF0\x59"); + Assert(pThis->fNumLockOn); /* Not for KF_NS! */ + if ((pThis->u8Modifiers & (MOD_LSHIFT | MOD_RSHIFT)) == 0) + strcpy((char *)abCodes, pThis->u8ScanSet == 2 ? + "\xE0\x12" : "\xE0\x2A"); + /* Else Shift cancels NumLock, so no prefix! */ } } /* Feed the bytes to the queue if there is room. */ - //@todo: check empty space! + ///@todo check empty space! while (abCodes[i]) - PS2InsertQueue((GeneriQ *)&pThis->keyQ, abCodes[i++]); + ps2kInsertQueue((GeneriQ *)&pThis->keyQ, abCodes[i++]); Assert(i < sizeof(abCodes)); /* Standard processing for regular keys only. */ + u8MakeCode = pThis->u8ScanSet == 2 ? pKeyDef->makeS2 : pKeyDef->makeS1; if (!(pKeyDef->keyFlags & (KF_PB | KF_PS))) { if (pKeyDef->keyFlags & (KF_E0 | KF_GK | KF_NS)) - PS2InsertQueue((GeneriQ *)&pThis->keyQ, 0xE0); - PS2InsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS2); + ps2kInsertQueue((GeneriQ *)&pThis->keyQ, 0xE0); + ps2kInsertQueue((GeneriQ *)&pThis->keyQ, u8MakeCode); } } else if (!(pKeyDef->keyFlags & (KF_NB | KF_PB))) @@ -960,75 +1001,73 @@ static int PS2KProcessKeyEvent(PPS2K pThis, uint8_t u8HidCode, bool fKeyDown) { /* Undo faked Print Screen state as needed. */ if (pThis->u8Modifiers & (MOD_LALT | MOD_RALT)) - strcpy((char *)abCodes, "\xF0\x84"); + strcpy((char *)abCodes, pThis->u8ScanSet == 2 ? + "\xF0\x84" : "\xD4"); else if (pThis->u8Modifiers & (MOD_LSHIFT | MOD_RSHIFT)) - strcpy((char *)abCodes, "\xE0\xF0\x7C"); + strcpy((char *)abCodes, pThis->u8ScanSet == 2 ? + "\xE0\xF0\x7C" : "\xE0\xB7"); else - strcpy((char *)abCodes, "\xE0\xF0\x7C\xE0\xF0\x12"); + strcpy((char *)abCodes, pThis->u8ScanSet == 2 ? + "\xE0\xF0\x7C\xE0\xF0\x12" : "\xE0\xB7\xE0\xAA"); } else { /* Process base scan code for less unusual keys. */ if (pKeyDef->keyFlags & (KF_E0 | KF_GK | KF_NS)) - PS2InsertQueue((GeneriQ *)&pThis->keyQ, 0xE0); - PS2InsertQueue((GeneriQ *)&pThis->keyQ, 0xF0); - PS2InsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS2); + ps2kInsertQueue((GeneriQ *)&pThis->keyQ, 0xE0); + if (pThis->u8ScanSet == 2) { + ps2kInsertQueue((GeneriQ *)&pThis->keyQ, 0xF0); + ps2kInsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS2); + } else { + Assert(pThis->u8ScanSet == 1); + ps2kInsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS1 | 0x80); + } /* Restore shift state for gray keys. */ - if (pKeyDef->keyFlags & KF_GK) + if (pKeyDef->keyFlags & (KF_GK | KF_NS)) { - if (pThis->fNumLockOn) + if (!pThis->fNumLockOn || (pKeyDef->keyFlags & KF_NS)) { - if ((pThis->u8Modifiers & (MOD_LSHIFT | MOD_RSHIFT)) == 0) - strcpy((char *)abCodes, "\xE0\xF0\x12"); + if (pThis->u8Modifiers & MOD_LSHIFT) + strcat((char *)abCodes, pThis->u8ScanSet == 2 ? + "\xE0\x12" : "\xE0\x2A"); + if (pThis->u8Modifiers & MOD_RSHIFT) + strcat((char *)abCodes, pThis->u8ScanSet == 2 ? + "\xE0\x59" : "\xE0\x36"); } else { - if (pThis->u8Modifiers & MOD_RSHIFT) - strcat((char *)abCodes, "\xE0\x59"); - if (pThis->u8Modifiers & MOD_LSHIFT) - strcat((char *)abCodes, "\xE0\x12"); + Assert(pThis->fNumLockOn); /* Not for KF_NS! */ + if ((pThis->u8Modifiers & (MOD_LSHIFT | MOD_RSHIFT)) == 0) + strcpy((char *)abCodes, pThis->u8ScanSet == 2 ? + "\xE0\xF0\x12" : "\xE0\xAA"); } } } /* Feed any additional bytes to the queue if there is room. */ - //@todo: check empty space! + ///@todo check empty space! while (abCodes[i]) - PS2InsertQueue((GeneriQ *)&pThis->keyQ, abCodes[i++]); + ps2kInsertQueue((GeneriQ *)&pThis->keyQ, abCodes[i++]); Assert(i < sizeof(abCodes)); } } - else if (pThis->u8ScanSet == 1) - { - /* Handle Scan Set 1 - similar in complexity to Set 2. */ - if (fKeyDown) - { - if (pKeyDef->keyFlags & (KF_E0 | KF_GK | KF_NS | KF_PS)) - PS2InsertQueue((GeneriQ *)&pThis->keyQ, 0xE0); - PS2InsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS1); - } - else if (!(pKeyDef->keyFlags & (KF_NB | KF_PB))) { - if (pKeyDef->keyFlags & (KF_E0 | KF_GK | KF_NS | KF_PS)) - PS2InsertQueue((GeneriQ *)&pThis->keyQ, 0xE0); - PS2InsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS1 | 0x80); - } - } else { /* Handle Scan Set 3 - very straightforward. */ + Assert(pThis->u8ScanSet == 3); if (fKeyDown) { - PS2InsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS3); + ps2kInsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS3); } else { /* Send a key release code unless it's a make only key. */ - //@todo: Look up the current typematic setting, not the default! + ///@todo Look up the current typematic setting, not the default! if (pKeyDef->keyMatic != T_M) { - PS2InsertQueue((GeneriQ *)&pThis->keyQ, 0xF0); - PS2InsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS3); + ps2kInsertQueue((GeneriQ *)&pThis->keyQ, 0xF0); + ps2kInsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS3); } } } @@ -1048,8 +1087,8 @@ static int PS2KProcessKeyEvent(PPS2K pThis, uint8_t u8HidCode, bool fKeyDown) { pThis->u8TypematicKey = 0; pThis->enmTypematicState = KBD_TMS_IDLE; - //@todo: Cancel timer right away? - //@todo: Cancel timer before pushing key up code!? + ///@todo Cancel timer right away? + ///@todo Cancel timer before pushing key up code!? } /* Poke the KBC to update its state. */ @@ -1061,12 +1100,9 @@ static int PS2KProcessKeyEvent(PPS2K pThis, uint8_t u8HidCode, bool fKeyDown) /* Timer handler for emulating typematic keys. Note that only the last key * held down repeats (if typematic). */ -static DECLCALLBACK(void) PS2KTypematicTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) +static DECLCALLBACK(void) ps2kTypematicTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) { - PPS2K pThis = (PS2K *)pvUser; //PDMINS_2_DATA(pDevIns, PS2K *); - int rc = PDMCritSectEnter(&pThis->KbdCritSect, VERR_SEM_BUSY); - AssertReleaseRC(rc); - + PPS2K pThis = (PS2K *)pvUser; NOREF(pDevIns); LogFlowFunc(("Typematic state=%d, key %02X\n", pThis->enmTypematicState, pThis->u8TypematicKey)); /* If the current typematic key is zero, the repeat was canceled just when @@ -1079,35 +1115,48 @@ static DECLCALLBACK(void) PS2KTypematicTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer if (pThis->enmTypematicState == KBD_TMS_REPEAT) { - PS2KProcessKeyEvent(pThis, pThis->u8TypematicKey, true /* Key down */ ); + psk2ProcessKeyEvent(pThis, pThis->u8TypematicKey, true /* Key down */ ); TMTimerSetMillies(pThis->CTX_SUFF(pKbdTypematicTimer), pThis->uTypematicRepeat); } } - - PDMCritSectLeave(&pThis->KbdCritSect); } /* The keyboard BAT is specified to take several hundred milliseconds. We need * to delay sending the result to the host for at least a tiny little while. */ -static DECLCALLBACK(void) PS2KDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) +static DECLCALLBACK(void) ps2kDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) { - PPS2K pThis = GetPS2KFromDevIns(pDevIns); - int rc = PDMCritSectEnter(&pThis->KbdCritSect, VERR_SEM_BUSY); - AssertReleaseRC(rc); + PPS2K pThis = (PS2K *)pvUser; NOREF(pDevIns); LogFlowFunc(("Delay timer: cmd %02X\n", pThis->u8CurrCmd)); Assert(pThis->u8CurrCmd == KCMD_RESET); - PS2InsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_BAT_OK); + ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_BAT_OK); pThis->fScanning = true; /* BAT completion enables scanning! */ pThis->u8CurrCmd = 0; - //@todo: Might want a PS2KCompleteCommand() to push last response, clear command, and kick the KBC... + ///@todo Might want a PS2KCompleteCommand() to push last response, clear command, and kick the KBC... /* Give the KBC a kick. */ KBCUpdateInterrupts(pThis->pParent); +} - PDMCritSectLeave(&pThis->KbdCritSect); +/* Release any and all currently depressed keys. Used whenever the guest keyboard + * is likely to be out of sync with the host, such as when loading a saved state + * or resuming a suspended host. + */ +static void ps2kReleaseKeys(PPS2K pThis) +{ + LogFlowFunc(("Releasing keys...\n")); + LogRel(("Releasing keys...\n")); + + for (unsigned uKey = 0; uKey < sizeof(pThis->abDepressedKeys); ++uKey) + if (pThis->abDepressedKeys[uKey]) + { + LogRel(("Releasing key %02X\n", uKey)); + psk2ProcessKeyEvent(pThis, uKey, false /* key up */); + pThis->abDepressedKeys[uKey] = 0; + } + LogFlowFunc(("Done releasing keys\n")); } @@ -1118,9 +1167,9 @@ static DECLCALLBACK(void) PS2KDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, vo * @param pHlp Callback functions for doing output. * @param pszArgs Argument string. Optional and specific to the handler. */ -static DECLCALLBACK(void) PS2KInfoState(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) +static DECLCALLBACK(void) ps2kInfoState(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) { - PPS2K pThis = GetPS2KFromDevIns(pDevIns); + PPS2K pThis = KBDGetPS2KFromDevIns(pDevIns); NOREF(pszArgs); pHlp->pfnPrintf(pHlp, "PS/2 Keyboard: scan set %d, scanning %s\n", @@ -1144,7 +1193,7 @@ static DECLCALLBACK(void) PS2KInfoState(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, /** * @interface_method_impl{PDMIBASE,pfnQueryInterface} */ -static DECLCALLBACK(void *) PS2KQueryInterface(PPDMIBASE pInterface, const char *pszIID) +static DECLCALLBACK(void *) ps2kQueryInterface(PPDMIBASE pInterface, const char *pszIID) { PPS2K pThis = RT_FROM_MEMBER(pInterface, PS2K, Keyboard.IBase); PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Keyboard.IBase); @@ -1159,13 +1208,12 @@ static DECLCALLBACK(void *) PS2KQueryInterface(PPDMIBASE pInterface, const char * Keyboard event handler. * * @returns VBox status code. - * @param pInterface Pointer to the keyboard port interface (KBDState::Keyboard.IPort). + * @param pThis The PS2 keyboard instance data. * @param u32Usage USB HID usage code with key * press/release flag. */ -static DECLCALLBACK(int) PS2KPutEvent(PPDMIKEYBOARDPORT pInterface, uint32_t u32Usage) +static int ps2kPutEventWorker(PPS2K pThis, uint32_t u32Usage) { - PPS2K pThis = RT_FROM_MEMBER(pInterface, PS2K, Keyboard.IPort); uint8_t u8HidCode; bool fKeyDown; bool fHaveEvent = true; @@ -1195,28 +1243,49 @@ static DECLCALLBACK(int) PS2KPutEvent(PPDMIKEYBOARDPORT pInterface, uint32_t u32 /* Unless this is a new key press/release, don't even bother. */ if (fHaveEvent) { - rc = PDMCritSectEnter(&pThis->KbdCritSect, VERR_SEM_BUSY); + rc = PDMCritSectEnter(pThis->pCritSectR3, VERR_SEM_BUSY); AssertReleaseRC(rc); - rc = PS2KProcessKeyEvent(pThis, u8HidCode, fKeyDown); + rc = psk2ProcessKeyEvent(pThis, u8HidCode, fKeyDown); - PDMCritSectLeave(&pThis->KbdCritSect); + PDMCritSectLeave(pThis->pCritSectR3); } return rc; } -static DECLCALLBACK(int) PS2KPutEventWrapper(PPDMIKEYBOARDPORT pInterface, uint8_t u8KeyCode) +static DECLCALLBACK(int) ps2kPutEventWrapper(PPDMIKEYBOARDPORT pInterface, uint8_t u8KeyCode) { PPS2K pThis = RT_FROM_MEMBER(pInterface, PS2K, Keyboard.IPort); uint32_t u32Usage = 0; + int rc; + + LogFlowFunc(("key code %02X\n", u8KeyCode)); - LogFlowFunc(("key code %02X\n", u8KeyCode )); - pThis->XlatState = ScancodeToHidUsage(pThis->XlatState, u8KeyCode, &u32Usage); + /* The 'BAT fail' scancode is reused as a signal to release keys. No actual + * key is allowed to use this scancode. + */ + if (RT_UNLIKELY(u8KeyCode == KRSP_BAT_FAIL)) + { + rc = PDMCritSectEnter(pThis->pCritSectR3, VERR_SEM_BUSY); + AssertReleaseRC(rc); + + ps2kReleaseKeys(pThis); - if (pThis->XlatState == SS_IDLE) + PDMCritSectLeave(pThis->pCritSectR3); + } + else { - PS2KPutEvent(pInterface, u32Usage); + pThis->XlatState = ScancodeToHidUsage(pThis->XlatState, u8KeyCode, &u32Usage); + + if (pThis->XlatState == SS_IDLE) + { + /* Stupid Korean key hack: convert a lone break key into a press/release sequence. */ + if (u32Usage == 0x80000090 || u32Usage == 0x80000091) + ps2kPutEventWorker(pThis, u32Usage & ~0x80000000); + + ps2kPutEventWorker(pThis, u32Usage); + } } return VINF_SUCCESS; @@ -1233,11 +1302,12 @@ static DECLCALLBACK(int) PS2KPutEventWrapper(PPDMIKEYBOARDPORT pInterface, uint8 * system. * * @returns VBox status code. + * @param pThis The PS/2 keyboard instance data. * @param pDevIns The device instance. * @param iLUN The logical unit which is being detached. * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines. */ -int PS2KAttach(PPDMDEVINS pDevIns, PPS2K pThis, unsigned iLUN, uint32_t fFlags) +int PS2KAttach(PPS2K pThis, PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags) { int rc; @@ -1270,7 +1340,7 @@ int PS2KAttach(PPDMDEVINS pDevIns, PPS2K pThis, unsigned iLUN, uint32_t fFlags) return rc; } -void PS2KSaveState(PSSMHANDLE pSSM, PPS2K pThis) +void PS2KSaveState(PPS2K pThis, PSSMHANDLE pSSM) { uint32_t cPressed = 0; uint32_t cbTMSSize = 0; @@ -1289,8 +1359,8 @@ void PS2KSaveState(PSSMHANDLE pSSM, PPS2K pThis) SSMR3PutBool(pSSM, pThis->fScanning); /* Save the command and keystroke queues. */ - PS2SaveQueue(pSSM, (GeneriQ *)&pThis->cmdQ); - PS2SaveQueue(pSSM, (GeneriQ *)&pThis->keyQ); + ps2kSaveQueue(pSSM, (GeneriQ *)&pThis->cmdQ); + ps2kSaveQueue(pSSM, (GeneriQ *)&pThis->keyQ); /* Save the command delay timer. Note that the typematic repeat * timer is *not* saved. @@ -1306,16 +1376,16 @@ void PS2KSaveState(PSSMHANDLE pSSM, PPS2K pThis) SSMR3PutU32(pSSM, cPressed); - for (unsigned i = 0; i < sizeof(pThis->abDepressedKeys); ++i) - if (pThis->abDepressedKeys[i]) - SSMR3PutU8(pSSM, pThis->abDepressedKeys[i]); + for (unsigned uKey = 0; uKey < sizeof(pThis->abDepressedKeys); ++uKey) + if (pThis->abDepressedKeys[uKey]) + SSMR3PutU8(pSSM, uKey); /* Save the typematic settings for Scan Set 3. */ SSMR3PutU32(pSSM, cbTMSSize); /* Currently not implemented. */ } -int PS2KLoadState(PSSMHANDLE pSSM, PPS2K pThis, uint32_t uVersion) +int PS2KLoadState(PPS2K pThis, PSSMHANDLE pSSM, uint32_t uVersion) { uint8_t u8; uint32_t cPressed; @@ -1337,43 +1407,56 @@ int PS2KLoadState(PSSMHANDLE pSSM, PPS2K pThis, uint32_t uVersion) SSMR3GetBool(pSSM, &pThis->fNumLockOn); SSMR3GetBool(pSSM, &pThis->fScanning); - do { - /* Load the command and keystroke queues. */ - rc = PS2LoadQueue(pSSM, (GeneriQ *)&pThis->cmdQ); - if (RT_FAILURE(rc)) break; - rc = PS2LoadQueue(pSSM, (GeneriQ *)&pThis->keyQ); - if (RT_FAILURE(rc)) break; + /* Load the command and keystroke queues. */ + rc = ps2kLoadQueue(pSSM, (GeneriQ *)&pThis->cmdQ); + AssertRCReturn(rc, rc); + rc = ps2kLoadQueue(pSSM, (GeneriQ *)&pThis->keyQ); + AssertRCReturn(rc, rc); - /* Load the command delay timer, just in case. */ - rc = TMR3TimerLoad(pThis->CTX_SUFF(pKbdDelayTimer), pSSM); - if (RT_FAILURE(rc)) break; + /* Load the command delay timer, just in case. */ + rc = TMR3TimerLoad(pThis->CTX_SUFF(pKbdDelayTimer), pSSM); + AssertRCReturn(rc, rc); - /* Fake key up events for keys that were held down at the time the state was saved. */ - rc = SSMR3GetU32(pSSM, &cPressed); - if (RT_FAILURE(rc)) break; + /* Recalculate the typematic delay/rate. */ + ps2kSetupTypematic(pThis, pThis->u8Typematic); - while (cPressed--) + /* Fake key up events for keys that were held down at the time the state was saved. */ + rc = SSMR3GetU32(pSSM, &cPressed); + AssertRCReturn(rc, rc); + + /* If any keys were down, load and then release them. */ + if (cPressed) + { + for (unsigned i = 0; i < cPressed; ++i) { rc = SSMR3GetU8(pSSM, &u8); - if (RT_FAILURE(rc)) break; - PS2KProcessKeyEvent(pThis, u8, false /* key up */); + AssertRCReturn(rc, rc); + pThis->abDepressedKeys[u8] = 1; } - if (RT_FAILURE(rc)) break; + } - /* Load typematic settings for Scan Set 3. */ - rc = SSMR3GetU32(pSSM, &cbTMSSize); - if (RT_FAILURE(rc)) break; + /* Load typematic settings for Scan Set 3. */ + rc = SSMR3GetU32(pSSM, &cbTMSSize); + AssertRCReturn(rc, rc); - while (cbTMSSize--) - { - rc = SSMR3GetU8(pSSM, &u8); - if (RT_FAILURE(rc)) break; - } - } while (0); + while (cbTMSSize--) + { + rc = SSMR3GetU8(pSSM, &u8); + AssertRCReturn(rc, rc); + } return rc; } +int PS2KLoadDone(PPS2K pThis, PSSMHANDLE pSSM) +{ + /* This *must* be done after the inital load because it may trigger + * interrupts and change the interrupt controller state. + */ + ps2kReleaseKeys(pThis); + return VINF_SUCCESS; +} + void PS2KReset(PPS2K pThis) { LogFlowFunc(("Resetting PS2K\n")); @@ -1387,15 +1470,15 @@ void PS2KReset(PPS2K pThis) /* Clear queues and any pressed keys. */ memset(pThis->abDepressedKeys, 0, sizeof(pThis->abDepressedKeys)); - PS2ClearQueue((GeneriQ *)&pThis->cmdQ); - PS2KSetDefaults(pThis); /* Also clears keystroke queue. */ + ps2kClearQueue((GeneriQ *)&pThis->cmdQ); + ps2kSetDefaults(pThis); /* Also clears keystroke queue. */ /* Activate the PS/2 keyboard by default. */ if (pThis->Keyboard.pDrv) pThis->Keyboard.pDrv->pfnSetActive(pThis->Keyboard.pDrv, true); } -void PS2KRelocate(PPS2K pThis, RTGCINTPTR offDelta) +void PS2KRelocate(PPS2K pThis, RTGCINTPTR offDelta, PPDMDEVINS pDevIns) { LogFlowFunc(("Relocating PS2K\n")); pThis->pKbdDelayTimerRC = TMTimerRCPtr(pThis->pKbdDelayTimerR3); @@ -1403,7 +1486,7 @@ void PS2KRelocate(PPS2K pThis, RTGCINTPTR offDelta) NOREF(offDelta); } -int PS2KConstruct(PPDMDEVINS pDevIns, PPS2K pThis, void *pParent, int iInstance) +int PS2KConstruct(PPS2K pThis, PPDMDEVINS pDevIns, void *pParent, int iInstance) { int rc; @@ -1415,23 +1498,21 @@ int PS2KConstruct(PPDMDEVINS pDevIns, PPS2K pThis, void *pParent, int iInstance) pThis->keyQ.cSize = KBD_KEY_QUEUE_SIZE; pThis->cmdQ.cSize = KBD_CMD_QUEUE_SIZE; - pThis->Keyboard.IBase.pfnQueryInterface = PS2KQueryInterface; - pThis->Keyboard.IPort.pfnPutEvent = PS2KPutEventWrapper; + pThis->Keyboard.IBase.pfnQueryInterface = ps2kQueryInterface; + pThis->Keyboard.IPort.pfnPutEvent = ps2kPutEventWrapper; /* - * Initialize the critical section. + * Initialize the critical section pointer(s). */ - rc = PDMDevHlpCritSectInit(pDevIns, &pThis->KbdCritSect, RT_SRC_POS, "PS2K#%u", iInstance); - if (RT_FAILURE(rc)) - return rc; + pThis->pCritSectR3 = pDevIns->pCritSectRoR3; /* * Create the typematic delay/repeat timer. Does not use virtual time! */ PTMTIMER pTimer; - rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_REAL, PS2KTypematicTimer, pThis, - TMTIMER_FLAGS_NO_CRIT_SECT, "PS2K Typematic Timer", &pTimer); - if (RT_FAILURE (rc)) + rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_REAL, ps2kTypematicTimer, pThis, + TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "PS2K Typematic Timer", &pTimer); + if (RT_FAILURE(rc)) return rc; pThis->pKbdTypematicTimerR3 = pTimer; @@ -1441,9 +1522,9 @@ int PS2KConstruct(PPDMDEVINS pDevIns, PPS2K pThis, void *pParent, int iInstance) /* * Create the command delay timer. */ - rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, PS2KDelayTimer, pThis, - TMTIMER_FLAGS_NO_CRIT_SECT, "PS2K Delay Timer", &pTimer); - if (RT_FAILURE (rc)) + rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ps2kDelayTimer, pThis, + TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "PS2K Delay Timer", &pTimer); + if (RT_FAILURE(rc)) return rc; pThis->pKbdDelayTimerR3 = pTimer; @@ -1453,14 +1534,14 @@ int PS2KConstruct(PPDMDEVINS pDevIns, PPS2K pThis, void *pParent, int iInstance) /* * Register debugger info callbacks. */ - PDMDevHlpDBGFInfoRegister(pDevIns, "ps2k", "Display PS/2 keyboard state.", PS2KInfoState); + PDMDevHlpDBGFInfoRegister(pDevIns, "ps2k", "Display PS/2 keyboard state.", ps2kInfoState); return rc; } #endif -//@todo: The following should live with the KBC implementation. +///@todo The following should live with the KBC implementation. /* Table used by the keyboard controller to optionally translate the incoming * keyboard data. Note that the translation is designed for essentially taking |