VirtualBox

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

Last change on this file since 82968 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: 39.4 KB
Line 
1/* $Id: DevPS2.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * DevPS2 - PS/2 keyboard & mouse controller device.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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 <VBox/AssertGuest.h>
51#include <iprt/assert.h>
52#include <iprt/uuid.h>
53
54#include "VBoxDD.h"
55#include "DevPS2.h"
56
57
58/*********************************************************************************************************************************
59* Defined Constants And Macros *
60*********************************************************************************************************************************/
61/* Do not remove this (unless eliminating the corresponding ifdefs), it will
62 * cause instant triple faults when booting Windows VMs. */
63#define TARGET_I386
64
65#define PCKBD_SAVED_STATE_VERSION 8
66
67/* debug PC keyboard */
68#define DEBUG_KBD
69
70/* debug PC keyboard : only mouse */
71#define DEBUG_MOUSE
72
73/* Keyboard Controller Commands */
74#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
75#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
76#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
77#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
78#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
79#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
80#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
81#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
82#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
83#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
84#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */
85#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */
86#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */
87#define KBD_CCMD_WRITE_OBUF 0xD2
88#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
89 initiated by the auxiliary device */
90#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
91#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */
92#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */
93#define KBD_CCMD_READ_TSTINP 0xE0 /* Read test inputs T0, T1 */
94#define KBD_CCMD_RESET_ALT 0xF0
95#define KBD_CCMD_RESET 0xFE
96
97/* Status Register Bits */
98#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
99#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
100#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
101#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
102#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
103#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
104#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
105#define KBD_STAT_PERR 0x80 /* Parity error */
106
107/* Controller Mode Register Bits */
108#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
109#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
110#define KBD_MODE_SYS 0x04 /* The system flag (?) */
111#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
112#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
113#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
114#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
115#define KBD_MODE_RFU 0x80
116
117
118/*********************************************************************************************************************************
119* Structures and Typedefs *
120*********************************************************************************************************************************/
121/** AT to PC scancode translator state. */
122typedef enum
123{
124 XS_IDLE, /**< Starting state. */
125 XS_BREAK, /**< F0 break byte was received. */
126 XS_HIBIT /**< Break code still active. */
127} xlat_state_t;
128
129
130/*********************************************************************************************************************************
131* Global Variables *
132*********************************************************************************************************************************/
133/* Table used by the keyboard controller to optionally translate the incoming
134 * keyboard data. Note that the translation is designed for essentially taking
135 * Scan Set 2 input and producing Scan Set 1 output, but can be turned on and
136 * off regardless of what the keyboard is sending.
137 */
138static uint8_t const g_aAT2PC[128] =
139{
140 0xff,0x43,0x41,0x3f,0x3d,0x3b,0x3c,0x58,0x64,0x44,0x42,0x40,0x3e,0x0f,0x29,0x59,
141 0x65,0x38,0x2a,0x70,0x1d,0x10,0x02,0x5a,0x66,0x71,0x2c,0x1f,0x1e,0x11,0x03,0x5b,
142 0x67,0x2e,0x2d,0x20,0x12,0x05,0x04,0x5c,0x68,0x39,0x2f,0x21,0x14,0x13,0x06,0x5d,
143 0x69,0x31,0x30,0x23,0x22,0x15,0x07,0x5e,0x6a,0x72,0x32,0x24,0x16,0x08,0x09,0x5f,
144 0x6b,0x33,0x25,0x17,0x18,0x0b,0x0a,0x60,0x6c,0x34,0x35,0x26,0x27,0x19,0x0c,0x61,
145 0x6d,0x73,0x28,0x74,0x1a,0x0d,0x62,0x6e,0x3a,0x36,0x1c,0x1b,0x75,0x2b,0x63,0x76,
146 0x55,0x56,0x77,0x78,0x79,0x7a,0x0e,0x7b,0x7c,0x4f,0x7d,0x4b,0x47,0x7e,0x7f,0x6f,
147 0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x54
148};
149
150
151
152/**
153 * Convert an AT (Scan Set 2) scancode to PC (Scan Set 1).
154 *
155 * @param state Current state of the translator
156 * (xlat_state_t).
157 * @param scanIn Incoming scan code.
158 * @param pScanOut Pointer to outgoing scan code. The
159 * contents are only valid if returned
160 * state is not XS_BREAK.
161 *
162 * @return xlat_state_t New state of the translator.
163 */
164static int32_t kbcXlateAT2PC(int32_t state, uint8_t scanIn, uint8_t *pScanOut)
165{
166 uint8_t scan_in;
167 uint8_t scan_out;
168
169 Assert(pScanOut);
170 Assert(state == XS_IDLE || state == XS_BREAK || state == XS_HIBIT);
171
172 /* Preprocess the scan code for a 128-entry translation table. */
173 if (scanIn == 0x83) /* Check for F7 key. */
174 scan_in = 0x02;
175 else if (scanIn == 0x84) /* Check for SysRq key. */
176 scan_in = 0x7f;
177 else
178 scan_in = scanIn;
179
180 /* Values 0x80 and above are passed through, except for 0xF0
181 * which indicates a key release.
182 */
183 if (scan_in < 0x80)
184 {
185 scan_out = g_aAT2PC[scan_in];
186 /* Turn into break code if required. */
187 if (state == XS_BREAK || state == XS_HIBIT)
188 scan_out |= 0x80;
189
190 state = XS_IDLE;
191 }
192 else
193 {
194 /* NB: F0 E0 10 will be translated to E0 E5 (high bit set on last byte)! */
195 if (scan_in == 0xF0) /* Check for break code. */
196 state = XS_BREAK;
197 else if (state == XS_BREAK)
198 state = XS_HIBIT; /* Remember the break bit. */
199 scan_out = scan_in;
200 }
201 LogFlowFunc(("scan code %02X translated to %02X; new state is %d\n",
202 scanIn, scan_out, state));
203
204 *pScanOut = scan_out;
205 return state;
206}
207
208
209/** update irq and KBD_STAT_[MOUSE_]OBF */
210static void kbd_update_irq(PPDMDEVINS pDevIns, PKBDSTATE s)
211{
212 int irq12_level, irq1_level;
213 uint8_t val;
214
215 irq1_level = 0;
216 irq12_level = 0;
217
218 /* Determine new OBF state, but only if OBF is clear. If OBF was already
219 * set, we cannot risk changing the event type after an ISR potentially
220 * started executing! Only kbd_read_data() clears the OBF bits.
221 */
222 if (!(s->status & KBD_STAT_OBF)) {
223 s->status &= ~KBD_STAT_MOUSE_OBF;
224 /* Keyboard data has priority if both kbd and aux data is available. */
225 if (!(s->mode & KBD_MODE_DISABLE_KBD) && PS2KByteFromKbd(pDevIns, &s->Kbd, &val) == VINF_SUCCESS)
226 {
227 bool fHaveData = true;
228
229 /* If scancode translation is on (it usually is), there's more work to do. */
230 if (s->translate)
231 {
232 uint8_t xlated_val;
233
234 s->xlat_state = kbcXlateAT2PC(s->xlat_state, val, &xlated_val);
235 val = xlated_val;
236
237 /* If the translation state is XS_BREAK, there's nothing to report
238 * and we keep going until the state changes or there's no more data.
239 */
240 while (s->xlat_state == XS_BREAK && PS2KByteFromKbd(pDevIns, &s->Kbd, &val) == VINF_SUCCESS)
241 {
242 s->xlat_state = kbcXlateAT2PC(s->xlat_state, val, &xlated_val);
243 val = xlated_val;
244 }
245 /* This can happen if the last byte in the queue is F0... */
246 if (s->xlat_state == XS_BREAK)
247 fHaveData = false;
248 }
249 if (fHaveData)
250 {
251 s->dbbout = val;
252 s->status |= KBD_STAT_OBF;
253 }
254 }
255 else if (!(s->mode & KBD_MODE_DISABLE_MOUSE) && PS2MByteFromAux(&s->Aux, &val) == VINF_SUCCESS)
256 {
257 s->dbbout = val;
258 s->status |= KBD_STAT_OBF | KBD_STAT_MOUSE_OBF;
259 }
260 }
261 /* Determine new IRQ state. */
262 if (s->status & KBD_STAT_OBF) {
263 if (s->status & KBD_STAT_MOUSE_OBF)
264 {
265 if (s->mode & KBD_MODE_MOUSE_INT)
266 irq12_level = 1;
267 }
268 else
269 { /* KBD_STAT_OBF set but KBD_STAT_MOUSE_OBF isn't. */
270 if (s->mode & KBD_MODE_KBD_INT)
271 irq1_level = 1;
272 }
273 }
274 PDMDevHlpISASetIrq(pDevIns, 1, irq1_level);
275 PDMDevHlpISASetIrq(pDevIns, 12, irq12_level);
276}
277
278void KBCUpdateInterrupts(PPDMDEVINS pDevIns)
279{
280 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
281 kbd_update_irq(pDevIns, pThis);
282}
283
284static void kbc_dbb_out(PPDMDEVINS pDevIns, PKBDSTATE s, uint8_t val)
285{
286 s->dbbout = val;
287 /* Set the OBF and raise IRQ. */
288 s->status |= KBD_STAT_OBF;
289 if (s->mode & KBD_MODE_KBD_INT)
290 PDMDevHlpISASetIrq(pDevIns, 1, 1);
291}
292
293static void kbc_dbb_out_aux(PPDMDEVINS pDevIns, PKBDSTATE s, uint8_t val)
294{
295 s->dbbout = val;
296 /* Set the aux OBF and raise IRQ. */
297 s->status |= KBD_STAT_OBF | KBD_STAT_MOUSE_OBF;
298 if (s->mode & KBD_MODE_MOUSE_INT)
299 PDMDevHlpISASetIrq(pDevIns, 12, PDM_IRQ_LEVEL_HIGH);
300}
301
302static VBOXSTRICTRC kbd_write_command(PPDMDEVINS pDevIns, PKBDSTATE s, uint32_t val)
303{
304#ifdef DEBUG_KBD
305 Log(("kbd: write cmd=0x%02x\n", val));
306#endif
307 switch(val) {
308 case KBD_CCMD_READ_MODE:
309 kbc_dbb_out(pDevIns, s, s->mode);
310 break;
311 case KBD_CCMD_WRITE_MODE:
312 case KBD_CCMD_WRITE_OBUF:
313 case KBD_CCMD_WRITE_AUX_OBUF:
314 case KBD_CCMD_WRITE_MOUSE:
315 case KBD_CCMD_WRITE_OUTPORT:
316 s->write_cmd = val;
317 break;
318 case KBD_CCMD_MOUSE_DISABLE:
319 s->mode |= KBD_MODE_DISABLE_MOUSE;
320 break;
321 case KBD_CCMD_MOUSE_ENABLE:
322 s->mode &= ~KBD_MODE_DISABLE_MOUSE;
323 /* Check for queued input. */
324 kbd_update_irq(pDevIns, s);
325 break;
326 case KBD_CCMD_TEST_MOUSE:
327 kbc_dbb_out(pDevIns, s, 0x00);
328 break;
329 case KBD_CCMD_SELF_TEST:
330 /* Enable the A20 line - that is the power-on state(!). */
331# ifndef IN_RING3
332 if (!PDMDevHlpA20IsEnabled(pDevIns))
333 return VINF_IOM_R3_IOPORT_WRITE;
334# else /* IN_RING3 */
335 PDMDevHlpA20Set(pDevIns, true);
336# endif /* IN_RING3 */
337 s->status |= KBD_STAT_SELFTEST;
338 s->mode |= KBD_MODE_DISABLE_KBD;
339 kbc_dbb_out(pDevIns, s, 0x55);
340 break;
341 case KBD_CCMD_KBD_TEST:
342 kbc_dbb_out(pDevIns, s, 0x00);
343 break;
344 case KBD_CCMD_KBD_DISABLE:
345 s->mode |= KBD_MODE_DISABLE_KBD;
346 break;
347 case KBD_CCMD_KBD_ENABLE:
348 s->mode &= ~KBD_MODE_DISABLE_KBD;
349 /* Check for queued input. */
350 kbd_update_irq(pDevIns, s);
351 break;
352 case KBD_CCMD_READ_INPORT:
353 kbc_dbb_out(pDevIns, s, 0xBF);
354 break;
355 case KBD_CCMD_READ_OUTPORT:
356 /* XXX: check that */
357#ifdef TARGET_I386
358 val = 0x01 | (PDMDevHlpA20IsEnabled(pDevIns) << 1);
359#else
360 val = 0x01;
361#endif
362 if (s->status & KBD_STAT_OBF)
363 val |= 0x10;
364 if (s->status & KBD_STAT_MOUSE_OBF)
365 val |= 0x20;
366 kbc_dbb_out(pDevIns, s, val);
367 break;
368#ifdef TARGET_I386
369 case KBD_CCMD_ENABLE_A20:
370# ifndef IN_RING3
371 if (!PDMDevHlpA20IsEnabled(pDevIns))
372 return VINF_IOM_R3_IOPORT_WRITE;
373# else /* IN_RING3 */
374 PDMDevHlpA20Set(pDevIns, true);
375# endif /* IN_RING3 */
376 break;
377 case KBD_CCMD_DISABLE_A20:
378# ifndef IN_RING3
379 if (PDMDevHlpA20IsEnabled(pDevIns))
380 return VINF_IOM_R3_IOPORT_WRITE;
381# else /* IN_RING3 */
382 PDMDevHlpA20Set(pDevIns, false);
383# endif /* IN_RING3 */
384 break;
385#endif
386 case KBD_CCMD_READ_TSTINP:
387 /* Keyboard clock line is zero IFF keyboard is disabled */
388 val = (s->mode & KBD_MODE_DISABLE_KBD) ? 0 : 1;
389 kbc_dbb_out(pDevIns, s, val);
390 break;
391 case KBD_CCMD_RESET:
392 case KBD_CCMD_RESET_ALT:
393#ifndef IN_RING3
394 return VINF_IOM_R3_IOPORT_WRITE;
395#else /* IN_RING3 */
396 LogRel(("Reset initiated by keyboard controller\n"));
397 return PDMDevHlpVMReset(pDevIns, PDMVMRESET_F_KBD);
398#endif /* IN_RING3 */
399 case 0xff:
400 /* ignore that - I don't know what is its use */
401 break;
402 /* Make OS/2 happy. */
403 /* The 8042 RAM is readable using commands 0x20 thru 0x3f, and writable
404 by 0x60 thru 0x7f. Now days only the first byte, the mode, is used.
405 We'll ignore the writes (0x61..7f) and return 0 for all the reads
406 just to make some OS/2 debug stuff a bit happier. */
407 case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
408 case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
409 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
410 case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
411 kbc_dbb_out(pDevIns, s, 0);
412 Log(("kbd: reading non-standard RAM addr %#x\n", val & 0x1f));
413 break;
414 default:
415 Log(("kbd: unsupported keyboard cmd=0x%02x\n", val));
416 break;
417 }
418 return VINF_SUCCESS;
419}
420
421static uint32_t kbd_read_data(PPDMDEVINS pDevIns, PKBDSTATE s)
422{
423 uint32_t val;
424
425 /* Return the current DBB contents. */
426 val = s->dbbout;
427
428 /* Reading the DBB deasserts IRQs... */
429 if (s->status & KBD_STAT_MOUSE_OBF)
430 PDMDevHlpISASetIrq(pDevIns, 12, 0);
431 else
432 PDMDevHlpISASetIrq(pDevIns, 1, 0);
433 /* ...and clears the OBF bits. */
434 s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
435
436 /* Check if more data is available. */
437 kbd_update_irq(pDevIns, s);
438#ifdef DEBUG_KBD
439 Log(("kbd: read data=0x%02x\n", val));
440#endif
441 return val;
442}
443
444static VBOXSTRICTRC kbd_write_data(PPDMDEVINS pDevIns, PKBDSTATE s, uint32_t val)
445{
446 VBOXSTRICTRC rc = VINF_SUCCESS;
447
448#ifdef DEBUG_KBD
449 Log(("kbd: write data=0x%02x\n", val));
450#endif
451
452 switch(s->write_cmd) {
453 case 0:
454 /* Automatically enables keyboard interface. */
455 s->mode &= ~KBD_MODE_DISABLE_KBD;
456 rc = PS2KByteToKbd(pDevIns, &s->Kbd, val);
457 if (rc == VINF_SUCCESS)
458 kbd_update_irq(pDevIns, s);
459 break;
460 case KBD_CCMD_WRITE_MODE:
461 s->mode = val;
462 s->translate = (s->mode & KBD_MODE_KCC) == KBD_MODE_KCC;
463 kbd_update_irq(pDevIns, s);
464 break;
465 case KBD_CCMD_WRITE_OBUF:
466 kbc_dbb_out(pDevIns, s, val);
467 break;
468 case KBD_CCMD_WRITE_AUX_OBUF:
469 kbc_dbb_out_aux(pDevIns, s, val);
470 break;
471 case KBD_CCMD_WRITE_OUTPORT:
472#ifdef TARGET_I386
473# ifndef IN_RING3
474 if (PDMDevHlpA20IsEnabled(pDevIns) != !!(val & 2))
475 rc = VINF_IOM_R3_IOPORT_WRITE;
476# else /* IN_RING3 */
477 PDMDevHlpA20Set(pDevIns, !!(val & 2));
478# endif /* IN_RING3 */
479#endif
480 if (!(val & 1)) {
481# ifndef IN_RING3
482 rc = VINF_IOM_R3_IOPORT_WRITE;
483# else
484 rc = PDMDevHlpVMReset(pDevIns, PDMVMRESET_F_KBD);
485# endif
486 }
487 break;
488 case KBD_CCMD_WRITE_MOUSE:
489 /* Automatically enables aux interface. */
490 s->mode &= ~KBD_MODE_DISABLE_MOUSE;
491 rc = PS2MByteToAux(pDevIns, &s->Aux, val);
492 if (rc == VINF_SUCCESS)
493 kbd_update_irq(pDevIns, s);
494 break;
495 default:
496 break;
497 }
498 if (rc != VINF_IOM_R3_IOPORT_WRITE)
499 s->write_cmd = 0;
500 return rc;
501}
502
503#ifdef IN_RING3
504
505static int kbd_load(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, PKBDSTATE s, PKBDSTATER3 pThisCC, uint32_t version_id)
506{
507 uint32_t u32, i;
508 uint8_t u8Dummy;
509 uint32_t u32Dummy;
510 int rc;
511
512#if 0
513 /** @todo enable this and remove the "if (version_id == 4)" code at some
514 * later time */
515 /* Version 4 was never created by any publicly released version of VBox */
516 AssertReturn(version_id != 4, VERR_NOT_SUPPORTED);
517#endif
518 if (version_id < 2 || version_id > PCKBD_SAVED_STATE_VERSION)
519 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
520 pHlp->pfnSSMGetU8(pSSM, &s->write_cmd);
521 pHlp->pfnSSMGetU8(pSSM, &s->status);
522 pHlp->pfnSSMGetU8(pSSM, &s->mode);
523 if (version_id <= 5)
524 {
525 pHlp->pfnSSMGetU32(pSSM, &u32Dummy);
526 pHlp->pfnSSMGetU32(pSSM, &u32Dummy);
527 }
528 else
529 {
530 pHlp->pfnSSMGetU8(pSSM, &s->dbbout);
531 }
532 if (version_id <= 7)
533 {
534 int32_t i32Dummy;
535 uint8_t u8State;
536 uint8_t u8Rate;
537 uint8_t u8Proto;
538
539 pHlp->pfnSSMGetU32(pSSM, &u32Dummy);
540 pHlp->pfnSSMGetU8(pSSM, &u8State);
541 pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
542 pHlp->pfnSSMGetU8(pSSM, &u8Rate);
543 pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
544 pHlp->pfnSSMGetU8(pSSM, &u8Proto);
545 pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
546 pHlp->pfnSSMGetS32(pSSM, &i32Dummy);
547 pHlp->pfnSSMGetS32(pSSM, &i32Dummy);
548 pHlp->pfnSSMGetS32(pSSM, &i32Dummy);
549 if (version_id > 2)
550 {
551 pHlp->pfnSSMGetS32(pSSM, &i32Dummy);
552 pHlp->pfnSSMGetS32(pSSM, &i32Dummy);
553 }
554 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
555 if (version_id == 4)
556 {
557 pHlp->pfnSSMGetU32(pSSM, &u32Dummy);
558 rc = pHlp->pfnSSMGetU32(pSSM, &u32Dummy);
559 }
560 if (version_id > 3)
561 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
562 if (version_id == 4)
563 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
564 AssertLogRelRCReturn(rc, rc);
565
566 PS2MR3FixupState(&s->Aux, &pThisCC->Aux, u8State, u8Rate, u8Proto);
567 }
568
569 /* Determine the translation state. */
570 s->translate = (s->mode & KBD_MODE_KCC) == KBD_MODE_KCC;
571
572 /*
573 * Load the queues
574 */
575 if (version_id <= 5)
576 {
577 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
578 if (RT_FAILURE(rc))
579 return rc;
580 for (i = 0; i < u32; i++)
581 {
582 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
583 if (RT_FAILURE(rc))
584 return rc;
585 }
586 Log(("kbd_load: %d keyboard queue items discarded from old saved state\n", u32));
587 }
588
589 if (version_id <= 7)
590 {
591 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
592 if (RT_FAILURE(rc))
593 return rc;
594 for (i = 0; i < u32; i++)
595 {
596 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
597 if (RT_FAILURE(rc))
598 return rc;
599 }
600 Log(("kbd_load: %d mouse event queue items discarded from old saved state\n", u32));
601
602 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
603 if (RT_FAILURE(rc))
604 return rc;
605 for (i = 0; i < u32; i++)
606 {
607 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
608 if (RT_FAILURE(rc))
609 return rc;
610 }
611 Log(("kbd_load: %d mouse command queue items discarded from old saved state\n", u32));
612 }
613
614 /* terminator */
615 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
616 if (RT_FAILURE(rc))
617 return rc;
618 if (u32 != ~0U)
619 {
620 AssertMsgFailed(("u32=%#x\n", u32));
621 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
622 }
623 return 0;
624}
625
626#endif /* IN_RING3 */
627
628
629/* VirtualBox code start */
630
631/* -=-=-=-=-=- wrappers -=-=-=-=-=- */
632
633/** Fluff bits indexed by size (1,2,4). */
634static uint32_t const g_afFluff[5] =
635{
636 /* [0] = */ 0,
637 /* [1] = */ 0,
638 /* [2] = */ UINT32_C(0xff00),
639 /* [3] = */ 0,
640 /* [4] = */ UINT32_C(0xffffff00) /* Crazy Apple (Darwin 6.0.2 and earlier). */
641};
642
643/**
644 * @callback_method_impl{FNIOMIOPORTNEWIN,
645 * Port I/O Handler for keyboard data IN operations.}
646 */
647static DECLCALLBACK(VBOXSTRICTRC) kbdIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
648{
649 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
650 RT_NOREF(pvUser, offPort);
651 Assert(offPort == 0);
652 Assert(cb == 1 || cb == 2 || cb == 4);
653
654 *pu32 = kbd_read_data(pDevIns, pThis) | g_afFluff[cb];
655 Log2(("kbdIOPortDataRead: cb=%u *pu32=%#x\n", cb, *pu32));
656 return VINF_SUCCESS;
657}
658
659/**
660 * @callback_method_impl{FNIOMIOPORTNEWOUT,
661 * Port I/O Handler for keyboard data OUT operations.}
662 */
663static DECLCALLBACK(VBOXSTRICTRC) kbdIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
664{
665 RT_NOREF(offPort, pvUser);
666 Assert(offPort == 0);
667
668 if (cb == 1 || cb == 2)
669 {
670 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
671 VBOXSTRICTRC rc = kbd_write_data(pDevIns, pThis, (uint8_t)u32);
672 Log2(("kbdIOPortDataWrite: Port=0x60+%x cb=%d u32=%#x rc=%Rrc\n", offPort, cb, u32, VBOXSTRICTRC_VAL(rc)));
673 return rc;
674 }
675 Assert(cb == 4);
676 ASSERT_GUEST_MSG_FAILED(("Port=0x60+%x cb=%d\n", offPort, cb));
677 return VINF_SUCCESS;
678}
679
680/**
681 * @callback_method_impl{FNIOMIOPORTNEWIN,
682 * Port I/O Handler for keyboard status IN operations.}
683 */
684static DECLCALLBACK(VBOXSTRICTRC) kbdIOPortStatusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
685{
686 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
687 RT_NOREF(offPort, pvUser);
688 Assert(offPort == 0);
689 Assert(cb == 1 || cb == 2 || cb == 4);
690
691 *pu32 = pThis->status | g_afFluff[cb];
692 Log2(("kbdIOPortStatusRead: cb=%u -> *pu32=%#x\n", cb, *pu32));
693 return VINF_SUCCESS;
694}
695
696/**
697 * @callback_method_impl{FNIOMIOPORTNEWIN,
698 * Port I/O Handler for keyboard command OUT operations.}
699 */
700static DECLCALLBACK(VBOXSTRICTRC) kbdIOPortCommandWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
701{
702 RT_NOREF(offPort, pvUser);
703 Assert(offPort == 0);
704
705 if (cb == 1 || cb == 2)
706 {
707 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
708 VBOXSTRICTRC rc = kbd_write_command(pDevIns, pThis, (uint8_t)u32);
709 Log2(("kbdIOPortCommandWrite: cb=%d u32=%#x rc=%Rrc\n", cb, u32, VBOXSTRICTRC_VAL(rc)));
710 return rc;
711 }
712 Assert(cb == 4);
713 ASSERT_GUEST_MSG_FAILED(("offPort=0x64+%x cb=%d\n", offPort, cb));
714 return VINF_SUCCESS;
715}
716
717/**
718 * Clear a queue.
719 *
720 * @param pQHdr The queue header.
721 * @param cElements The queue size.
722 */
723void PS2CmnClearQueue(PPS2QHDR pQHdr, size_t cElements)
724{
725 Assert(cElements > 0);
726 LogFlowFunc(("Clearing queue %p\n", pQHdr));
727 pQHdr->wpos = pQHdr->rpos = pQHdr->rpos % cElements;
728 pQHdr->cUsed = 0;
729}
730
731
732/**
733 * Add a byte to a queue.
734 *
735 * @param pQHdr The queue header.
736 * @param cElements The queue size.
737 * @param pbElements The queue element array.
738 * @param bValue The byte to store.
739 */
740void PS2CmnInsertQueue(PPS2QHDR pQHdr, size_t cElements, uint8_t *pbElements, uint8_t bValue)
741{
742 Assert(cElements > 0);
743
744 /* Check that the queue is not full. */
745 uint32_t cUsed = pQHdr->cUsed;
746 if (cUsed < cElements)
747 {
748 /* Insert data and update circular buffer write position. */
749 uint32_t wpos = pQHdr->wpos % cElements;
750 pbElements[wpos] = bValue;
751
752 wpos += 1;
753 if (wpos < cElements)
754 pQHdr->wpos = wpos;
755 else
756 pQHdr->wpos = 0; /* Roll over. */
757 pQHdr->cUsed = cUsed + 1;
758
759 LogRelFlowFunc(("inserted %#04x into queue %p\n", bValue, pQHdr));
760 }
761 else
762 {
763 Assert(cUsed == cElements);
764 LogRelFlowFunc(("queue %p full (%zu entries)\n", pQHdr, cElements));
765 }
766}
767
768/**
769 * Retrieve a byte from a queue.
770 *
771 * @param pQHdr The queue header.
772 * @param cElements The queue size.
773 * @param pbElements The queue element array.
774 * @param pbValue Where to return the byte on success.
775 *
776 * @retval VINF_TRY_AGAIN if queue is empty,
777 * @retval VINF_SUCCESS if a byte was read.
778 */
779int PS2CmnRemoveQueue(PPS2QHDR pQHdr, size_t cElements, uint8_t const *pbElements, uint8_t *pbValue)
780{
781 int rc;
782
783 Assert(cElements > 0);
784 Assert(pbValue);
785
786 uint32_t cUsed = (uint32_t)RT_MIN(pQHdr->cUsed, cElements);
787 if (cUsed > 0)
788 {
789 uint32_t rpos = pQHdr->rpos % cElements;
790 *pbValue = pbElements[rpos];
791
792 rpos += 1;
793 if (rpos < cElements)
794 pQHdr->rpos = rpos;
795 else
796 pQHdr->rpos = 0; /* Roll over. */
797 pQHdr->cUsed = cUsed - 1;
798
799 LogFlowFunc(("removed 0x%02X from queue %p\n", *pbValue, pQHdr));
800 rc = VINF_SUCCESS;
801 }
802 else
803 {
804 LogFlowFunc(("queue %p empty\n", pQHdr));
805 rc = VINF_TRY_AGAIN;
806 }
807 return rc;
808}
809
810#ifdef IN_RING3
811
812/**
813 * Save a queue state.
814 *
815 * @param pHlp The device helpers.
816 * @param pSSM SSM handle to write the state to.
817 * @param pQHdr The queue header.
818 * @param cElements The queue size.
819 * @param pbElements The queue element array.
820 */
821void PS2CmnR3SaveQueue(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, PPS2QHDR pQHdr, size_t cElements, uint8_t const *pbElements)
822{
823 uint32_t cItems = (uint32_t)RT_MIN(pQHdr->cUsed, cElements);
824
825 /* Only save the number of items. Note that the read/write
826 * positions aren't saved as they will be rebuilt on load.
827 */
828 pHlp->pfnSSMPutU32(pSSM, cItems);
829
830 LogFlow(("Storing %u items from queue %p\n", cItems, pQHdr));
831
832 /* Save queue data - only the bytes actually used (typically zero). */
833 for (uint32_t i = pQHdr->rpos % cElements; cItems-- > 0; i = (i + 1) % cElements)
834 pHlp->pfnSSMPutU8(pSSM, pbElements[i]);
835}
836
837/**
838 * Load a queue state.
839 *
840 * @param pHlp The device helpers.
841 * @param pSSM SSM handle to read the state from.
842 * @param pQHdr The queue header.
843 * @param cElements The queue size.
844 * @param pbElements The queue element array.
845 *
846 * @returns VBox status/error code.
847 */
848int PS2CmnR3LoadQueue(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, PPS2QHDR pQHdr, size_t cElements, uint8_t *pbElements)
849{
850 /* On load, always put the read pointer at zero. */
851 uint32_t cUsed;
852 int rc = pHlp->pfnSSMGetU32(pSSM, &cUsed);
853 AssertRCReturn(rc, rc);
854
855 LogFlow(("Loading %u items to queue %p\n", cUsed, pQHdr));
856
857 AssertMsgReturn(cUsed <= cElements, ("Saved size=%u, actual=%zu\n", cUsed, cElements),
858 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
859
860 /* Recalculate queue positions and load data in one go. */
861 pQHdr->rpos = 0;
862 pQHdr->wpos = cUsed;
863 pQHdr->cUsed = cUsed;
864 return pHlp->pfnSSMGetMem(pSSM, pbElements, cUsed);
865}
866
867
868/**
869 * @callback_method_impl{FNSSMDEVSAVEEXEC, Saves a state of the keyboard device.}
870 *
871 * @returns VBox status code.
872 * @param pDevIns The device instance.
873 * @param pSSM The handle to save the state to.
874 */
875static DECLCALLBACK(int) kbdR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
876{
877 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
878 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
879
880 pHlp->pfnSSMPutU8(pSSM, pThis->write_cmd);
881 pHlp->pfnSSMPutU8(pSSM, pThis->status);
882 pHlp->pfnSSMPutU8(pSSM, pThis->mode);
883 pHlp->pfnSSMPutU8(pSSM, pThis->dbbout);
884 /* terminator */
885 pHlp->pfnSSMPutU32(pSSM, UINT32_MAX);
886
887 PS2KR3SaveState(pDevIns, &pThis->Kbd, pSSM);
888 PS2MR3SaveState(pDevIns, &pThis->Aux, pSSM);
889 return VINF_SUCCESS;
890}
891
892
893/**
894 * @callback_method_impl{FNSSMDEVLOADEXEC, Loads a saved keyboard device state.}
895 */
896static DECLCALLBACK(int) kbdR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
897{
898 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
899 PKBDSTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PKBDSTATER3);
900 int rc;
901
902 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
903 rc = kbd_load(pDevIns->pHlpR3, pSSM, pThis, pThisCC, uVersion);
904 AssertRCReturn(rc, rc);
905
906 if (uVersion >= 6)
907 rc = PS2KR3LoadState(pDevIns, &pThis->Kbd, pSSM, uVersion);
908 AssertRCReturn(rc, rc);
909
910 if (uVersion >= 8)
911 rc = PS2MR3LoadState(pDevIns, &pThis->Aux, &pThisCC->Aux, pSSM, uVersion);
912 AssertRCReturn(rc, rc);
913 return rc;
914}
915
916
917/**
918 * @callback_method_impl{FNSSMDEVLOADDONE, Key state fix-up after loading}
919 */
920static DECLCALLBACK(int) kbdR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
921{
922 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
923 PKBDSTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PKBDSTATER3);
924 RT_NOREF(pSSM);
925 return PS2KR3LoadDone(pDevIns, &pThis->Kbd, &pThisCC->Kbd);
926}
927
928
929/* -=-=-=-=-=- real code -=-=-=-=-=- */
930
931/**
932 * Reset notification.
933 *
934 * @returns VBox status code.
935 * @param pDevIns The device instance data.
936 */
937static DECLCALLBACK(void) kbdR3Reset(PPDMDEVINS pDevIns)
938{
939 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
940 PKBDSTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PKBDSTATER3);
941
942 pThis->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
943 pThis->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
944 /* Resetting everything, keyword was not working right on NT4 reboot. */
945 pThis->write_cmd = 0;
946 pThis->translate = 0;
947
948 PS2KR3Reset(pDevIns, &pThis->Kbd, &pThisCC->Kbd);
949 PS2MR3Reset(&pThis->Aux);
950}
951
952
953/**
954 * @interface_method_impl{PDMDEVREGR3,pfnAttach}
955 *
956 * @remark The keyboard controller doesn't support this action, this is just
957 * implemented to try out the driver<->device structure.
958 */
959static DECLCALLBACK(int) kbdR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
960{
961 PKBDSTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PKBDSTATER3);
962 int rc;
963
964 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
965 ("PS/2 device does not support hotplugging\n"),
966 VERR_INVALID_PARAMETER);
967
968 switch (iLUN)
969 {
970 /* LUN #0: keyboard */
971 case 0:
972 rc = PS2KR3Attach(pDevIns, &pThisCC->Kbd, iLUN, fFlags);
973 break;
974
975 /* LUN #1: aux/mouse */
976 case 1:
977 rc = PS2MR3Attach(pDevIns, &pThisCC->Aux, iLUN, fFlags);
978 break;
979
980 default:
981 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
982 return VERR_PDM_NO_SUCH_LUN;
983 }
984
985 return rc;
986}
987
988
989/**
990 * @interface_method_impl{PDMDEVREGR3,pfnDetach}
991 * @remark The keyboard controller doesn't support this action, this is just
992 * implemented to try out the driver<->device structure.
993 */
994static DECLCALLBACK(void) kbdR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
995{
996#if 0
997 /*
998 * Reset the interfaces and update the controller state.
999 */
1000 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
1001 switch (iLUN)
1002 {
1003 /* LUN #0: keyboard */
1004 case 0:
1005 pThisCC->Keyboard.pDrv = NULL;
1006 pThisCC->Keyboard.pDrvBase = NULL;
1007 break;
1008
1009 /* LUN #1: aux/mouse */
1010 case 1:
1011 pThisCC->Mouse.pDrv = NULL;
1012 pThisCC->Mouse.pDrvBase = NULL;
1013 break;
1014
1015 default:
1016 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
1017 break;
1018 }
1019#else
1020 NOREF(pDevIns); NOREF(iLUN); NOREF(fFlags);
1021#endif
1022}
1023
1024
1025/**
1026 * @interface_method_impl{PDMDEVREGR3,pfnConstruct}
1027 */
1028static DECLCALLBACK(int) kbdR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1029{
1030 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1031 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
1032 PKBDSTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PKBDSTATER3);
1033 int rc;
1034 RT_NOREF(iInstance);
1035
1036 Assert(iInstance == 0);
1037
1038 /*
1039 * Validate and read the configuration.
1040 */
1041 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "KbdThrottleEnabled", "");
1042 Log(("pckbd: fRCEnabled=%RTbool fR0Enabled=%RTbool\n", pDevIns->fRCEnabled, pDevIns->fR0Enabled));
1043
1044 /*
1045 * Initialize the sub-components.
1046 */
1047 rc = PS2KR3Construct(pDevIns, &pThis->Kbd, &pThisCC->Kbd, pCfg);
1048 AssertRCReturn(rc, rc);
1049
1050 rc = PS2MR3Construct(pDevIns, &pThis->Aux, &pThisCC->Aux);
1051 AssertRCReturn(rc, rc);
1052
1053 /*
1054 * Register I/O ports.
1055 */
1056 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x60 /*uPort*/, 1 /*cPorts*/, kbdIOPortDataWrite, kbdIOPortDataRead,
1057 "PC Keyboard - Data", NULL /*pExtDescs*/, &pThis->hIoPortData);
1058 AssertRCReturn(rc, rc);
1059 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x64 /*uPort*/, 1 /*cPorts*/, kbdIOPortCommandWrite, kbdIOPortStatusRead,
1060 "PC Keyboard - Command / Status", NULL /*pExtDescs*/, &pThis->hIoPortCmdStatus);
1061 AssertRCReturn(rc, rc);
1062
1063 /*
1064 * Saved state.
1065 */
1066 rc = PDMDevHlpSSMRegisterEx(pDevIns, PCKBD_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
1067 NULL, NULL, NULL,
1068 NULL, kbdR3SaveExec, NULL,
1069 NULL, kbdR3LoadExec, kbdR3LoadDone);
1070 AssertRCReturn(rc, rc);
1071
1072 /*
1073 * Attach to the keyboard and mouse drivers.
1074 */
1075 rc = kbdR3Attach(pDevIns, 0 /* keyboard LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
1076 AssertRCReturn(rc, rc);
1077 rc = kbdR3Attach(pDevIns, 1 /* aux/mouse LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
1078 AssertRCReturn(rc, rc);
1079
1080 /*
1081 * Initialize the device state.
1082 */
1083 kbdR3Reset(pDevIns);
1084
1085 return VINF_SUCCESS;
1086}
1087
1088#else /* !IN_RING3 */
1089
1090/**
1091 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1092 */
1093static DECLCALLBACK(int) kbdRZConstruct(PPDMDEVINS pDevIns)
1094{
1095 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1096 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
1097
1098 int rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortData, kbdIOPortDataWrite, kbdIOPortDataRead, NULL /*pvUser*/);
1099 AssertRCReturn(rc, rc);
1100 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortCmdStatus, kbdIOPortCommandWrite, kbdIOPortStatusRead, NULL /*pvUser*/);
1101 AssertRCReturn(rc, rc);
1102
1103 return VINF_SUCCESS;
1104}
1105
1106#endif /* !IN_RING3 */
1107
1108/**
1109 * The device registration structure.
1110 */
1111const PDMDEVREG g_DevicePS2KeyboardMouse =
1112{
1113 /* .u32Version = */ PDM_DEVREG_VERSION,
1114 /* .uReserved0 = */ 0,
1115 /* .szName = */ "pckbd",
1116 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
1117 /* .fClass = */ PDM_DEVREG_CLASS_INPUT,
1118 /* .cMaxInstances = */ 1,
1119 /* .uSharedVersion = */ 42,
1120 /* .cbInstanceShared = */ sizeof(KBDSTATE),
1121 /* .cbInstanceCC = */ CTX_EXPR(sizeof(KBDSTATER3), 0, 0),
1122 /* .cbInstanceRC = */ 0,
1123 /* .cMaxPciDevices = */ 0,
1124 /* .cMaxMsixVectors = */ 0,
1125 /* .pszDescription = */ "PS/2 Keyboard and Mouse device. Emulates both the keyboard, mouse and the keyboard controller.\n"
1126 "LUN #0 is the keyboard connector.\n"
1127 "LUN #1 is the aux/mouse connector.",
1128#if defined(IN_RING3)
1129 /* .pszRCMod = */ "VBoxDDRC.rc",
1130 /* .pszR0Mod = */ "VBoxDDR0.r0",
1131 /* .pfnConstruct = */ kbdR3Construct,
1132 /* .pfnDestruct = */ NULL,
1133 /* .pfnRelocate = */ NULL,
1134 /* .pfnMemSetup = */ NULL,
1135 /* .pfnPowerOn = */ NULL,
1136 /* .pfnReset = */ kbdR3Reset,
1137 /* .pfnSuspend = */ NULL,
1138 /* .pfnResume = */ NULL,
1139 /* .pfnAttach = */ kbdR3Attach,
1140 /* .pfnDetach = */ kbdR3Detach,
1141 /* .pfnQueryInterface = */ NULL,
1142 /* .pfnInitComplete = */ NULL,
1143 /* .pfnPowerOff = */ NULL,
1144 /* .pfnSoftReset = */ NULL,
1145 /* .pfnReserved0 = */ NULL,
1146 /* .pfnReserved1 = */ NULL,
1147 /* .pfnReserved2 = */ NULL,
1148 /* .pfnReserved3 = */ NULL,
1149 /* .pfnReserved4 = */ NULL,
1150 /* .pfnReserved5 = */ NULL,
1151 /* .pfnReserved6 = */ NULL,
1152 /* .pfnReserved7 = */ NULL,
1153#elif defined(IN_RING0)
1154 /* .pfnEarlyConstruct = */ NULL,
1155 /* .pfnConstruct = */ kbdRZConstruct,
1156 /* .pfnDestruct = */ NULL,
1157 /* .pfnFinalDestruct = */ NULL,
1158 /* .pfnRequest = */ NULL,
1159 /* .pfnReserved0 = */ NULL,
1160 /* .pfnReserved1 = */ NULL,
1161 /* .pfnReserved2 = */ NULL,
1162 /* .pfnReserved3 = */ NULL,
1163 /* .pfnReserved4 = */ NULL,
1164 /* .pfnReserved5 = */ NULL,
1165 /* .pfnReserved6 = */ NULL,
1166 /* .pfnReserved7 = */ NULL,
1167#elif defined(IN_RC)
1168 /* .pfnConstruct = */ kbdRZConstruct,
1169 /* .pfnReserved0 = */ NULL,
1170 /* .pfnReserved1 = */ NULL,
1171 /* .pfnReserved2 = */ NULL,
1172 /* .pfnReserved3 = */ NULL,
1173 /* .pfnReserved4 = */ NULL,
1174 /* .pfnReserved5 = */ NULL,
1175 /* .pfnReserved6 = */ NULL,
1176 /* .pfnReserved7 = */ NULL,
1177#else
1178# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1179#endif
1180 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1181};
1182
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