VirtualBox

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

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

DevPS2: Moved XlateAT2PC to the DevPS2.cpp file. bugref:9218

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette