/** * Receive and process a byte sent by the keyboard controller. * * @param pThis The PS/2 auxiliary device instance data. * @param cmd The command (or data) byte. */ int PS2MByteToAux(PPS2M pThis, uint8_t cmd) { uint8_t u8Val; bool fHandled = true; LogFlowFunc(("cmd=0x%02X, active cmd=0x%02X\n", cmd, pThis->u8CurrCmd)); //LogRel(("aux: cmd=0x%02X, active cmd=0x%02X\n", cmd, pThis->u8CurrCmd)); if (pThis->enmMode == AUX_MODE_RESET) { /* In reset mode, do not respond at all. */ return VINF_SUCCESS; } else if (pThis->enmMode == AUX_MODE_WRAP) { /* In wrap mode, bounce most data right back.*/ if (cmd == ACMD_RESET || cmd == ACMD_RESET_WRAP) ; /* Handle as regular commands. */ else { ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, cmd); return VINF_SUCCESS; } } switch (cmd) { case ACMD_SET_SCALE_11: pThis->u8State &= ~AUX_STATE_SCALING; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_SET_SCALE_21: pThis->u8State |= AUX_STATE_SCALING; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_REQ_STATUS: /* Report current status, sample rate, and resolution. */ //@todo: buttons u8Val = pThis->u8State; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, u8Val); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, pThis->u8Resolution); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, pThis->u8SampleRate); pThis->u8CurrCmd = 0; break; case ACMD_SET_STREAM: pThis->u8State &= ~AUX_STATE_REMOTE; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_RESET_WRAP: pThis->enmMode = AUX_MODE_STD; /* NB: Stream mode reporting remains disabled! */ ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_SET_WRAP: pThis->enmMode = AUX_MODE_WRAP; pThis->u8State &= ~AUX_STATE_ENABLED; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_SET_REMOTE: pThis->u8State |= AUX_STATE_REMOTE; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_READ_ID: ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, pThis->enmProtocol); pThis->u8CurrCmd = 0; break; case ACMD_ENABLE: pThis->u8State |= AUX_STATE_ENABLED; //@todo: R3 only! #ifdef IN_RING3 ps2mSetDriverState(pThis, true); #endif ps2kClearQueue((GeneriQ *)&pThis->evtQ); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_DFLT_DISABLE: ps2mSetDefaults(pThis); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_SET_DEFAULT: ps2mSetDefaults(pThis); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_RESEND: pThis->u8CurrCmd = 0; break; case ACMD_RESET: ps2mSetDefaults(pThis); ///@todo reset more? pThis->u8CurrCmd = cmd; pThis->enmMode = AUX_MODE_RESET; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); /* Slightly delay reset completion; it might take hundreds of ms. */ TMTimerSetMillies(pThis->CTX_SUFF(pDelayTimer), 1); break; /* The following commands need a parameter. */ case ACMD_SET_RES: case ACMD_SET_SAMP_RATE: ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = cmd; break; default: /* Sending a command instead of a parameter starts the new command. */ switch (pThis->u8CurrCmd) { case ACMD_SET_RES: //@todo reject unsupported resolutions pThis->u8Resolution = cmd; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_SET_SAMP_RATE: //@todo reject unsupported rates ps2mSetRate(pThis, cmd); ps2mRateProtocolKnock(pThis, cmd); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; default: fHandled = false; } /* Fall through only to handle unrecognized commands. */ if (fHandled) break; case ACMD_INVALID_1: case ACMD_INVALID_2: case ACMD_INVALID_3: case ACMD_INVALID_4: case ACMD_INVALID_5: case ACMD_INVALID_6: case ACMD_INVALID_7: case ACMD_INVALID_8: case ACMD_INVALID_9: case ACMD_INVALID_10: Log(("Unsupported command 0x%02X!\n", cmd)); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_RESEND); pThis->u8CurrCmd = 0; break; } LogFlowFunc(("Active cmd now 0x%02X; updating interrupts\n", pThis->u8CurrCmd)); // KBCUpdateInterrupts(pThis->pParent); return VINF_SUCCESS; }
/** * Receive and process a byte sent by the keyboard controller. * * @param pThis The PS/2 auxiliary device instance data. * @param cmd The command (or data) byte. */ int PS2MByteToAux(PPS2M pThis, uint8_t cmd) { uint8_t u8Val; bool fHandled = true; LogFlowFunc(("cmd=0x%02X, active cmd=0x%02X\n", cmd, pThis->u8CurrCmd)); //LogRel(("aux: cmd=0x%02X, active cmd=0x%02X\n", cmd, pThis->u8CurrCmd)); if (pThis->enmMode == AUX_MODE_RESET) /* In reset mode, do not respond at all. */ return VINF_SUCCESS; /* If there's anything left in the command response queue, trash it. */ ps2kClearQueue((GeneriQ *)&pThis->cmdQ); if (pThis->enmMode == AUX_MODE_WRAP) { /* In wrap mode, bounce most data right back.*/ if (cmd == ACMD_RESET || cmd == ACMD_RESET_WRAP) ; /* Handle as regular commands. */ else { ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, cmd); return VINF_SUCCESS; } } #ifndef IN_RING3 /* Reset, Enable, and Set Default commands must be run in R3. */ if (cmd == ACMD_RESET || cmd == ACMD_ENABLE || cmd == ACMD_SET_DEFAULT) return VINF_IOM_R3_IOPORT_WRITE; #endif switch (cmd) { case ACMD_SET_SCALE_11: pThis->u8State &= ~AUX_STATE_SCALING; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_SET_SCALE_21: pThis->u8State |= AUX_STATE_SCALING; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_REQ_STATUS: /* Report current status, sample rate, and resolution. */ u8Val = (pThis->u8State & AUX_STATE_EXTERNAL) | (pThis->fCurrB & PS2M_STD_BTN_MASK); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, u8Val); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, pThis->u8Resolution); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, pThis->u8SampleRate); pThis->u8CurrCmd = 0; break; case ACMD_SET_STREAM: pThis->u8State &= ~AUX_STATE_REMOTE; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_READ_REMOTE: ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); ps2mReportAccumulatedEvents(pThis, (GeneriQ *)&pThis->cmdQ, false); pThis->u8CurrCmd = 0; break; case ACMD_RESET_WRAP: pThis->enmMode = AUX_MODE_STD; /* NB: Stream mode reporting remains disabled! */ ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_SET_WRAP: pThis->enmMode = AUX_MODE_WRAP; pThis->u8State &= ~AUX_STATE_ENABLED; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_SET_REMOTE: pThis->u8State |= AUX_STATE_REMOTE; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_READ_ID: ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, pThis->enmProtocol); pThis->u8CurrCmd = 0; break; case ACMD_ENABLE: pThis->u8State |= AUX_STATE_ENABLED; #ifdef IN_RING3 ps2mSetDriverState(pThis, true); #else AssertLogRelMsgFailed(("Invalid ACMD_ENABLE outside R3!\n")); #endif ps2kClearQueue((GeneriQ *)&pThis->evtQ); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_DISABLE: pThis->u8State &= ~AUX_STATE_ENABLED; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_SET_DEFAULT: ps2mSetDefaults(pThis); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; break; case ACMD_RESEND: pThis->u8CurrCmd = 0; break; case ACMD_RESET: ps2mSetDefaults(pThis); /// @todo reset more? pThis->u8CurrCmd = cmd; pThis->enmMode = AUX_MODE_RESET; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); if (pThis->fDelayReset) /* Slightly delay reset completion; it might take hundreds of ms. */ TMTimerSetMillies(pThis->CTX_SUFF(pDelayTimer), 1); else #ifdef IN_RING3 ps2mReset(pThis); #else AssertLogRelMsgFailed(("Invalid ACMD_RESET outside R3!\n")); #endif break; /* The following commands need a parameter. */ case ACMD_SET_RES: case ACMD_SET_SAMP_RATE: ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = cmd; break; default: /* Sending a command instead of a parameter starts the new command. */ switch (pThis->u8CurrCmd) { case ACMD_SET_RES: if (cmd < 4) /* Valid resolutions are 0-3. */ { pThis->u8Resolution = cmd; pThis->u8State &= ~AUX_STATE_RES_ERR; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; } else { /* Bad resolution. Reply with Resend or Error. */ if (pThis->u8State & AUX_STATE_RES_ERR) { pThis->u8State &= ~AUX_STATE_RES_ERR; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ERROR); pThis->u8CurrCmd = 0; } else { pThis->u8State |= AUX_STATE_RES_ERR; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_RESEND); /* NB: Current command remains unchanged. */ } } break; case ACMD_SET_SAMP_RATE: if (ps2mIsRateSupported(cmd)) { pThis->u8State &= ~AUX_STATE_RATE_ERR; ps2mSetRate(pThis, cmd); ps2mRateProtocolKnock(pThis, cmd); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ACK); pThis->u8CurrCmd = 0; } else { /* Bad rate. Reply with Resend or Error. */ if (pThis->u8State & AUX_STATE_RATE_ERR) { pThis->u8State &= ~AUX_STATE_RATE_ERR; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_ERROR); pThis->u8CurrCmd = 0; } else { pThis->u8State |= AUX_STATE_RATE_ERR; ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_RESEND); /* NB: Current command remains unchanged. */ } } break; default: fHandled = false; } /* Fall through only to handle unrecognized commands. */ if (fHandled) break; case ACMD_INVALID_1: case ACMD_INVALID_2: case ACMD_INVALID_3: case ACMD_INVALID_4: case ACMD_INVALID_5: case ACMD_INVALID_6: case ACMD_INVALID_7: case ACMD_INVALID_8: case ACMD_INVALID_9: case ACMD_INVALID_10: Log(("Unsupported command 0x%02X!\n", cmd)); ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, ARSP_RESEND); pThis->u8CurrCmd = 0; break; } LogFlowFunc(("Active cmd now 0x%02X; updating interrupts\n", pThis->u8CurrCmd)); // KBCUpdateInterrupts(pThis->pParent); return VINF_SUCCESS; }