VirtualBox

source: vbox/trunk/src/VBox/Devices/Input/testcase/tstUsbMouse.cpp@ 100429

Last change on this file since 100429 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.1 KB
Line 
1/* $Id: tstUsbMouse.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * tstUsbMouse.cpp - testcase USB mouse and tablet devices.
4 */
5
6/*
7 * Copyright (C) 2013-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include "VBoxDD.h"
33#include <VBox/vmm/pdmdrv.h>
34#include <iprt/mem.h>
35#include <iprt/rand.h>
36#include <iprt/stream.h>
37#include <iprt/test.h>
38#include <iprt/uuid.h>
39
40
41/*********************************************************************************************************************************
42* Structures and Typedefs *
43*********************************************************************************************************************************/
44/** Test mouse driver structure. */
45typedef struct DRVTSTMOUSE
46{
47 /** The USBHID structure. */
48 struct USBHID *pUsbHid;
49 /** The base interface for the mouse driver. */
50 PDMIBASE IBase;
51 /** Our mouse connector interface. */
52 PDMIMOUSECONNECTOR IConnector;
53 /** The base interface of the attached mouse port. */
54 PPDMIBASE pDrvBase;
55 /** The mouse port interface of the attached mouse port. */
56 PPDMIMOUSEPORT pDrv;
57 /** Is relative mode currently supported? */
58 bool fRel;
59 /** Is absolute mode currently supported? */
60 bool fAbs;
61 /** Is absolute multi-touch mode currently supported? */
62 bool fMTAbs;
63 /** Is relative multi-touch mode currently supported? */
64 bool fMTRel;
65} DRVTSTMOUSE;
66typedef DRVTSTMOUSE *PDRVTSTMOUSE;
67
68
69/*********************************************************************************************************************************
70* Global Variables *
71*********************************************************************************************************************************/
72static PDMUSBHLP g_tstUsbHlp;
73/** Global mouse driver variable.
74 * @todo To be improved some time. */
75static DRVTSTMOUSE g_drvTstMouse;
76
77
78/** @interface_method_impl{PDMUSBHLPR3,pfnVMSetErrorV} */
79static DECLCALLBACK(int) tstVMSetErrorV(PPDMUSBINS pUsbIns, int rc,
80 RT_SRC_POS_DECL, const char *pszFormat,
81 va_list va)
82{
83 RT_NOREF(pUsbIns);
84 RTPrintf("Error: %s:%u:%s:", RT_SRC_POS_ARGS);
85 RTPrintfV(pszFormat, va);
86 return rc;
87}
88
89/** @interface_method_impl{PDMUSBHLPR3,pfnDriverAttach} */
90/** @todo We currently just take the driver interface from the global
91 * variable. This is sufficient for a unit test but still a bit sad. */
92static DECLCALLBACK(int) tstDriverAttach(PPDMUSBINS pUsbIns, RTUINT iLun, PPDMIBASE pBaseInterface,
93 PPDMIBASE *ppBaseInterface, const char *pszDesc)
94{
95 RT_NOREF3(pUsbIns, iLun, pszDesc);
96 g_drvTstMouse.pDrvBase = pBaseInterface;
97 g_drvTstMouse.pDrv = PDMIBASE_QUERY_INTERFACE(pBaseInterface, PDMIMOUSEPORT);
98 *ppBaseInterface = &g_drvTstMouse.IBase;
99 return VINF_SUCCESS;
100}
101
102
103/**
104 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
105 */
106static DECLCALLBACK(void *) tstMouseQueryInterface(PPDMIBASE pInterface,
107 const char *pszIID)
108{
109 PDRVTSTMOUSE pUsbIns = RT_FROM_MEMBER(pInterface, DRVTSTMOUSE, IBase);
110 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pUsbIns->IBase);
111 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSECONNECTOR, &pUsbIns->IConnector);
112 return NULL;
113}
114
115
116/**
117 * @interface_method_impl{PDMIMOUSECONNECTOR,pfnReportModes}
118 */
119static DECLCALLBACK(void) tstMouseReportModes(PPDMIMOUSECONNECTOR pInterface,
120 bool fRel, bool fAbs,
121 bool fMTAbs, bool fMTRel)
122{
123 PDRVTSTMOUSE pDrv = RT_FROM_MEMBER(pInterface, DRVTSTMOUSE, IConnector);
124 pDrv->fRel = fRel;
125 pDrv->fAbs = fAbs;
126 pDrv->fMTAbs = fMTAbs;
127 pDrv->fMTRel = fMTRel;
128}
129
130
131static int tstMouseConstruct(RTTEST hTest, int iInstance, const char *pcszMode,
132 uint8_t u8CoordShift, PPDMUSBINS *ppThis,
133 uint32_t uInstanceVersion = PDM_USBINS_VERSION)
134{
135 size_t cbUsbIns = RT_UOFFSETOF(PDMUSBINS, achInstanceData) + g_UsbHidMou.cbInstance;
136 PPDMUSBINS pUsbIns;
137 int rc = RTTestGuardedAlloc(hTest, cbUsbIns, 1, RTRandU32Ex(0, 1) != 0 /*fHead*/, (void **)&pUsbIns);
138 if (RT_SUCCESS(rc))
139 {
140 RT_BZERO(pUsbIns, cbUsbIns);
141
142 PCFGMNODE pCfg = CFGMR3CreateTree(NULL);
143 if (pCfg)
144 {
145 rc = CFGMR3InsertString(pCfg, "Mode", pcszMode);
146 if (RT_SUCCESS(rc))
147 rc = CFGMR3InsertInteger(pCfg, "CoordShift", u8CoordShift);
148 if (RT_SUCCESS(rc))
149 {
150 g_drvTstMouse.pDrv = NULL;
151 g_drvTstMouse.pDrvBase = NULL;
152 pUsbIns->u32Version = uInstanceVersion;
153 pUsbIns->iInstance = iInstance;
154 pUsbIns->pHlpR3 = &g_tstUsbHlp;
155 pUsbIns->pvInstanceDataR3 = pUsbIns->achInstanceData;
156 pUsbIns->pCfg = pCfg;
157 rc = g_UsbHidMou.pfnConstruct(pUsbIns, iInstance, pCfg, NULL);
158 if (RT_SUCCESS(rc))
159 {
160 *ppThis = pUsbIns;
161 return rc;
162 }
163 }
164 /* Failure */
165 CFGMR3DestroyTree(pCfg);
166 }
167 }
168 RTTestGuardedFree(hTest, pUsbIns);
169 return rc;
170}
171
172
173static void tstMouseDestruct(RTTEST hTest, PPDMUSBINS pUsbIns)
174{
175 if (pUsbIns)
176 {
177 g_UsbHidMou.pfnDestruct(pUsbIns);
178 CFGMR3DestroyTree(pUsbIns->pCfg);
179 RTTestGuardedFree(hTest, pUsbIns);
180 }
181}
182
183
184static void testConstructAndDestruct(RTTEST hTest)
185{
186 RTTestSub(hTest, "simple construction and destruction");
187
188 /*
189 * Normal check first.
190 */
191 PPDMUSBINS pUsbIns = NULL;
192 RTTEST_CHECK_RC(hTest, tstMouseConstruct(hTest, 0, "relative", 1, &pUsbIns), VINF_SUCCESS);
193 tstMouseDestruct(hTest, pUsbIns);
194
195 /*
196 * Modify the dev hlp version.
197 */
198 static struct
199 {
200 int rc;
201 uint32_t uInsVersion;
202 uint32_t uHlpVersion;
203 } const s_aVersionTests[] =
204 {
205 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, 0 },
206 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION - PDM_VERSION_MAKE(0, 1, 0) },
207 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION + PDM_VERSION_MAKE(0, 1, 0) },
208 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION + PDM_VERSION_MAKE(0, 1, 1) },
209 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION + PDM_VERSION_MAKE(1, 0, 0) },
210 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION - PDM_VERSION_MAKE(1, 0, 0) },
211 { VINF_SUCCESS, PDM_USBINS_VERSION, PDM_USBHLP_VERSION + PDM_VERSION_MAKE(0, 0, 1) },
212 { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION - PDM_VERSION_MAKE(0, 1, 0), PDM_USBHLP_VERSION },
213 { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION + PDM_VERSION_MAKE(0, 1, 0), PDM_USBHLP_VERSION },
214 { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION + PDM_VERSION_MAKE(0, 1, 1), PDM_USBHLP_VERSION },
215 { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION + PDM_VERSION_MAKE(1, 0, 0), PDM_USBHLP_VERSION },
216 { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION - PDM_VERSION_MAKE(1, 0, 0), PDM_USBHLP_VERSION },
217 { VINF_SUCCESS, PDM_USBINS_VERSION + PDM_VERSION_MAKE(0, 0, 1), PDM_USBHLP_VERSION },
218 { VINF_SUCCESS,
219 PDM_USBINS_VERSION + PDM_VERSION_MAKE(0, 0, 1), PDM_USBHLP_VERSION + PDM_VERSION_MAKE(0, 0, 1) },
220 };
221 bool const fSavedMayPanic = RTAssertSetMayPanic(false);
222 bool const fSavedQuiet = RTAssertSetQuiet(true);
223 for (unsigned i = 0; i < RT_ELEMENTS(s_aVersionTests); i++)
224 {
225 g_tstUsbHlp.u32Version = g_tstUsbHlp.u32TheEnd = s_aVersionTests[i].uHlpVersion;
226 pUsbIns = NULL;
227 RTTEST_CHECK_RC(hTest, tstMouseConstruct(hTest, 0, "relative", 1, &pUsbIns, s_aVersionTests[i].uInsVersion),
228 s_aVersionTests[i].rc);
229 tstMouseDestruct(hTest, pUsbIns);
230 }
231 RTAssertSetMayPanic(fSavedMayPanic);
232 RTAssertSetQuiet(fSavedQuiet);
233
234 g_tstUsbHlp.u32Version = g_tstUsbHlp.u32TheEnd = PDM_USBHLP_VERSION;
235}
236
237
238static void testSendPositionRel(RTTEST hTest)
239{
240 PPDMUSBINS pUsbIns = NULL;
241 VUSBURB Urb;
242 RTTestSub(hTest, "sending a relative position event");
243 int rc = tstMouseConstruct(hTest, 0, "relative", 1, &pUsbIns);
244 RT_ZERO(Urb);
245 if (RT_SUCCESS(rc))
246 rc = g_UsbHidMou.pfnUsbReset(pUsbIns, false);
247 if (RT_SUCCESS(rc) && !g_drvTstMouse.pDrv)
248 rc = VERR_PDM_MISSING_INTERFACE;
249 RTTEST_CHECK_RC_OK(hTest, rc);
250 if (RT_SUCCESS(rc))
251 {
252 g_drvTstMouse.pDrv->pfnPutEvent(g_drvTstMouse.pDrv, 123, -16, 1, -1, 3);
253 Urb.EndPt = 0x01;
254 Urb.enmType = VUSBXFERTYPE_INTR;
255 Urb.cbData = 4;
256 rc = g_UsbHidMou.pfnUrbQueue(pUsbIns, &Urb);
257 }
258 if (RT_SUCCESS(rc))
259 {
260 PVUSBURB pUrb = g_UsbHidMou.pfnUrbReap(pUsbIns, 0);
261 if (pUrb)
262 {
263 if (pUrb == &Urb)
264 {
265 if ( Urb.abData[0] != 3 /* Buttons */
266 || Urb.abData[1] != 123 /* x */
267 || Urb.abData[2] != 240 /* 256 - y */
268 || Urb.abData[3] != 255 /* z */)
269 rc = VERR_GENERAL_FAILURE;
270 }
271 else
272 rc = VERR_GENERAL_FAILURE;
273 }
274 else
275 rc = VERR_GENERAL_FAILURE;
276 }
277 RTTEST_CHECK_RC_OK(hTest, rc);
278 tstMouseDestruct(hTest, pUsbIns);
279}
280
281
282static void testSendPositionAbs(RTTEST hTest)
283{
284 PPDMUSBINS pUsbIns = NULL;
285 VUSBURB Urb;
286 RTTestSub(hTest, "sending an absolute position event");
287 int rc = tstMouseConstruct(hTest, 0, "absolute", 1, &pUsbIns);
288 RT_ZERO(Urb);
289 if (RT_SUCCESS(rc))
290 rc = g_UsbHidMou.pfnUsbReset(pUsbIns, false);
291 if (RT_SUCCESS(rc))
292 {
293 if (g_drvTstMouse.pDrv)
294 g_drvTstMouse.pDrv->pfnPutEventAbs(g_drvTstMouse.pDrv, 300, 200, 1, 3, 3);
295 else
296 rc = VERR_PDM_MISSING_INTERFACE;
297 }
298 if (RT_SUCCESS(rc))
299 {
300 Urb.EndPt = 0x01;
301 Urb.enmType = VUSBXFERTYPE_INTR;
302 Urb.cbData = 8;
303 rc = g_UsbHidMou.pfnUrbQueue(pUsbIns, &Urb);
304 }
305 if (RT_SUCCESS(rc))
306 {
307 PVUSBURB pUrb = g_UsbHidMou.pfnUrbReap(pUsbIns, 0);
308 if (pUrb)
309 {
310 if (pUrb == &Urb)
311 {
312 if ( Urb.abData[0] != 3 /* Buttons */
313 || (int8_t)Urb.abData[1] != -1 /* dz */
314 || (int8_t)Urb.abData[2] != -3 /* dw */
315 || *(uint16_t *)&Urb.abData[4] != 150 /* x >> 1 */
316 || *(uint16_t *)&Urb.abData[6] != 100 /* y >> 1 */)
317 rc = VERR_GENERAL_FAILURE;
318 }
319 else
320 rc = VERR_GENERAL_FAILURE;
321 }
322 else
323 rc = VERR_GENERAL_FAILURE;
324 }
325 RTTEST_CHECK_RC_OK(hTest, rc);
326 tstMouseDestruct(hTest, pUsbIns);
327}
328
329#if 0
330/** @todo PDM interface was updated. This is not working anymore. */
331static void testSendPositionMT(RTTEST hTest)
332{
333 PPDMUSBINS pUsbIns = NULL;
334 VUSBURB Urb;
335 RTTestSub(hTest, "sending a multi-touch position event");
336 int rc = tstMouseConstruct(hTest, 0, "multitouch", 1, &pUsbIns);
337 RT_ZERO(Urb);
338 if (RT_SUCCESS(rc))
339 {
340 rc = g_UsbHidMou.pfnUsbReset(pUsbIns, false);
341 }
342 if (RT_SUCCESS(rc))
343 {
344 if (g_drvTstMouse.pDrv)
345 g_drvTstMouse.pDrv->pfnPutEventMT(g_drvTstMouse.pDrv, 300, 200, 2,
346 3);
347 else
348 rc = VERR_PDM_MISSING_INTERFACE;
349 }
350 if (RT_SUCCESS(rc))
351 {
352 Urb.EndPt = 0x01;
353 Urb.enmType = VUSBXFERTYPE_INTR;
354 Urb.cbData = 8;
355 rc = g_UsbHidMou.pfnUrbQueue(pUsbIns, &Urb);
356 }
357 if (RT_SUCCESS(rc))
358 {
359 PVUSBURB pUrb = g_UsbHidMou.pfnUrbReap(pUsbIns, 0);
360 if (pUrb)
361 {
362 if (pUrb == &Urb)
363 {
364 if ( Urb.abData[0] != 1 /* Report ID */
365 || Urb.abData[1] != 3 /* Contact flags */
366 || *(uint16_t *)&Urb.abData[2] != 150 /* x >> 1 */
367 || *(uint16_t *)&Urb.abData[4] != 100 /* y >> 1 */
368 || Urb.abData[6] != 2 /* Contact number */)
369 rc = VERR_GENERAL_FAILURE;
370 }
371 else
372 rc = VERR_GENERAL_FAILURE;
373 }
374 else
375 rc = VERR_GENERAL_FAILURE;
376 }
377 RTTEST_CHECK_RC_OK(hTest, rc);
378 tstMouseDestruct(hTest, pUsbIns);
379}
380#endif
381
382int main()
383{
384 /*
385 * Init the runtime, test and say hello.
386 */
387 RTTEST hTest;
388 int rc = RTTestInitAndCreate("tstUsbMouse", &hTest);
389 if (rc)
390 return rc;
391 RTTestBanner(hTest);
392 /* Set up our faked PDMUSBHLP interface. */
393 g_tstUsbHlp.u32Version = PDM_USBHLP_VERSION;
394 g_tstUsbHlp.pfnVMSetErrorV = tstVMSetErrorV;
395 g_tstUsbHlp.pfnDriverAttach = tstDriverAttach;
396 g_tstUsbHlp.pfnCFGMValidateConfig = CFGMR3ValidateConfig;
397 g_tstUsbHlp.pfnCFGMQueryStringDef = CFGMR3QueryStringDef;
398 g_tstUsbHlp.pfnCFGMQueryU8Def = CFGMR3QueryU8Def;
399 g_tstUsbHlp.u32TheEnd = PDM_USBHLP_VERSION;
400 /* Set up our global mouse driver */
401 g_drvTstMouse.IBase.pfnQueryInterface = tstMouseQueryInterface;
402 g_drvTstMouse.IConnector.pfnReportModes = tstMouseReportModes;
403
404 /*
405 * Run the tests.
406 */
407 testConstructAndDestruct(hTest);
408 testSendPositionRel(hTest);
409 testSendPositionAbs(hTest);
410 /* testSendPositionMT(hTest); */
411 return RTTestSummaryAndDestroy(hTest);
412}
Note: See TracBrowser for help on using the repository browser.

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