From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- src/VBox/Devices/Input/testcase/tstUsbMouse.cpp | 412 ++++++++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100644 src/VBox/Devices/Input/testcase/tstUsbMouse.cpp (limited to 'src/VBox/Devices/Input/testcase/tstUsbMouse.cpp') diff --git a/src/VBox/Devices/Input/testcase/tstUsbMouse.cpp b/src/VBox/Devices/Input/testcase/tstUsbMouse.cpp new file mode 100644 index 00000000..1b411583 --- /dev/null +++ b/src/VBox/Devices/Input/testcase/tstUsbMouse.cpp @@ -0,0 +1,412 @@ +/* $Id: tstUsbMouse.cpp $ */ +/** @file + * tstUsbMouse.cpp - testcase USB mouse and tablet devices. + */ + +/* + * Copyright (C) 2013-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "VBoxDD.h" +#include +#include +#include +#include +#include +#include + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** Test mouse driver structure. */ +typedef struct DRVTSTMOUSE +{ + /** The USBHID structure. */ + struct USBHID *pUsbHid; + /** The base interface for the mouse driver. */ + PDMIBASE IBase; + /** Our mouse connector interface. */ + PDMIMOUSECONNECTOR IConnector; + /** The base interface of the attached mouse port. */ + PPDMIBASE pDrvBase; + /** The mouse port interface of the attached mouse port. */ + PPDMIMOUSEPORT pDrv; + /** Is relative mode currently supported? */ + bool fRel; + /** Is absolute mode currently supported? */ + bool fAbs; + /** Is absolute multi-touch mode currently supported? */ + bool fMTAbs; + /** Is relative multi-touch mode currently supported? */ + bool fMTRel; +} DRVTSTMOUSE; +typedef DRVTSTMOUSE *PDRVTSTMOUSE; + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static PDMUSBHLP g_tstUsbHlp; +/** Global mouse driver variable. + * @todo To be improved some time. */ +static DRVTSTMOUSE g_drvTstMouse; + + +/** @interface_method_impl{PDMUSBHLPR3,pfnVMSetErrorV} */ +static DECLCALLBACK(int) tstVMSetErrorV(PPDMUSBINS pUsbIns, int rc, + RT_SRC_POS_DECL, const char *pszFormat, + va_list va) +{ + RT_NOREF(pUsbIns); + RTPrintf("Error: %s:%u:%s:", RT_SRC_POS_ARGS); + RTPrintfV(pszFormat, va); + return rc; +} + +/** @interface_method_impl{PDMUSBHLPR3,pfnDriverAttach} */ +/** @todo We currently just take the driver interface from the global + * variable. This is sufficient for a unit test but still a bit sad. */ +static DECLCALLBACK(int) tstDriverAttach(PPDMUSBINS pUsbIns, RTUINT iLun, PPDMIBASE pBaseInterface, + PPDMIBASE *ppBaseInterface, const char *pszDesc) +{ + RT_NOREF3(pUsbIns, iLun, pszDesc); + g_drvTstMouse.pDrvBase = pBaseInterface; + g_drvTstMouse.pDrv = PDMIBASE_QUERY_INTERFACE(pBaseInterface, PDMIMOUSEPORT); + *ppBaseInterface = &g_drvTstMouse.IBase; + return VINF_SUCCESS; +} + + +/** + * @interface_method_impl{PDMIBASE,pfnQueryInterface} + */ +static DECLCALLBACK(void *) tstMouseQueryInterface(PPDMIBASE pInterface, + const char *pszIID) +{ + PDRVTSTMOUSE pUsbIns = RT_FROM_MEMBER(pInterface, DRVTSTMOUSE, IBase); + PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pUsbIns->IBase); + PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSECONNECTOR, &pUsbIns->IConnector); + return NULL; +} + + +/** + * @interface_method_impl{PDMIMOUSECONNECTOR,pfnReportModes} + */ +static DECLCALLBACK(void) tstMouseReportModes(PPDMIMOUSECONNECTOR pInterface, + bool fRel, bool fAbs, + bool fMTAbs, bool fMTRel) +{ + PDRVTSTMOUSE pDrv = RT_FROM_MEMBER(pInterface, DRVTSTMOUSE, IConnector); + pDrv->fRel = fRel; + pDrv->fAbs = fAbs; + pDrv->fMTAbs = fMTAbs; + pDrv->fMTRel = fMTRel; +} + + +static int tstMouseConstruct(RTTEST hTest, int iInstance, const char *pcszMode, + uint8_t u8CoordShift, PPDMUSBINS *ppThis, + uint32_t uInstanceVersion = PDM_USBINS_VERSION) +{ + size_t cbUsbIns = RT_UOFFSETOF(PDMUSBINS, achInstanceData) + g_UsbHidMou.cbInstance; + PPDMUSBINS pUsbIns; + int rc = RTTestGuardedAlloc(hTest, cbUsbIns, 1, RTRandU32Ex(0, 1) != 0 /*fHead*/, (void **)&pUsbIns); + if (RT_SUCCESS(rc)) + { + RT_BZERO(pUsbIns, cbUsbIns); + + PCFGMNODE pCfg = CFGMR3CreateTree(NULL); + if (pCfg) + { + rc = CFGMR3InsertString(pCfg, "Mode", pcszMode); + if (RT_SUCCESS(rc)) + rc = CFGMR3InsertInteger(pCfg, "CoordShift", u8CoordShift); + if (RT_SUCCESS(rc)) + { + g_drvTstMouse.pDrv = NULL; + g_drvTstMouse.pDrvBase = NULL; + pUsbIns->u32Version = uInstanceVersion; + pUsbIns->iInstance = iInstance; + pUsbIns->pHlpR3 = &g_tstUsbHlp; + pUsbIns->pvInstanceDataR3 = pUsbIns->achInstanceData; + pUsbIns->pCfg = pCfg; + rc = g_UsbHidMou.pfnConstruct(pUsbIns, iInstance, pCfg, NULL); + if (RT_SUCCESS(rc)) + { + *ppThis = pUsbIns; + return rc; + } + } + /* Failure */ + CFGMR3DestroyTree(pCfg); + } + } + RTTestGuardedFree(hTest, pUsbIns); + return rc; +} + + +static void tstMouseDestruct(RTTEST hTest, PPDMUSBINS pUsbIns) +{ + if (pUsbIns) + { + g_UsbHidMou.pfnDestruct(pUsbIns); + CFGMR3DestroyTree(pUsbIns->pCfg); + RTTestGuardedFree(hTest, pUsbIns); + } +} + + +static void testConstructAndDestruct(RTTEST hTest) +{ + RTTestSub(hTest, "simple construction and destruction"); + + /* + * Normal check first. + */ + PPDMUSBINS pUsbIns = NULL; + RTTEST_CHECK_RC(hTest, tstMouseConstruct(hTest, 0, "relative", 1, &pUsbIns), VINF_SUCCESS); + tstMouseDestruct(hTest, pUsbIns); + + /* + * Modify the dev hlp version. + */ + static struct + { + int rc; + uint32_t uInsVersion; + uint32_t uHlpVersion; + } const s_aVersionTests[] = + { + { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, 0 }, + { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION - PDM_VERSION_MAKE(0, 1, 0) }, + { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION + PDM_VERSION_MAKE(0, 1, 0) }, + { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION + PDM_VERSION_MAKE(0, 1, 1) }, + { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION + PDM_VERSION_MAKE(1, 0, 0) }, + { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION - PDM_VERSION_MAKE(1, 0, 0) }, + { VINF_SUCCESS, PDM_USBINS_VERSION, PDM_USBHLP_VERSION + PDM_VERSION_MAKE(0, 0, 1) }, + { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION - PDM_VERSION_MAKE(0, 1, 0), PDM_USBHLP_VERSION }, + { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION + PDM_VERSION_MAKE(0, 1, 0), PDM_USBHLP_VERSION }, + { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION + PDM_VERSION_MAKE(0, 1, 1), PDM_USBHLP_VERSION }, + { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION + PDM_VERSION_MAKE(1, 0, 0), PDM_USBHLP_VERSION }, + { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION - PDM_VERSION_MAKE(1, 0, 0), PDM_USBHLP_VERSION }, + { VINF_SUCCESS, PDM_USBINS_VERSION + PDM_VERSION_MAKE(0, 0, 1), PDM_USBHLP_VERSION }, + { VINF_SUCCESS, + PDM_USBINS_VERSION + PDM_VERSION_MAKE(0, 0, 1), PDM_USBHLP_VERSION + PDM_VERSION_MAKE(0, 0, 1) }, + }; + bool const fSavedMayPanic = RTAssertSetMayPanic(false); + bool const fSavedQuiet = RTAssertSetQuiet(true); + for (unsigned i = 0; i < RT_ELEMENTS(s_aVersionTests); i++) + { + g_tstUsbHlp.u32Version = g_tstUsbHlp.u32TheEnd = s_aVersionTests[i].uHlpVersion; + pUsbIns = NULL; + RTTEST_CHECK_RC(hTest, tstMouseConstruct(hTest, 0, "relative", 1, &pUsbIns, s_aVersionTests[i].uInsVersion), + s_aVersionTests[i].rc); + tstMouseDestruct(hTest, pUsbIns); + } + RTAssertSetMayPanic(fSavedMayPanic); + RTAssertSetQuiet(fSavedQuiet); + + g_tstUsbHlp.u32Version = g_tstUsbHlp.u32TheEnd = PDM_USBHLP_VERSION; +} + + +static void testSendPositionRel(RTTEST hTest) +{ + PPDMUSBINS pUsbIns = NULL; + VUSBURB Urb; + RTTestSub(hTest, "sending a relative position event"); + int rc = tstMouseConstruct(hTest, 0, "relative", 1, &pUsbIns); + RT_ZERO(Urb); + if (RT_SUCCESS(rc)) + rc = g_UsbHidMou.pfnUsbReset(pUsbIns, false); + if (RT_SUCCESS(rc) && !g_drvTstMouse.pDrv) + rc = VERR_PDM_MISSING_INTERFACE; + RTTEST_CHECK_RC_OK(hTest, rc); + if (RT_SUCCESS(rc)) + { + g_drvTstMouse.pDrv->pfnPutEvent(g_drvTstMouse.pDrv, 123, -16, 1, -1, 3); + Urb.EndPt = 0x01; + Urb.enmType = VUSBXFERTYPE_INTR; + Urb.cbData = 4; + rc = g_UsbHidMou.pfnUrbQueue(pUsbIns, &Urb); + } + if (RT_SUCCESS(rc)) + { + PVUSBURB pUrb = g_UsbHidMou.pfnUrbReap(pUsbIns, 0); + if (pUrb) + { + if (pUrb == &Urb) + { + if ( Urb.abData[0] != 3 /* Buttons */ + || Urb.abData[1] != 123 /* x */ + || Urb.abData[2] != 240 /* 256 - y */ + || Urb.abData[3] != 255 /* z */) + rc = VERR_GENERAL_FAILURE; + } + else + rc = VERR_GENERAL_FAILURE; + } + else + rc = VERR_GENERAL_FAILURE; + } + RTTEST_CHECK_RC_OK(hTest, rc); + tstMouseDestruct(hTest, pUsbIns); +} + + +static void testSendPositionAbs(RTTEST hTest) +{ + PPDMUSBINS pUsbIns = NULL; + VUSBURB Urb; + RTTestSub(hTest, "sending an absolute position event"); + int rc = tstMouseConstruct(hTest, 0, "absolute", 1, &pUsbIns); + RT_ZERO(Urb); + if (RT_SUCCESS(rc)) + rc = g_UsbHidMou.pfnUsbReset(pUsbIns, false); + if (RT_SUCCESS(rc)) + { + if (g_drvTstMouse.pDrv) + g_drvTstMouse.pDrv->pfnPutEventAbs(g_drvTstMouse.pDrv, 300, 200, 1, 3, 3); + else + rc = VERR_PDM_MISSING_INTERFACE; + } + if (RT_SUCCESS(rc)) + { + Urb.EndPt = 0x01; + Urb.enmType = VUSBXFERTYPE_INTR; + Urb.cbData = 8; + rc = g_UsbHidMou.pfnUrbQueue(pUsbIns, &Urb); + } + if (RT_SUCCESS(rc)) + { + PVUSBURB pUrb = g_UsbHidMou.pfnUrbReap(pUsbIns, 0); + if (pUrb) + { + if (pUrb == &Urb) + { + if ( Urb.abData[0] != 3 /* Buttons */ + || (int8_t)Urb.abData[1] != -1 /* dz */ + || (int8_t)Urb.abData[2] != -3 /* dw */ + || *(uint16_t *)&Urb.abData[4] != 150 /* x >> 1 */ + || *(uint16_t *)&Urb.abData[6] != 100 /* y >> 1 */) + rc = VERR_GENERAL_FAILURE; + } + else + rc = VERR_GENERAL_FAILURE; + } + else + rc = VERR_GENERAL_FAILURE; + } + RTTEST_CHECK_RC_OK(hTest, rc); + tstMouseDestruct(hTest, pUsbIns); +} + +#if 0 +/** @todo PDM interface was updated. This is not working anymore. */ +static void testSendPositionMT(RTTEST hTest) +{ + PPDMUSBINS pUsbIns = NULL; + VUSBURB Urb; + RTTestSub(hTest, "sending a multi-touch position event"); + int rc = tstMouseConstruct(hTest, 0, "multitouch", 1, &pUsbIns); + RT_ZERO(Urb); + if (RT_SUCCESS(rc)) + { + rc = g_UsbHidMou.pfnUsbReset(pUsbIns, false); + } + if (RT_SUCCESS(rc)) + { + if (g_drvTstMouse.pDrv) + g_drvTstMouse.pDrv->pfnPutEventMT(g_drvTstMouse.pDrv, 300, 200, 2, + 3); + else + rc = VERR_PDM_MISSING_INTERFACE; + } + if (RT_SUCCESS(rc)) + { + Urb.EndPt = 0x01; + Urb.enmType = VUSBXFERTYPE_INTR; + Urb.cbData = 8; + rc = g_UsbHidMou.pfnUrbQueue(pUsbIns, &Urb); + } + if (RT_SUCCESS(rc)) + { + PVUSBURB pUrb = g_UsbHidMou.pfnUrbReap(pUsbIns, 0); + if (pUrb) + { + if (pUrb == &Urb) + { + if ( Urb.abData[0] != 1 /* Report ID */ + || Urb.abData[1] != 3 /* Contact flags */ + || *(uint16_t *)&Urb.abData[2] != 150 /* x >> 1 */ + || *(uint16_t *)&Urb.abData[4] != 100 /* y >> 1 */ + || Urb.abData[6] != 2 /* Contact number */) + rc = VERR_GENERAL_FAILURE; + } + else + rc = VERR_GENERAL_FAILURE; + } + else + rc = VERR_GENERAL_FAILURE; + } + RTTEST_CHECK_RC_OK(hTest, rc); + tstMouseDestruct(hTest, pUsbIns); +} +#endif + +int main() +{ + /* + * Init the runtime, test and say hello. + */ + RTTEST hTest; + int rc = RTTestInitAndCreate("tstUsbMouse", &hTest); + if (rc) + return rc; + RTTestBanner(hTest); + /* Set up our faked PDMUSBHLP interface. */ + g_tstUsbHlp.u32Version = PDM_USBHLP_VERSION; + g_tstUsbHlp.pfnVMSetErrorV = tstVMSetErrorV; + g_tstUsbHlp.pfnDriverAttach = tstDriverAttach; + g_tstUsbHlp.pfnCFGMValidateConfig = CFGMR3ValidateConfig; + g_tstUsbHlp.pfnCFGMQueryStringDef = CFGMR3QueryStringDef; + g_tstUsbHlp.pfnCFGMQueryU8Def = CFGMR3QueryU8Def; + g_tstUsbHlp.u32TheEnd = PDM_USBHLP_VERSION; + /* Set up our global mouse driver */ + g_drvTstMouse.IBase.pfnQueryInterface = tstMouseQueryInterface; + g_drvTstMouse.IConnector.pfnReportModes = tstMouseReportModes; + + /* + * Run the tests. + */ + testConstructAndDestruct(hTest); + testSendPositionRel(hTest); + testSendPositionAbs(hTest); + /* testSendPositionMT(hTest); */ + return RTTestSummaryAndDestroy(hTest); +} -- cgit v1.2.3