VirtualBox

source: vbox/trunk/src/VBox/Main/MouseImpl.cpp@ 33760

Last change on this file since 33760 was 33758, checked in by vboxsync, 15 years ago

Main, Devices/VMMDev, VBoxBFE: some rewrites of the mouse handling code

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.8 KB
Line 
1/* $Id: MouseImpl.cpp 33758 2010-11-04 10:30:19Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2008 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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#include <iprt/cpp/utils.h>
19
20#include "MouseImpl.h"
21#include "DisplayImpl.h"
22#include "VMMDev.h"
23
24#include "AutoCaller.h"
25#include "Logging.h"
26
27#include <VBox/pdmdrv.h>
28#include <VBox/VMMDev.h>
29
30#include <iprt/asm.h>
31
32/** @name Mouse device capabilities bitfield
33 * @{ */
34enum
35{
36 /** The mouse device can do relative reporting */
37 MOUSE_DEVCAP_RELATIVE = 1,
38 /** The mouse device can do absolute reporting */
39 MOUSE_DEVCAP_ABSOLUTE = 2
40};
41/** @} */
42
43/**
44 * Mouse driver instance data.
45 */
46struct DRVMAINMOUSE
47{
48 /** Pointer to the mouse object. */
49 Mouse *pMouse;
50 /** Pointer to the driver instance structure. */
51 PPDMDRVINS pDrvIns;
52 /** Pointer to the mouse port interface of the driver/device above us. */
53 PPDMIMOUSEPORT pUpPort;
54 /** Our mouse connector interface. */
55 PDMIMOUSECONNECTOR IConnector;
56 /** The capabilities of this device. */
57 uint32_t u32DevCaps;
58};
59
60
61// constructor / destructor
62/////////////////////////////////////////////////////////////////////////////
63
64Mouse::Mouse()
65 : mParent(NULL)
66{
67}
68
69Mouse::~Mouse()
70{
71}
72
73
74HRESULT Mouse::FinalConstruct()
75{
76 RT_ZERO(mpDrv);
77 mcLastAbsX = 0x8000;
78 mcLastAbsY = 0x8000;
79 mfLastButtons = 0;
80 return S_OK;
81}
82
83void Mouse::FinalRelease()
84{
85 uninit();
86}
87
88// public methods only for internal purposes
89/////////////////////////////////////////////////////////////////////////////
90
91/**
92 * Initializes the mouse object.
93 *
94 * @returns COM result indicator
95 * @param parent handle of our parent object
96 */
97HRESULT Mouse::init (Console *parent)
98{
99 LogFlowThisFunc(("\n"));
100
101 ComAssertRet(parent, E_INVALIDARG);
102
103 /* Enclose the state transition NotReady->InInit->Ready */
104 AutoInitSpan autoInitSpan(this);
105 AssertReturn(autoInitSpan.isOk(), E_FAIL);
106
107 unconst(mParent) = parent;
108
109#ifndef VBOXBFE_WITHOUT_COM
110 unconst(mEventSource).createObject();
111 HRESULT rc = mEventSource->init(static_cast<IMouse*>(this));
112 AssertComRCReturnRC(rc);
113 mMouseEvent.init(mEventSource, VBoxEventType_OnGuestMouseEvent,
114 0, 0, 0, 0, 0);
115#endif
116
117 /* Confirm a successful initialization */
118 autoInitSpan.setSucceeded();
119
120 return S_OK;
121}
122
123/**
124 * Uninitializes the instance and sets the ready flag to FALSE.
125 * Called either from FinalRelease() or by the parent when it gets destroyed.
126 */
127void Mouse::uninit()
128{
129 LogFlowThisFunc(("\n"));
130
131 /* Enclose the state transition Ready->InUninit->NotReady */
132 AutoUninitSpan autoUninitSpan(this);
133 if (autoUninitSpan.uninitDone())
134 return;
135
136 for (unsigned i = 0; i < MOUSE_MAX_DEVICES; ++i)
137 {
138 if (mpDrv[i])
139 mpDrv[i]->pMouse = NULL;
140 mpDrv[i] = NULL;
141 }
142
143#ifdef VBOXBFE_WITHOUT_COM
144 mParent = NULL;
145#else
146 mMouseEvent.uninit();
147 unconst(mEventSource).setNull();
148 unconst(mParent) = NULL;
149#endif
150}
151
152
153// IMouse properties
154/////////////////////////////////////////////////////////////////////////////
155
156/** Report the front-end's mouse handling capabilities to the VMM device and
157 * thus to the guest.
158 * @note all calls out of this object are made with no locks held! */
159HRESULT Mouse::updateVMMDevMouseCaps(uint32_t fCapsAdded,
160 uint32_t fCapsRemoved)
161{
162 VMMDev *pVMMDev = mParent->getVMMDev();
163 if (!pVMMDev)
164 return E_FAIL; /* No assertion, as the front-ends can send events
165 * at all sorts of inconvenient times. */
166 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
167 ComAssertRet(pVMMDevPort, E_FAIL);
168
169 int rc = pVMMDevPort->pfnUpdateMouseCapabilities(pVMMDevPort, fCapsAdded,
170 fCapsRemoved);
171 return RT_SUCCESS(rc) ? S_OK : E_FAIL;
172}
173
174/**
175 * Returns whether the current setup can accept absolute mouse events, either
176 * because an emulated absolute pointing device is active or because the Guest
177 * Additions are.
178 *
179 * @returns COM status code
180 * @param absoluteSupported address of result variable
181 */
182STDMETHODIMP Mouse::COMGETTER(AbsoluteSupported) (BOOL *absoluteSupported)
183{
184 if (!absoluteSupported)
185 return E_POINTER;
186
187 AutoCaller autoCaller(this);
188 if (FAILED(autoCaller.rc())) return autoCaller.rc();
189
190 *absoluteSupported = supportsAbs();
191 return S_OK;
192}
193
194/**
195 * Returns whether the current setup can accept relative mouse events, that is,
196 * whether an emulated relative pointing device is active.
197 *
198 * @returns COM status code
199 * @param relativeSupported address of result variable
200 */
201STDMETHODIMP Mouse::COMGETTER(RelativeSupported) (BOOL *relativeSupported)
202{
203 if (!relativeSupported)
204 return E_POINTER;
205
206 AutoCaller autoCaller(this);
207 if (FAILED(autoCaller.rc())) return autoCaller.rc();
208
209 *relativeSupported = supportsRel();
210 return S_OK;
211}
212
213/**
214 * Returns whether the guest can currently switch to drawing the mouse cursor
215 * itself if it is asked to by the front-end.
216 *
217 * @returns COM status code
218 * @param pfNeedsHostCursor address of result variable
219 */
220STDMETHODIMP Mouse::COMGETTER(NeedsHostCursor) (BOOL *pfNeedsHostCursor)
221{
222 if (!pfNeedsHostCursor)
223 return E_POINTER;
224
225 AutoCaller autoCaller(this);
226 if (FAILED(autoCaller.rc())) return autoCaller.rc();
227
228 *pfNeedsHostCursor = guestNeedsHostCursor();
229 return S_OK;
230}
231
232// IMouse methods
233/////////////////////////////////////////////////////////////////////////////
234
235/** Converts a bitfield containing information about mouse buttons currently
236 * held down from the format used by the front-end to the format used by PDM
237 * and the emulated pointing devices. */
238static uint32_t mouseButtonsToPDM(LONG buttonState)
239{
240 uint32_t fButtons = 0;
241 if (buttonState & MouseButtonState_LeftButton)
242 fButtons |= PDMIMOUSEPORT_BUTTON_LEFT;
243 if (buttonState & MouseButtonState_RightButton)
244 fButtons |= PDMIMOUSEPORT_BUTTON_RIGHT;
245 if (buttonState & MouseButtonState_MiddleButton)
246 fButtons |= PDMIMOUSEPORT_BUTTON_MIDDLE;
247 if (buttonState & MouseButtonState_XButton1)
248 fButtons |= PDMIMOUSEPORT_BUTTON_X1;
249 if (buttonState & MouseButtonState_XButton2)
250 fButtons |= PDMIMOUSEPORT_BUTTON_X2;
251 return fButtons;
252}
253
254#ifndef VBOXBFE_WITHOUT_COM
255STDMETHODIMP Mouse::COMGETTER(EventSource)(IEventSource ** aEventSource)
256{
257 CheckComArgOutPointerValid(aEventSource);
258
259 AutoCaller autoCaller(this);
260 if (FAILED(autoCaller.rc())) return autoCaller.rc();
261
262 // no need to lock - lifetime constant
263 mEventSource.queryInterfaceTo(aEventSource);
264
265 return S_OK;
266}
267#endif
268
269/**
270 * Send a relative pointer event to the relative device we deem most
271 * appropriate.
272 *
273 * @returns COM status code
274 */
275HRESULT Mouse::reportRelEventToMouseDev(int32_t dx, int32_t dy, int32_t dz,
276 int32_t dw, uint32_t fButtons)
277{
278 if (dx || dy || dz || dw || fButtons != mfLastButtons)
279 {
280 PPDMIMOUSEPORT pUpPort = NULL;
281 {
282 AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
283
284 for (unsigned i = 0; !pUpPort && i < MOUSE_MAX_DEVICES; ++i)
285 {
286 if (mpDrv[i] && (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_RELATIVE))
287 pUpPort = mpDrv[i]->pUpPort;
288 }
289 }
290 if (!pUpPort)
291 return S_OK;
292
293 int vrc = pUpPort->pfnPutEvent(pUpPort, dx, dy, dz, dw, fButtons);
294
295 if (RT_FAILURE(vrc))
296 return setError(VBOX_E_IPRT_ERROR,
297 tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
298 vrc);
299 mfLastButtons = fButtons;
300 }
301 return S_OK;
302}
303
304
305/**
306 * Send an absolute pointer event to the emulated absolute device we deem most
307 * appropriate.
308 *
309 * @returns COM status code
310 */
311HRESULT Mouse::reportAbsEventToMouseDev(uint32_t mouseXAbs, uint32_t mouseYAbs,
312 int32_t dz, int32_t dw, uint32_t fButtons)
313{
314 if ( mouseXAbs != mcLastAbsX || mouseYAbs != mcLastAbsY
315 || dz || dw || fButtons != mfLastButtons)
316 {
317 PPDMIMOUSEPORT pUpPort = NULL;
318 {
319 AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
320
321 for (unsigned i = 0; !pUpPort && i < MOUSE_MAX_DEVICES; ++i)
322 {
323 if (mpDrv[i] && (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_ABSOLUTE))
324 pUpPort = mpDrv[i]->pUpPort;
325 }
326 }
327 if (!pUpPort)
328 return S_OK;
329
330 int vrc = pUpPort->pfnPutEventAbs(pUpPort, mouseXAbs, mouseYAbs, dz,
331 dw, fButtons);
332 if (RT_FAILURE(vrc))
333 return setError(VBOX_E_IPRT_ERROR,
334 tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
335 vrc);
336 mfLastButtons = fButtons;
337
338 }
339 return S_OK;
340}
341
342
343/**
344 * Send an absolute position event to the VMM device.
345 * @note all calls out of this object are made with no locks held!
346 *
347 * @returns COM status code
348 */
349HRESULT Mouse::reportAbsEventToVMMDev(uint32_t mouseXAbs, uint32_t mouseYAbs)
350{
351 VMMDev *pVMMDev = mParent->getVMMDev();
352 ComAssertRet(pVMMDev, E_FAIL);
353 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
354 ComAssertRet(pVMMDevPort, E_FAIL);
355
356 if (mouseXAbs != mcLastAbsX || mouseYAbs != mcLastAbsY)
357 {
358 int vrc = pVMMDevPort->pfnSetAbsoluteMouse(pVMMDevPort,
359 mouseXAbs, mouseYAbs);
360 if (RT_FAILURE(vrc))
361 return setError(VBOX_E_IPRT_ERROR,
362 tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
363 vrc);
364 }
365 return S_OK;
366}
367
368
369/**
370 * Send an absolute pointer event to a pointing device (the VMM device if
371 * possible or whatever emulated absolute device seems best to us if not).
372 *
373 * @returns COM status code
374 */
375HRESULT Mouse::reportAbsEvent(uint32_t mouseXAbs, uint32_t mouseYAbs,
376 int32_t dz, int32_t dw, uint32_t fButtons,
377 bool fUsesVMMDevEvent)
378{
379 HRESULT rc;
380 /** If we are using the VMMDev to report absolute position but without
381 * VMMDev IRQ support then we need to send a small "jiggle" to the emulated
382 * relative mouse device to alert the guest to changes. */
383 LONG cJiggle = 0;
384
385 if (vmmdevCanAbs())
386 {
387 /*
388 * Send the absolute mouse position to the VMM device.
389 */
390 if (mouseXAbs != mcLastAbsX || mouseYAbs != mcLastAbsY)
391 {
392 rc = reportAbsEventToVMMDev(mouseXAbs, mouseYAbs);
393 cJiggle = !fUsesVMMDevEvent;
394 }
395 rc = reportRelEventToMouseDev(cJiggle, 0, dz, dw, fButtons);
396 }
397 else
398 rc = reportAbsEventToMouseDev(mouseXAbs, mouseYAbs, dz, dw, fButtons);
399
400 mcLastAbsX = mouseXAbs;
401 mcLastAbsY = mouseYAbs;
402 return rc;
403}
404
405/**
406 * Send a relative mouse event to the guest.
407 * @note the VMMDev capability change is so that the guest knows we are sending
408 * real events over the PS/2 device and not dummy events to signal the
409 * arrival of new absolute pointer data
410 *
411 * @returns COM status code
412 * @param dx X movement
413 * @param dy Y movement
414 * @param dz Z movement
415 * @param buttonState The mouse button state
416 */
417STDMETHODIMP Mouse::PutMouseEvent(LONG dx, LONG dy, LONG dz, LONG dw, LONG buttonState)
418{
419 HRESULT rc;
420 uint32_t fButtons;
421
422 AutoCaller autoCaller(this);
423 if (FAILED(autoCaller.rc())) return autoCaller.rc();
424 LogRel3(("%s: dx=%d, dy=%d, dz=%d, dw=%d\n", __PRETTY_FUNCTION__,
425 dx, dy, dz, dw));
426
427 fButtons = mouseButtonsToPDM(buttonState);
428 /* Make sure that the guest knows that we are sending real movement
429 * events to the PS/2 device and not just dummy wake-up ones. */
430 updateVMMDevMouseCaps(0, VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE);
431 rc = reportRelEventToMouseDev(dx, dy, dz, dw, fButtons);
432
433#ifndef VBOXBFE_WITHOUT_COM
434 mMouseEvent.reinit(VBoxEventType_OnGuestMouseEvent, false, dx, dy, dz, dw, fButtons);
435 mMouseEvent.fire(0);
436#endif
437
438 return rc;
439}
440
441/**
442 * Convert an (X, Y) value pair in screen co-ordinates (starting from 1) to a
443 * value from 0 to 0xffff.
444 *
445 * @returns COM status value
446 */
447HRESULT Mouse::convertDisplayRes(LONG x, LONG y, uint32_t *pcX, uint32_t *pcY)
448{
449 AssertPtrReturn(pcX, E_POINTER);
450 AssertPtrReturn(pcY, E_POINTER);
451 Display *pDisplay = mParent->getDisplay();
452 ComAssertRet(pDisplay, E_FAIL);
453
454 ULONG displayWidth, displayHeight;
455 /* Takes the display lock */
456 HRESULT rc = pDisplay->GetScreenResolution (0, &displayWidth, &displayHeight,
457 NULL);
458 if (FAILED(rc))
459 return rc;
460
461 *pcX = displayWidth ? ((x - 1) * 0xFFFF) / displayWidth: 0;
462 *pcY = displayHeight ? ((y - 1) * 0xFFFF) / displayHeight: 0;
463 return S_OK;
464}
465
466
467/**
468 * Send an absolute mouse event to the VM. This requires either VirtualBox-
469 * specific drivers installed in the guest or absolute pointing device
470 * emulation.
471 * @note the VMMDev capability change is so that the guest knows we are sending
472 * dummy events over the PS/2 device to signal the arrival of new
473 * absolute pointer data, and not pointer real movement data
474 * @note all calls out of this object are made with no locks held!
475 *
476 * @returns COM status code
477 * @param x X position (pixel), starting from 1
478 * @param y Y position (pixel), starting from 1
479 * @param dz Z movement
480 * @param buttonState The mouse button state
481 */
482STDMETHODIMP Mouse::PutMouseEventAbsolute(LONG x, LONG y, LONG dz, LONG dw,
483 LONG buttonState)
484{
485 AutoCaller autoCaller(this);
486 if (FAILED(autoCaller.rc())) return autoCaller.rc();
487
488 LogRel3(("%s: x=%d, y=%d, dz=%d, dw=%d, buttonState=0x%x\n",
489 __PRETTY_FUNCTION__, x, y, dz, dw, buttonState));
490
491 uint32_t mouseXAbs, mouseYAbs, fButtons;
492
493 /** @todo the front end should do this conversion to avoid races */
494 /** @note Or maybe not... races are pretty inherent in everything done in
495 * this object and not really bad as far as I can see. */
496 HRESULT rc = convertDisplayRes(x, y, &mouseXAbs, &mouseYAbs);
497 if (FAILED(rc)) return rc;
498
499 /** @todo multi-monitor Windows guests expect this to be unbounded.
500 * Understand the issues involved and fix for the rest. */
501 /* if (mouseXAbs > 0xffff)
502 mouseXAbs = mcLastAbsX;
503 if (mouseYAbs > 0xffff)
504 mouseYAbs = mcLastAbsY; */
505
506 fButtons = mouseButtonsToPDM(buttonState);
507 /* If we are doing old-style (IRQ-less) absolute reporting to the VMM
508 * device then make sure the guest is aware of it, so that it knows to
509 * ignore relative movement on the PS/2 device. */
510 updateVMMDevMouseCaps(VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE, 0);
511 rc = reportAbsEvent(mouseXAbs, mouseYAbs, dz, dw, fButtons,
512 RT_BOOL( mfVMMDevGuestCaps
513 & VMMDEV_MOUSE_GUEST_USES_EVENT));
514
515#ifndef VBOXBFE_WITHOUT_COM
516 mMouseEvent.reinit(VBoxEventType_OnGuestMouseEvent, true, x, y, dz, dw, fButtons);
517 mMouseEvent.fire(0);
518#endif
519
520 return rc;
521}
522
523// private methods
524/////////////////////////////////////////////////////////////////////////////
525
526
527/** Does the guest currently rely on the host to draw the mouse cursor or
528 * can it switch to doing it itself in software? */
529bool Mouse::guestNeedsHostCursor(void)
530{
531 return RT_BOOL(mfVMMDevGuestCaps & VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
532}
533
534
535/** Check what sort of reporting can be done using the devices currently
536 * enabled. Does not consider the VMM device. */
537void Mouse::getDeviceCaps(bool *pfAbs, bool *pfRel)
538{
539 bool fAbsDev = false;
540 bool fRelDev = false;
541
542 AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
543
544 for (unsigned i = 0; i < MOUSE_MAX_DEVICES; ++i)
545 if (mpDrv[i])
546 {
547 if (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_ABSOLUTE)
548 fAbsDev = true;
549 if (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_RELATIVE)
550 fRelDev = true;
551 }
552 if (pfAbs)
553 *pfAbs = fAbsDev;
554 if (pfRel)
555 *pfRel = fRelDev;
556}
557
558
559/** Does the VMM device currently support absolute reporting? */
560bool Mouse::vmmdevCanAbs(void)
561{
562 bool fRelDev;
563
564 getDeviceCaps(NULL, &fRelDev);
565 return (mfVMMDevGuestCaps & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE)
566 && fRelDev;
567}
568
569
570/** Does the VMM device currently support absolute reporting? */
571bool Mouse::deviceCanAbs(void)
572{
573 bool fAbsDev;
574
575 getDeviceCaps(&fAbsDev, NULL);
576 return fAbsDev;
577}
578
579
580/** Can we currently send relative events to the guest? */
581bool Mouse::supportsRel(void)
582{
583 bool fRelDev;
584
585 getDeviceCaps(NULL, &fRelDev);
586 return fRelDev;
587}
588
589
590/** Can we currently send absolute events to the guest? */
591bool Mouse::supportsAbs(void)
592{
593 bool fAbsDev;
594
595 getDeviceCaps(&fAbsDev, NULL);
596 return fAbsDev || vmmdevCanAbs();
597}
598
599
600/** Check what sort of reporting can be done using the devices currently
601 * enabled (including the VMM device) and notify the guest and the front-end.
602 */
603void Mouse::sendMouseCapsNotifications(void)
604{
605 bool fAbsDev, fRelDev, fCanAbs, fNeedsHostCursor;
606
607 {
608 AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
609
610 getDeviceCaps(&fAbsDev, &fRelDev);
611 fCanAbs = supportsAbs();
612 fNeedsHostCursor = guestNeedsHostCursor();
613 }
614 if (fAbsDev)
615 updateVMMDevMouseCaps(VMMDEV_MOUSE_HOST_HAS_ABS_DEV, 0);
616 else
617 updateVMMDevMouseCaps(0, VMMDEV_MOUSE_HOST_HAS_ABS_DEV);
618 /** @todo this call takes the Console lock in order to update the cached
619 * callback data atomically. However I can't see any sign that the cached
620 * data is ever used again. */
621 mParent->onMouseCapabilityChange(fCanAbs, fRelDev, fNeedsHostCursor);
622}
623
624
625/**
626 * @interface_method_impl{PDMIMOUSECONNECTOR,pfnReportModes}
627 * A virtual device is notifying us about its current state and capabilities
628 */
629DECLCALLBACK(void) Mouse::mouseReportModes(PPDMIMOUSECONNECTOR pInterface, bool fRel, bool fAbs)
630{
631 PDRVMAINMOUSE pDrv = RT_FROM_MEMBER(pInterface, DRVMAINMOUSE, IConnector);
632 if (fRel)
633 pDrv->u32DevCaps |= MOUSE_DEVCAP_RELATIVE;
634 else
635 pDrv->u32DevCaps &= ~MOUSE_DEVCAP_RELATIVE;
636 if (fAbs)
637 pDrv->u32DevCaps |= MOUSE_DEVCAP_ABSOLUTE;
638 else
639 pDrv->u32DevCaps &= ~MOUSE_DEVCAP_ABSOLUTE;
640
641 pDrv->pMouse->sendMouseCapsNotifications();
642}
643
644
645/**
646 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
647 */
648DECLCALLBACK(void *) Mouse::drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
649{
650 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
651 PDRVMAINMOUSE pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
652
653 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
654 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSECONNECTOR, &pDrv->IConnector);
655 return NULL;
656}
657
658
659/**
660 * Destruct a mouse driver instance.
661 *
662 * @returns VBox status.
663 * @param pDrvIns The driver instance data.
664 */
665DECLCALLBACK(void) Mouse::drvDestruct(PPDMDRVINS pDrvIns)
666{
667 PDRVMAINMOUSE pData = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
668 LogFlow(("Mouse::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
669 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
670
671 if (pData->pMouse)
672 {
673 AutoWriteLock mouseLock(pData->pMouse COMMA_LOCKVAL_SRC_POS);
674 for (unsigned cDev = 0; cDev < MOUSE_MAX_DEVICES; ++cDev)
675 if (pData->pMouse->mpDrv[cDev] == pData)
676 {
677 pData->pMouse->mpDrv[cDev] = NULL;
678 break;
679 }
680 }
681}
682
683
684/**
685 * Construct a mouse driver instance.
686 *
687 * @copydoc FNPDMDRVCONSTRUCT
688 */
689DECLCALLBACK(int) Mouse::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
690{
691 PDRVMAINMOUSE pData = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
692 LogFlow(("drvMainMouse_Construct: iInstance=%d\n", pDrvIns->iInstance));
693 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
694
695 /*
696 * Validate configuration.
697 */
698 if (!CFGMR3AreValuesValid(pCfg, "Object\0"))
699 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
700 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
701 ("Configuration error: Not possible to attach anything to this driver!\n"),
702 VERR_PDM_DRVINS_NO_ATTACH);
703
704 /*
705 * IBase.
706 */
707 pDrvIns->IBase.pfnQueryInterface = Mouse::drvQueryInterface;
708
709 pData->IConnector.pfnReportModes = Mouse::mouseReportModes;
710
711 /*
712 * Get the IMousePort interface of the above driver/device.
713 */
714 pData->pUpPort = (PPDMIMOUSEPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMIMOUSEPORT_IID);
715 if (!pData->pUpPort)
716 {
717 AssertMsgFailed(("Configuration error: No mouse port interface above!\n"));
718 return VERR_PDM_MISSING_INTERFACE_ABOVE;
719 }
720
721 /*
722 * Get the Mouse object pointer and update the mpDrv member.
723 */
724 void *pv;
725 int rc = CFGMR3QueryPtr(pCfg, "Object", &pv);
726 if (RT_FAILURE(rc))
727 {
728 AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc));
729 return rc;
730 }
731 pData->pMouse = (Mouse *)pv; /** @todo Check this cast! */
732 unsigned cDev;
733 {
734 AutoReadLock mouseLock(pData->pMouse COMMA_LOCKVAL_SRC_POS);
735
736 for (cDev = 0; cDev < MOUSE_MAX_DEVICES; ++cDev)
737 if (!pData->pMouse->mpDrv[cDev])
738 {
739 pData->pMouse->mpDrv[cDev] = pData;
740 break;
741 }
742 }
743 if (cDev == MOUSE_MAX_DEVICES)
744 return VERR_NO_MORE_HANDLES;
745
746 return VINF_SUCCESS;
747}
748
749
750/**
751 * Main mouse driver registration record.
752 */
753const PDMDRVREG Mouse::DrvReg =
754{
755 /* u32Version */
756 PDM_DRVREG_VERSION,
757 /* szName */
758 "MainMouse",
759 /* szRCMod */
760 "",
761 /* szR0Mod */
762 "",
763 /* pszDescription */
764 "Main mouse driver (Main as in the API).",
765 /* fFlags */
766 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
767 /* fClass. */
768 PDM_DRVREG_CLASS_MOUSE,
769 /* cMaxInstances */
770 ~0,
771 /* cbInstance */
772 sizeof(DRVMAINMOUSE),
773 /* pfnConstruct */
774 Mouse::drvConstruct,
775 /* pfnDestruct */
776 Mouse::drvDestruct,
777 /* pfnRelocate */
778 NULL,
779 /* pfnIOCtl */
780 NULL,
781 /* pfnPowerOn */
782 NULL,
783 /* pfnReset */
784 NULL,
785 /* pfnSuspend */
786 NULL,
787 /* pfnResume */
788 NULL,
789 /* pfnAttach */
790 NULL,
791 /* pfnDetach */
792 NULL,
793 /* pfnPowerOff */
794 NULL,
795 /* pfnSoftReset */
796 NULL,
797 /* u32EndVersion */
798 PDM_DRVREG_VERSION
799};
800/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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