VirtualBox

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

Last change on this file since 33517 was 33321, checked in by vboxsync, 14 years ago

Main. VBoxShell: demo recorder fully functional

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