VirtualBox

source: vbox/trunk/src/VBox/Devices/Input/DevPS2.cpp@ 60404

Last change on this file since 60404 was 60404, checked in by vboxsync, 8 years ago

VMM,Devices,Main: Implemented soft/warm reset for shutdown status codes 05h, 09h and 0Ah.

This is a shot at adjusting our VM reset handling to handle the ancient way of
getting a 286 out of protected mode and back to real mode. Our exiting reset
code (XXXR3Reset, PDMDEVREG::pfnReset, and so on) is doing a cold reset of the
system and then some additional device & memory initialization that the firmware
is usually responsible for doing. When the guest triggers a reset via the
keyboard controller, system control port A, CPU triple fault, and possibly ACPI,
only the CPU is supposed to be reset. The BIOS would then decide whether memory
and devices needed resetting as well, or if the resetter justed wanted to get out
protected mode and resume executing some real mode code pointed to by 467h.

  • New states SOFT_RESETTING and SOFT_RESETTING_LS. The latter returns to RUNNING_LS, not SUSPENDED_LS like for hard reset.
  • Added a firmware interface so the VMM/PDM can ask it whether we're supposed to do a hard reset or a soft(/warm) one.
  • Implemented firmware interface for the PC BIOS (but not EFI). It indicates soft(/warm) reset when CMOS[0xf] is 5, 9 or 10.
  • Moved the CMOS[0xf] resetting from the RTC device to the PC BIOS since it's firmware thing, not RTC.
  • Added a flag parameter to PDMDevHlpVMReset for specifying the source of the reset operation. One class of sources (GIM) will always trigger hard resets, whereas the others will check with the firmware first.
  • Added PDMR3GetResetInfo for query the flags passed to PDMDevHlpVMReset and for asking the firmware whether it's a hard or soft reset. The latter, however, is only done if only CPU 0 is active. Systems with more than one CPU in a state other than EMSTATE_WAIT_SIPI status will always be hard reset.
  • Added internal VMR3ResetFF and VMR3ResetTripleFault APIs for handling the VM_FF_RESET and VINF_EM_TRIPLE_FAULT conditions.
  • Added PMDR3ResetSoft and had it call pfnSoftReset (which is now defined).

Warning! Major PDM_DEVHLPR3_VERSION change, minor PDM_DEVREG_VERSION change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 59.2 KB
Line 
1/* $Id: DevPS2.cpp 60404 2016-04-09 23:45:55Z vboxsync $ */
2/** @file
3 * DevPS2 - PS/2 keyboard & mouse controller device.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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 * This code is based on:
19 *
20 * QEMU PC keyboard emulation (revision 1.12)
21 *
22 * Copyright (c) 2003 Fabrice Bellard
23 *
24 * Permission is hereby granted, free of charge, to any person obtaining a copy
25 * of this software and associated documentation files (the "Software"), to deal
26 * in the Software without restriction, including without limitation the rights
27 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28 * copies of the Software, and to permit persons to whom the Software is
29 * furnished to do so, subject to the following conditions:
30 *
31 * The above copyright notice and this permission notice shall be included in
32 * all copies or substantial portions of the Software.
33 *
34 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
37 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
40 * THE SOFTWARE.
41 *
42 */
43
44
45/*********************************************************************************************************************************
46* Header Files *
47*********************************************************************************************************************************/
48#define LOG_GROUP LOG_GROUP_DEV_KBD
49#include <VBox/vmm/pdmdev.h>
50#include <iprt/assert.h>
51#include <iprt/uuid.h>
52
53#include "VBoxDD.h"
54#include "PS2Dev.h"
55
56/* Do not remove this (unless eliminating the corresponding ifdefs), it will
57 * cause instant triple faults when booting Windows VMs. */
58#define TARGET_I386
59
60#ifndef VBOX_WITH_NEW_PS2M
61#define PCKBD_SAVED_STATE_VERSION 7
62#else
63#define PCKBD_SAVED_STATE_VERSION 8
64#endif
65
66#ifndef VBOX_DEVICE_STRUCT_TESTCASE
67
68
69/*********************************************************************************************************************************
70* Internal Functions *
71*********************************************************************************************************************************/
72RT_C_DECLS_BEGIN
73PDMBOTHCBDECL(int) kbdIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
74PDMBOTHCBDECL(int) kbdIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
75PDMBOTHCBDECL(int) kbdIOPortStatusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
76PDMBOTHCBDECL(int) kbdIOPortCommandWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
77RT_C_DECLS_END
78#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
79
80/* debug PC keyboard */
81#define DEBUG_KBD
82
83/* debug PC keyboard : only mouse */
84#define DEBUG_MOUSE
85
86/* Keyboard Controller Commands */
87#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
88#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
89#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
90#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
91#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
92#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
93#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
94#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
95#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
96#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
97#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */
98#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */
99#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */
100#define KBD_CCMD_WRITE_OBUF 0xD2
101#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
102 initiated by the auxiliary device */
103#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
104#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */
105#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */
106#define KBD_CCMD_READ_TSTINP 0xE0 /* Read test inputs T0, T1 */
107#define KBD_CCMD_RESET_ALT 0xF0
108#define KBD_CCMD_RESET 0xFE
109
110/* Status Register Bits */
111#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
112#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
113#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
114#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
115#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
116#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
117#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
118#define KBD_STAT_PERR 0x80 /* Parity error */
119
120/* Controller Mode Register Bits */
121#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
122#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
123#define KBD_MODE_SYS 0x04 /* The system flag (?) */
124#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
125#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
126#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
127#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
128#define KBD_MODE_RFU 0x80
129
130#ifndef VBOX_WITH_NEW_PS2M
131/* Mouse Commands */
132#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
133#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
134#define AUX_SET_RES 0xE8 /* Set resolution */
135#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
136#define AUX_SET_STREAM 0xEA /* Set stream mode */
137#define AUX_POLL 0xEB /* Poll */
138#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
139#define AUX_SET_WRAP 0xEE /* Set wrap mode */
140#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
141#define AUX_GET_TYPE 0xF2 /* Get type */
142#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
143#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
144#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
145#define AUX_SET_DEFAULT 0xF6
146#define AUX_RESET 0xFF /* Reset aux device */
147#define AUX_ACK 0xFA /* Command byte ACK. */
148#define AUX_NACK 0xFE /* Command byte NACK. */
149
150#define MOUSE_STATUS_REMOTE 0x40
151#define MOUSE_STATUS_ENABLED 0x20
152#define MOUSE_STATUS_SCALE21 0x10
153
154/** Supported mouse protocols */
155enum
156{
157 MOUSE_PROT_PS2 = 0,
158 MOUSE_PROT_IMPS2 = 3,
159 MOUSE_PROT_IMEX = 4
160};
161
162/** @name Mouse flags */
163/** @{ */
164/** IMEX horizontal scroll-wheel mode is active */
165# define MOUSE_REPORT_HORIZONTAL 0x01
166/** @} */
167
168#define MOUSE_CMD_QUEUE_SIZE 8
169
170typedef struct {
171 uint8_t data[MOUSE_CMD_QUEUE_SIZE];
172 int rptr, wptr, count;
173} MouseCmdQueue;
174
175
176#define MOUSE_EVENT_QUEUE_SIZE 256
177
178typedef struct
179{
180 uint8_t data[MOUSE_EVENT_QUEUE_SIZE];
181 int rptr;
182 int wptr;
183 int count;
184} MouseEventQueue;
185#endif
186
187/**
188 * The keyboard controller/device state.
189 *
190 * @note We use the default critical section for serialize data access.
191 */
192typedef struct KBDState
193{
194#ifndef VBOX_WITH_NEW_PS2M
195 MouseCmdQueue mouse_command_queue;
196 MouseEventQueue mouse_event_queue;
197#endif
198 uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
199 uint8_t status;
200 uint8_t mode;
201 uint8_t dbbout; /* data buffer byte */
202 /* keyboard state */
203 int32_t translate;
204 int32_t xlat_state;
205#ifndef VBOX_WITH_NEW_PS2M
206 /* mouse state */
207 int32_t mouse_write_cmd;
208 uint8_t mouse_status;
209 uint8_t mouse_resolution;
210 uint8_t mouse_sample_rate;
211 uint8_t mouse_wrap;
212 uint8_t mouse_type; /* MOUSE_PROT_PS2, *_IMPS/2, *_IMEX */
213 uint8_t mouse_detect_state;
214 int32_t mouse_dx; /* current values, needed for 'poll' mode */
215 int32_t mouse_dy;
216 int32_t mouse_dz;
217 int32_t mouse_dw;
218 int32_t mouse_flags;
219 uint8_t mouse_buttons;
220 uint8_t mouse_buttons_reported;
221
222 uint32_t Alignment0;
223#endif
224
225 /** Pointer to the device instance - RC. */
226 PPDMDEVINSRC pDevInsRC;
227 /** Pointer to the device instance - R3 . */
228 PPDMDEVINSR3 pDevInsR3;
229 /** Pointer to the device instance. */
230 PPDMDEVINSR0 pDevInsR0;
231
232 /** Keyboard state (implemented in separate PS2K module). */
233#ifdef VBOX_DEVICE_STRUCT_TESTCASE
234 uint8_t KbdFiller[PS2K_STRUCT_FILLER];
235#else
236 PS2K Kbd;
237#endif
238
239#ifdef VBOX_WITH_NEW_PS2M
240 /** Mouse state (implemented in separate PS2M module). */
241#ifdef VBOX_DEVICE_STRUCT_TESTCASE
242 uint8_t AuxFiller[PS2M_STRUCT_FILLER];
243#else
244 PS2M Aux;
245#endif
246#else
247 /**
248 * Mouse port - LUN#1.
249 *
250 * @implements PDMIBASE
251 * @implements PDMIMOUSEPORT
252 */
253 struct
254 {
255 /** The base interface for the mouse port. */
256 PDMIBASE IBase;
257 /** The mouse port base interface. */
258 PDMIMOUSEPORT IPort;
259
260 /** The base interface of the attached mouse driver. */
261 R3PTRTYPE(PPDMIBASE) pDrvBase;
262 /** The mouse interface of the attached mouse driver. */
263 R3PTRTYPE(PPDMIMOUSECONNECTOR) pDrv;
264 } Mouse;
265#endif
266} KBDState;
267
268#ifndef VBOX_DEVICE_STRUCT_TESTCASE
269
270/* update irq and KBD_STAT_[MOUSE_]OBF */
271static void kbd_update_irq(KBDState *s)
272{
273#ifndef VBOX_WITH_NEW_PS2M
274 MouseCmdQueue *mcq = &s->mouse_command_queue;
275 MouseEventQueue *meq = &s->mouse_event_queue;
276#endif
277 int irq12_level, irq1_level;
278 uint8_t val;
279
280 irq1_level = 0;
281 irq12_level = 0;
282
283 /* Determine new OBF state, but only if OBF is clear. If OBF was already
284 * set, we cannot risk changing the event type after an ISR potentially
285 * started executing! Only kbd_read_data() clears the OBF bits.
286 */
287 if (!(s->status & KBD_STAT_OBF)) {
288 s->status &= ~KBD_STAT_MOUSE_OBF;
289 /* Keyboard data has priority if both kbd and aux data is available. */
290 if (!(s->mode & KBD_MODE_DISABLE_KBD) && PS2KByteFromKbd(&s->Kbd, &val) == VINF_SUCCESS)
291 {
292 bool fHaveData = true;
293
294 /* If scancode translation is on (it usually is), there's more work to do. */
295 if (s->translate)
296 {
297 uint8_t xlated_val;
298
299 s->xlat_state = XlateAT2PC(s->xlat_state, val, &xlated_val);
300 val = xlated_val;
301
302 /* If the translation state is XS_BREAK, there's nothing to report
303 * and we keep going until the state changes or there's no more data.
304 */
305 while (s->xlat_state == XS_BREAK && PS2KByteFromKbd(&s->Kbd, &val) == VINF_SUCCESS)
306 {
307 s->xlat_state = XlateAT2PC(s->xlat_state, val, &xlated_val);
308 val = xlated_val;
309 }
310 /* This can happen if the last byte in the queue is F0... */
311 if (s->xlat_state == XS_BREAK)
312 fHaveData = false;
313 }
314 if (fHaveData)
315 {
316 s->dbbout = val;
317 s->status |= KBD_STAT_OBF;
318 }
319 }
320#ifdef VBOX_WITH_NEW_PS2M
321 else if (!(s->mode & KBD_MODE_DISABLE_MOUSE) && PS2MByteFromAux(&s->Aux, &val) == VINF_SUCCESS)
322 {
323 s->dbbout = val;
324 s->status |= KBD_STAT_OBF | KBD_STAT_MOUSE_OBF;
325 }
326#else
327 else if ((mcq->count || meq->count) && !(s->mode & KBD_MODE_DISABLE_MOUSE))
328 {
329 s->status |= KBD_STAT_OBF | KBD_STAT_MOUSE_OBF;
330 if (mcq->count)
331 {
332 s->dbbout = mcq->data[mcq->rptr];
333 if (++mcq->rptr == MOUSE_CMD_QUEUE_SIZE)
334 mcq->rptr = 0;
335 mcq->count--;
336 }
337 else
338 {
339 s->dbbout = meq->data[meq->rptr];
340 if (++meq->rptr == MOUSE_EVENT_QUEUE_SIZE)
341 meq->rptr = 0;
342 meq->count--;
343 }
344 }
345#endif
346 }
347 /* Determine new IRQ state. */
348 if (s->status & KBD_STAT_OBF) {
349 if (s->status & KBD_STAT_MOUSE_OBF)
350 {
351 if (s->mode & KBD_MODE_MOUSE_INT)
352 irq12_level = 1;
353 }
354 else
355 { /* KBD_STAT_OBF set but KBD_STAT_MOUSE_OBF isn't. */
356 if (s->mode & KBD_MODE_KBD_INT)
357 irq1_level = 1;
358 }
359 }
360 PDMDevHlpISASetIrq(s->CTX_SUFF(pDevIns), 1, irq1_level);
361 PDMDevHlpISASetIrq(s->CTX_SUFF(pDevIns), 12, irq12_level);
362}
363
364void KBCUpdateInterrupts(void *pKbc)
365{
366 KBDState *s = (KBDState *)pKbc;
367 kbd_update_irq(s);
368}
369
370#ifndef VBOX_WITH_NEW_PS2M
371static void kbd_queue(KBDState *s, int b, int aux)
372{
373 MouseCmdQueue *mcq = &s->mouse_command_queue;
374 MouseEventQueue *meq = &s->mouse_event_queue;
375
376#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
377 if (aux == 1)
378 LogRel3(("%s: mouse command response: 0x%02x\n", __PRETTY_FUNCTION__, b));
379 else if (aux == 2)
380 LogRel3(("%s: mouse event data: 0x%02x\n", __PRETTY_FUNCTION__, b));
381#ifdef DEBUG_KBD
382 else
383 LogRel3(("%s: kbd event: 0x%02x\n", __PRETTY_FUNCTION__, b));
384#endif
385#endif
386 switch (aux)
387 {
388 case 0: /* keyboard */
389 AssertMsgFailed(("kbd_queue() no longer supported for keyboard!\n"));
390 break;
391 case 1: /* mouse command response */
392 if (mcq->count >= MOUSE_CMD_QUEUE_SIZE)
393 return;
394 mcq->data[mcq->wptr] = b;
395 if (++mcq->wptr == MOUSE_CMD_QUEUE_SIZE)
396 mcq->wptr = 0;
397 mcq->count++;
398 break;
399 case 2: /* mouse event data */
400 if (meq->count >= MOUSE_EVENT_QUEUE_SIZE)
401 return;
402 meq->data[meq->wptr] = b;
403 if (++meq->wptr == MOUSE_EVENT_QUEUE_SIZE)
404 meq->wptr = 0;
405 meq->count++;
406 break;
407 default:
408 AssertMsgFailed(("aux=%d\n", aux));
409 }
410 kbd_update_irq(s);
411}
412#endif
413
414static void kbc_dbb_out(void *opaque, uint8_t val)
415{
416 KBDState *s = (KBDState*)opaque;
417
418 s->dbbout = val;
419 /* Set the OBF and raise IRQ. */
420 s->status |= KBD_STAT_OBF;
421 if (s->mode & KBD_MODE_KBD_INT)
422 PDMDevHlpISASetIrq(s->CTX_SUFF(pDevIns), 1, 1);
423}
424
425static void kbc_dbb_out_aux(void *opaque, uint8_t val)
426{
427 KBDState *s = (KBDState*)opaque;
428
429 s->dbbout = val;
430 /* Set the aux OBF and raise IRQ. */
431 s->status |= KBD_STAT_OBF | KBD_STAT_MOUSE_OBF;
432 if (s->mode & KBD_MODE_MOUSE_INT)
433 PDMDevHlpISASetIrq(s->CTX_SUFF(pDevIns), 12, PDM_IRQ_LEVEL_HIGH);
434}
435
436static uint32_t kbd_read_status(void *opaque, uint32_t addr)
437{
438 KBDState *s = (KBDState*)opaque;
439 int val = s->status;
440 NOREF(addr);
441
442#if defined(DEBUG_KBD)
443 Log(("kbd: read status=0x%02x\n", val));
444#endif
445 return val;
446}
447
448static int kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
449{
450 int rc = VINF_SUCCESS;
451 KBDState *s = (KBDState*)opaque;
452 NOREF(addr);
453
454#ifdef DEBUG_KBD
455 Log(("kbd: write cmd=0x%02x\n", val));
456#endif
457 switch(val) {
458 case KBD_CCMD_READ_MODE:
459 kbc_dbb_out(s, s->mode);
460 break;
461 case KBD_CCMD_WRITE_MODE:
462 case KBD_CCMD_WRITE_OBUF:
463 case KBD_CCMD_WRITE_AUX_OBUF:
464 case KBD_CCMD_WRITE_MOUSE:
465 case KBD_CCMD_WRITE_OUTPORT:
466 s->write_cmd = val;
467 break;
468 case KBD_CCMD_MOUSE_DISABLE:
469 s->mode |= KBD_MODE_DISABLE_MOUSE;
470 break;
471 case KBD_CCMD_MOUSE_ENABLE:
472 s->mode &= ~KBD_MODE_DISABLE_MOUSE;
473 /* Check for queued input. */
474 kbd_update_irq(s);
475 break;
476 case KBD_CCMD_TEST_MOUSE:
477 kbc_dbb_out(s, 0x00);
478 break;
479 case KBD_CCMD_SELF_TEST:
480 /* Enable the A20 line - that is the power-on state(!). */
481# ifndef IN_RING3
482 if (!PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)))
483 {
484 rc = VINF_IOM_R3_IOPORT_WRITE;
485 break;
486 }
487# else /* IN_RING3 */
488 PDMDevHlpA20Set(s->CTX_SUFF(pDevIns), true);
489# endif /* IN_RING3 */
490 s->status |= KBD_STAT_SELFTEST;
491 s->mode |= KBD_MODE_DISABLE_KBD;
492 kbc_dbb_out(s, 0x55);
493 break;
494 case KBD_CCMD_KBD_TEST:
495 kbc_dbb_out(s, 0x00);
496 break;
497 case KBD_CCMD_KBD_DISABLE:
498 s->mode |= KBD_MODE_DISABLE_KBD;
499 break;
500 case KBD_CCMD_KBD_ENABLE:
501 s->mode &= ~KBD_MODE_DISABLE_KBD;
502 /* Check for queued input. */
503 kbd_update_irq(s);
504 break;
505 case KBD_CCMD_READ_INPORT:
506 kbc_dbb_out(s, 0xBF);
507 break;
508 case KBD_CCMD_READ_OUTPORT:
509 /* XXX: check that */
510#ifdef TARGET_I386
511 val = 0x01 | (PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)) << 1);
512#else
513 val = 0x01;
514#endif
515 if (s->status & KBD_STAT_OBF)
516 val |= 0x10;
517 if (s->status & KBD_STAT_MOUSE_OBF)
518 val |= 0x20;
519 kbc_dbb_out(s, val);
520 break;
521#ifdef TARGET_I386
522 case KBD_CCMD_ENABLE_A20:
523# ifndef IN_RING3
524 if (!PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)))
525 rc = VINF_IOM_R3_IOPORT_WRITE;
526# else /* IN_RING3 */
527 PDMDevHlpA20Set(s->CTX_SUFF(pDevIns), true);
528# endif /* IN_RING3 */
529 break;
530 case KBD_CCMD_DISABLE_A20:
531# ifndef IN_RING3
532 if (PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)))
533 rc = VINF_IOM_R3_IOPORT_WRITE;
534# else /* IN_RING3 */
535 PDMDevHlpA20Set(s->CTX_SUFF(pDevIns), false);
536# endif /* !IN_RING3 */
537 break;
538#endif
539 case KBD_CCMD_READ_TSTINP:
540 /* Keyboard clock line is zero IFF keyboard is disabled */
541 val = (s->mode & KBD_MODE_DISABLE_KBD) ? 0 : 1;
542 kbc_dbb_out(s, val);
543 break;
544 case KBD_CCMD_RESET:
545 case KBD_CCMD_RESET_ALT:
546#ifndef IN_RING3
547 rc = VINF_IOM_R3_IOPORT_WRITE;
548#else /* IN_RING3 */
549 LogRel(("Reset initiated by keyboard controller\n"));
550 rc = PDMDevHlpVMReset(s->CTX_SUFF(pDevIns), PDMVMRESET_F_KBD);
551#endif /* !IN_RING3 */
552 break;
553 case 0xff:
554 /* ignore that - I don't know what is its use */
555 break;
556 /* Make OS/2 happy. */
557 /* The 8042 RAM is readable using commands 0x20 thru 0x3f, and writable
558 by 0x60 thru 0x7f. Now days only the first byte, the mode, is used.
559 We'll ignore the writes (0x61..7f) and return 0 for all the reads
560 just to make some OS/2 debug stuff a bit happier. */
561 case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
562 case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
563 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
564 case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
565 kbc_dbb_out(s, 0);
566 Log(("kbd: reading non-standard RAM addr %#x\n", val & 0x1f));
567 break;
568 default:
569 Log(("kbd: unsupported keyboard cmd=0x%02x\n", val));
570 break;
571 }
572 return rc;
573}
574
575static uint32_t kbd_read_data(void *opaque, uint32_t addr)
576{
577 KBDState *s = (KBDState*)opaque;
578 uint32_t val;
579 NOREF(addr);
580
581 /* Return the current DBB contents. */
582 val = s->dbbout;
583
584 /* Reading the DBB deasserts IRQs... */
585 if (s->status & KBD_STAT_MOUSE_OBF)
586 PDMDevHlpISASetIrq(s->CTX_SUFF(pDevIns), 12, 0);
587 else
588 PDMDevHlpISASetIrq(s->CTX_SUFF(pDevIns), 1, 0);
589 /* ...and clears the OBF bits. */
590 s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
591
592 /* Check if more data is available. */
593 kbd_update_irq(s);
594#ifdef DEBUG_KBD
595 Log(("kbd: read data=0x%02x\n", val));
596#endif
597 return val;
598}
599
600PS2K *KBDGetPS2KFromDevIns(PPDMDEVINS pDevIns)
601{
602 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
603 return &pThis->Kbd;
604}
605
606PS2M *KBDGetPS2MFromDevIns(PPDMDEVINS pDevIns)
607{
608 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
609#ifdef VBOX_WITH_NEW_PS2M
610 return &pThis->Aux;
611#else
612 return NULL;
613#endif
614}
615
616#ifndef VBOX_WITH_NEW_PS2M
617static void kbd_mouse_set_reported_buttons(KBDState *s, unsigned fButtons, unsigned fButtonMask)
618{
619 s->mouse_buttons_reported |= (fButtons & fButtonMask);
620 s->mouse_buttons_reported &= (fButtons | ~fButtonMask);
621}
622
623/**
624 * Send a single relative packet in 3-byte PS/2 format to the PS/2 controller.
625 * @param s keyboard state object
626 * @param dx relative X value, must be between -256 and +255
627 * @param dy relative y value, must be between -256 and +255
628 * @param fButtonsLow the state of the two first mouse buttons
629 * @param fButtonsPacked the state of the upper three mouse buttons and
630 * scroll wheel movement, packed as per the
631 * MOUSE_EXT_* defines. For standard PS/2 packets
632 * only pass the value of button 3 here.
633 */
634static void kbd_mouse_send_rel3_packet(KBDState *s, bool fToCmdQueue)
635{
636 int aux = fToCmdQueue ? 1 : 2;
637 int dx1 = s->mouse_dx < 0 ? RT_MAX(s->mouse_dx, -256)
638 : RT_MIN(s->mouse_dx, 255);
639 int dy1 = s->mouse_dy < 0 ? RT_MAX(s->mouse_dy, -256)
640 : RT_MIN(s->mouse_dy, 255);
641 unsigned int b;
642 unsigned fButtonsLow = s->mouse_buttons & 0x07;
643 s->mouse_dx -= dx1;
644 s->mouse_dy -= dy1;
645 kbd_mouse_set_reported_buttons(s, fButtonsLow, 0x07);
646 LogRel3(("%s: dx1=%d, dy1=%d, fButtonsLow=0x%x\n",
647 __PRETTY_FUNCTION__, dx1, dy1, fButtonsLow));
648 b = 0x08 | ((dx1 < 0 ? 1 : 0) << 4) | ((dy1 < 0 ? 1 : 0) << 5)
649 | fButtonsLow;
650 kbd_queue(s, b, aux);
651 kbd_queue(s, dx1 & 0xff, aux);
652 kbd_queue(s, dy1 & 0xff, aux);
653}
654
655static void kbd_mouse_send_imps2_byte4(KBDState *s, bool fToCmdQueue)
656{
657 int aux = fToCmdQueue ? 1 : 2;
658
659 int dz1 = s->mouse_dz < 0 ? RT_MAX(s->mouse_dz, -127)
660 : RT_MIN(s->mouse_dz, 127);
661 LogRel3(("%s: dz1=%d\n", __PRETTY_FUNCTION__, dz1));
662 s->mouse_dz -= dz1;
663 kbd_queue(s, dz1 & 0xff, aux);
664}
665
666static void kbd_mouse_send_imex_byte4(KBDState *s, bool fToCmdQueue)
667{
668 int aux = fToCmdQueue ? 1 : 2;
669 int dz1 = 0, dw1 = 0;
670 unsigned fButtonsHigh = s->mouse_buttons & 0x18;
671
672 if (s->mouse_dw > 0)
673 dw1 = 1;
674 else if (s->mouse_dw < 0)
675 dw1 = -1;
676 else if (s->mouse_dz > 0)
677 dz1 = 1;
678 else if (s->mouse_dz < 0)
679 dz1 = -1;
680 if (s->mouse_dw && s->mouse_flags & MOUSE_REPORT_HORIZONTAL)
681 {
682 LogRel3(("%s: dw1=%d\n", __PRETTY_FUNCTION__, dw1));
683 kbd_queue(s, 0x40 | (dw1 & 0x3f), aux);
684 }
685 else
686 {
687 LogRel3(("%s: dz1=%d, dw1=%d, fButtonsHigh=0x%x\n",
688 __PRETTY_FUNCTION__, dz1, dw1, fButtonsHigh));
689 unsigned u4Low = dw1 > 0 ? 9 /* -7 & 0xf */
690 : dw1 < 0 ? 7
691 : dz1 > 0 ? 1
692 : dz1 < 0 ? 0xf /* -1 & 0xf */
693 : 0;
694 kbd_mouse_set_reported_buttons(s, fButtonsHigh, 0x18);
695 kbd_queue(s, (fButtonsHigh << 1) | u4Low, aux);
696 }
697 s->mouse_dz -= dz1;
698 s->mouse_dw -= dw1;
699}
700
701/**
702 * Send a single relative packet in (IM)PS/2 or IMEX format to the PS/2
703 * controller.
704 * @param s keyboard state object
705 * @param fToCmdQueue should this packet go to the command queue (or the
706 * event queue)?
707 */
708static void kbd_mouse_send_packet(KBDState *s, bool fToCmdQueue)
709{
710 kbd_mouse_send_rel3_packet(s, fToCmdQueue);
711 if (s->mouse_type == MOUSE_PROT_IMPS2)
712 kbd_mouse_send_imps2_byte4(s, fToCmdQueue);
713 if (s->mouse_type == MOUSE_PROT_IMEX)
714 kbd_mouse_send_imex_byte4(s, fToCmdQueue);
715}
716
717#ifdef IN_RING3
718
719static bool kbd_mouse_unreported(KBDState *s)
720{
721 return s->mouse_dx
722 || s->mouse_dy
723 || s->mouse_dz
724 || s->mouse_dw
725 || s->mouse_buttons != s->mouse_buttons_reported;
726}
727
728static size_t kbd_mouse_event_queue_free(KBDState *s)
729{
730 AssertReturn(s->mouse_event_queue.count <= MOUSE_EVENT_QUEUE_SIZE, 0);
731 return MOUSE_EVENT_QUEUE_SIZE - s->mouse_event_queue.count;
732}
733
734static void pc_kbd_mouse_event(void *opaque, int dx, int dy, int dz, int dw,
735 int buttons_state)
736{
737 LogRel3(("%s: dx=%d, dy=%d, dz=%d, dw=%d, buttons_state=0x%x\n",
738 __PRETTY_FUNCTION__, dx, dy, dz, dw, buttons_state));
739 KBDState *s = (KBDState*)opaque;
740
741 /* check if deltas are recorded when disabled */
742 if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
743 return;
744 AssertReturnVoid((buttons_state & ~0x1f) == 0);
745
746 s->mouse_dx += dx;
747 s->mouse_dy -= dy;
748 if ( (s->mouse_type == MOUSE_PROT_IMPS2)
749 || (s->mouse_type == MOUSE_PROT_IMEX))
750 s->mouse_dz += dz;
751 if (s->mouse_type == MOUSE_PROT_IMEX)
752 s->mouse_dw += dw;
753 s->mouse_buttons = buttons_state;
754 if (!(s->mouse_status & MOUSE_STATUS_REMOTE))
755 /* if not remote, send event. Multiple events are sent if
756 too big deltas */
757 while ( kbd_mouse_unreported(s)
758 && kbd_mouse_event_queue_free(s) > 4)
759 kbd_mouse_send_packet(s, false);
760}
761
762/* Report a change in status down the driver chain */
763static void kbd_mouse_update_downstream_status(KBDState *pThis)
764{
765 PPDMIMOUSECONNECTOR pDrv = pThis->Mouse.pDrv;
766 bool fEnabled = !!(pThis->mouse_status & MOUSE_STATUS_ENABLED);
767 if (pDrv)
768 pDrv->pfnReportModes(pDrv, fEnabled, false, false);
769}
770
771#endif /* IN_RING3 */
772
773static int kbd_write_mouse(KBDState *s, int val)
774{
775#ifdef DEBUG_MOUSE
776 LogRelFlowFunc(("kbd: write mouse 0x%02x\n", val));
777#endif
778 int rc = VINF_SUCCESS;
779 /* Flush the mouse command response queue. */
780 s->mouse_command_queue.count = 0;
781 s->mouse_command_queue.rptr = 0;
782 s->mouse_command_queue.wptr = 0;
783 switch(s->mouse_write_cmd) {
784 default:
785 case -1:
786 /* mouse command */
787 if (s->mouse_wrap) {
788 if (val == AUX_RESET_WRAP) {
789 s->mouse_wrap = 0;
790 kbd_queue(s, AUX_ACK, 1);
791 return VINF_SUCCESS;
792 } else if (val != AUX_RESET) {
793 kbd_queue(s, val, 1);
794 return VINF_SUCCESS;
795 }
796 }
797 switch(val) {
798 case AUX_SET_SCALE11:
799 s->mouse_status &= ~MOUSE_STATUS_SCALE21;
800 kbd_queue(s, AUX_ACK, 1);
801 break;
802 case AUX_SET_SCALE21:
803 s->mouse_status |= MOUSE_STATUS_SCALE21;
804 kbd_queue(s, AUX_ACK, 1);
805 break;
806 case AUX_SET_STREAM:
807 s->mouse_status &= ~MOUSE_STATUS_REMOTE;
808 kbd_queue(s, AUX_ACK, 1);
809 break;
810 case AUX_SET_WRAP:
811 s->mouse_wrap = 1;
812 kbd_queue(s, AUX_ACK, 1);
813 break;
814 case AUX_SET_REMOTE:
815 s->mouse_status |= MOUSE_STATUS_REMOTE;
816 kbd_queue(s, AUX_ACK, 1);
817 break;
818 case AUX_GET_TYPE:
819 kbd_queue(s, AUX_ACK, 1);
820 kbd_queue(s, s->mouse_type, 1);
821 break;
822 case AUX_SET_RES:
823 case AUX_SET_SAMPLE:
824 s->mouse_write_cmd = val;
825 kbd_queue(s, AUX_ACK, 1);
826 break;
827 case AUX_GET_SCALE:
828 kbd_queue(s, AUX_ACK, 1);
829 kbd_queue(s, s->mouse_status, 1);
830 kbd_queue(s, s->mouse_resolution, 1);
831 kbd_queue(s, s->mouse_sample_rate, 1);
832 break;
833 case AUX_POLL:
834 kbd_queue(s, AUX_ACK, 1);
835 kbd_mouse_send_packet(s, true);
836 break;
837 case AUX_ENABLE_DEV:
838#ifdef IN_RING3
839 LogRelFlowFunc(("Enabling mouse device\n"));
840 s->mouse_status |= MOUSE_STATUS_ENABLED;
841 kbd_queue(s, AUX_ACK, 1);
842 kbd_mouse_update_downstream_status(s);
843#else
844 LogRelFlowFunc(("Enabling mouse device, R0 stub\n"));
845 rc = VINF_IOM_R3_IOPORT_WRITE;
846#endif
847 break;
848 case AUX_DISABLE_DEV:
849#ifdef IN_RING3
850 s->mouse_status &= ~MOUSE_STATUS_ENABLED;
851 kbd_queue(s, AUX_ACK, 1);
852 /* Flush the mouse events queue. */
853 s->mouse_event_queue.count = 0;
854 s->mouse_event_queue.rptr = 0;
855 s->mouse_event_queue.wptr = 0;
856 kbd_mouse_update_downstream_status(s);
857#else
858 rc = VINF_IOM_R3_IOPORT_WRITE;
859#endif
860 break;
861 case AUX_SET_DEFAULT:
862#ifdef IN_RING3
863 s->mouse_sample_rate = 100;
864 s->mouse_resolution = 2;
865 s->mouse_status = 0;
866 kbd_queue(s, AUX_ACK, 1);
867 kbd_mouse_update_downstream_status(s);
868#else
869 rc = VINF_IOM_R3_IOPORT_WRITE;
870#endif
871 break;
872 case AUX_RESET:
873#ifdef IN_RING3
874 s->mouse_sample_rate = 100;
875 s->mouse_resolution = 2;
876 s->mouse_status = 0;
877 s->mouse_type = MOUSE_PROT_PS2;
878 kbd_queue(s, AUX_ACK, 1);
879 kbd_queue(s, 0xaa, 1);
880 kbd_queue(s, s->mouse_type, 1);
881 /* Flush the mouse events queue. */
882 s->mouse_event_queue.count = 0;
883 s->mouse_event_queue.rptr = 0;
884 s->mouse_event_queue.wptr = 0;
885 kbd_mouse_update_downstream_status(s);
886#else
887 rc = VINF_IOM_R3_IOPORT_WRITE;
888#endif
889 break;
890 default:
891 /* NACK all commands we don't know.
892
893 The usecase for this is the OS/2 mouse driver which will try
894 read 0xE2 in order to figure out if it's a trackpoint device
895 or not. If it doesn't get a NACK (or ACK) on the command it'll
896 do several hundred thousand status reads before giving up. This
897 is slows down the OS/2 boot up considerably. (It also seems that
898 the code is somehow vulnerable while polling like this and that
899 mouse or keyboard input at this point might screw things up badly.)
900
901 From http://www.win.tue.nl/~aeb/linux/kbd/scancodes-13.html:
902
903 Every command or data byte sent to the mouse (except for the
904 resend command fe) is ACKed with fa. If the command or data
905 is invalid, it is NACKed with fe. If the next byte is again
906 invalid, the reply is ERROR: fc. */
907 /** @todo send error if we NACKed the previous command? */
908 kbd_queue(s, AUX_NACK, 1);
909 break;
910 }
911 break;
912 case AUX_SET_SAMPLE:
913 s->mouse_sample_rate = val;
914 /* detect IMPS/2 or IMEX */
915 /* And enable horizontal scrolling reporting when requested */
916 switch(s->mouse_detect_state) {
917 default:
918 case 0:
919 if (val == 200)
920 s->mouse_detect_state = 1;
921 break;
922 case 1:
923 if (val == 100)
924 s->mouse_detect_state = 2;
925 else if (val == 200)
926 s->mouse_detect_state = 3;
927 else if ((val == 80) && s->mouse_type == MOUSE_PROT_IMEX)
928 /* enable horizontal scrolling, byte two */
929 s->mouse_detect_state = 4;
930 else
931 s->mouse_detect_state = 0;
932 break;
933 case 2:
934 if (val == 80 && s->mouse_type < MOUSE_PROT_IMEX)
935 {
936 LogRelFlowFunc(("switching mouse device to IMPS/2 mode\n"));
937 s->mouse_type = MOUSE_PROT_IMPS2;
938 }
939 s->mouse_detect_state = 0;
940 break;
941 case 3:
942 if (val == 80)
943 {
944 LogRelFlowFunc(("switching mouse device to IMEX mode\n"));
945 s->mouse_type = MOUSE_PROT_IMEX;
946 }
947 s->mouse_detect_state = 0;
948 break;
949 case 4:
950 if (val == 40)
951 {
952 LogRelFlowFunc(("enabling IMEX horizontal scrolling reporting\n"));
953 s->mouse_flags |= MOUSE_REPORT_HORIZONTAL;
954 }
955 s->mouse_detect_state = 0;
956 break;
957 }
958 kbd_queue(s, AUX_ACK, 1);
959 s->mouse_write_cmd = -1;
960 break;
961 case AUX_SET_RES:
962 if (0 <= val && val < 4)
963 {
964 s->mouse_resolution = val;
965 kbd_queue(s, AUX_ACK, 1);
966 }
967 else
968 kbd_queue(s, AUX_NACK, 1);
969 s->mouse_write_cmd = -1;
970 break;
971 }
972 return rc;
973}
974#endif
975
976static int kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
977{
978 int rc = VINF_SUCCESS;
979 KBDState *s = (KBDState*)opaque;
980 NOREF(addr);
981
982#ifdef DEBUG_KBD
983 Log(("kbd: write data=0x%02x\n", val));
984#endif
985
986 switch(s->write_cmd) {
987 case 0:
988 /* Automatically enables keyboard interface. */
989 s->mode &= ~KBD_MODE_DISABLE_KBD;
990 rc = PS2KByteToKbd(&s->Kbd, val);
991 if (rc == VINF_SUCCESS)
992 kbd_update_irq(s);
993 break;
994 case KBD_CCMD_WRITE_MODE:
995 s->mode = val;
996 s->translate = (s->mode & KBD_MODE_KCC) == KBD_MODE_KCC;
997 kbd_update_irq(s);
998 break;
999 case KBD_CCMD_WRITE_OBUF:
1000 kbc_dbb_out(s, val);
1001 break;
1002 case KBD_CCMD_WRITE_AUX_OBUF:
1003 kbc_dbb_out_aux(s, val);
1004 break;
1005 case KBD_CCMD_WRITE_OUTPORT:
1006#ifdef TARGET_I386
1007# ifndef IN_RING3
1008 if (PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)) != !!(val & 2))
1009 rc = VINF_IOM_R3_IOPORT_WRITE;
1010# else /* IN_RING3 */
1011 PDMDevHlpA20Set(s->CTX_SUFF(pDevIns), !!(val & 2));
1012# endif /* !IN_RING3 */
1013#endif
1014 if (!(val & 1)) {
1015# ifndef IN_RING3
1016 rc = VINF_IOM_R3_IOPORT_WRITE;
1017# else
1018 rc = PDMDevHlpVMReset(s->CTX_SUFF(pDevIns), PDMVMRESET_F_KBD);
1019# endif
1020 }
1021 break;
1022 case KBD_CCMD_WRITE_MOUSE:
1023 /* Automatically enables aux interface. */
1024 s->mode &= ~KBD_MODE_DISABLE_MOUSE;
1025#ifdef VBOX_WITH_NEW_PS2M
1026 rc = PS2MByteToAux(&s->Aux, val);
1027 if (rc == VINF_SUCCESS)
1028 kbd_update_irq(s);
1029#else
1030 rc = kbd_write_mouse(s, val);
1031#endif
1032 break;
1033 default:
1034 break;
1035 }
1036 if (rc != VINF_IOM_R3_IOPORT_WRITE)
1037 s->write_cmd = 0;
1038 return rc;
1039}
1040
1041#ifdef IN_RING3
1042
1043static void kbd_reset(void *opaque)
1044{
1045 KBDState *s = (KBDState*)opaque;
1046#ifndef VBOX_WITH_NEW_PS2M
1047 MouseCmdQueue *mcq;
1048 MouseEventQueue *meq;
1049
1050 s->mouse_write_cmd = -1;
1051#endif
1052 s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
1053 s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
1054 /* Resetting everything, keyword was not working right on NT4 reboot. */
1055 s->write_cmd = 0;
1056 s->translate = 0;
1057#ifndef VBOX_WITH_NEW_PS2M
1058 if (s->mouse_status)
1059 {
1060 s->mouse_status = 0;
1061 kbd_mouse_update_downstream_status(s);
1062 }
1063 s->mouse_resolution = 0;
1064 s->mouse_sample_rate = 0;
1065 s->mouse_wrap = 0;
1066 s->mouse_type = MOUSE_PROT_PS2;
1067 s->mouse_detect_state = 0;
1068 s->mouse_dx = 0;
1069 s->mouse_dy = 0;
1070 s->mouse_dz = 0;
1071 s->mouse_dw = 0;
1072 s->mouse_flags = 0;
1073 s->mouse_buttons = 0;
1074 s->mouse_buttons_reported = 0;
1075 mcq = &s->mouse_command_queue;
1076 mcq->rptr = 0;
1077 mcq->wptr = 0;
1078 mcq->count = 0;
1079 meq = &s->mouse_event_queue;
1080 meq->rptr = 0;
1081 meq->wptr = 0;
1082 meq->count = 0;
1083#endif
1084}
1085
1086static void kbd_save(PSSMHANDLE pSSM, KBDState *s)
1087{
1088#ifndef VBOX_WITH_NEW_PS2M
1089 uint32_t cItems;
1090 int i;
1091#endif
1092
1093 SSMR3PutU8(pSSM, s->write_cmd);
1094 SSMR3PutU8(pSSM, s->status);
1095 SSMR3PutU8(pSSM, s->mode);
1096 SSMR3PutU8(pSSM, s->dbbout);
1097#ifndef VBOX_WITH_NEW_PS2M
1098 SSMR3PutU32(pSSM, s->mouse_write_cmd);
1099 SSMR3PutU8(pSSM, s->mouse_status);
1100 SSMR3PutU8(pSSM, s->mouse_resolution);
1101 SSMR3PutU8(pSSM, s->mouse_sample_rate);
1102 SSMR3PutU8(pSSM, s->mouse_wrap);
1103 SSMR3PutU8(pSSM, s->mouse_type);
1104 SSMR3PutU8(pSSM, s->mouse_detect_state);
1105 SSMR3PutU32(pSSM, s->mouse_dx);
1106 SSMR3PutU32(pSSM, s->mouse_dy);
1107 SSMR3PutU32(pSSM, s->mouse_dz);
1108 SSMR3PutU32(pSSM, s->mouse_dw);
1109 SSMR3PutU32(pSSM, s->mouse_flags);
1110 SSMR3PutU8(pSSM, s->mouse_buttons);
1111 SSMR3PutU8(pSSM, s->mouse_buttons_reported);
1112
1113 cItems = s->mouse_command_queue.count;
1114 SSMR3PutU32(pSSM, cItems);
1115 for (i = s->mouse_command_queue.rptr; cItems-- > 0; i = (i + 1) % RT_ELEMENTS(s->mouse_command_queue.data))
1116 SSMR3PutU8(pSSM, s->mouse_command_queue.data[i]);
1117 Log(("kbd_save: %d mouse command queue items stored\n", s->mouse_command_queue.count));
1118
1119 cItems = s->mouse_event_queue.count;
1120 SSMR3PutU32(pSSM, cItems);
1121 for (i = s->mouse_event_queue.rptr; cItems-- > 0; i = (i + 1) % RT_ELEMENTS(s->mouse_event_queue.data))
1122 SSMR3PutU8(pSSM, s->mouse_event_queue.data[i]);
1123 Log(("kbd_save: %d mouse event queue items stored\n", s->mouse_event_queue.count));
1124#endif
1125
1126 /* terminator */
1127 SSMR3PutU32(pSSM, ~0);
1128}
1129
1130static int kbd_load(PSSMHANDLE pSSM, KBDState *s, uint32_t version_id)
1131{
1132 uint32_t u32, i;
1133 uint8_t u8Dummy;
1134 uint32_t u32Dummy;
1135 int rc;
1136
1137#if 0
1138 /** @todo enable this and remove the "if (version_id == 4)" code at some
1139 * later time */
1140 /* Version 4 was never created by any publicly released version of VBox */
1141 AssertReturn(version_id != 4, VERR_NOT_SUPPORTED);
1142#endif
1143 if (version_id < 2 || version_id > PCKBD_SAVED_STATE_VERSION)
1144 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1145 SSMR3GetU8(pSSM, &s->write_cmd);
1146 SSMR3GetU8(pSSM, &s->status);
1147 SSMR3GetU8(pSSM, &s->mode);
1148 if (version_id <= 5)
1149 {
1150 SSMR3GetU32(pSSM, (uint32_t *)&u32Dummy);
1151 SSMR3GetU32(pSSM, (uint32_t *)&u32Dummy);
1152 }
1153 else
1154 {
1155 SSMR3GetU8(pSSM, &s->dbbout);
1156 }
1157#ifndef VBOX_WITH_NEW_PS2M
1158 SSMR3GetU32(pSSM, (uint32_t *)&s->mouse_write_cmd);
1159 SSMR3GetU8(pSSM, &s->mouse_status);
1160 SSMR3GetU8(pSSM, &s->mouse_resolution);
1161 SSMR3GetU8(pSSM, &s->mouse_sample_rate);
1162 SSMR3GetU8(pSSM, &s->mouse_wrap);
1163 SSMR3GetU8(pSSM, &s->mouse_type);
1164 SSMR3GetU8(pSSM, &s->mouse_detect_state);
1165 SSMR3GetU32(pSSM, (uint32_t *)&s->mouse_dx);
1166 SSMR3GetU32(pSSM, (uint32_t *)&s->mouse_dy);
1167 SSMR3GetU32(pSSM, (uint32_t *)&s->mouse_dz);
1168 if (version_id > 2)
1169 {
1170 SSMR3GetS32(pSSM, &s->mouse_dw);
1171 SSMR3GetS32(pSSM, &s->mouse_flags);
1172 }
1173 SSMR3GetU8(pSSM, &s->mouse_buttons);
1174 if (version_id == 4)
1175 {
1176 SSMR3GetU32(pSSM, &u32Dummy);
1177 SSMR3GetU32(pSSM, &u32Dummy);
1178 }
1179 if (version_id > 3)
1180 SSMR3GetU8(pSSM, &s->mouse_buttons_reported);
1181 if (version_id == 4)
1182 SSMR3GetU8(pSSM, &u8Dummy);
1183 s->mouse_command_queue.count = 0;
1184 s->mouse_command_queue.rptr = 0;
1185 s->mouse_command_queue.wptr = 0;
1186 s->mouse_event_queue.count = 0;
1187 s->mouse_event_queue.rptr = 0;
1188 s->mouse_event_queue.wptr = 0;
1189#else
1190 if (version_id <= 7)
1191 {
1192 int32_t i32Dummy;
1193 uint8_t u8State;
1194 uint8_t u8Rate;
1195 uint8_t u8Proto;
1196
1197 SSMR3GetU32(pSSM, &u32Dummy);
1198 SSMR3GetU8(pSSM, &u8State);
1199 SSMR3GetU8(pSSM, &u8Dummy);
1200 SSMR3GetU8(pSSM, &u8Rate);
1201 SSMR3GetU8(pSSM, &u8Dummy);
1202 SSMR3GetU8(pSSM, &u8Proto);
1203 SSMR3GetU8(pSSM, &u8Dummy);
1204 SSMR3GetS32(pSSM, &i32Dummy);
1205 SSMR3GetS32(pSSM, &i32Dummy);
1206 SSMR3GetS32(pSSM, &i32Dummy);
1207 if (version_id > 2)
1208 {
1209 SSMR3GetS32(pSSM, &i32Dummy);
1210 SSMR3GetS32(pSSM, &i32Dummy);
1211 }
1212 rc = SSMR3GetU8(pSSM, &u8Dummy);
1213 if (version_id == 4)
1214 {
1215 SSMR3GetU32(pSSM, &u32Dummy);
1216 rc = SSMR3GetU32(pSSM, &u32Dummy);
1217 }
1218 if (version_id > 3)
1219 rc = SSMR3GetU8(pSSM, &u8Dummy);
1220 if (version_id == 4)
1221 rc = SSMR3GetU8(pSSM, &u8Dummy);
1222 AssertLogRelRCReturn(rc, rc);
1223
1224 PS2MFixupState(&s->Aux, u8State, u8Rate, u8Proto);
1225 }
1226#endif
1227
1228 /* Determine the translation state. */
1229 s->translate = (s->mode & KBD_MODE_KCC) == KBD_MODE_KCC;
1230
1231 /*
1232 * Load the queues
1233 */
1234 if (version_id <= 5)
1235 {
1236 rc = SSMR3GetU32(pSSM, &u32);
1237 if (RT_FAILURE(rc))
1238 return rc;
1239 for (i = 0; i < u32; i++)
1240 {
1241 rc = SSMR3GetU8(pSSM, &u8Dummy);
1242 if (RT_FAILURE(rc))
1243 return rc;
1244 }
1245 Log(("kbd_load: %d keyboard queue items discarded from old saved state\n", u32));
1246 }
1247
1248#ifndef VBOX_WITH_NEW_PS2M
1249 rc = SSMR3GetU32(pSSM, &u32);
1250 if (RT_FAILURE(rc))
1251 return rc;
1252 if (u32 > RT_ELEMENTS(s->mouse_command_queue.data))
1253 {
1254 AssertMsgFailed(("u32=%#x\n", u32));
1255 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1256 }
1257 for (i = 0; i < u32; i++)
1258 {
1259 rc = SSMR3GetU8(pSSM, &s->mouse_command_queue.data[i]);
1260 if (RT_FAILURE(rc))
1261 return rc;
1262 }
1263 s->mouse_command_queue.wptr = u32 % RT_ELEMENTS(s->mouse_command_queue.data);
1264 s->mouse_command_queue.count = u32;
1265 Log(("kbd_load: %d mouse command queue items loaded\n", u32));
1266
1267 rc = SSMR3GetU32(pSSM, &u32);
1268 if (RT_FAILURE(rc))
1269 return rc;
1270 if (u32 > RT_ELEMENTS(s->mouse_event_queue.data))
1271 {
1272 AssertMsgFailed(("u32=%#x\n", u32));
1273 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1274 }
1275 for (i = 0; i < u32; i++)
1276 {
1277 rc = SSMR3GetU8(pSSM, &s->mouse_event_queue.data[i]);
1278 if (RT_FAILURE(rc))
1279 return rc;
1280 }
1281 s->mouse_event_queue.wptr = u32 % RT_ELEMENTS(s->mouse_event_queue.data);
1282 s->mouse_event_queue.count = u32;
1283 Log(("kbd_load: %d mouse event queue items loaded\n", u32));
1284#else
1285 if (version_id <= 7)
1286 {
1287 rc = SSMR3GetU32(pSSM, &u32);
1288 if (RT_FAILURE(rc))
1289 return rc;
1290 for (i = 0; i < u32; i++)
1291 {
1292 rc = SSMR3GetU8(pSSM, &u8Dummy);
1293 if (RT_FAILURE(rc))
1294 return rc;
1295 }
1296 Log(("kbd_load: %d mouse event queue items discarded from old saved state\n", u32));
1297
1298 rc = SSMR3GetU32(pSSM, &u32);
1299 if (RT_FAILURE(rc))
1300 return rc;
1301 for (i = 0; i < u32; i++)
1302 {
1303 rc = SSMR3GetU8(pSSM, &u8Dummy);
1304 if (RT_FAILURE(rc))
1305 return rc;
1306 }
1307 Log(("kbd_load: %d mouse command queue items discarded from old saved state\n", u32));
1308 }
1309#endif
1310
1311 /* terminator */
1312 rc = SSMR3GetU32(pSSM, &u32);
1313 if (RT_FAILURE(rc))
1314 return rc;
1315 if (u32 != ~0U)
1316 {
1317 AssertMsgFailed(("u32=%#x\n", u32));
1318 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1319 }
1320#ifndef VBOX_WITH_NEW_PS2M
1321 /* Resend a notification to Main if the device is active */
1322 kbd_mouse_update_downstream_status(s);
1323#endif
1324 return 0;
1325}
1326#endif /* IN_RING3 */
1327
1328
1329/* VirtualBox code start */
1330
1331/* -=-=-=-=-=- wrappers -=-=-=-=-=- */
1332
1333/**
1334 * Port I/O Handler for keyboard data IN operations.
1335 *
1336 * @returns VBox status code.
1337 *
1338 * @param pDevIns The device instance.
1339 * @param pvUser User argument - ignored.
1340 * @param Port Port number used for the IN operation.
1341 * @param pu32 Where to store the result.
1342 * @param cb Number of bytes read.
1343 */
1344PDMBOTHCBDECL(int) kbdIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1345{
1346 NOREF(pvUser);
1347 if (cb == 1)
1348 {
1349 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1350 *pu32 = kbd_read_data(pThis, Port);
1351 Log2(("kbdIOPortDataRead: Port=%#x cb=%d *pu32=%#x\n", Port, cb, *pu32));
1352 return VINF_SUCCESS;
1353 }
1354 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1355 return VERR_IOM_IOPORT_UNUSED;
1356}
1357
1358/**
1359 * Port I/O Handler for keyboard data OUT operations.
1360 *
1361 * @returns VBox status code.
1362 *
1363 * @param pDevIns The device instance.
1364 * @param pvUser User argument - ignored.
1365 * @param Port Port number used for the IN operation.
1366 * @param u32 The value to output.
1367 * @param cb The value size in bytes.
1368 */
1369PDMBOTHCBDECL(int) kbdIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1370{
1371 int rc = VINF_SUCCESS;
1372 NOREF(pvUser);
1373 if (cb == 1 || cb == 2)
1374 {
1375 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1376 rc = kbd_write_data(pThis, Port, (uint8_t)u32);
1377 Log2(("kbdIOPortDataWrite: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1378 }
1379 else
1380 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1381 return rc;
1382}
1383
1384/**
1385 * Port I/O Handler for keyboard status IN operations.
1386 *
1387 * @returns VBox status code.
1388 *
1389 * @param pDevIns The device instance.
1390 * @param pvUser User argument - ignored.
1391 * @param Port Port number used for the IN operation.
1392 * @param pu32 Where to store the result.
1393 * @param cb Number of bytes read.
1394 */
1395PDMBOTHCBDECL(int) kbdIOPortStatusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1396{
1397 uint16_t fluff = 0;
1398 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1399
1400 NOREF(pvUser);
1401 switch (cb) {
1402 case 2:
1403 fluff = 0xff00;
1404 case 1:
1405 *pu32 = fluff | kbd_read_status(pThis, Port);
1406 Log2(("kbdIOPortStatusRead: Port=%#x cb=%d -> *pu32=%#x\n", Port, cb, *pu32));
1407 return VINF_SUCCESS;
1408 default:
1409 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1410 return VERR_IOM_IOPORT_UNUSED;
1411 }
1412}
1413
1414/**
1415 * Port I/O Handler for keyboard command OUT operations.
1416 *
1417 * @returns VBox status code.
1418 *
1419 * @param pDevIns The device instance.
1420 * @param pvUser User argument - ignored.
1421 * @param Port Port number used for the IN operation.
1422 * @param u32 The value to output.
1423 * @param cb The value size in bytes.
1424 */
1425PDMBOTHCBDECL(int) kbdIOPortCommandWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1426{
1427 int rc = VINF_SUCCESS;
1428 NOREF(pvUser);
1429 if (cb == 1 || cb == 2)
1430 {
1431 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1432 rc = kbd_write_command(pThis, Port, (uint8_t)u32);
1433 Log2(("kbdIOPortCommandWrite: Port=%#x cb=%d u32=%#x rc=%Rrc\n", Port, cb, u32, rc));
1434 }
1435 else
1436 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1437 return rc;
1438}
1439
1440#ifdef IN_RING3
1441
1442/**
1443 * Saves a state of the keyboard device.
1444 *
1445 * @returns VBox status code.
1446 * @param pDevIns The device instance.
1447 * @param pSSM The handle to save the state to.
1448 */
1449static DECLCALLBACK(int) kbdSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1450{
1451 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1452 kbd_save(pSSM, pThis);
1453 PS2KSaveState(&pThis->Kbd, pSSM);
1454#ifdef VBOX_WITH_NEW_PS2M
1455 PS2MSaveState(&pThis->Aux, pSSM);
1456#endif
1457 return VINF_SUCCESS;
1458}
1459
1460
1461/**
1462 * Loads a saved keyboard device state.
1463 *
1464 * @returns VBox status code.
1465 * @param pDevIns The device instance.
1466 * @param pSSM The handle to the saved state.
1467 * @param uVersion The data unit version number.
1468 * @param uPass The data pass.
1469 */
1470static DECLCALLBACK(int) kbdLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1471{
1472 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1473 int rc;
1474
1475 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1476 rc = kbd_load(pSSM, pThis, uVersion);
1477 if (uVersion >= 6)
1478 rc = PS2KLoadState(&pThis->Kbd, pSSM, uVersion);
1479#ifdef VBOX_WITH_NEW_PS2M
1480 if (uVersion >= 8)
1481 rc = PS2MLoadState(&pThis->Aux, pSSM, uVersion);
1482#endif
1483 return rc;
1484}
1485
1486/**
1487 * @callback_method_impl{FNSSMDEVLOADDONE, Key state fix-up after loading
1488 */
1489static DECLCALLBACK(int) kbdLoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1490{
1491 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1492 int rc;
1493
1494 rc = PS2KLoadDone(&pThis->Kbd, pSSM);
1495 return rc;
1496}
1497
1498/**
1499 * Reset notification.
1500 *
1501 * @returns VBox status code.
1502 * @param pDevIns The device instance data.
1503 */
1504static DECLCALLBACK(void) kbdReset(PPDMDEVINS pDevIns)
1505{
1506 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1507
1508 kbd_reset(pThis);
1509 PS2KReset(&pThis->Kbd);
1510#ifdef VBOX_WITH_NEW_PS2M
1511 PS2MReset(&pThis->Aux);
1512#endif
1513}
1514
1515
1516#ifndef VBOX_WITH_NEW_PS2M
1517/* -=-=-=-=-=- Mouse: IBase -=-=-=-=-=- */
1518
1519/**
1520 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1521 */
1522static DECLCALLBACK(void *) kbdMouseQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1523{
1524 KBDState *pThis = RT_FROM_MEMBER(pInterface, KBDState, Mouse.IBase);
1525 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Mouse.IBase);
1526 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSEPORT, &pThis->Mouse.IPort);
1527 return NULL;
1528}
1529
1530
1531/* -=-=-=-=-=- Mouse: IMousePort -=-=-=-=-=- */
1532
1533/**
1534 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEvent}
1535 */
1536static DECLCALLBACK(int) kbdMousePutEvent(PPDMIMOUSEPORT pInterface, int32_t dx,
1537 int32_t dy, int32_t dz, int32_t dw,
1538 uint32_t fButtons)
1539{
1540 KBDState *pThis = RT_FROM_MEMBER(pInterface, KBDState, Mouse.IPort);
1541 int rc = PDMCritSectEnter(pThis->pDevInsR3->pCritSectRoR3, VERR_SEM_BUSY);
1542 AssertReleaseRC(rc);
1543
1544 pc_kbd_mouse_event(pThis, dx, dy, dz, dw, fButtons);
1545
1546 PDMCritSectLeave(pThis->pDevInsR3->pCritSectRoR3);
1547 return VINF_SUCCESS;
1548}
1549
1550/**
1551 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventAbs}
1552 */
1553static DECLCALLBACK(int) kbdMousePutEventAbs(PPDMIMOUSEPORT pInterface,
1554 uint32_t x, uint32_t y, int32_t dz,
1555 int32_t dw, uint32_t fButtons)
1556{
1557 AssertFailedReturn(VERR_NOT_SUPPORTED);
1558 NOREF(pInterface); NOREF(x); NOREF(y); NOREF(dz); NOREF(dw); NOREF(fButtons);
1559}
1560
1561/**
1562 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventMultiTouch}
1563 */
1564static DECLCALLBACK(int) kbdMousePutEventMultiTouch(PPDMIMOUSEPORT pInterface,
1565 uint8_t cContacts,
1566 const uint64_t *pau64Contacts,
1567 uint32_t u32ScanTime)
1568{
1569 AssertFailedReturn(VERR_NOT_SUPPORTED);
1570 NOREF(pInterface); NOREF(cContacts); NOREF(pau64Contacts); NOREF(u32ScanTime);
1571}
1572#endif
1573
1574/* -=-=-=-=-=- real code -=-=-=-=-=- */
1575
1576
1577/**
1578 * Attach command.
1579 *
1580 * This is called to let the device attach to a driver for a specified LUN
1581 * during runtime. This is not called during VM construction, the device
1582 * constructor have to attach to all the available drivers.
1583 *
1584 * This is like plugging in the keyboard or mouse after turning on the PC.
1585 *
1586 * @returns VBox status code.
1587 * @param pDevIns The device instance.
1588 * @param iLUN The logical unit which is being detached.
1589 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1590 * @remark The keyboard controller doesn't support this action, this is just
1591 * implemented to try out the driver<->device structure.
1592 */
1593static DECLCALLBACK(int) kbdAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1594{
1595 int rc;
1596 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1597
1598 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
1599 ("PS/2 device does not support hotplugging\n"),
1600 VERR_INVALID_PARAMETER);
1601
1602 switch (iLUN)
1603 {
1604 /* LUN #0: keyboard */
1605 case 0:
1606 rc = PS2KAttach(&pThis->Kbd, pDevIns, iLUN, fFlags);
1607 if (RT_FAILURE(rc))
1608 return rc;
1609 break;
1610
1611 /* LUN #1: aux/mouse */
1612 case 1:
1613#ifdef VBOX_WITH_NEW_PS2M
1614 rc = PS2MAttach(&pThis->Aux, pDevIns, iLUN, fFlags);
1615#else
1616 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->Mouse.IBase, &pThis->Mouse.pDrvBase, "Aux (Mouse) Port");
1617 if (RT_SUCCESS(rc))
1618 {
1619 pThis->Mouse.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Mouse.pDrvBase, PDMIMOUSECONNECTOR);
1620 if (!pThis->Mouse.pDrv)
1621 {
1622 AssertLogRelMsgFailed(("LUN #1 doesn't have a mouse interface! rc=%Rrc\n", rc));
1623 rc = VERR_PDM_MISSING_INTERFACE;
1624 }
1625 }
1626 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1627 {
1628 Log(("%s/%d: warning: no driver attached to LUN #1!\n", pDevIns->pReg->szName, pDevIns->iInstance));
1629 rc = VINF_SUCCESS;
1630 }
1631 else
1632 AssertLogRelMsgFailed(("Failed to attach LUN #1! rc=%Rrc\n", rc));
1633#endif
1634 break;
1635
1636 default:
1637 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
1638 return VERR_PDM_NO_SUCH_LUN;
1639 }
1640
1641 return rc;
1642}
1643
1644
1645/**
1646 * Detach notification.
1647 *
1648 * This is called when a driver is detaching itself from a LUN of the device.
1649 * The device should adjust it's state to reflect this.
1650 *
1651 * This is like unplugging the network cable to use it for the laptop or
1652 * something while the PC is still running.
1653 *
1654 * @param pDevIns The device instance.
1655 * @param iLUN The logical unit which is being detached.
1656 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1657 * @remark The keyboard controller doesn't support this action, this is just
1658 * implemented to try out the driver<->device structure.
1659 */
1660static DECLCALLBACK(void) kbdDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1661{
1662#if 0
1663 /*
1664 * Reset the interfaces and update the controller state.
1665 */
1666 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1667 switch (iLUN)
1668 {
1669 /* LUN #0: keyboard */
1670 case 0:
1671 pThis->Keyboard.pDrv = NULL;
1672 pThis->Keyboard.pDrvBase = NULL;
1673 break;
1674
1675 /* LUN #1: aux/mouse */
1676 case 1:
1677 pThis->Mouse.pDrv = NULL;
1678 pThis->Mouse.pDrvBase = NULL;
1679 break;
1680
1681 default:
1682 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
1683 break;
1684 }
1685#else
1686 NOREF(pDevIns); NOREF(iLUN); NOREF(fFlags);
1687#endif
1688}
1689
1690
1691/**
1692 * @copydoc FNPDMDEVRELOCATE
1693 */
1694static DECLCALLBACK(void) kbdRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1695{
1696 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1697 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1698 PS2KRelocate(&pThis->Kbd, offDelta, pDevIns);
1699#ifdef VBOX_WITH_NEW_PS2M
1700 PS2MRelocate(&pThis->Aux, offDelta, pDevIns);
1701#endif
1702}
1703
1704
1705/**
1706 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1707 */
1708static DECLCALLBACK(int) kbdConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1709{
1710 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1711 int rc;
1712 bool fGCEnabled;
1713 bool fR0Enabled;
1714 Assert(iInstance == 0);
1715
1716 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1717
1718 /*
1719 * Validate and read the configuration.
1720 */
1721 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0R0Enabled\0"))
1722 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1723 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
1724 if (RT_FAILURE(rc))
1725 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to query \"GCEnabled\" from the config"));
1726 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
1727 if (RT_FAILURE(rc))
1728 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to query \"R0Enabled\" from the config"));
1729 Log(("pckbd: fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fGCEnabled, fR0Enabled));
1730
1731
1732 /*
1733 * Initialize the interfaces.
1734 */
1735 pThis->pDevInsR3 = pDevIns;
1736 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1737 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1738
1739 rc = PS2KConstruct(&pThis->Kbd, pDevIns, pThis, iInstance);
1740 if (RT_FAILURE(rc))
1741 return rc;
1742
1743#ifdef VBOX_WITH_NEW_PS2M
1744 rc = PS2MConstruct(&pThis->Aux, pDevIns, pThis, iInstance);
1745 if (RT_FAILURE(rc))
1746 return rc;
1747#else
1748 pThis->Mouse.IBase.pfnQueryInterface = kbdMouseQueryInterface;
1749 pThis->Mouse.IPort.pfnPutEvent = kbdMousePutEvent;
1750 pThis->Mouse.IPort.pfnPutEventAbs = kbdMousePutEventAbs;
1751 pThis->Mouse.IPort.pfnPutEventMultiTouch = kbdMousePutEventMultiTouch;
1752#endif
1753
1754 /*
1755 * Register I/O ports, save state, keyboard event handler and mouse event handlers.
1756 */
1757 rc = PDMDevHlpIOPortRegister(pDevIns, 0x60, 1, NULL, kbdIOPortDataWrite, kbdIOPortDataRead, NULL, NULL, "PC Keyboard - Data");
1758 if (RT_FAILURE(rc))
1759 return rc;
1760 rc = PDMDevHlpIOPortRegister(pDevIns, 0x64, 1, NULL, kbdIOPortCommandWrite, kbdIOPortStatusRead, NULL, NULL, "PC Keyboard - Command / Status");
1761 if (RT_FAILURE(rc))
1762 return rc;
1763 if (fGCEnabled)
1764 {
1765 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x60, 1, 0, "kbdIOPortDataWrite", "kbdIOPortDataRead", NULL, NULL, "PC Keyboard - Data");
1766 if (RT_FAILURE(rc))
1767 return rc;
1768 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x64, 1, 0, "kbdIOPortCommandWrite", "kbdIOPortStatusRead", NULL, NULL, "PC Keyboard - Command / Status");
1769 if (RT_FAILURE(rc))
1770 return rc;
1771 }
1772 if (fR0Enabled)
1773 {
1774 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x60, 1, 0, "kbdIOPortDataWrite", "kbdIOPortDataRead", NULL, NULL, "PC Keyboard - Data");
1775 if (RT_FAILURE(rc))
1776 return rc;
1777 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x64, 1, 0, "kbdIOPortCommandWrite", "kbdIOPortStatusRead", NULL, NULL, "PC Keyboard - Command / Status");
1778 if (RT_FAILURE(rc))
1779 return rc;
1780 }
1781 rc = PDMDevHlpSSMRegisterEx(pDevIns, PCKBD_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
1782 NULL, NULL, NULL,
1783 NULL, kbdSaveExec, NULL,
1784 NULL, kbdLoadExec, kbdLoadDone);
1785 if (RT_FAILURE(rc))
1786 return rc;
1787
1788 /*
1789 * Attach to the keyboard and mouse drivers.
1790 */
1791 rc = kbdAttach(pDevIns, 0 /* keyboard LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
1792 if (RT_FAILURE(rc))
1793 return rc;
1794 rc = kbdAttach(pDevIns, 1 /* aux/mouse LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
1795 if (RT_FAILURE(rc))
1796 return rc;
1797
1798 /*
1799 * Initialize the device state.
1800 */
1801 kbdReset(pDevIns);
1802
1803 return VINF_SUCCESS;
1804}
1805
1806
1807/**
1808 * The device registration structure.
1809 */
1810const PDMDEVREG g_DevicePS2KeyboardMouse =
1811{
1812 /* u32Version */
1813 PDM_DEVREG_VERSION,
1814 /* szName */
1815 "pckbd",
1816 /* szRCMod */
1817 "VBoxDDRC.rc",
1818 /* szR0Mod */
1819 "VBoxDDR0.r0",
1820 /* pszDescription */
1821 "PS/2 Keyboard and Mouse device. Emulates both the keyboard, mouse and the keyboard controller. "
1822 "LUN #0 is the keyboard connector. "
1823 "LUN #1 is the aux/mouse connector.",
1824 /* fFlags */
1825 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36 | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1826 /* fClass */
1827 PDM_DEVREG_CLASS_INPUT,
1828 /* cMaxInstances */
1829 1,
1830 /* cbInstance */
1831 sizeof(KBDState),
1832 /* pfnConstruct */
1833 kbdConstruct,
1834 /* pfnDestruct */
1835 NULL,
1836 /* pfnRelocate */
1837 kbdRelocate,
1838 /* pfnMemSetup */
1839 NULL,
1840 /* pfnPowerOn */
1841 NULL,
1842 /* pfnReset */
1843 kbdReset,
1844 /* pfnSuspend */
1845 NULL,
1846 /* pfnResume */
1847 NULL,
1848 /* pfnAttach */
1849 kbdAttach,
1850 /* pfnDetach */
1851 kbdDetach,
1852 /* pfnQueryInterface. */
1853 NULL,
1854 /* pfnInitComplete */
1855 NULL,
1856 /* pfnPowerOff */
1857 NULL,
1858 /* pfnSoftReset */
1859 NULL,
1860 /* u32VersionEnd */
1861 PDM_DEVREG_VERSION
1862};
1863
1864#endif /* IN_RING3 */
1865#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1866
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use