VirtualBox

source: vbox/trunk/src/VBox/ExtPacks/BusMouseSample/DevBusMouse.cpp@ 84395

Last change on this file since 84395 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.8 KB
Line 
1/* $Id: DevBusMouse.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * BusMouse - Microsoft Bus (parallel) mouse controller device.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31
32/*********************************************************************************************************************************
33* Header Files *
34*********************************************************************************************************************************/
35#define LOG_GROUP LOG_GROUP_DEV_KBD
36#include <VBox/vmm/pdmdev.h>
37#ifndef IN_RING3
38# include <VBox/vmm/pdmapi.h>
39#endif
40#include <VBox/AssertGuest.h>
41#include <VBox/version.h>
42#include <iprt/assert.h>
43#include <iprt/uuid.h>
44
45/** @page pg_busmouse DevBusMouse - Microsoft Bus Mouse Emulation
46 *
47 * The Microsoft Bus Mouse was an early mouse sold by Microsoft, originally
48 * introduced in 1983. The mouse had a D-shaped 9-pin connector which plugged
49 * into a small ISA add-in board.
50 *
51 * The mouse itself was very simple (compared to a serial mouse) and most of the
52 * logic was located on the ISA board. Later, Microsoft sold an InPort mouse,
53 * which was also called a "bus mouse", but used a different interface.
54 *
55 * Microsoft part numbers for the Bus Mouse were 037-099 (100 ppi)
56 * and 037-199 (200 ppi).
57 *
58 * The Bus Mouse adapter included IRQ configuration jumpers (ref. MS article
59 * Q12230). The IRQ could be set to one of 2, 3, 4, 5. The typical setting
60 * would be IRQ 2 for a PC/XT and IRQ 5 for an AT compatible. Because IRQ 5
61 * may conflict with a SoundBlaster or a PCI device, this device defaults to
62 * IRQ 3. Note that IRQ 3 is also used by the COM 2 device, not often needed.
63 *
64 * The ISA adapter was built around an Intel 8255A compatible chip (ref.
65 * MS article Q46369). Once enabled, the adapter raises the configured IRQ
66 * 30 times per second; the rate is not configurable. The interrupts
67 * occur regardless of whether the mouse state has changed or not.
68 *
69 * To function properly, the 8255A must be programmed as follows:
70 * - Port A: Input. Used to read motion deltas and button states.
71 * - Port B: Output. Not used except for mouse detection.
72 * - Port C: Split. Upper bits set as output, used for control purposes.
73 * Lower bits set as input, reflecting IRQ state.
74 *
75 * Detailed information was gleaned from Windows and OS/2 DDK mouse samples.
76 */
77
78
79/*********************************************************************************************************************************
80* Defined Constants And Macros *
81*********************************************************************************************************************************/
82/** The original bus mouse controller is fixed at I/O port 0x23C. */
83#define BMS_IO_BASE 0x23C
84#define BMS_IO_SIZE 4
85
86/** @name Offsets relative to the I/O base.
87 *@{ */
88#define BMS_PORT_DATA 0 /**< 8255 Port A. */
89#define BMS_PORT_SIG 1 /**< 8255 Port B. */
90#define BMS_PORT_CTRL 2 /**< 8255 Port C. */
91#define BMS_PORT_INIT 3 /**< 8255 Control Port. */
92/** @} */
93
94/** @name Port C bits (control port).
95 * @{ */
96#define BMS_CTL_INT_DIS RT_BIT(4) /**< Disable IRQ (else enabled). */
97#define BMS_CTL_SEL_HIGH RT_BIT(5) /**< Select hi nibble (else lo). */
98#define BMS_CTL_SEL_Y RT_BIT(6) /**< Select X to read (else Y). */
99#define BMS_CTL_HOLD RT_BIT(7) /**< Hold counter (else clear). */
100/** @} */
101
102/** @name Port A bits (data port).
103 * @{ */
104#define BMS_DATA_DELTA 0x0F /**< Motion delta in lower nibble. */
105#define BMS_DATA_B3_UP RT_BIT(5) /**< Button 3 (right) is up. */
106#define BMS_DATA_B2_UP RT_BIT(6) /**< Button 2 (middle) is up. */
107#define BMS_DATA_B1_UP RT_BIT(7) /**< Button 1 (left) is up. */
108/** @} */
109
110/** Convert IRQ level (2/3/4/5) to a bit in the control register. */
111#define BMS_IRQ_BIT(a) (1 << (5 - a))
112
113/** IRQ period, corresponds to approx. 30 Hz. */
114#define BMS_IRQ_PERIOD_MS 34
115
116/** Default IRQ setting. */
117#define BMS_DEFAULT_IRQ 3
118
119/** The saved state version. */
120#define BMS_SAVED_STATE_VERSION 1
121
122
123/*********************************************************************************************************************************
124* Structures and Typedefs *
125*********************************************************************************************************************************/
126/**
127 * The shared Bus Mouse device state.
128 */
129typedef struct MouState
130{
131 /** @name 8255A state
132 * @{ */
133 uint8_t port_a;
134 uint8_t port_b;
135 uint8_t port_c;
136 uint8_t ctrl_port;
137 uint8_t cnt_held; /**< Counters held for reading. */
138 uint8_t held_dx;
139 uint8_t held_dy;
140 uint8_t irq; /**< The "jumpered" IRQ level. */
141 int32_t irq_toggle_counter;
142 /** Timer period in milliseconds. */
143 uint32_t cTimerPeriodMs;
144 /** Mouse timer handle. */
145 TMTIMERHANDLE hMouseTimer;
146 /** @} */
147
148 /** @name mouse state
149 * @{ */
150 int32_t disable_counter;
151 int32_t mouse_dx; /* current values, needed for 'poll' mode */
152 int32_t mouse_dy;
153 uint8_t mouse_enabled;
154 uint8_t mouse_buttons;
155 uint8_t mouse_buttons_reported;
156 uint8_t bAlignment;
157 /** @} */
158
159 /** The I/O ports registration. */
160 IOMIOPORTHANDLE hIoPorts;
161
162} MouState, BMSSTATE;
163/** Pointer to the shared Bus Mouse device state. */
164typedef BMSSTATE *PBMSSTATE;
165
166
167/**
168 * The ring-3 Bus Mouse device state.
169 */
170typedef struct BMSSTATER3
171{
172 /** Pointer to the device instance.
173 * @note Only for getting our bearings in an interface method. */
174 PPDMDEVINSR3 pDevIns;
175
176 /**
177 * Mouse port - LUN#0.
178 *
179 * @implements PDMIBASE
180 * @implements PDMIMOUSEPORT
181 */
182 struct
183 {
184 /** The base interface for the mouse port. */
185 PDMIBASE IBase;
186 /** The mouse port base interface. */
187 PDMIMOUSEPORT IPort;
188
189 /** The base interface of the attached mouse driver. */
190 R3PTRTYPE(PPDMIBASE) pDrvBase;
191 /** The mouse interface of the attached mouse driver. */
192 R3PTRTYPE(PPDMIMOUSECONNECTOR) pDrv;
193 } Mouse;
194} BMSSTATER3;
195/** Pointer to the ring-3 Bus Mouse device state. */
196typedef BMSSTATER3 *PBMSSTATER3;
197
198
199#ifndef VBOX_DEVICE_STRUCT_TESTCASE
200
201# ifdef IN_RING3
202
203/**
204 * Report a change in status down the driver chain.
205 *
206 * We want to report the mouse as enabled if and only if the guest is "using"
207 * it. That way, other devices (e.g. a PS/2 or USB mouse) can receive mouse
208 * events when the bus mouse is disabled. Enabling interrupts constitutes
209 * enabling the bus mouse. The mouse is considered disabled if interrupts are
210 * disabled for several consecutive mouse timer ticks; this is because the
211 * interrupt handler in the guest typically temporarily disables interrupts and
212 * we do not want to toggle the enabled/disabled state more often than
213 * necessary.
214 */
215static void bmsR3UpdateDownstreamStatus(PBMSSTATE pThis, PBMSSTATER3 pThisCC)
216{
217 PPDMIMOUSECONNECTOR pDrv = pThisCC->Mouse.pDrv;
218 bool fEnabled = !!pThis->mouse_enabled;
219 pDrv->pfnReportModes(pDrv, fEnabled, false, false);
220}
221
222/**
223 * Process a mouse event coming from the host.
224 */
225static void bmsR3MouseEvent(PBMSSTATE pThis, int dx, int dy, int dz, int dw, int buttons_state)
226{
227 LogRel3(("%s: dx=%d, dy=%d, dz=%d, dw=%d, buttons_state=0x%x\n",
228 __PRETTY_FUNCTION__, dx, dy, dz, dw, buttons_state));
229
230 /* Only record X/Y movement and buttons. */
231 pThis->mouse_dx += dx;
232 pThis->mouse_dy += dy;
233 pThis->mouse_buttons = buttons_state;
234}
235
236/**
237 * @callback_method_impl{FNTMTIMERDEV}
238 */
239static DECLCALLBACK(void) bmsR3TimerCallback(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
240{
241 PBMSSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PBMSSTATE);
242 PBMSSTATER3 pThisCC = PDMDEVINS_2_DATA(pDevIns, PBMSSTATER3);
243 uint8_t irq_bit;
244 RT_NOREF(pvUser, pTimer);
245
246 /* Toggle the IRQ line if interrupts are enabled. */
247 irq_bit = BMS_IRQ_BIT(pThis->irq);
248
249 if (pThis->port_c & irq_bit)
250 {
251 if (!(pThis->port_c & BMS_CTL_INT_DIS))
252 PDMDevHlpISASetIrq(pDevIns, pThis->irq, PDM_IRQ_LEVEL_LOW);
253 pThis->port_c &= ~irq_bit;
254 }
255 else
256 {
257 pThis->port_c |= irq_bit;
258 if (!(pThis->port_c & BMS_CTL_INT_DIS))
259 PDMDevHlpISASetIrq(pDevIns, pThis->irq, PDM_IRQ_LEVEL_HIGH);
260 }
261
262 /* Handle enabling/disabling of the mouse interface. */
263 if (pThis->port_c & BMS_CTL_INT_DIS)
264 {
265 if (pThis->disable_counter)
266 --pThis->disable_counter;
267
268 if (pThis->disable_counter == 0 && pThis->mouse_enabled)
269 {
270 pThis->mouse_enabled = false;
271 bmsR3UpdateDownstreamStatus(pThis, pThisCC);
272 }
273 }
274 else
275 {
276 pThis->disable_counter = 8; /* Re-arm the disable countdown. */
277 if (!pThis->mouse_enabled)
278 {
279 pThis->mouse_enabled = true;
280 bmsR3UpdateDownstreamStatus(pThis, pThisCC);
281 }
282 }
283
284 /* Re-arm the timer. */
285 PDMDevHlpTimerSetMillies(pDevIns, pThis->hMouseTimer, pThis->cTimerPeriodMs);
286}
287
288# endif /* IN_RING3 */
289
290static void bmsSetReportedButtons(PBMSSTATE pThis, unsigned fButtons, unsigned fButtonMask)
291{
292 pThis->mouse_buttons_reported |= (fButtons & fButtonMask);
293 pThis->mouse_buttons_reported &= (fButtons | ~fButtonMask);
294}
295
296/**
297 * Update the internal state after a write to port C.
298 */
299static void bmsUpdateCtrl(PPDMDEVINS pDevIns, PBMSSTATE pThis)
300{
301 int32_t dx, dy;
302
303 /* If the controller is in hold state, transfer data from counters. */
304 if (pThis->port_c & BMS_CTL_HOLD)
305 {
306 if (!pThis->cnt_held)
307 {
308 pThis->cnt_held = true;
309 dx = pThis->mouse_dx < 0 ? RT_MAX(pThis->mouse_dx, -128)
310 : RT_MIN(pThis->mouse_dx, 127);
311 dy = pThis->mouse_dy < 0 ? RT_MAX(pThis->mouse_dy, -128)
312 : RT_MIN(pThis->mouse_dy, 127);
313 pThis->mouse_dx -= dx;
314 pThis->mouse_dy -= dy;
315 bmsSetReportedButtons(pThis, pThis->mouse_buttons & 0x07, 0x07);
316
317 /* Force type conversion. */
318 pThis->held_dx = dx;
319 pThis->held_dy = dy;
320 }
321 }
322 else
323 pThis->cnt_held = false;
324
325 /* Move the appropriate nibble into port A. */
326 if (pThis->cnt_held)
327 {
328 if (pThis->port_c & BMS_CTL_SEL_Y)
329 {
330 if (pThis->port_c & BMS_CTL_SEL_HIGH)
331 pThis->port_a = pThis->held_dy >> 4;
332 else
333 pThis->port_a = pThis->held_dy & 0xF;
334 }
335 else
336 {
337 if (pThis->port_c & BMS_CTL_SEL_HIGH)
338 pThis->port_a = pThis->held_dx >> 4;
339 else
340 pThis->port_a = pThis->held_dx & 0xF;
341 }
342 /* And update the button bits. */
343 pThis->port_a |= pThis->mouse_buttons & 1 ? 0 : BMS_DATA_B1_UP;
344 pThis->port_a |= pThis->mouse_buttons & 2 ? 0 : BMS_DATA_B3_UP;
345 pThis->port_a |= pThis->mouse_buttons & 4 ? 0 : BMS_DATA_B2_UP;
346 }
347 /* Immediately clear the IRQ if necessary. */
348 if (pThis->port_c & BMS_CTL_INT_DIS)
349 {
350 PDMDevHlpISASetIrq(pDevIns, pThis->irq, PDM_IRQ_LEVEL_LOW);
351 pThis->port_c &= ~BMS_IRQ_BIT(pThis->irq);
352 }
353}
354
355/**
356 * @callback_method_impl{FNIOMIOPORTNEWIN}
357 */
358static DECLCALLBACK(VBOXSTRICTRC) bmsIoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
359{
360 RT_NOREF(pvUser);
361 if (cb == 1)
362 {
363 PBMSSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PBMSSTATE);
364 uint32_t uValue;
365
366 switch (offPort)
367 {
368 case BMS_PORT_DATA:
369 /* Read port A. */
370 uValue = pThis->port_a;
371 break;
372 case BMS_PORT_SIG:
373 /* Read port B. */
374 uValue = pThis->port_b;
375 break;
376 case BMS_PORT_CTRL:
377 /* Read port C. */
378 uValue = pThis->port_c;
379 /* Some Microsoft driver code reads the control port 10,000 times when
380 * determining the IRQ level. This can occur faster than the IRQ line
381 * transitions and the detection fails. To work around this, we force
382 * the IRQ bit to toggle every once in a while.
383 */
384 if (pThis->irq_toggle_counter)
385 pThis->irq_toggle_counter--;
386 else
387 {
388 pThis->irq_toggle_counter = 1000;
389 uValue ^= BMS_IRQ_BIT(pThis->irq);
390 }
391 break;
392 case BMS_PORT_INIT:
393 /* Read the 8255A control port. */
394 uValue = pThis->ctrl_port;
395 break;
396 default:
397 ASSERT_GUEST_MSG_FAILED(("invalid port %#x\n", offPort));
398 uValue = 0xff;
399 break;
400 }
401
402 *pu32 = uValue;
403 Log2(("mouIoPortRead: offPort=%#x+%x cb=%d *pu32=%#x\n", BMS_IO_BASE, offPort, cb, uValue));
404 LogRel3(("mouIoPortRead: read port %u: %#04x\n", offPort, uValue));
405 return VINF_SUCCESS;
406 }
407 ASSERT_GUEST_MSG_FAILED(("offPort=%#x cb=%d\n", offPort, cb));
408 return VERR_IOM_IOPORT_UNUSED;
409}
410
411/**
412 * @callback_method_impl{FNIOMIOPORTNEWOUT}
413 */
414static DECLCALLBACK(VBOXSTRICTRC) bmsIoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
415{
416 RT_NOREF(pvUser);
417 if (cb == 1)
418 {
419 PBMSSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PBMSSTATE);
420 LogRel3(("mouIoPortWrite: write port %u: %#04x\n", offPort, u32));
421
422 switch (offPort)
423 {
424 case BMS_PORT_SIG:
425 /* Update port B. */
426 pThis->port_b = u32;
427 break;
428 case BMS_PORT_DATA:
429 /* Do nothing, port A is not writable. */
430 break;
431 case BMS_PORT_INIT:
432 pThis->ctrl_port = u32;
433 break;
434 case BMS_PORT_CTRL:
435 /* Update the high nibble of port C. */
436 pThis->port_c = (u32 & 0xF0) | (pThis->port_c & 0x0F);
437 bmsUpdateCtrl(pDevIns, pThis);
438 break;
439 default:
440 ASSERT_GUEST_MSG_FAILED(("invalid port %#x\n", offPort));
441 break;
442 }
443
444 Log2(("mouIoPortWrite: offPort=%#x+%u cb=%d u32=%#x\n", BMS_IO_BASE, offPort, cb, u32));
445 }
446 else
447 ASSERT_GUEST_MSG_FAILED(("offPort=%#x cb=%d\n", offPort, cb));
448 return VINF_SUCCESS;
449}
450
451# ifdef IN_RING3
452
453/**
454 * @callback_method_impl{FNSSMDEVSAVEEXEC}
455 */
456static DECLCALLBACK(int) bmsR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
457{
458 PBMSSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PBMSSTATE);
459 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
460
461 /* 8255A state. */
462 pHlp->pfnSSMPutU8(pSSMHandle, pThis->port_a);
463 pHlp->pfnSSMPutU8(pSSMHandle, pThis->port_b);
464 pHlp->pfnSSMPutU8(pSSMHandle, pThis->port_c);
465 pHlp->pfnSSMPutU8(pSSMHandle, pThis->ctrl_port);
466 /* Other device state. */
467 pHlp->pfnSSMPutU8(pSSMHandle, pThis->cnt_held);
468 pHlp->pfnSSMPutU8(pSSMHandle, pThis->held_dx);
469 pHlp->pfnSSMPutU8(pSSMHandle, pThis->held_dy);
470 pHlp->pfnSSMPutU8(pSSMHandle, pThis->irq);
471 pHlp->pfnSSMPutU32(pSSMHandle, pThis->cTimerPeriodMs);
472 /* Current mouse state deltas. */
473 pHlp->pfnSSMPutS32(pSSMHandle, pThis->mouse_dx);
474 pHlp->pfnSSMPutS32(pSSMHandle, pThis->mouse_dy);
475 pHlp->pfnSSMPutU8(pSSMHandle, pThis->mouse_buttons_reported);
476 /* Timer. */
477 return PDMDevHlpTimerSave(pDevIns, pThis->hMouseTimer, pSSMHandle);
478}
479
480/**
481 * @callback_method_impl{FNSSMDEVLOADEXEC}
482 */
483static DECLCALLBACK(int) bmsR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t uVersion, uint32_t uPass)
484{
485 PBMSSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PBMSSTATE);
486 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
487
488 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
489
490 if (uVersion > BMS_SAVED_STATE_VERSION)
491 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
492
493 /* 8255A state. */
494 pHlp->pfnSSMGetU8(pSSMHandle, &pThis->port_a);
495 pHlp->pfnSSMGetU8(pSSMHandle, &pThis->port_b);
496 pHlp->pfnSSMGetU8(pSSMHandle, &pThis->port_c);
497 pHlp->pfnSSMGetU8(pSSMHandle, &pThis->ctrl_port);
498 /* Other device state. */
499 pHlp->pfnSSMGetU8(pSSMHandle, &pThis->cnt_held);
500 pHlp->pfnSSMGetU8(pSSMHandle, &pThis->held_dx);
501 pHlp->pfnSSMGetU8(pSSMHandle, &pThis->held_dy);
502 pHlp->pfnSSMGetU8(pSSMHandle, &pThis->irq);
503 pHlp->pfnSSMGetU32(pSSMHandle, &pThis->cTimerPeriodMs);
504 /* Current mouse state deltas. */
505 pHlp->pfnSSMGetS32(pSSMHandle, &pThis->mouse_dx);
506 pHlp->pfnSSMGetS32(pSSMHandle, &pThis->mouse_dy);
507 pHlp->pfnSSMGetU8(pSSMHandle, &pThis->mouse_buttons_reported);
508 /* Timer. */
509 return PDMDevHlpTimerLoad(pDevIns, pThis->hMouseTimer, pSSMHandle);
510}
511
512/**
513 * Reset notification.
514 *
515 * @returns VBox status code.
516 * @param pDevIns The device instance data.
517 */
518static DECLCALLBACK(void) bmsR3Reset(PPDMDEVINS pDevIns)
519{
520 PBMSSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PBMSSTATE);
521 PBMSSTATER3 pThisCC = PDMDEVINS_2_DATA(pDevIns, PBMSSTATER3);
522
523 /* Reinitialize the timer. */
524 pThis->cTimerPeriodMs = BMS_IRQ_PERIOD_MS / 2;
525 PDMDevHlpTimerSetMillies(pDevIns, pThis->hMouseTimer, pThis->cTimerPeriodMs);
526
527 /* Clear the device setup. */
528 pThis->port_a = pThis->port_b = 0;
529 pThis->port_c = BMS_CTL_INT_DIS; /* Interrupts disabled. */
530 pThis->ctrl_port = 0x91; /* Default 8255A setup. */
531
532 /* Clear motion/button state. */
533 pThis->cnt_held = false;
534 pThis->mouse_dx = pThis->mouse_dy = 0;
535 pThis->mouse_buttons = 0;
536 pThis->mouse_buttons_reported = 0;
537 pThis->disable_counter = 0;
538 pThis->irq_toggle_counter = 1000;
539
540 if (pThis->mouse_enabled)
541 {
542 pThis->mouse_enabled = false;
543 bmsR3UpdateDownstreamStatus(pThis, pThisCC);
544 }
545}
546
547
548/* -=-=-=-=-=- Mouse: IBase -=-=-=-=-=- */
549
550/**
551 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
552 */
553static DECLCALLBACK(void *) bmsR3Base_QueryMouseInterface(PPDMIBASE pInterface, const char *pszIID)
554{
555 PBMSSTATER3 pThisCC = RT_FROM_MEMBER(pInterface, BMSSTATER3, Mouse.IBase);
556 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->Mouse.IBase);
557 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSEPORT, &pThisCC->Mouse.IPort);
558 return NULL;
559}
560
561
562/* -=-=-=-=-=- Mouse: IMousePort -=-=-=-=-=- */
563
564/**
565 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEvent}
566 */
567static DECLCALLBACK(int) bmsR3MousePort_PutEvent(PPDMIMOUSEPORT pInterface, int32_t dx,
568 int32_t dy, int32_t dz, int32_t dw,
569 uint32_t fButtons)
570{
571 PBMSSTATER3 pThisCC = RT_FROM_MEMBER(pInterface, BMSSTATER3, Mouse.IPort);
572 PPDMDEVINS pDevIns = pThisCC->pDevIns;
573 PBMSSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PBMSSTATE);
574 int rc = PDMDevHlpCritSectEnter(pDevIns, pDevIns->CTX_SUFF(pCritSectRo), VERR_SEM_BUSY);
575 AssertReleaseRC(rc);
576
577 bmsR3MouseEvent(pThis, dx, dy, dz, dw, fButtons);
578
579 PDMDevHlpCritSectLeave(pDevIns, pDevIns->CTX_SUFF(pCritSectRo));
580 return VINF_SUCCESS;
581}
582
583/**
584 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventAbs}
585 */
586static DECLCALLBACK(int) bmsR3MousePort_PutEventAbs(PPDMIMOUSEPORT pInterface, uint32_t x, uint32_t y,
587 int32_t dz, int32_t dw, uint32_t fButtons)
588{
589 RT_NOREF(pInterface, x, y, dz, dw, fButtons);
590 AssertFailedReturn(VERR_NOT_SUPPORTED);
591}
592
593/**
594 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventMultiTouch}
595 */
596static DECLCALLBACK(int) bmsR3MousePort_PutEventMultiTouch(PPDMIMOUSEPORT pInterface, uint8_t cContacts,
597 const uint64_t *pau64Contacts, uint32_t u32ScanTime)
598{
599 RT_NOREF(pInterface, cContacts, pau64Contacts, u32ScanTime);
600 AssertFailedReturn(VERR_NOT_SUPPORTED);
601}
602
603/* -=-=-=-=-=- setup code -=-=-=-=-=- */
604
605
606/**
607 * @interface_method_impl{PDMDEVREGR3,pfnAttach}
608 */
609static DECLCALLBACK(int) bmsR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
610{
611 PBMSSTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PBMSSTATER3);
612 int rc;
613
614 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
615 ("Bus mouse device does not support hotplugging\n"),
616 VERR_INVALID_PARAMETER);
617
618 switch (iLUN)
619 {
620 /* LUN #0: mouse */
621 case 0:
622 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThisCC->Mouse.IBase, &pThisCC->Mouse.pDrvBase, "Bus Mouse Port");
623 if (RT_SUCCESS(rc))
624 {
625 pThisCC->Mouse.pDrv = PDMIBASE_QUERY_INTERFACE(pThisCC->Mouse.pDrvBase, PDMIMOUSECONNECTOR);
626 if (!pThisCC->Mouse.pDrv)
627 {
628 AssertLogRelMsgFailed(("LUN #0 doesn't have a mouse interface! rc=%Rrc\n", rc));
629 rc = VERR_PDM_MISSING_INTERFACE;
630 }
631 }
632 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
633 {
634 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pReg->szName, pDevIns->iInstance));
635 rc = VINF_SUCCESS;
636 }
637 else
638 AssertLogRelMsgFailed(("Failed to attach LUN #0! rc=%Rrc\n", rc));
639 break;
640
641 default:
642 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
643 return VERR_PDM_NO_SUCH_LUN;
644 }
645
646 return rc;
647}
648
649
650/**
651 * @interface_method_impl{PDMDEVREGR3,pfnDetach}
652 */
653static DECLCALLBACK(void) bmsR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
654{
655# if 0
656 /*
657 * Reset the interfaces and update the controller state.
658 */
659 PBMSSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PBMSSTATE);
660 switch (iLUN)
661 {
662 /* LUN #0: mouse */
663 case 0:
664 pThis->Mouse.pDrv = NULL;
665 pThis->Mouse.pDrvBase = NULL;
666 break;
667
668 default:
669 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
670 break;
671 }
672# else
673 RT_NOREF(pDevIns, iLUN, fFlags);
674# endif
675}
676
677
678/**
679 * @interface_method_impl{PDMDEVREG,pfnConstruct}
680 */
681static DECLCALLBACK(int) bmsR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
682{
683 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
684 PBMSSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PBMSSTATE);
685 PBMSSTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PBMSSTATER3);
686 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
687 int rc;
688 RT_NOREF(iInstance);
689
690 Assert(iInstance == 0);
691
692 /*
693 * Validate and read the configuration.
694 */
695 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "IRQ", "");
696
697 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "IRQ", &pThis->irq, BMS_DEFAULT_IRQ);
698 if (RT_FAILURE(rc))
699 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to query \"IRQ\" from the config"));
700 if (pThis->irq < 2 || pThis->irq > 5)
701 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Invalid \"IRQ\" config setting"));
702
703 Log(("busmouse: IRQ=%u fRCEnabled=%RTbool fR0Enabled=%RTbool\n", pThis->irq, pDevIns->fRCEnabled, pDevIns->fR0Enabled));
704
705 /*
706 * Initialize the interfaces.
707 */
708 pThisCC->pDevIns = pDevIns;
709 pThisCC->Mouse.IBase.pfnQueryInterface = bmsR3Base_QueryMouseInterface;
710 pThisCC->Mouse.IPort.pfnPutEvent = bmsR3MousePort_PutEvent;
711 pThisCC->Mouse.IPort.pfnPutEventAbs = bmsR3MousePort_PutEventAbs;
712 pThisCC->Mouse.IPort.pfnPutEventMultiTouch = bmsR3MousePort_PutEventMultiTouch;
713
714 /*
715 * Create the interrupt timer.
716 */
717 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL, bmsR3TimerCallback, pThis,
718 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "Bus Mouse Timer", &pThis->hMouseTimer);
719 AssertRCReturn(rc, rc);
720
721 /*
722 * Register I/O ports.
723 */
724 static const IOMIOPORTDESC s_aDescs[] =
725 {
726 { "DATA", "DATA", NULL, NULL },
727 { "SIG", "SIG", NULL, NULL },
728 { "CTRL", "CTRL", NULL, NULL },
729 { "INIT", "INIT", NULL, NULL },
730 { NULL, NULL, NULL, NULL }
731 };
732 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, BMS_IO_BASE, BMS_IO_SIZE, bmsIoPortWrite, bmsIoPortRead,
733 "Bus Mouse", s_aDescs, &pThis->hIoPorts);
734 AssertRCReturn(rc, rc);
735
736 /*
737 * Register saved state.
738 */
739 rc = PDMDevHlpSSMRegister(pDevIns, BMS_SAVED_STATE_VERSION, sizeof(*pThis), bmsR3SaveExec, bmsR3LoadExec);
740 AssertRCReturn(rc, rc);
741
742 /*
743 * Attach to the mouse driver.
744 */
745 rc = bmsR3Attach(pDevIns, 0, PDM_TACH_FLAGS_NOT_HOT_PLUG);
746 AssertRCReturn(rc, rc);
747
748 /*
749 * Initialize the device state.
750 */
751 bmsR3Reset(pDevIns);
752
753 return VINF_SUCCESS;
754}
755
756# else /* !IN_RING3 */
757
758/**
759 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
760 */
761static DECLCALLBACK(int) bmsRZConstruct(PPDMDEVINS pDevIns)
762{
763 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
764 PBMSSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PBMSSTATE);
765
766 int rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPorts, bmsIoPortWrite, bmsIoPortRead, NULL /*pvUser*/);
767 AssertRCReturn(rc, rc);
768
769 return VINF_SUCCESS;
770}
771
772# endif /* !IN_RING3 */
773
774
775/**
776 * The device registration structure.
777 */
778static const PDMDEVREG g_DeviceBusMouse =
779{
780 /* .u32Version = */ PDM_DEVREG_VERSION,
781 /* .uReserved0 = */ 0,
782 /* .szName = */ "busmouse",
783 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS /** @todo | PDM_DEVREG_FLAGS_RZ */ | PDM_DEVREG_FLAGS_NEW_STYLE,
784 /* .fClass = */ PDM_DEVREG_CLASS_INPUT,
785 /* .cMaxInstances = */ 1,
786 /* .uSharedVersion = */ 42,
787 /* .cbInstanceShared = */ sizeof(BMSSTATE),
788 /* .cbInstanceCC = */ CTX_EXPR(sizeof(BMSSTATER3), 0, 0),
789 /* .cbInstanceRC = */ 0,
790 /* .cMaxPciDevices = */ 0,
791 /* .cMaxMsixVectors = */ 0,
792 /* .pszDescription = */ "Microsoft Bus Mouse controller. LUN #0 is the mouse connector.",
793# if defined(IN_RING3)
794 /* .pszRCMod = */ "VBoxDDRC.rc",
795 /* .pszR0Mod = */ "VBoxDDR0.r0",
796 /* .pfnConstruct = */ bmsR3Construct,
797 /* .pfnDestruct = */ NULL,
798 /* .pfnRelocate = */ NULL,
799 /* .pfnMemSetup = */ NULL,
800 /* .pfnPowerOn = */ NULL,
801 /* .pfnReset = */ bmsR3Reset,
802 /* .pfnSuspend = */ NULL,
803 /* .pfnResume = */ NULL,
804 /* .pfnAttach = */ bmsR3Attach,
805 /* .pfnDetach = */ bmsR3Detach,
806 /* .pfnQueryInterface = */ NULL,
807 /* .pfnInitComplete = */ NULL,
808 /* .pfnPowerOff = */ NULL,
809 /* .pfnSoftReset = */ NULL,
810 /* .pfnReserved0 = */ NULL,
811 /* .pfnReserved1 = */ NULL,
812 /* .pfnReserved2 = */ NULL,
813 /* .pfnReserved3 = */ NULL,
814 /* .pfnReserved4 = */ NULL,
815 /* .pfnReserved5 = */ NULL,
816 /* .pfnReserved6 = */ NULL,
817 /* .pfnReserved7 = */ NULL,
818# elif defined(IN_RING0)
819 /* .pfnEarlyConstruct = */ NULL,
820 /* .pfnConstruct = */ bmsRZConstruct,
821 /* .pfnDestruct = */ NULL,
822 /* .pfnFinalDestruct = */ NULL,
823 /* .pfnRequest = */ NULL,
824 /* .pfnReserved0 = */ NULL,
825 /* .pfnReserved1 = */ NULL,
826 /* .pfnReserved2 = */ NULL,
827 /* .pfnReserved3 = */ NULL,
828 /* .pfnReserved4 = */ NULL,
829 /* .pfnReserved5 = */ NULL,
830 /* .pfnReserved6 = */ NULL,
831 /* .pfnReserved7 = */ NULL,
832# elif defined(IN_RC)
833 /* .pfnConstruct = */ bmsRZConstruct,
834 /* .pfnReserved0 = */ NULL,
835 /* .pfnReserved1 = */ NULL,
836 /* .pfnReserved2 = */ NULL,
837 /* .pfnReserved3 = */ NULL,
838 /* .pfnReserved4 = */ NULL,
839 /* .pfnReserved5 = */ NULL,
840 /* .pfnReserved6 = */ NULL,
841 /* .pfnReserved7 = */ NULL,
842# else
843# error "Not in IN_RING3, IN_RING0 or IN_RC!"
844# endif
845 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
846};
847
848# ifdef VBOX_IN_EXTPACK_R3
849
850/**
851 * @callback_method_impl{FNPDMVBOXDEVICESREGISTER}
852 */
853extern "C" DECLEXPORT(int) VBoxDevicesRegister(PPDMDEVREGCB pCallbacks, uint32_t u32Version)
854{
855 AssertLogRelMsgReturn(u32Version >= VBOX_VERSION,
856 ("u32Version=%#x VBOX_VERSION=%#x\n", u32Version, VBOX_VERSION),
857 VERR_EXTPACK_VBOX_VERSION_MISMATCH);
858 AssertLogRelMsgReturn(pCallbacks->u32Version == PDM_DEVREG_CB_VERSION,
859 ("pCallbacks->u32Version=%#x PDM_DEVREG_CB_VERSION=%#x\n", pCallbacks->u32Version, PDM_DEVREG_CB_VERSION),
860 VERR_VERSION_MISMATCH);
861
862 return pCallbacks->pfnRegister(pCallbacks, &g_DeviceBusMouse);
863}
864
865# else /* !VBOX_IN_EXTPACK_R3 */
866
867/** Pointer to the ring-0 device registrations for the Bus Mouse. */
868static PCPDMDEVREGR0 g_apDevRegs[] =
869{
870 &g_DeviceBusMouse,
871};
872
873/** Module device registration record for the Bus Mouse. */
874static PDMDEVMODREGR0 g_ModDevReg =
875{
876 /* .u32Version = */ PDM_DEVMODREGR0_VERSION,
877 /* .cDevRegs = */ RT_ELEMENTS(g_apDevRegs),
878 /* .papDevRegs = */ &g_apDevRegs[0],
879 /* .hMod = */ NULL,
880 /* .ListEntry = */ { NULL, NULL },
881};
882
883DECLEXPORT(int) ModuleInit(void *hMod)
884{
885 LogFlow(("VBoxBusMouseRZ/ModuleInit: %p\n", hMod));
886 return PDMR0DeviceRegisterModule(hMod, &g_ModDevReg);
887}
888
889DECLEXPORT(void) ModuleTerm(void *hMod)
890{
891 LogFlow(("VBoxBusMouseRZ/ModuleTerm: %p\n", hMod));
892 PDMR0DeviceDeregisterModule(hMod, &g_ModDevReg);
893}
894
895# endif /* !VBOX_IN_EXTPACK_R3 */
896
897#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
898
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