VirtualBox

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

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

DevPS2: Converted I/O ports. bugref:9218

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.1 KB
Line 
1/* $Id: DevPS2.cpp 82201 2019-11-25 21:32:30Z vboxsync $ */
2/** @file
3 * DevPS2 - PS/2 keyboard & mouse controller device.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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, KBDState *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(s->CTX_SUFF(pDevIns), 1, irq1_level);
275 PDMDevHlpISASetIrq(s->CTX_SUFF(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(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(s->CTX_SUFF(pDevIns), 1, 1);
291}
292
293static void kbc_dbb_out_aux(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(s->CTX_SUFF(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(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(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(s->CTX_SUFF(pDevIns)))
333 return VINF_IOM_R3_IOPORT_WRITE;
334# else /* IN_RING3 */
335 PDMDevHlpA20Set(s->CTX_SUFF(pDevIns), true);
336# endif /* IN_RING3 */
337 s->status |= KBD_STAT_SELFTEST;
338 s->mode |= KBD_MODE_DISABLE_KBD;
339 kbc_dbb_out(s, 0x55);
340 break;
341 case KBD_CCMD_KBD_TEST:
342 kbc_dbb_out(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(s, 0xBF);
354 break;
355 case KBD_CCMD_READ_OUTPORT:
356 /* XXX: check that */
357#ifdef TARGET_I386
358 val = 0x01 | (PDMDevHlpA20IsEnabled(s->CTX_SUFF(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(s, val);
367 break;
368#ifdef TARGET_I386
369 case KBD_CCMD_ENABLE_A20:
370# ifndef IN_RING3
371 if (!PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)))
372 return VINF_IOM_R3_IOPORT_WRITE;
373# else /* IN_RING3 */
374 PDMDevHlpA20Set(s->CTX_SUFF(pDevIns), true);
375# endif /* IN_RING3 */
376 break;
377 case KBD_CCMD_DISABLE_A20:
378# ifndef IN_RING3
379 if (PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)))
380 return VINF_IOM_R3_IOPORT_WRITE;
381# else /* IN_RING3 */
382 PDMDevHlpA20Set(s->CTX_SUFF(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(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(s->CTX_SUFF(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(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(s->CTX_SUFF(pDevIns), 12, 0);
431 else
432 PDMDevHlpISASetIrq(s->CTX_SUFF(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
444PS2K *KBDGetPS2KFromDevIns(PPDMDEVINS pDevIns)
445{
446 KBDState *pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
447 return &pThis->Kbd;
448}
449
450PS2M *KBDGetPS2MFromDevIns(PPDMDEVINS pDevIns)
451{
452 KBDState *pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
453 return &pThis->Aux;
454}
455
456static int kbd_write_data(PPDMDEVINS pDevIns, PKBDSTATE s, uint32_t val)
457{
458 int rc = VINF_SUCCESS;
459
460#ifdef DEBUG_KBD
461 Log(("kbd: write data=0x%02x\n", val));
462#endif
463
464 switch(s->write_cmd) {
465 case 0:
466 /* Automatically enables keyboard interface. */
467 s->mode &= ~KBD_MODE_DISABLE_KBD;
468 rc = PS2KByteToKbd(pDevIns, &s->Kbd, val);
469 if (rc == VINF_SUCCESS)
470 kbd_update_irq(pDevIns, s);
471 break;
472 case KBD_CCMD_WRITE_MODE:
473 s->mode = val;
474 s->translate = (s->mode & KBD_MODE_KCC) == KBD_MODE_KCC;
475 kbd_update_irq(pDevIns, s);
476 break;
477 case KBD_CCMD_WRITE_OBUF:
478 kbc_dbb_out(s, val);
479 break;
480 case KBD_CCMD_WRITE_AUX_OBUF:
481 kbc_dbb_out_aux(s, val);
482 break;
483 case KBD_CCMD_WRITE_OUTPORT:
484#ifdef TARGET_I386
485# ifndef IN_RING3
486 if (PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)) != !!(val & 2))
487 rc = VINF_IOM_R3_IOPORT_WRITE;
488# else /* IN_RING3 */
489 PDMDevHlpA20Set(s->CTX_SUFF(pDevIns), !!(val & 2));
490# endif /* !IN_RING3 */
491#endif
492 if (!(val & 1)) {
493# ifndef IN_RING3
494 rc = VINF_IOM_R3_IOPORT_WRITE;
495# else
496 rc = PDMDevHlpVMReset(s->CTX_SUFF(pDevIns), PDMVMRESET_F_KBD);
497# endif
498 }
499 break;
500 case KBD_CCMD_WRITE_MOUSE:
501 /* Automatically enables aux interface. */
502 s->mode &= ~KBD_MODE_DISABLE_MOUSE;
503 rc = PS2MByteToAux(pDevIns, &s->Aux, val);
504 if (rc == VINF_SUCCESS)
505 kbd_update_irq(pDevIns, s);
506 break;
507 default:
508 break;
509 }
510 if (rc != VINF_IOM_R3_IOPORT_WRITE)
511 s->write_cmd = 0;
512 return rc;
513}
514
515#ifdef IN_RING3
516
517static int kbd_load(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, KBDState *s, uint32_t version_id)
518{
519 uint32_t u32, i;
520 uint8_t u8Dummy;
521 uint32_t u32Dummy;
522 int rc;
523
524#if 0
525 /** @todo enable this and remove the "if (version_id == 4)" code at some
526 * later time */
527 /* Version 4 was never created by any publicly released version of VBox */
528 AssertReturn(version_id != 4, VERR_NOT_SUPPORTED);
529#endif
530 if (version_id < 2 || version_id > PCKBD_SAVED_STATE_VERSION)
531 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
532 pHlp->pfnSSMGetU8(pSSM, &s->write_cmd);
533 pHlp->pfnSSMGetU8(pSSM, &s->status);
534 pHlp->pfnSSMGetU8(pSSM, &s->mode);
535 if (version_id <= 5)
536 {
537 pHlp->pfnSSMGetU32(pSSM, &u32Dummy);
538 pHlp->pfnSSMGetU32(pSSM, &u32Dummy);
539 }
540 else
541 {
542 pHlp->pfnSSMGetU8(pSSM, &s->dbbout);
543 }
544 if (version_id <= 7)
545 {
546 int32_t i32Dummy;
547 uint8_t u8State;
548 uint8_t u8Rate;
549 uint8_t u8Proto;
550
551 pHlp->pfnSSMGetU32(pSSM, &u32Dummy);
552 pHlp->pfnSSMGetU8(pSSM, &u8State);
553 pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
554 pHlp->pfnSSMGetU8(pSSM, &u8Rate);
555 pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
556 pHlp->pfnSSMGetU8(pSSM, &u8Proto);
557 pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
558 pHlp->pfnSSMGetS32(pSSM, &i32Dummy);
559 pHlp->pfnSSMGetS32(pSSM, &i32Dummy);
560 pHlp->pfnSSMGetS32(pSSM, &i32Dummy);
561 if (version_id > 2)
562 {
563 pHlp->pfnSSMGetS32(pSSM, &i32Dummy);
564 pHlp->pfnSSMGetS32(pSSM, &i32Dummy);
565 }
566 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
567 if (version_id == 4)
568 {
569 pHlp->pfnSSMGetU32(pSSM, &u32Dummy);
570 rc = pHlp->pfnSSMGetU32(pSSM, &u32Dummy);
571 }
572 if (version_id > 3)
573 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
574 if (version_id == 4)
575 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
576 AssertLogRelRCReturn(rc, rc);
577
578 PS2MR3FixupState(&s->Aux, u8State, u8Rate, u8Proto);
579 }
580
581 /* Determine the translation state. */
582 s->translate = (s->mode & KBD_MODE_KCC) == KBD_MODE_KCC;
583
584 /*
585 * Load the queues
586 */
587 if (version_id <= 5)
588 {
589 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
590 if (RT_FAILURE(rc))
591 return rc;
592 for (i = 0; i < u32; i++)
593 {
594 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
595 if (RT_FAILURE(rc))
596 return rc;
597 }
598 Log(("kbd_load: %d keyboard queue items discarded from old saved state\n", u32));
599 }
600
601 if (version_id <= 7)
602 {
603 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
604 if (RT_FAILURE(rc))
605 return rc;
606 for (i = 0; i < u32; i++)
607 {
608 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
609 if (RT_FAILURE(rc))
610 return rc;
611 }
612 Log(("kbd_load: %d mouse event queue items discarded from old saved state\n", u32));
613
614 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
615 if (RT_FAILURE(rc))
616 return rc;
617 for (i = 0; i < u32; i++)
618 {
619 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
620 if (RT_FAILURE(rc))
621 return rc;
622 }
623 Log(("kbd_load: %d mouse command queue items discarded from old saved state\n", u32));
624 }
625
626 /* terminator */
627 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
628 if (RT_FAILURE(rc))
629 return rc;
630 if (u32 != ~0U)
631 {
632 AssertMsgFailed(("u32=%#x\n", u32));
633 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
634 }
635 return 0;
636}
637
638#endif /* IN_RING3 */
639
640
641/* VirtualBox code start */
642
643/* -=-=-=-=-=- wrappers -=-=-=-=-=- */
644
645/**
646 * @callback_method_impl{FNIOMIOPORTNEWIN,
647 * Port I/O Handler for keyboard data IN operations.}
648 */
649static DECLCALLBACK(VBOXSTRICTRC) kbdIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
650{
651 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
652 RT_NOREF(pvUser, offPort);
653 Assert(offPort == 0);
654
655 switch (cb)
656 {
657 case 1:
658 *pu32 = kbd_read_data(pDevIns, pThis);
659 Log2(("kbdIOPortDataRead: *pu32=%#x\n", *pu32));
660 return VINF_SUCCESS;
661
662 case 4:
663 case 2:
664 {
665 uint32_t const uFluff = cb == 2 ? UINT32_C(0x0000ff00)
666 : UINT32_C(0xffffff00) /* Crazy Apple (Darwin 6.0.2 and earlier). */;
667 *pu32 = uFluff | kbd_read_data(pDevIns, pThis);
668 Log2(("kbdIOPortDataRead: cb=%u *pu32=%#x\n", cb, *pu32));
669 return VINF_SUCCESS;
670 }
671
672 default:
673 ASSERT_GUEST_MSG_FAILED(("Port=0x60+%x cb=%d\n", offPort, cb));
674 return VERR_IOM_IOPORT_UNUSED;
675 }
676}
677
678/**
679 * @callback_method_impl{FNIOMIOPORTNEWOUT,
680 * Port I/O Handler for keyboard data OUT operations.}
681 */
682static DECLCALLBACK(VBOXSTRICTRC) kbdIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
683{
684 VBOXSTRICTRC rc = VINF_SUCCESS;
685 RT_NOREF(offPort, pvUser);
686 Assert(offPort == 0);
687
688 if (cb == 1 || cb == 2)
689 {
690 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
691 rc = kbd_write_data(pDevIns, pThis, (uint8_t)u32);
692 Log2(("kbdIOPortDataWrite: Port=0x60+%x cb=%d u32=%#x\n", offPort, cb, u32));
693 }
694 else
695 ASSERT_GUEST_MSG_FAILED(("Port=0x60+%x cb=%d\n", offPort, cb));
696 return rc;
697}
698
699/**
700 * @callback_method_impl{FNIOMIOPORTNEWIN,
701 * Port I/O Handler for keyboard status IN operations.}
702 */
703static DECLCALLBACK(VBOXSTRICTRC) kbdIOPortStatusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
704{
705 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
706 RT_NOREF(offPort, pvUser);
707 Assert(offPort == 0);
708
709 switch (cb)
710 {
711 case 1:
712 *pu32 = pThis->status;
713 Log2(("kbdIOPortStatusRead: -> *pu32=%#x\n", *pu32));
714 return VINF_SUCCESS;
715
716 case 2:
717 case 4:
718 {
719 uint32_t const uFluff = cb == 2 ? UINT32_C(0x0000ff00)
720 : UINT32_C(0xffffff00) /* Crazy Apple (Darwin 6.0.2 and earlier). */;
721 *pu32 = uFluff | pThis->status;
722 Log2(("kbdIOPortStatusRead: cb=%u -> *pu32=%#x\n", cb, *pu32));
723 return VINF_SUCCESS;
724 }
725
726 default:
727 ASSERT_GUEST_MSG_FAILED(("Port=0x64+%x cb=%d\n", offPort, cb));
728 return VERR_IOM_IOPORT_UNUSED;
729 }
730}
731
732/**
733 * @callback_method_impl{FNIOMIOPORTNEWIN,
734 * Port I/O Handler for keyboard command OUT operations.}
735 */
736static DECLCALLBACK(VBOXSTRICTRC) kbdIOPortCommandWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
737{
738 RT_NOREF(offPort, pvUser);
739 Assert(offPort == 0);
740
741 if (cb == 1 || cb == 2)
742 {
743 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
744 VBOXSTRICTRC rc = kbd_write_command(pDevIns, pThis, (uint8_t)u32);
745 Log2(("kbdIOPortCommandWrite: cb=%d u32=%#x rc=%Rrc\n", cb, u32, VBOXSTRICTRC_VAL(rc)));
746 return rc;
747 }
748 ASSERT_GUEST_MSG_FAILED(("offPort=0x64+%x cb=%d\n", offPort, cb));
749 return VINF_SUCCESS;
750}
751
752/**
753 * Clear a queue.
754 *
755 * @param pQ Pointer to the queue.
756 */
757void PS2CmnClearQueue(GeneriQ *pQ)
758{
759 LogFlowFunc(("Clearing queue %p\n", pQ));
760 pQ->wpos = pQ->rpos;
761 pQ->cUsed = 0;
762}
763
764
765/**
766 * Add a byte to a queue.
767 *
768 * @param pQ Pointer to the queue.
769 * @param val The byte to store.
770 */
771void PS2CmnInsertQueue(GeneriQ *pQ, uint8_t val)
772{
773 /* Check if queue is full. */
774 if (pQ->cUsed >= pQ->cSize)
775 {
776 LogRelFlowFunc(("queue %p full (%d entries)\n", pQ, pQ->cUsed));
777 return;
778 }
779 /* Insert data and update circular buffer write position. */
780 pQ->abQueue[pQ->wpos] = val;
781 if (++pQ->wpos == pQ->cSize)
782 pQ->wpos = 0; /* Roll over. */
783 ++pQ->cUsed;
784 LogRelFlowFunc(("inserted 0x%02X into queue %p\n", val, pQ));
785}
786
787/**
788 * Retrieve a byte from a queue.
789 *
790 * @param pQ Pointer to the queue.
791 * @param pVal Pointer to storage for the byte.
792 *
793 * @retval VINF_TRY_AGAIN if queue is empty,
794 * @retval VINF_SUCCESS if a byte was read.
795 */
796int PS2CmnRemoveQueue(GeneriQ *pQ, uint8_t *pVal)
797{
798 int rc;
799
800 Assert(pVal);
801 if (pQ->cUsed)
802 {
803 *pVal = pQ->abQueue[pQ->rpos];
804 if (++pQ->rpos == pQ->cSize)
805 pQ->rpos = 0; /* Roll over. */
806 --pQ->cUsed;
807 LogFlowFunc(("removed 0x%02X from queue %p\n", *pVal, pQ));
808 rc = VINF_SUCCESS;
809 }
810 else
811 {
812 LogFlowFunc(("queue %p empty\n", pQ));
813 rc = VINF_TRY_AGAIN;
814 }
815 return rc;
816}
817
818#ifdef IN_RING3
819
820/**
821 * Save a queue state.
822 *
823 * @param pHlp The device helpers.
824 * @param pSSM SSM handle to write the state to.
825 * @param pQ Pointer to the queue.
826 */
827void PS2CmnR3SaveQueue(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, GeneriQ *pQ)
828{
829 uint32_t cItems = pQ->cUsed;
830 uint32_t i;
831
832 /* Only save the number of items. Note that the read/write
833 * positions aren't saved as they will be rebuilt on load.
834 */
835 pHlp->pfnSSMPutU32(pSSM, cItems);
836
837 LogFlow(("Storing %d items from queue %p\n", cItems, pQ));
838
839 /* Save queue data - only the bytes actually used (typically zero). */
840 for (i = pQ->rpos % pQ->cSize; cItems-- > 0; i = (i + 1) % pQ->cSize)
841 pHlp->pfnSSMPutU8(pSSM, pQ->abQueue[i]);
842}
843
844/**
845 * Load a queue state.
846 *
847 * @param pHlp The device helpers.
848 * @param pSSM SSM handle to read the state from.
849 * @param pQ Pointer to the queue.
850 *
851 * @returns VBox status/error code.
852 */
853int PS2CmnR3LoadQueue(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, GeneriQ *pQ)
854{
855 int rc;
856
857 /* On load, always put the read pointer at zero. */
858 rc = pHlp->pfnSSMGetU32(pSSM, &pQ->cUsed);
859 AssertRCReturn(rc, rc);
860
861 LogFlow(("Loading %d items to queue %p\n", pQ->cUsed, pQ));
862
863 AssertMsgReturn(pQ->cUsed <= pQ->cSize, ("Saved size=%u, actual=%u\n", pQ->cUsed, pQ->cSize),
864 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
865
866 /* Recalculate queue positions and load data in one go. */
867 pQ->rpos = 0;
868 pQ->wpos = pQ->cUsed;
869 return pHlp->pfnSSMGetMem(pSSM, pQ->abQueue, pQ->cUsed);
870}
871
872
873/**
874 * @callback_method_impl{FNSSMDEVSAVEEXEC, Saves a state of the keyboard device.}
875 *
876 * @returns VBox status code.
877 * @param pDevIns The device instance.
878 * @param pSSM The handle to save the state to.
879 */
880static DECLCALLBACK(int) kbdR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
881{
882 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
883 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
884
885 pHlp->pfnSSMPutU8(pSSM, pThis->write_cmd);
886 pHlp->pfnSSMPutU8(pSSM, pThis->status);
887 pHlp->pfnSSMPutU8(pSSM, pThis->mode);
888 pHlp->pfnSSMPutU8(pSSM, pThis->dbbout);
889 /* terminator */
890 pHlp->pfnSSMPutU32(pSSM, UINT32_MAX);
891
892 PS2KR3SaveState(pDevIns, &pThis->Kbd, pSSM);
893 PS2MR3SaveState(pDevIns, &pThis->Aux, pSSM);
894 return VINF_SUCCESS;
895}
896
897
898/**
899 * @callback_method_impl{FNSSMDEVLOADEXEC, Loads a saved keyboard device state.}
900 */
901static DECLCALLBACK(int) kbdR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
902{
903 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
904 int rc;
905
906 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
907 rc = kbd_load(pDevIns->pHlpR3, pSSM, pThis, uVersion);
908 AssertRCReturn(rc, rc);
909
910 if (uVersion >= 6)
911 rc = PS2KR3LoadState(pDevIns, &pThis->Kbd, pSSM, uVersion);
912 AssertRCReturn(rc, rc);
913
914 if (uVersion >= 8)
915 rc = PS2MR3LoadState(pDevIns, &pThis->Aux, pSSM, uVersion);
916 AssertRCReturn(rc, rc);
917 return rc;
918}
919
920/**
921 * @callback_method_impl{FNSSMDEVLOADDONE, Key state fix-up after loading}
922 */
923static DECLCALLBACK(int) kbdR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
924{
925 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
926 RT_NOREF(pSSM);
927 return PS2KR3LoadDone(pDevIns, &pThis->Kbd);
928}
929
930/**
931 * Reset notification.
932 *
933 * @returns VBox status code.
934 * @param pDevIns The device instance data.
935 */
936static DECLCALLBACK(void) kbdR3Reset(PPDMDEVINS pDevIns)
937{
938 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
939
940 pThis->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
941 pThis->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
942 /* Resetting everything, keyword was not working right on NT4 reboot. */
943 pThis->write_cmd = 0;
944 pThis->translate = 0;
945
946 PS2KR3Reset(pDevIns, &pThis->Kbd);
947 PS2MR3Reset(&pThis->Aux);
948}
949
950
951/* -=-=-=-=-=- real code -=-=-=-=-=- */
952
953
954/**
955 * @interface_method_impl{PDMDEVREGR3,pfnAttach}
956 *
957 * @remark The keyboard controller doesn't support this action, this is just
958 * implemented to try out the driver<->device structure.
959 */
960static DECLCALLBACK(int) kbdR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
961{
962 int rc;
963 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
964
965 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
966 ("PS/2 device does not support hotplugging\n"),
967 VERR_INVALID_PARAMETER);
968
969 switch (iLUN)
970 {
971 /* LUN #0: keyboard */
972 case 0:
973 rc = PS2KR3Attach(&pThis->Kbd, pDevIns, iLUN, fFlags);
974 break;
975
976 /* LUN #1: aux/mouse */
977 case 1:
978 rc = PS2MR3Attach(&pThis->Aux, pDevIns, iLUN, fFlags);
979 break;
980
981 default:
982 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
983 return VERR_PDM_NO_SUCH_LUN;
984 }
985
986 return rc;
987}
988
989
990/**
991 * @interface_method_impl{PDMDEVREGR3,pfnDetach}
992 * @remark The keyboard controller doesn't support this action, this is just
993 * implemented to try out the driver<->device structure.
994 */
995static DECLCALLBACK(void) kbdR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
996{
997#if 0
998 /*
999 * Reset the interfaces and update the controller state.
1000 */
1001 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
1002 switch (iLUN)
1003 {
1004 /* LUN #0: keyboard */
1005 case 0:
1006 pThis->Keyboard.pDrv = NULL;
1007 pThis->Keyboard.pDrvBase = NULL;
1008 break;
1009
1010 /* LUN #1: aux/mouse */
1011 case 1:
1012 pThis->Mouse.pDrv = NULL;
1013 pThis->Mouse.pDrvBase = NULL;
1014 break;
1015
1016 default:
1017 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
1018 break;
1019 }
1020#else
1021 NOREF(pDevIns); NOREF(iLUN); NOREF(fFlags);
1022#endif
1023}
1024
1025
1026/**
1027 * @interface_method_impl{PDMDEVREGR3,pfnConstruct}
1028 */
1029static DECLCALLBACK(int) kbdR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1030{
1031 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1032 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
1033 int rc;
1034 Assert(iInstance == 0);
1035
1036 /*
1037 * Validate and read the configuration.
1038 */
1039 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "KbdThrottleEnabled", "");
1040 Log(("pckbd: fRCEnabled=%RTbool fR0Enabled=%RTbool\n", pDevIns->fRCEnabled, pDevIns->fR0Enabled));
1041
1042 /*
1043 * Initialize the interfaces.
1044 */
1045 pThis->pDevInsR3 = pDevIns;
1046 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1047 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1048
1049 rc = PS2KR3Construct(&pThis->Kbd, pDevIns, pThis, iInstance, pCfg);
1050 AssertRCReturn(rc, rc);
1051
1052 rc = PS2MR3Construct(&pThis->Aux, pDevIns, pThis, iInstance);
1053 AssertRCReturn(rc, rc);
1054
1055 /*
1056 * Register I/O ports.
1057 */
1058 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x60 /*uPort*/, 1 /*cPorts*/, kbdIOPortDataWrite, kbdIOPortDataRead,
1059 "PC Keyboard - Data", NULL /*pExtDescs*/, &pThis->hIoPortData);
1060 AssertRCReturn(rc, rc);
1061 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x64 /*uPort*/, 1 /*cPorts*/, kbdIOPortCommandWrite, kbdIOPortStatusRead,
1062 "PC Keyboard - Command / Status", NULL /*pExtDescs*/, &pThis->hIoPortCmdStatus);
1063 AssertRCReturn(rc, rc);
1064
1065 /*
1066 * Saved state.
1067 */
1068 rc = PDMDevHlpSSMRegisterEx(pDevIns, PCKBD_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
1069 NULL, NULL, NULL,
1070 NULL, kbdR3SaveExec, NULL,
1071 NULL, kbdR3LoadExec, kbdR3LoadDone);
1072 AssertRCReturn(rc, rc);
1073
1074 /*
1075 * Attach to the keyboard and mouse drivers.
1076 */
1077 rc = kbdR3Attach(pDevIns, 0 /* keyboard LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
1078 AssertRCReturn(rc, rc);
1079 rc = kbdR3Attach(pDevIns, 1 /* aux/mouse LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
1080 AssertRCReturn(rc, rc);
1081
1082 /*
1083 * Initialize the device state.
1084 */
1085 kbdR3Reset(pDevIns);
1086
1087 return VINF_SUCCESS;
1088}
1089
1090#else /* !IN_RING3 */
1091
1092/**
1093 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1094 */
1095static DECLCALLBACK(int) kbdRZConstruct(PPDMDEVINS pDevIns)
1096{
1097 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1098 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
1099
1100 int rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortData, kbdIOPortDataWrite, kbdIOPortDataRead, NULL /*pvUser*/);
1101 AssertRCReturn(rc, rc);
1102 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortCmdStatus, kbdIOPortCommandWrite, kbdIOPortStatusRead, NULL /*pvUser*/);
1103 AssertRCReturn(rc, rc);
1104
1105 return VINF_SUCCESS;
1106}
1107
1108#endif /* !IN_RING3 */
1109
1110/**
1111 * The device registration structure.
1112 */
1113const PDMDEVREG g_DevicePS2KeyboardMouse =
1114{
1115 /* .u32Version = */ PDM_DEVREG_VERSION,
1116 /* .uReserved0 = */ 0,
1117 /* .szName = */ "pckbd",
1118 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ,
1119 /* .fClass = */ PDM_DEVREG_CLASS_INPUT,
1120 /* .cMaxInstances = */ 1,
1121 /* .uSharedVersion = */ 42,
1122 /* .cbInstanceShared = */ sizeof(KBDState),
1123 /* .cbInstanceCC = */ 0,
1124 /* .cbInstanceRC = */ 0,
1125 /* .cMaxPciDevices = */ 0,
1126 /* .cMaxMsixVectors = */ 0,
1127 /* .pszDescription = */ "PS/2 Keyboard and Mouse device. Emulates both the keyboard, mouse and the keyboard controller.\n"
1128 "LUN #0 is the keyboard connector.\n"
1129 "LUN #1 is the aux/mouse connector.",
1130#if defined(IN_RING3)
1131 /* .pszRCMod = */ "VBoxDDRC.rc",
1132 /* .pszR0Mod = */ "VBoxDDR0.r0",
1133 /* .pfnConstruct = */ kbdR3Construct,
1134 /* .pfnDestruct = */ NULL,
1135 /* .pfnRelocate = */ NULL,
1136 /* .pfnMemSetup = */ NULL,
1137 /* .pfnPowerOn = */ NULL,
1138 /* .pfnReset = */ kbdR3Reset,
1139 /* .pfnSuspend = */ NULL,
1140 /* .pfnResume = */ NULL,
1141 /* .pfnAttach = */ kbdR3Attach,
1142 /* .pfnDetach = */ kbdR3Detach,
1143 /* .pfnQueryInterface = */ NULL,
1144 /* .pfnInitComplete = */ NULL,
1145 /* .pfnPowerOff = */ NULL,
1146 /* .pfnSoftReset = */ NULL,
1147 /* .pfnReserved0 = */ NULL,
1148 /* .pfnReserved1 = */ NULL,
1149 /* .pfnReserved2 = */ NULL,
1150 /* .pfnReserved3 = */ NULL,
1151 /* .pfnReserved4 = */ NULL,
1152 /* .pfnReserved5 = */ NULL,
1153 /* .pfnReserved6 = */ NULL,
1154 /* .pfnReserved7 = */ NULL,
1155#elif defined(IN_RING0)
1156 /* .pfnEarlyConstruct = */ NULL,
1157 /* .pfnConstruct = */ kbdRZConstruct,
1158 /* .pfnDestruct = */ NULL,
1159 /* .pfnFinalDestruct = */ NULL,
1160 /* .pfnRequest = */ NULL,
1161 /* .pfnReserved0 = */ NULL,
1162 /* .pfnReserved1 = */ NULL,
1163 /* .pfnReserved2 = */ NULL,
1164 /* .pfnReserved3 = */ NULL,
1165 /* .pfnReserved4 = */ NULL,
1166 /* .pfnReserved5 = */ NULL,
1167 /* .pfnReserved6 = */ NULL,
1168 /* .pfnReserved7 = */ NULL,
1169#elif defined(IN_RC)
1170 /* .pfnConstruct = */ kbdRZConstruct,
1171 /* .pfnReserved0 = */ NULL,
1172 /* .pfnReserved1 = */ NULL,
1173 /* .pfnReserved2 = */ NULL,
1174 /* .pfnReserved3 = */ NULL,
1175 /* .pfnReserved4 = */ NULL,
1176 /* .pfnReserved5 = */ NULL,
1177 /* .pfnReserved6 = */ NULL,
1178 /* .pfnReserved7 = */ NULL,
1179#else
1180# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1181#endif
1182 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1183};
1184
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