VirtualBox

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

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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