VirtualBox

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

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

Touchpad: First part of touchpad support, PDM interface and device emulation (see bugref:9891).

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