VirtualBox

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

Last change on this file since 106061 was 106061, checked in by vboxsync, 2 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.2 KB
Line 
1/* $Id: DrvMouseQueue.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBox input devices: Mouse queue driver
4 */
5
6/*
7 * Copyright (C) 2006-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#define LOG_GROUP LOG_GROUP_DRV_MOUSE_QUEUE
33#include <VBox/vmm/pdmdrv.h>
34#include <iprt/assert.h>
35#include <iprt/uuid.h>
36
37#include "VBoxDD.h"
38
39
40
41/*********************************************************************************************************************************
42* Structures and Typedefs *
43*********************************************************************************************************************************/
44/**
45 * Mouse queue driver instance data.
46 *
47 * @implements PDMIMOUSECONNECTOR
48 * @implements PDMIMOUSEPORT
49 */
50typedef struct DRVMOUSEQUEUE
51{
52 /** Pointer to the driver instance structure. */
53 PPDMDRVINS pDrvIns;
54 /** Pointer to the mouse port interface of the driver/device above us. */
55 PPDMIMOUSEPORT pUpPort;
56 /** Pointer to the mouse port interface of the driver/device below us. */
57 PPDMIMOUSECONNECTOR pDownConnector;
58 /** Our mouse connector interface. */
59 PDMIMOUSECONNECTOR IConnector;
60 /** Our mouse port interface. */
61 PDMIMOUSEPORT IPort;
62 /** The queue handle. */
63 PDMQUEUEHANDLE hQueue;
64 /** Discard input when this flag is set.
65 * We only accept input when the VM is running. */
66 bool fInactive;
67} DRVMOUSEQUEUE, *PDRVMOUSEQUEUE;
68
69
70/**
71 * Event type for @a DRVMOUSEQUEUEITEM
72 */
73enum EVENTTYPE { RELATIVE, ABSOLUTE };
74
75/**
76 * Mouse queue item.
77 */
78typedef struct DRVMOUSEQUEUEITEM
79{
80 /** The core part owned by the queue manager. */
81 PDMQUEUEITEMCORE Core;
82 enum EVENTTYPE enmType;
83 union
84 {
85 uint32_t padding[5];
86 struct
87 {
88 uint32_t fButtons;
89 int32_t dx;
90 int32_t dy;
91 int32_t dz;
92 int32_t dw;
93 } Relative;
94 struct
95 {
96 uint32_t fButtons;
97 uint32_t x;
98 uint32_t y;
99 int32_t dz;
100 int32_t dw;
101 } Absolute;
102 } u;
103} DRVMOUSEQUEUEITEM, *PDRVMOUSEQUEUEITEM;
104
105
106
107/* -=-=-=-=- IBase -=-=-=-=- */
108
109/**
110 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
111 */
112static DECLCALLBACK(void *) drvMouseQueueQueryInterface(PPDMIBASE pInterface, const char *pszIID)
113{
114 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
115 PDRVMOUSEQUEUE pThis = PDMINS_2_DATA(pDrvIns, PDRVMOUSEQUEUE);
116 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
117 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSEPORT, &pThis->IPort);
118 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSECONNECTOR, &pThis->IConnector);
119 return NULL;
120}
121
122
123/* -=-=-=-=- IMousePort -=-=-=-=- */
124
125/** Converts a pointer to DRVMOUSEQUEUE::Port to a DRVMOUSEQUEUE pointer. */
126#define IMOUSEPORT_2_DRVMOUSEQUEUE(pInterface) ( (PDRVMOUSEQUEUE)((char *)(pInterface) - RT_UOFFSETOF(DRVMOUSEQUEUE, IPort)) )
127
128
129/**
130 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEvent}
131 */
132static DECLCALLBACK(int) drvMouseQueuePutEvent(PPDMIMOUSEPORT pInterface,
133 int32_t dx, int32_t dy,
134 int32_t dz, int32_t dw,
135 uint32_t fButtons)
136{
137 PDRVMOUSEQUEUE pDrv = IMOUSEPORT_2_DRVMOUSEQUEUE(pInterface);
138 if (pDrv->fInactive)
139 return VINF_SUCCESS;
140
141 PDRVMOUSEQUEUEITEM pItem = (PDRVMOUSEQUEUEITEM)PDMDrvHlpQueueAlloc(pDrv->pDrvIns, pDrv->hQueue);
142 if (pItem)
143 {
144 RT_ZERO(pItem->u.padding);
145 pItem->enmType = RELATIVE;
146 pItem->u.Relative.dx = dx;
147 pItem->u.Relative.dy = dy;
148 pItem->u.Relative.dz = dz;
149 pItem->u.Relative.dw = dw;
150 pItem->u.Relative.fButtons = fButtons;
151 PDMDrvHlpQueueInsert(pDrv->pDrvIns, pDrv->hQueue, &pItem->Core);
152 return VINF_SUCCESS;
153 }
154 return VERR_PDM_NO_QUEUE_ITEMS;
155}
156
157/**
158 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventAbs}
159 */
160static DECLCALLBACK(int) drvMouseQueuePutEventAbs(PPDMIMOUSEPORT pInterface,
161 uint32_t x, uint32_t y,
162 int32_t dz, int32_t dw,
163 uint32_t fButtons)
164{
165 PDRVMOUSEQUEUE pDrv = IMOUSEPORT_2_DRVMOUSEQUEUE(pInterface);
166 if (pDrv->fInactive)
167 return VINF_SUCCESS;
168
169 PDRVMOUSEQUEUEITEM pItem = (PDRVMOUSEQUEUEITEM)PDMDrvHlpQueueAlloc(pDrv->pDrvIns, pDrv->hQueue);
170 if (pItem)
171 {
172 RT_ZERO(pItem->u.padding);
173 pItem->enmType = ABSOLUTE;
174 pItem->u.Absolute.x = x;
175 pItem->u.Absolute.y = y;
176 pItem->u.Absolute.dz = dz;
177 pItem->u.Absolute.dw = dw;
178 pItem->u.Absolute.fButtons = fButtons;
179 PDMDrvHlpQueueInsert(pDrv->pDrvIns, pDrv->hQueue, &pItem->Core);
180 return VINF_SUCCESS;
181 }
182 return VERR_PDM_NO_QUEUE_ITEMS;
183}
184
185
186static DECLCALLBACK(int) drvMouseQueuePutEventMTAbs(PPDMIMOUSEPORT pInterface,
187 uint8_t cContacts,
188 const uint64_t *pau64Contacts,
189 uint32_t u32ScanTime)
190{
191 PDRVMOUSEQUEUE pThis = IMOUSEPORT_2_DRVMOUSEQUEUE(pInterface);
192 return pThis->pUpPort->pfnPutEventTouchScreen(pThis->pUpPort, cContacts, pau64Contacts, u32ScanTime);
193}
194
195static DECLCALLBACK(int) drvMouseQueuePutEventMTRel(PPDMIMOUSEPORT pInterface,
196 uint8_t cContacts,
197 const uint64_t *pau64Contacts,
198 uint32_t u32ScanTime)
199{
200 PDRVMOUSEQUEUE pThis = IMOUSEPORT_2_DRVMOUSEQUEUE(pInterface);
201 return pThis->pUpPort->pfnPutEventTouchPad(pThis->pUpPort, cContacts, pau64Contacts, u32ScanTime);
202}
203
204/* -=-=-=-=- IConnector -=-=-=-=- */
205
206#define PPDMIMOUSECONNECTOR_2_DRVMOUSEQUEUE(pInterface) ( (PDRVMOUSEQUEUE)((char *)(pInterface) - RT_UOFFSETOF(DRVMOUSEQUEUE, IConnector)) )
207
208
209/**
210 * Pass absolute mode status changes from the guest through to the frontend
211 * driver.
212 *
213 * @param pInterface Pointer to the mouse connector interface structure.
214 * @param fRel Is relative reporting supported?
215 * @param fAbs Is absolute reporting supported?
216 * @param fMTAbs Is absolute multi-touch reporting supported?
217 * @param fMTRel Is relative multi-touch reporting supported?
218 */
219static DECLCALLBACK(void) drvMousePassThruReportModes(PPDMIMOUSECONNECTOR pInterface, bool fRel, bool fAbs, bool fMTAbs, bool fMTRel)
220{
221 PDRVMOUSEQUEUE pDrv = PPDMIMOUSECONNECTOR_2_DRVMOUSEQUEUE(pInterface);
222 pDrv->pDownConnector->pfnReportModes(pDrv->pDownConnector, fRel, fAbs, fMTAbs, fMTRel);
223}
224
225
226/**
227 * Flush the mouse queue if there are pending events.
228 *
229 * @param pInterface Pointer to the mouse connector interface structure.
230 */
231static DECLCALLBACK(void) drvMouseFlushQueue(PPDMIMOUSECONNECTOR pInterface)
232{
233 PDRVMOUSEQUEUE pDrv = PPDMIMOUSECONNECTOR_2_DRVMOUSEQUEUE(pInterface);
234
235 PDMDrvHlpQueueFlushIfNecessary(pDrv->pDrvIns, pDrv->hQueue);
236}
237
238
239
240/* -=-=-=-=- queue -=-=-=-=- */
241
242/**
243 * Queue callback for processing a queued item.
244 *
245 * @returns Success indicator.
246 * If false the item will not be removed and the flushing will stop.
247 * @param pDrvIns The driver instance.
248 * @param pItemCore Pointer to the queue item to process.
249 */
250static DECLCALLBACK(bool) drvMouseQueueConsumer(PPDMDRVINS pDrvIns, PPDMQUEUEITEMCORE pItemCore)
251{
252 PDRVMOUSEQUEUE pThis = PDMINS_2_DATA(pDrvIns, PDRVMOUSEQUEUE);
253 PDRVMOUSEQUEUEITEM pItem = (PDRVMOUSEQUEUEITEM)pItemCore;
254 int rc;
255 if (pItem->enmType == RELATIVE)
256 rc = pThis->pUpPort->pfnPutEvent(pThis->pUpPort,
257 pItem->u.Relative.dx,
258 pItem->u.Relative.dy,
259 pItem->u.Relative.dz,
260 pItem->u.Relative.dw,
261 pItem->u.Relative.fButtons);
262 else if (pItem->enmType == ABSOLUTE)
263 rc = pThis->pUpPort->pfnPutEventAbs(pThis->pUpPort,
264 pItem->u.Absolute.x,
265 pItem->u.Absolute.y,
266 pItem->u.Absolute.dz,
267 pItem->u.Absolute.dw,
268 pItem->u.Absolute.fButtons);
269 else
270 AssertMsgFailedReturn(("enmType=%d\n", pItem->enmType), true /* remove buggy data */);
271 return rc != VERR_TRY_AGAIN;
272}
273
274
275/* -=-=-=-=- driver interface -=-=-=-=- */
276
277/**
278 * Power On notification.
279 *
280 * @param pDrvIns The drive instance data.
281 */
282static DECLCALLBACK(void) drvMouseQueuePowerOn(PPDMDRVINS pDrvIns)
283{
284 PDRVMOUSEQUEUE pThis = PDMINS_2_DATA(pDrvIns, PDRVMOUSEQUEUE);
285 pThis->fInactive = false;
286}
287
288
289/**
290 * Reset notification.
291 *
292 * @param pDrvIns The drive instance data.
293 */
294static DECLCALLBACK(void) drvMouseQueueReset(PPDMDRVINS pDrvIns)
295{
296 //PDRVKBDQUEUE pThis = PDMINS_2_DATA(pDrvIns, PDRVKBDQUEUE);
297 /** @todo purge the queue on reset. */
298 RT_NOREF(pDrvIns);
299}
300
301
302/**
303 * Suspend notification.
304 *
305 * @param pDrvIns The drive instance data.
306 */
307static DECLCALLBACK(void) drvMouseQueueSuspend(PPDMDRVINS pDrvIns)
308{
309 PDRVMOUSEQUEUE pThis = PDMINS_2_DATA(pDrvIns, PDRVMOUSEQUEUE);
310 pThis->fInactive = true;
311}
312
313
314/**
315 * Resume notification.
316 *
317 * @param pDrvIns The drive instance data.
318 */
319static DECLCALLBACK(void) drvMouseQueueResume(PPDMDRVINS pDrvIns)
320{
321 PDRVMOUSEQUEUE pThis = PDMINS_2_DATA(pDrvIns, PDRVMOUSEQUEUE);
322 pThis->fInactive = false;
323}
324
325
326/**
327 * Power Off notification.
328 *
329 * @param pDrvIns The drive instance data.
330 */
331static DECLCALLBACK(void) drvMouseQueuePowerOff(PPDMDRVINS pDrvIns)
332{
333 PDRVMOUSEQUEUE pThis = PDMINS_2_DATA(pDrvIns, PDRVMOUSEQUEUE);
334 pThis->fInactive = true;
335}
336
337
338/**
339 * Construct a mouse driver instance.
340 *
341 * @copydoc FNPDMDRVCONSTRUCT
342 */
343static DECLCALLBACK(int) drvMouseQueueConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
344{
345 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
346 PDRVMOUSEQUEUE pDrv = PDMINS_2_DATA(pDrvIns, PDRVMOUSEQUEUE);
347 PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
348
349 LogFlow(("drvMouseQueueConstruct: iInstance=%d\n", pDrvIns->iInstance));
350
351 /*
352 * Validate configuration.
353 */
354 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "QueueSize|Interval", "");
355
356 /*
357 * Init basic data members and interfaces.
358 */
359 pDrv->pDrvIns = pDrvIns;
360 pDrv->fInactive = true;
361 /* IBase. */
362 pDrvIns->IBase.pfnQueryInterface = drvMouseQueueQueryInterface;
363 /* IMouseConnector. */
364 pDrv->IConnector.pfnReportModes = drvMousePassThruReportModes;
365 pDrv->IConnector.pfnFlushQueue = drvMouseFlushQueue;
366 /* IMousePort. */
367 pDrv->IPort.pfnPutEvent = drvMouseQueuePutEvent;
368 pDrv->IPort.pfnPutEventAbs = drvMouseQueuePutEventAbs;
369 pDrv->IPort.pfnPutEventTouchScreen = drvMouseQueuePutEventMTAbs;
370 pDrv->IPort.pfnPutEventTouchPad = drvMouseQueuePutEventMTRel;
371
372 /*
373 * Get the IMousePort interface of the above driver/device.
374 */
375 pDrv->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMOUSEPORT);
376 AssertMsgReturn(pDrv->pUpPort, ("Configuration error: No mouse port interface above!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
377
378 /*
379 * Attach driver below and query it's connector interface.
380 */
381 PPDMIBASE pDownBase;
382 int rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pDownBase);
383 AssertMsgRCReturn(rc, ("Failed to attach driver below us! rc=%Rra\n", rc), rc);
384
385 pDrv->pDownConnector = PDMIBASE_QUERY_INTERFACE(pDownBase, PDMIMOUSECONNECTOR);
386 AssertMsgReturn(pDrv->pDownConnector, ("Configuration error: No mouse connector interface below!\n"),
387 VERR_PDM_MISSING_INTERFACE_BELOW);
388
389 /*
390 * Create the queue.
391 */
392 uint32_t cMilliesInterval = 0;
393 rc = pHlp->pfnCFGMQueryU32(pCfg, "Interval", &cMilliesInterval);
394 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
395 cMilliesInterval = 0;
396 else
397 AssertMsgRCReturn(rc, ("Configuration error: 32-bit \"Interval\" -> rc=%Rrc\n", rc), rc);
398
399 uint32_t cItems = 0;
400 rc = pHlp->pfnCFGMQueryU32(pCfg, "QueueSize", &cItems);
401 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
402 cItems = 128;
403 else
404 AssertMsgRCReturn(rc, ("Configuration error: 32-bit \"QueueSize\" -> rc=%Rrc\n", rc), rc);
405
406 rc = PDMDrvHlpQueueCreate(pDrvIns, sizeof(DRVMOUSEQUEUEITEM), cItems, cMilliesInterval,
407 drvMouseQueueConsumer, "Mouse", &pDrv->hQueue);
408 AssertMsgRCReturn(rc, ("Failed to create driver: cItems=%d cMilliesInterval=%d rc=%Rrc\n", cItems, cMilliesInterval, rc), rc);
409
410 return VINF_SUCCESS;
411}
412
413
414/**
415 * Mouse queue driver registration record.
416 */
417const PDMDRVREG g_DrvMouseQueue =
418{
419 /* u32Version */
420 PDM_DRVREG_VERSION,
421 /* szName */
422 "MouseQueue",
423 /* szRCMod */
424 "",
425 /* szR0Mod */
426 "",
427 /* pszDescription */
428 "Mouse queue driver to plug in between the key source and the device to do queueing and inter-thread transport.",
429 /* fFlags */
430 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
431 /* fClass. */
432 PDM_DRVREG_CLASS_MOUSE,
433 /* cMaxInstances */
434 ~0U,
435 /* cbInstance */
436 sizeof(DRVMOUSEQUEUE),
437 /* pfnConstruct */
438 drvMouseQueueConstruct,
439 /* pfnRelocate */
440 NULL,
441 /* pfnDestruct */
442 NULL,
443 /* pfnIOCtl */
444 NULL,
445 /* pfnPowerOn */
446 drvMouseQueuePowerOn,
447 /* pfnReset */
448 drvMouseQueueReset,
449 /* pfnSuspend */
450 drvMouseQueueSuspend,
451 /* pfnResume */
452 drvMouseQueueResume,
453 /* pfnAttach */
454 NULL,
455 /* pfnDetach */
456 NULL,
457 /* pfnPowerOff */
458 drvMouseQueuePowerOff,
459 /* pfnSoftReset */
460 NULL,
461 /* u32EndVersion */
462 PDM_DRVREG_VERSION
463};
464
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