VirtualBox

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

Last change on this file since 106061 was 106061, checked in by vboxsync, 3 months 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.8 KB
Line 
1/* $Id: tstUsbMouse.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * tstUsbMouse.cpp - testcase USB mouse and tablet devices.
4 */
5
6/*
7 * Copyright (C) 2013-2024 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/** @interface_method_impl{PDMUSBHLP,pfnTimerCreate} */
104static DECLCALLBACK(int) tstTimerCreate(PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, void *pvUser,
105 uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer)
106{
107 RT_NOREF7(pUsbIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, phTimer);
108 return VINF_SUCCESS;
109}
110
111
112/** @interface_method_impl{PDMUSBHLP,pfnTimerCreate} */
113static DECLCALLBACK(int) tstTimerDestroy(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
114{
115 RT_NOREF2(pUsbIns, hTimer);
116 return VINF_SUCCESS;
117}
118
119
120/**
121 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
122 */
123static DECLCALLBACK(void *) tstMouseQueryInterface(PPDMIBASE pInterface,
124 const char *pszIID)
125{
126 PDRVTSTMOUSE pUsbIns = RT_FROM_MEMBER(pInterface, DRVTSTMOUSE, IBase);
127 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pUsbIns->IBase);
128 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSECONNECTOR, &pUsbIns->IConnector);
129 return NULL;
130}
131
132
133/**
134 * @interface_method_impl{PDMIMOUSECONNECTOR,pfnReportModes}
135 */
136static DECLCALLBACK(void) tstMouseReportModes(PPDMIMOUSECONNECTOR pInterface,
137 bool fRel, bool fAbs,
138 bool fMTAbs, bool fMTRel)
139{
140 PDRVTSTMOUSE pDrv = RT_FROM_MEMBER(pInterface, DRVTSTMOUSE, IConnector);
141 pDrv->fRel = fRel;
142 pDrv->fAbs = fAbs;
143 pDrv->fMTAbs = fMTAbs;
144 pDrv->fMTRel = fMTRel;
145}
146
147
148static int tstMouseConstruct(RTTEST hTest, int iInstance, const char *pcszMode,
149 uint8_t u8CoordShift, PPDMUSBINS *ppThis,
150 uint32_t uInstanceVersion = PDM_USBINS_VERSION)
151{
152 size_t cbUsbIns = RT_UOFFSETOF(PDMUSBINS, achInstanceData) + g_UsbHidMou.cbInstance;
153 PPDMUSBINS pUsbIns;
154 int rc = RTTestGuardedAlloc(hTest, cbUsbIns, 1, RTRandU32Ex(0, 1) != 0 /*fHead*/, (void **)&pUsbIns);
155 if (RT_SUCCESS(rc))
156 {
157 RT_BZERO(pUsbIns, cbUsbIns);
158
159 PCFGMNODE pCfg = CFGMR3CreateTree(NULL);
160 if (pCfg)
161 {
162 rc = CFGMR3InsertString(pCfg, "Mode", pcszMode);
163 if (RT_SUCCESS(rc))
164 rc = CFGMR3InsertInteger(pCfg, "CoordShift", u8CoordShift);
165 if (RT_SUCCESS(rc))
166 {
167 g_drvTstMouse.pDrv = NULL;
168 g_drvTstMouse.pDrvBase = NULL;
169 pUsbIns->u32Version = uInstanceVersion;
170 pUsbIns->iInstance = iInstance;
171 pUsbIns->pHlpR3 = &g_tstUsbHlp;
172 pUsbIns->pvInstanceDataR3 = pUsbIns->achInstanceData;
173 pUsbIns->pCfg = pCfg;
174 rc = g_UsbHidMou.pfnConstruct(pUsbIns, iInstance, pCfg, NULL);
175 if (RT_SUCCESS(rc))
176 {
177 *ppThis = pUsbIns;
178 return rc;
179 }
180 }
181 /* Failure */
182 CFGMR3DestroyTree(pCfg);
183 }
184 }
185 RTTestGuardedFree(hTest, pUsbIns);
186 return rc;
187}
188
189
190static void tstMouseDestruct(RTTEST hTest, PPDMUSBINS pUsbIns)
191{
192 if (pUsbIns)
193 {
194 g_UsbHidMou.pfnDestruct(pUsbIns);
195 CFGMR3DestroyTree(pUsbIns->pCfg);
196 RTTestGuardedFree(hTest, pUsbIns);
197 }
198}
199
200
201static void testConstructAndDestruct(RTTEST hTest)
202{
203 RTTestSub(hTest, "simple construction and destruction");
204
205 /*
206 * Normal check first.
207 */
208 PPDMUSBINS pUsbIns = NULL;
209 RTTEST_CHECK_RC(hTest, tstMouseConstruct(hTest, 0, "relative", 1, &pUsbIns), VINF_SUCCESS);
210 tstMouseDestruct(hTest, pUsbIns);
211
212 /*
213 * Modify the dev hlp version.
214 */
215 static struct
216 {
217 int rc;
218 uint32_t uInsVersion;
219 uint32_t uHlpVersion;
220 } const s_aVersionTests[] =
221 {
222 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, 0 },
223 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION - PDM_VERSION_MAKE(0, 1, 0) },
224 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION + PDM_VERSION_MAKE(0, 1, 0) },
225 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION + PDM_VERSION_MAKE(0, 1, 1) },
226 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION + PDM_VERSION_MAKE(1, 0, 0) },
227 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION - PDM_VERSION_MAKE(1, 0, 0) },
228 { VINF_SUCCESS, PDM_USBINS_VERSION, PDM_USBHLP_VERSION + PDM_VERSION_MAKE(0, 0, 1) },
229 { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION - PDM_VERSION_MAKE(0, 1, 0), PDM_USBHLP_VERSION },
230 { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION + PDM_VERSION_MAKE(0, 1, 0), PDM_USBHLP_VERSION },
231 { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION + PDM_VERSION_MAKE(0, 1, 1), PDM_USBHLP_VERSION },
232 { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION + PDM_VERSION_MAKE(1, 0, 0), PDM_USBHLP_VERSION },
233 { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION - PDM_VERSION_MAKE(1, 0, 0), PDM_USBHLP_VERSION },
234 { VINF_SUCCESS, PDM_USBINS_VERSION + PDM_VERSION_MAKE(0, 0, 1), PDM_USBHLP_VERSION },
235 { VINF_SUCCESS,
236 PDM_USBINS_VERSION + PDM_VERSION_MAKE(0, 0, 1), PDM_USBHLP_VERSION + PDM_VERSION_MAKE(0, 0, 1) },
237 };
238 bool const fSavedMayPanic = RTAssertSetMayPanic(false);
239 bool const fSavedQuiet = RTAssertSetQuiet(true);
240 for (unsigned i = 0; i < RT_ELEMENTS(s_aVersionTests); i++)
241 {
242 g_tstUsbHlp.u32Version = g_tstUsbHlp.u32TheEnd = s_aVersionTests[i].uHlpVersion;
243 pUsbIns = NULL;
244 RTTEST_CHECK_RC(hTest, tstMouseConstruct(hTest, 0, "relative", 1, &pUsbIns, s_aVersionTests[i].uInsVersion),
245 s_aVersionTests[i].rc);
246 tstMouseDestruct(hTest, pUsbIns);
247 }
248 RTAssertSetMayPanic(fSavedMayPanic);
249 RTAssertSetQuiet(fSavedQuiet);
250
251 g_tstUsbHlp.u32Version = g_tstUsbHlp.u32TheEnd = PDM_USBHLP_VERSION;
252}
253
254
255static void testSendPositionRel(RTTEST hTest)
256{
257 PPDMUSBINS pUsbIns = NULL;
258 VUSBURB Urb;
259 RTTestSub(hTest, "sending a relative position event");
260 int rc = tstMouseConstruct(hTest, 0, "relative", 1, &pUsbIns);
261 RT_ZERO(Urb);
262 if (RT_SUCCESS(rc))
263 rc = g_UsbHidMou.pfnUsbReset(pUsbIns, false);
264 if (RT_SUCCESS(rc) && !g_drvTstMouse.pDrv)
265 rc = VERR_PDM_MISSING_INTERFACE;
266 RTTEST_CHECK_RC_OK(hTest, rc);
267 if (RT_SUCCESS(rc))
268 {
269 g_drvTstMouse.pDrv->pfnPutEvent(g_drvTstMouse.pDrv, 123, -16, 1, -1, 3);
270 Urb.EndPt = 0x01;
271 Urb.enmType = VUSBXFERTYPE_INTR;
272 Urb.cbData = 4;
273 rc = g_UsbHidMou.pfnUrbQueue(pUsbIns, &Urb);
274 }
275 if (RT_SUCCESS(rc))
276 {
277 PVUSBURB pUrb = g_UsbHidMou.pfnUrbReap(pUsbIns, 0);
278 if (pUrb)
279 {
280 if (pUrb == &Urb)
281 {
282 if ( Urb.abData[0] != 3 /* Buttons */
283 || Urb.abData[1] != 123 /* x */
284 || Urb.abData[2] != 240 /* 256 - y */
285 || Urb.abData[3] != 255 /* z */)
286 rc = VERR_GENERAL_FAILURE;
287 }
288 else
289 rc = VERR_GENERAL_FAILURE;
290 }
291 else
292 rc = VERR_GENERAL_FAILURE;
293 }
294 RTTEST_CHECK_RC_OK(hTest, rc);
295 tstMouseDestruct(hTest, pUsbIns);
296}
297
298
299static void testSendPositionAbs(RTTEST hTest)
300{
301 PPDMUSBINS pUsbIns = NULL;
302 VUSBURB Urb;
303 RTTestSub(hTest, "sending an absolute position event");
304 int rc = tstMouseConstruct(hTest, 0, "absolute", 1, &pUsbIns);
305 RT_ZERO(Urb);
306 if (RT_SUCCESS(rc))
307 rc = g_UsbHidMou.pfnUsbReset(pUsbIns, false);
308 if (RT_SUCCESS(rc))
309 {
310 if (g_drvTstMouse.pDrv)
311 g_drvTstMouse.pDrv->pfnPutEventAbs(g_drvTstMouse.pDrv, 300, 200, 1, 3, 3);
312 else
313 rc = VERR_PDM_MISSING_INTERFACE;
314 }
315 if (RT_SUCCESS(rc))
316 {
317 Urb.EndPt = 0x01;
318 Urb.enmType = VUSBXFERTYPE_INTR;
319 Urb.cbData = 8;
320 rc = g_UsbHidMou.pfnUrbQueue(pUsbIns, &Urb);
321 }
322 if (RT_SUCCESS(rc))
323 {
324 PVUSBURB pUrb = g_UsbHidMou.pfnUrbReap(pUsbIns, 0);
325 if (pUrb)
326 {
327 if (pUrb == &Urb)
328 {
329 if ( Urb.abData[0] != 3 /* Buttons */
330 || (int8_t)Urb.abData[1] != -1 /* dz */
331 || (int8_t)Urb.abData[2] != -3 /* dw */
332 || *(uint16_t *)&Urb.abData[4] != 150 /* x >> 1 */
333 || *(uint16_t *)&Urb.abData[6] != 100 /* y >> 1 */)
334 rc = VERR_GENERAL_FAILURE;
335 }
336 else
337 rc = VERR_GENERAL_FAILURE;
338 }
339 else
340 rc = VERR_GENERAL_FAILURE;
341 }
342 RTTEST_CHECK_RC_OK(hTest, rc);
343 tstMouseDestruct(hTest, pUsbIns);
344}
345
346#if 0
347/** @todo PDM interface was updated. This is not working anymore. */
348static void testSendPositionMT(RTTEST hTest)
349{
350 PPDMUSBINS pUsbIns = NULL;
351 VUSBURB Urb;
352 RTTestSub(hTest, "sending a multi-touch position event");
353 int rc = tstMouseConstruct(hTest, 0, "multitouch", 1, &pUsbIns);
354 RT_ZERO(Urb);
355 if (RT_SUCCESS(rc))
356 {
357 rc = g_UsbHidMou.pfnUsbReset(pUsbIns, false);
358 }
359 if (RT_SUCCESS(rc))
360 {
361 if (g_drvTstMouse.pDrv)
362 g_drvTstMouse.pDrv->pfnPutEventMT(g_drvTstMouse.pDrv, 300, 200, 2,
363 3);
364 else
365 rc = VERR_PDM_MISSING_INTERFACE;
366 }
367 if (RT_SUCCESS(rc))
368 {
369 Urb.EndPt = 0x01;
370 Urb.enmType = VUSBXFERTYPE_INTR;
371 Urb.cbData = 8;
372 rc = g_UsbHidMou.pfnUrbQueue(pUsbIns, &Urb);
373 }
374 if (RT_SUCCESS(rc))
375 {
376 PVUSBURB pUrb = g_UsbHidMou.pfnUrbReap(pUsbIns, 0);
377 if (pUrb)
378 {
379 if (pUrb == &Urb)
380 {
381 if ( Urb.abData[0] != 1 /* Report ID */
382 || Urb.abData[1] != 3 /* Contact flags */
383 || *(uint16_t *)&Urb.abData[2] != 150 /* x >> 1 */
384 || *(uint16_t *)&Urb.abData[4] != 100 /* y >> 1 */
385 || Urb.abData[6] != 2 /* Contact number */)
386 rc = VERR_GENERAL_FAILURE;
387 }
388 else
389 rc = VERR_GENERAL_FAILURE;
390 }
391 else
392 rc = VERR_GENERAL_FAILURE;
393 }
394 RTTEST_CHECK_RC_OK(hTest, rc);
395 tstMouseDestruct(hTest, pUsbIns);
396}
397#endif
398
399int main()
400{
401 /*
402 * Init the runtime, test and say hello.
403 */
404 RTTEST hTest;
405 int rc = RTTestInitAndCreate("tstUsbMouse", &hTest);
406 if (rc)
407 return rc;
408 RTTestBanner(hTest);
409 /* Set up our faked PDMUSBHLP interface. */
410 g_tstUsbHlp.u32Version = PDM_USBHLP_VERSION;
411 g_tstUsbHlp.pfnVMSetErrorV = tstVMSetErrorV;
412 g_tstUsbHlp.pfnDriverAttach = tstDriverAttach;
413 g_tstUsbHlp.pfnTimerCreate = tstTimerCreate;
414 g_tstUsbHlp.pfnTimerDestroy = tstTimerDestroy;
415 g_tstUsbHlp.pfnCFGMValidateConfig = CFGMR3ValidateConfig;
416 g_tstUsbHlp.pfnCFGMQueryStringDef = CFGMR3QueryStringDef;
417 g_tstUsbHlp.pfnCFGMQueryU8Def = CFGMR3QueryU8Def;
418 g_tstUsbHlp.u32TheEnd = PDM_USBHLP_VERSION;
419 /* Set up our global mouse driver */
420 g_drvTstMouse.IBase.pfnQueryInterface = tstMouseQueryInterface;
421 g_drvTstMouse.IConnector.pfnReportModes = tstMouseReportModes;
422
423 /*
424 * Run the tests.
425 */
426 testConstructAndDestruct(hTest);
427 testSendPositionRel(hTest);
428 testSendPositionAbs(hTest);
429 /* testSendPositionMT(hTest); */
430 return RTTestSummaryAndDestroy(hTest);
431}
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