void Mouse::fireMultiTouchEvent(uint8_t cContacts, const LONG64 *paContacts, uint32_t u32ScanTime) { com::SafeArray<SHORT> xPositions(cContacts); com::SafeArray<SHORT> yPositions(cContacts); com::SafeArray<USHORT> contactIds(cContacts); com::SafeArray<USHORT> contactFlags(cContacts); uint8_t i; for (i = 0; i < cContacts; i++) { uint32_t u32Lo = RT_LO_U32(paContacts[i]); uint32_t u32Hi = RT_HI_U32(paContacts[i]); xPositions[i] = (int16_t)u32Lo; yPositions[i] = (int16_t)(u32Lo >> 16); contactIds[i] = RT_BYTE1(u32Hi); contactFlags[i] = RT_BYTE2(u32Hi); } VBoxEventDesc evDesc; evDesc.init(mEventSource, VBoxEventType_OnGuestMultiTouch, cContacts, ComSafeArrayAsInParam(xPositions), ComSafeArrayAsInParam(yPositions), ComSafeArrayAsInParam(contactIds), ComSafeArrayAsInParam(contactFlags), u32ScanTime); evDesc.fire(0); }
/* Used by PutEventMultiTouch and PutEventMultiTouchString. */ HRESULT Mouse::putEventMultiTouch(LONG aCount, LONG64 *paContacts, ULONG aScanTime) { if (aCount >= 256) { return E_INVALIDARG; } DisplayMouseInterface *pDisplay = mParent->getDisplayMouseInterface(); ComAssertRet(pDisplay, E_FAIL); HRESULT rc = S_OK; uint64_t* pau64Contacts = NULL; uint8_t cContacts = 0; /* Deliver 0 contacts too, touch device may use this to reset the state. */ if (aCount > 0) { /* Create a copy with converted coords. */ pau64Contacts = (uint64_t *)RTMemTmpAlloc(aCount * sizeof(uint64_t)); if (pau64Contacts) { int32_t x1, y1, x2, y2; /* Takes the display lock */ pDisplay->getFramebufferDimensions(&x1, &y1, &x2, &y2); LONG i; for (i = 0; i < aCount; i++) { uint32_t u32Lo = RT_LO_U32(paContacts[i]); uint32_t u32Hi = RT_HI_U32(paContacts[i]); int32_t x = (int16_t)u32Lo; int32_t y = (int16_t)(u32Lo >> 16); uint8_t contactId = RT_BYTE1(u32Hi); bool fInContact = (RT_BYTE2(u32Hi) & 0x1) != 0; bool fInRange = (RT_BYTE2(u32Hi) & 0x2) != 0; LogRel3(("%s: [%d] %d,%d id %d, inContact %d, inRange %d\n", __FUNCTION__, i, x, y, contactId, fInContact, fInRange)); /* Framebuffer dimensions are 0,0 width, height, that is x2,y2 are exclusive, * while coords are inclusive. */ int32_t xAdj = x1 < x2 ? ((x - 1 - x1) * VMMDEV_MOUSE_RANGE) / (x2 - x1) : 0; int32_t yAdj = y1 < y2 ? ((y - 1 - y1) * VMMDEV_MOUSE_RANGE) / (y2 - y1) : 0; bool fValid = ( xAdj >= VMMDEV_MOUSE_RANGE_MIN && xAdj <= VMMDEV_MOUSE_RANGE_MAX && yAdj >= VMMDEV_MOUSE_RANGE_MIN && yAdj <= VMMDEV_MOUSE_RANGE_MAX); if (fValid) { uint8_t fu8 = (fInContact? 0x01: 0x00) | (fInRange? 0x02: 0x00); pau64Contacts[cContacts] = RT_MAKE_U64_FROM_U16((uint16_t)xAdj, (uint16_t)yAdj, RT_MAKE_U16(contactId, fu8), 0); cContacts++; } } } else {
/* Used by PutEventMultiTouch and PutEventMultiTouchString. */ HRESULT Mouse::putEventMultiTouch(LONG aCount, LONG64 *paContacts, ULONG aScanTime) { if (aCount >= 256) { return E_INVALIDARG; } DisplayMouseInterface *pDisplay = mParent->getDisplayMouseInterface(); ComAssertRet(pDisplay, E_FAIL); /* Touch events are mapped to the primary monitor, because the emulated USB * touchscreen device is associated with one (normally the primary) screen in the guest. */ ULONG uScreenId = 0; ULONG cWidth = 0; ULONG cHeight = 0; LONG xOrigin = 0; LONG yOrigin = 0; HRESULT rc = pDisplay->getScreenResolution(uScreenId, &cWidth, &cHeight, NULL, &xOrigin, &yOrigin); ComAssertComRCRetRC(rc); uint64_t* pau64Contacts = NULL; uint8_t cContacts = 0; /* Deliver 0 contacts too, touch device may use this to reset the state. */ if (aCount > 0) { /* Create a copy with converted coords. */ pau64Contacts = (uint64_t *)RTMemTmpAlloc(aCount * sizeof(uint64_t)); if (pau64Contacts) { int32_t x1 = xOrigin; int32_t y1 = yOrigin; int32_t x2 = x1 + cWidth; int32_t y2 = y1 + cHeight; LogRel3(("%s: screen [%d] %d,%d %d,%d\n", __FUNCTION__, uScreenId, x1, y1, x2, y2)); LONG i; for (i = 0; i < aCount; i++) { uint32_t u32Lo = RT_LO_U32(paContacts[i]); uint32_t u32Hi = RT_HI_U32(paContacts[i]); int32_t x = (int16_t)u32Lo; int32_t y = (int16_t)(u32Lo >> 16); uint8_t contactId = RT_BYTE1(u32Hi); bool fInContact = (RT_BYTE2(u32Hi) & 0x1) != 0; bool fInRange = (RT_BYTE2(u32Hi) & 0x2) != 0; LogRel3(("%s: [%d] %d,%d id %d, inContact %d, inRange %d\n", __FUNCTION__, i, x, y, contactId, fInContact, fInRange)); /* x1,y1 are inclusive and x2,y2 are exclusive, * while x,y start from 1 and are inclusive. */ if (x <= x1 || x > x2 || y <= y1 || y > y2) { /* Out of range. Skip the contact. */ continue; } int32_t xAdj = x1 < x2? ((x - 1 - x1) * VMMDEV_MOUSE_RANGE) / (x2 - x1) : 0; int32_t yAdj = y1 < y2? ((y - 1 - y1) * VMMDEV_MOUSE_RANGE) / (y2 - y1) : 0; bool fValid = ( xAdj >= VMMDEV_MOUSE_RANGE_MIN && xAdj <= VMMDEV_MOUSE_RANGE_MAX && yAdj >= VMMDEV_MOUSE_RANGE_MIN && yAdj <= VMMDEV_MOUSE_RANGE_MAX); if (fValid) { uint8_t fu8 = (fInContact? 0x01: 0x00) | (fInRange? 0x02: 0x00); pau64Contacts[cContacts] = RT_MAKE_U64_FROM_U16((uint16_t)xAdj, (uint16_t)yAdj, RT_MAKE_U16(contactId, fu8), 0); cContacts++; } } } else {
/** * 32-bit write to a config register. * * @returns Strict VBox status code. * * @param pThis The HPET state. * @param idxReg The register being written to. * @param u32NewValue The value being written. * * @remarks The caller should not hold the device lock, unless it also holds * the TM lock. */ static int hpetConfigRegWrite32(HPET *pThis, uint32_t idxReg, uint32_t u32NewValue) { Assert(!PDMCritSectIsOwner(&pThis->CritSect) || TMTimerIsLockOwner(pThis->aTimers[0].CTX_SUFF(pTimer))); int rc = VINF_SUCCESS; switch (idxReg) { case HPET_ID: case HPET_ID + 4: { Log(("write HPET_ID, useless\n")); break; } case HPET_CFG: { DEVHPET_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); uint32_t const iOldValue = (uint32_t)(pThis->u64HpetConfig); Log(("write HPET_CFG: %x (old %x)\n", u32NewValue, iOldValue)); /* * This check must be here, before actual update, as hpetLegacyMode * may request retry in R3 - so we must keep state intact. */ if ( ((iOldValue ^ u32NewValue) & HPET_CFG_LEGACY) && pThis->pHpetHlpR3 != NIL_RTR3PTR) { #ifdef IN_RING3 rc = pThis->pHpetHlpR3->pfnSetLegacyMode(pThis->pDevInsR3, RT_BOOL(u32NewValue & HPET_CFG_LEGACY)); if (rc != VINF_SUCCESS) #else rc = VINF_IOM_R3_MMIO_WRITE; #endif { DEVHPET_UNLOCK_BOTH(pThis); break; } } pThis->u64HpetConfig = hpetUpdateMasked(u32NewValue, iOldValue, HPET_CFG_WRITE_MASK); uint32_t const cTimers = HPET_CAP_GET_TIMERS(pThis->u32Capabilities); if (hpetBitJustSet(iOldValue, u32NewValue, HPET_CFG_ENABLE)) { /** @todo Only get the time stamp once when reprogramming? */ /* Enable main counter and interrupt generation. */ pThis->u64HpetOffset = hpetTicksToNs(pThis, pThis->u64HpetCounter) - TMTimerGet(pThis->aTimers[0].CTX_SUFF(pTimer)); for (uint32_t i = 0; i < cTimers; i++) if (pThis->aTimers[i].u64Cmp != hpetInvalidValue(&pThis->aTimers[i])) hpetProgramTimer(&pThis->aTimers[i]); } else if (hpetBitJustCleared(iOldValue, u32NewValue, HPET_CFG_ENABLE)) { /* Halt main counter and disable interrupt generation. */ pThis->u64HpetCounter = hpetGetTicks(pThis); for (uint32_t i = 0; i < cTimers; i++) TMTimerStop(pThis->aTimers[i].CTX_SUFF(pTimer)); } DEVHPET_UNLOCK_BOTH(pThis); break; } case HPET_CFG + 4: { DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); pThis->u64HpetConfig = hpetUpdateMasked((uint64_t)u32NewValue << 32, pThis->u64HpetConfig, UINT64_C(0xffffffff00000000)); Log(("write HPET_CFG + 4: %x -> %#llx\n", u32NewValue, pThis->u64HpetConfig)); DEVHPET_UNLOCK(pThis); break; } case HPET_STATUS: { DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); /* Clear ISR for all set bits in u32NewValue, see p. 14 of the HPET spec. */ pThis->u64Isr &= ~((uint64_t)u32NewValue); Log(("write HPET_STATUS: %x -> ISR=%#llx\n", u32NewValue, pThis->u64Isr)); DEVHPET_UNLOCK(pThis); break; } case HPET_STATUS + 4: { Log(("write HPET_STATUS + 4: %x\n", u32NewValue)); if (u32NewValue != 0) { static unsigned s_cOccurrences = 0; if (s_cOccurrences++ < 10) LogRel(("Writing HPET_STATUS + 4 with non-zero, ignored\n")); } break; } case HPET_COUNTER: { DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); pThis->u64HpetCounter = RT_MAKE_U64(u32NewValue, RT_HI_U32(pThis->u64HpetCounter)); Log(("write HPET_COUNTER: %#x -> %llx\n", u32NewValue, pThis->u64HpetCounter)); DEVHPET_UNLOCK(pThis); break; } case HPET_COUNTER + 4: { DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); pThis->u64HpetCounter = RT_MAKE_U64(RT_LO_U32(pThis->u64HpetCounter), u32NewValue); Log(("write HPET_COUNTER + 4: %#x -> %llx\n", u32NewValue, pThis->u64HpetCounter)); DEVHPET_UNLOCK(pThis); break; } default: { static unsigned s_cOccurences = 0; if (s_cOccurences++ < 10) LogRel(("invalid HPET config write: %x\n", idxReg)); break; } } return rc; }
/** * 32-bit write to a HPET timer register. * * @returns Strict VBox status code. * * @param pThis The HPET state. * @param idxReg The register being written to. * @param u32NewValue The value being written. * * @remarks The caller should not hold the device lock, unless it also holds * the TM lock. */ static int hpetTimerRegWrite32(HPET *pThis, uint32_t iTimerNo, uint32_t iTimerReg, uint32_t u32NewValue) { Assert(!PDMCritSectIsOwner(&pThis->CritSect) || TMTimerIsLockOwner(pThis->aTimers[0].CTX_SUFF(pTimer))); if ( iTimerNo >= HPET_CAP_GET_TIMERS(pThis->u32Capabilities) || iTimerNo >= RT_ELEMENTS(pThis->aTimers) ) /* Parfait - see above. */ { static unsigned s_cOccurences = 0; if (s_cOccurences++ < 10) LogRel(("HPET: using timer above configured range: %d\n", iTimerNo)); return VINF_SUCCESS; } HPETTIMER *pHpetTimer = &pThis->aTimers[iTimerNo]; switch (iTimerReg) { case HPET_TN_CFG: { DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); uint64_t u64Mask = HPET_TN_CFG_WRITE_MASK; Log(("write HPET_TN_CFG: %d: %x\n", iTimerNo, u32NewValue)); if (pHpetTimer->u64Config & HPET_TN_PERIODIC_CAP) u64Mask |= HPET_TN_PERIODIC; if (pHpetTimer->u64Config & HPET_TN_SIZE_CAP) u64Mask |= HPET_TN_32BIT; else u32NewValue &= ~HPET_TN_32BIT; if (u32NewValue & HPET_TN_32BIT) { Log(("setting timer %d to 32-bit mode\n", iTimerNo)); pHpetTimer->u64Cmp = (uint32_t)pHpetTimer->u64Cmp; pHpetTimer->u64Period = (uint32_t)pHpetTimer->u64Period; } if ((u32NewValue & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_LEVEL) { static unsigned s_cOccurences = 0; if (s_cOccurences++ < 10) LogRel(("level-triggered config not yet supported\n")); AssertFailed(); } /* We only care about lower 32-bits so far */ pHpetTimer->u64Config = hpetUpdateMasked(u32NewValue, pHpetTimer->u64Config, u64Mask); DEVHPET_UNLOCK(pThis); break; } case HPET_TN_CFG + 4: /* Interrupt capabilities - read only. */ { Log(("write HPET_TN_CFG + 4, useless\n")); break; } case HPET_TN_CMP: /* lower bits of comparator register */ { DEVHPET_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); Log(("write HPET_TN_CMP on %d: %#x\n", iTimerNo, u32NewValue)); if (pHpetTimer->u64Config & HPET_TN_PERIODIC) pHpetTimer->u64Period = RT_MAKE_U64(u32NewValue, RT_HI_U32(pHpetTimer->u64Period)); pHpetTimer->u64Cmp = RT_MAKE_U64(u32NewValue, RT_HI_U32(pHpetTimer->u64Cmp)); pHpetTimer->u64Config &= ~HPET_TN_SETVAL; Log2(("after HPET_TN_CMP cmp=%#llx per=%#llx\n", pHpetTimer->u64Cmp, pHpetTimer->u64Period)); if (pThis->u64HpetConfig & HPET_CFG_ENABLE) hpetProgramTimer(pHpetTimer); DEVHPET_UNLOCK_BOTH(pThis); break; } case HPET_TN_CMP + 4: /* upper bits of comparator register */ { DEVHPET_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); Log(("write HPET_TN_CMP + 4 on %d: %#x\n", iTimerNo, u32NewValue)); if (!hpet32bitTimer(pHpetTimer)) { if (pHpetTimer->u64Config & HPET_TN_PERIODIC) pHpetTimer->u64Period = RT_MAKE_U64(RT_LO_U32(pHpetTimer->u64Period), u32NewValue); pHpetTimer->u64Cmp = RT_MAKE_U64(RT_LO_U32(pHpetTimer->u64Cmp), u32NewValue); Log2(("after HPET_TN_CMP+4 cmp=%llx per=%llx tmr=%d\n", pHpetTimer->u64Cmp, pHpetTimer->u64Period, iTimerNo)); pHpetTimer->u64Config &= ~HPET_TN_SETVAL; if (pThis->u64HpetConfig & HPET_CFG_ENABLE) hpetProgramTimer(pHpetTimer); } DEVHPET_UNLOCK_BOTH(pThis); break; } case HPET_TN_ROUTE: { Log(("write HPET_TN_ROUTE\n")); break; } case HPET_TN_ROUTE + 4: { Log(("write HPET_TN_ROUTE + 4\n")); break; } default: { static unsigned s_cOccurences = 0; if (s_cOccurences++ < 10) LogRel(("invalid timer register write: %d\n", iTimerReg)); break; } } return VINF_SUCCESS; }