VirtualBox

Changeset 71351 in vbox


Ignore:
Timestamp:
Mar 15, 2018 1:26:21 PM (7 years ago)
Author:
vboxsync
Message:

PS2K: Throttle keyboard input to satisfy questionable software (see bugref:4118:51).

Location:
trunk/src/VBox/Devices
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Input/DevPS2.cpp

    r69704 r71351  
    963963     * Validate and read the configuration.
    964964     */
    965     if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0R0Enabled\0"))
     965    if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0R0Enabled\0KbdThrottleEnabled\0"))
    966966        return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
    967967    rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
     
    981981    pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
    982982
    983     rc = PS2KConstruct(&pThis->Kbd, pDevIns, pThis, iInstance);
     983    rc = PS2KConstruct(&pThis->Kbd, pDevIns, pThis, iInstance, pCfg);
    984984    if (RT_FAILURE(rc))
    985985        return rc;
  • trunk/src/VBox/Devices/Input/PS2Dev.h

    r69500 r71351  
    4646int  PS2KByteFromKbd(PPS2K pThis, uint8_t *pVal);
    4747
    48 int  PS2KConstruct(PPS2K pThis, PPDMDEVINS pDevIns, void *pParent, int iInstance);
     48int  PS2KConstruct(PPS2K pThis, PPDMDEVINS pDevIns, void *pParent, int iInstance, PCFGMNODE pCfg);
    4949int  PS2KAttach(PPS2K pThis, PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags);
    5050void PS2KReset(PPS2K pThis);
  • trunk/src/VBox/Devices/Input/PS2K.cpp

    r69500 r71351  
    3030 *    However, Num Lock is not and the keyboard internally tracks its state.
    3131 *  - The way Print Screen works in scan set 1/2 is totally insane.
     32 *  - A PS/2 keyboard can send at most 1,000 to 1,500 bytes per second. There is
     33 *    software which relies on that fact and assumes that a scan code can be
     34 *    read twice before the next scan code comes in.
    3235 */
    3336
     
    112115#define KBD_DFL_RATE_DELAY  0x2B
    113116
     117/* Input throttling delay in milliseconds. */
     118#define KBD_THROTTLE_DELAY  1
     119
    114120/** Define a simple PS/2 input device queue. */
    115121#define DEF_PS2Q_TYPE(name, size)   \
     
    132138*   Structures and Typedefs                                                                                                      *
    133139*********************************************************************************************************************************/
    134 
    135 /** Scancode translator state.  */
    136 typedef enum {
    137     SS_IDLE,    /**< Starting state. */
    138     SS_EXT,     /**< E0 byte was received. */
    139     SS_EXT1     /**< E1 byte was received. */
    140 } scan_state_t;
    141140
    142141/** Typematic state. */
     
    188187    /** Typematic repeat period in milliseconds. */
    189188    unsigned            uTypematicRepeat;
    190 #if HC_ARCH_BITS == 32
    191     uint32_t            Alignment0;
    192 #endif
     189    /** Set if the throttle delay is currently active. */
     190    bool                fThrottleActive;
     191    /** Set if the input rate should be throttled. */
     192    bool                fThrottleEnabled;
     193
     194    uint8_t             Alignment0[2];
    193195
    194196    /** Command delay timer - RC Ptr. */
     
    196198    /** Typematic timer - RC Ptr. */
    197199    PTMTIMERRC          pKbdTypematicTimerRC;
     200    /** Input throttle timer - RC Ptr. */
     201    PTMTIMERRC          pThrottleTimerRC;
    198202
    199203    /** The device critical section protecting everything - R3 Ptr */
    200204    R3PTRTYPE(PPDMCRITSECT) pCritSectR3;
     205
    201206    /** Command delay timer - R3 Ptr. */
    202207    PTMTIMERR3          pKbdDelayTimerR3;
    203208    /** Typematic timer - R3 Ptr. */
    204209    PTMTIMERR3          pKbdTypematicTimerR3;
    205     RTR3PTR             Alignment2;
     210    /** Input throttle timer - R3 Ptr. */
     211    PTMTIMERR3          pThrottleTimerR3;
    206212
    207213    /** Command delay timer - R0 Ptr. */
     
    209215    /** Typematic timer - R0 Ptr. */
    210216    PTMTIMERR0          pKbdTypematicTimerR0;
    211 
    212     scan_state_t        XlatState;      /// @todo temporary
    213     uint32_t            Alignment1;
     217    /** Input throttle timer - R0 Ptr. */
     218    PTMTIMERR0          pThrottleTimerR0;
    214219
    215220    /**
     
    576581
    577582}
     583
     584/**
     585 * Query the number of items currently in a queue.
     586 *
     587 * @param   pQ                  Pointer to the queue.
     588 *
     589 * @return  uint32_t            Number of items in queue.
     590 */
     591static uint32_t ps2kInQueue(GeneriQ *pQ)
     592{
     593    return pQ->cUsed;
     594}
     595
    578596#endif /* IN_RING3 */
    579597
     
    785803    rc = ps2kRemoveQueue((GeneriQ *)&pThis->cmdQ, pb);
    786804    if (rc != VINF_SUCCESS && !pThis->u8CurrCmd && pThis->fScanning)
    787         rc = ps2kRemoveQueue((GeneriQ *)&pThis->keyQ, pb);
     805        if (!pThis->fThrottleActive)
     806        {
     807            rc = ps2kRemoveQueue((GeneriQ *)&pThis->keyQ, pb);
     808            if (pThis->fThrottleEnabled) {
     809                pThis->fThrottleActive = true;
     810                TMTimerSetMillies(pThis->CTX_SUFF(pThrottleTimer), KBD_THROTTLE_DELAY);
     811            }
     812        }
    788813
    789814    LogFlowFunc(("keyboard sends 0x%02x (%svalid data)\n", *pb, rc == VINF_SUCCESS ? "" : "not "));
     
    10071032}
    10081033
     1034/* Throttling timer to emulate the finite keyboard communication speed. A PS/2 keyboard is
     1035 * limited by the serial link speed and cannot send much more than 1,000 bytes per second.
     1036 * Some software (notably Borland Pascal and programs built with its run-time) relies on
     1037 * being able to read an incoming scan-code twice. Throttling the data rate enables such
     1038 * software to function, while human typists cannot tell any difference.
     1039 *
     1040 * Note: The throttling is currently only done for keyboard data, not command responses.
     1041 * The throttling could and perhaps should be done for any data (including command
     1042 * response) scoming from PS/2 devices, both keyboard and auxiliary. That is not currently
     1043 * done because it would needlessly slow things down.
     1044 */
     1045static DECLCALLBACK(void) ps2kThrottleTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
     1046{
     1047    RT_NOREF2(pDevIns, pTimer);
     1048    PPS2K       pThis = (PS2K *)pvUser;
     1049    unsigned    uHaveData;
     1050
     1051    /* Grab the lock to avoid races with event delivery or EMTs. */
     1052    int rc = PDMCritSectEnter(pThis->pCritSectR3, VERR_SEM_BUSY);
     1053    AssertReleaseRC(rc);
     1054
     1055    /* If data is available, poke the KBC. Once the data
     1056     * is actually read, the timer may be re-triggered.
     1057     */
     1058    pThis->fThrottleActive = false;
     1059    uHaveData = ps2kInQueue((GeneriQ *)&pThis->keyQ);
     1060    LogFlowFunc(("Have%s bytes\n", uHaveData ? "" : " no"));
     1061    if (uHaveData)
     1062        KBCUpdateInterrupts(pThis->pParent);
     1063
     1064    PDMCritSectLeave(pThis->pCritSectR3);
     1065}
     1066
    10091067/* Timer handler for emulating typematic keys. Note that only the last key
    10101068 * held down repeats (if typematic).
     
    13651423
    13661424    pThis->fScanning         = true;
     1425    pThis->fThrottleActive   = false;
    13671426    pThis->u8ScanSet         = 2;
    13681427    pThis->u8CurrCmd         = 0;
     
    13901449}
    13911450
    1392 int PS2KConstruct(PPS2K pThis, PPDMDEVINS pDevIns, void *pParent, int iInstance)
     1451int PS2KConstruct(PPS2K pThis, PPDMDEVINS pDevIns, void *pParent, int iInstance, PCFGMNODE pCfg)
    13931452{
    13941453    RT_NOREF2(pDevIns, iInstance);
     
    13961455
    13971456    pThis->pParent = pParent;
     1457
     1458    bool fThrottleEnabled;
     1459    int rc = CFGMR3QueryBoolDef(pCfg, "KbdThrottleEnabled", &fThrottleEnabled, true);
     1460    if (RT_FAILURE(rc))
     1461        return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to query \"KbdThrottleEnabled\" from the config"));
     1462    Log(("KbdThrottleEnabled=%u\n", fThrottleEnabled));
     1463    pThis->fThrottleEnabled = fThrottleEnabled;
    13981464
    13991465    /* Initialize the queues. */
     
    14101476
    14111477    /*
     1478     * Create the input rate throttling timer. Does not use virtual time!
     1479     */
     1480    PTMTIMER pTimer;
     1481    rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_REAL, ps2kThrottleTimer, pThis,
     1482                                    TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "PS2K Throttle Timer", &pTimer);
     1483    if (RT_FAILURE(rc))
     1484        return rc;
     1485
     1486    pThis->pThrottleTimerR3 = pTimer;
     1487    pThis->pThrottleTimerR0 = TMTimerR0Ptr(pTimer);
     1488    pThis->pThrottleTimerRC = TMTimerRCPtr(pTimer);
     1489
     1490    /*
    14121491     * Create the typematic delay/repeat timer. Does not use virtual time!
    14131492     */
    1414     PTMTIMER pTimer;
    1415     int rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_REAL, ps2kTypematicTimer, pThis,
    1416                                     TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "PS2K Typematic Timer", &pTimer);
     1493    rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_REAL, ps2kTypematicTimer, pThis,
     1494                                TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "PS2K Typematic Timer", &pTimer);
    14171495    if (RT_FAILURE(rc))
    14181496        return rc;
  • trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp

    r71210 r71351  
    439439    GEN_CHECK_OFF(PS2K, cmdQ);
    440440    GEN_CHECK_OFF(PS2K, uTypematicDelay);
     441    GEN_CHECK_OFF(PS2K, fThrottleActive);
    441442    GEN_CHECK_OFF(PS2K, pKbdDelayTimerRC);
    442443    GEN_CHECK_OFF(PS2K, pKbdDelayTimerR3);
     
    445446    GEN_CHECK_OFF(PS2K, pKbdTypematicTimerR3);
    446447    GEN_CHECK_OFF(PS2K, pKbdTypematicTimerR0);
     448    GEN_CHECK_OFF(PS2K, pThrottleTimerRC);
     449    GEN_CHECK_OFF(PS2K, pThrottleTimerR3);
     450    GEN_CHECK_OFF(PS2K, pThrottleTimerR0);
    447451    GEN_CHECK_OFF(PS2K, pCritSectR3);
    448452    GEN_CHECK_OFF(PS2K, Keyboard.IBase);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette