VirtualBox

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

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

DevPS2: type name cleanup. bugref:9218

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.2 KB
Line 
1/* $Id: DevPS2.cpp 82204 2019-11-25 21:55:12Z 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, 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
444PS2K *KBDGetPS2KFromDevIns(PPDMDEVINS pDevIns)
445{
446 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
447 return &pThis->Kbd;
448}
449
450PS2M *KBDGetPS2MFromDevIns(PPDMDEVINS pDevIns)
451{
452 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
453 return &pThis->Aux;
454}
455
456static VBOXSTRICTRC kbd_write_data(PPDMDEVINS pDevIns, PKBDSTATE s, uint32_t val)
457{
458 VBOXSTRICTRC 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(pDevIns, s, val);
479 break;
480 case KBD_CCMD_WRITE_AUX_OBUF:
481 kbc_dbb_out_aux(pDevIns, s, val);
482 break;
483 case KBD_CCMD_WRITE_OUTPORT:
484#ifdef TARGET_I386
485# ifndef IN_RING3
486 if (PDMDevHlpA20IsEnabled(pDevIns) != !!(val & 2))
487 rc = VINF_IOM_R3_IOPORT_WRITE;
488# else /* IN_RING3 */
489 PDMDevHlpA20Set(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(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, PKBDSTATE 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/** Fluff bits indexed by size (1,2,4). */
646static uint32_t const g_afFluff[5] =
647{
648 /* [0] = */ 0,
649 /* [1] = */ 0,
650 /* [2] = */ UINT32_C(0xff00),
651 /* [3] = */ 0,
652 /* [4] = */ UINT32_C(0xffffff00) /* Crazy Apple (Darwin 6.0.2 and earlier). */
653};
654
655/**
656 * @callback_method_impl{FNIOMIOPORTNEWIN,
657 * Port I/O Handler for keyboard data IN operations.}
658 */
659static DECLCALLBACK(VBOXSTRICTRC) kbdIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
660{
661 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
662 RT_NOREF(pvUser, offPort);
663 Assert(offPort == 0);
664 Assert(cb == 1 || cb == 2 || cb == 4);
665
666 *pu32 = kbd_read_data(pDevIns, pThis) | g_afFluff[cb];
667 Log2(("kbdIOPortDataRead: cb=%u *pu32=%#x\n", cb, *pu32));
668 return VINF_SUCCESS;
669}
670
671/**
672 * @callback_method_impl{FNIOMIOPORTNEWOUT,
673 * Port I/O Handler for keyboard data OUT operations.}
674 */
675static DECLCALLBACK(VBOXSTRICTRC) kbdIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
676{
677 RT_NOREF(offPort, pvUser);
678 Assert(offPort == 0);
679
680 if (cb == 1 || cb == 2)
681 {
682 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
683 VBOXSTRICTRC rc = kbd_write_data(pDevIns, pThis, (uint8_t)u32);
684 Log2(("kbdIOPortDataWrite: Port=0x60+%x cb=%d u32=%#x rc=%Rrc\n", offPort, cb, u32, VBOXSTRICTRC_VAL(rc)));
685 return rc;
686 }
687 Assert(cb == 4);
688 ASSERT_GUEST_MSG_FAILED(("Port=0x60+%x cb=%d\n", offPort, cb));
689 return VINF_SUCCESS;
690}
691
692/**
693 * @callback_method_impl{FNIOMIOPORTNEWIN,
694 * Port I/O Handler for keyboard status IN operations.}
695 */
696static DECLCALLBACK(VBOXSTRICTRC) kbdIOPortStatusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
697{
698 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
699 RT_NOREF(offPort, pvUser);
700 Assert(offPort == 0);
701 Assert(cb == 1 || cb == 2 || cb == 4);
702
703 *pu32 = pThis->status | g_afFluff[cb];
704 Log2(("kbdIOPortStatusRead: cb=%u -> *pu32=%#x\n", cb, *pu32));
705 return VINF_SUCCESS;
706}
707
708/**
709 * @callback_method_impl{FNIOMIOPORTNEWIN,
710 * Port I/O Handler for keyboard command OUT operations.}
711 */
712static DECLCALLBACK(VBOXSTRICTRC) kbdIOPortCommandWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
713{
714 RT_NOREF(offPort, pvUser);
715 Assert(offPort == 0);
716
717 if (cb == 1 || cb == 2)
718 {
719 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
720 VBOXSTRICTRC rc = kbd_write_command(pDevIns, pThis, (uint8_t)u32);
721 Log2(("kbdIOPortCommandWrite: cb=%d u32=%#x rc=%Rrc\n", cb, u32, VBOXSTRICTRC_VAL(rc)));
722 return rc;
723 }
724 Assert(cb == 4);
725 ASSERT_GUEST_MSG_FAILED(("offPort=0x64+%x cb=%d\n", offPort, cb));
726 return VINF_SUCCESS;
727}
728
729/**
730 * Clear a queue.
731 *
732 * @param pQ Pointer to the queue.
733 */
734void PS2CmnClearQueue(GeneriQ *pQ)
735{
736 LogFlowFunc(("Clearing queue %p\n", pQ));
737 pQ->wpos = pQ->rpos;
738 pQ->cUsed = 0;
739}
740
741
742/**
743 * Add a byte to a queue.
744 *
745 * @param pQ Pointer to the queue.
746 * @param val The byte to store.
747 */
748void PS2CmnInsertQueue(GeneriQ *pQ, uint8_t val)
749{
750 /* Check if queue is full. */
751 if (pQ->cUsed >= pQ->cSize)
752 {
753 LogRelFlowFunc(("queue %p full (%d entries)\n", pQ, pQ->cUsed));
754 return;
755 }
756 /* Insert data and update circular buffer write position. */
757 pQ->abQueue[pQ->wpos] = val;
758 if (++pQ->wpos == pQ->cSize)
759 pQ->wpos = 0; /* Roll over. */
760 ++pQ->cUsed;
761 LogRelFlowFunc(("inserted 0x%02X into queue %p\n", val, pQ));
762}
763
764/**
765 * Retrieve a byte from a queue.
766 *
767 * @param pQ Pointer to the queue.
768 * @param pVal Pointer to storage for the byte.
769 *
770 * @retval VINF_TRY_AGAIN if queue is empty,
771 * @retval VINF_SUCCESS if a byte was read.
772 */
773int PS2CmnRemoveQueue(GeneriQ *pQ, uint8_t *pVal)
774{
775 int rc;
776
777 Assert(pVal);
778 if (pQ->cUsed)
779 {
780 *pVal = pQ->abQueue[pQ->rpos];
781 if (++pQ->rpos == pQ->cSize)
782 pQ->rpos = 0; /* Roll over. */
783 --pQ->cUsed;
784 LogFlowFunc(("removed 0x%02X from queue %p\n", *pVal, pQ));
785 rc = VINF_SUCCESS;
786 }
787 else
788 {
789 LogFlowFunc(("queue %p empty\n", pQ));
790 rc = VINF_TRY_AGAIN;
791 }
792 return rc;
793}
794
795#ifdef IN_RING3
796
797/**
798 * Save a queue state.
799 *
800 * @param pHlp The device helpers.
801 * @param pSSM SSM handle to write the state to.
802 * @param pQ Pointer to the queue.
803 */
804void PS2CmnR3SaveQueue(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, GeneriQ *pQ)
805{
806 uint32_t cItems = pQ->cUsed;
807 uint32_t i;
808
809 /* Only save the number of items. Note that the read/write
810 * positions aren't saved as they will be rebuilt on load.
811 */
812 pHlp->pfnSSMPutU32(pSSM, cItems);
813
814 LogFlow(("Storing %d items from queue %p\n", cItems, pQ));
815
816 /* Save queue data - only the bytes actually used (typically zero). */
817 for (i = pQ->rpos % pQ->cSize; cItems-- > 0; i = (i + 1) % pQ->cSize)
818 pHlp->pfnSSMPutU8(pSSM, pQ->abQueue[i]);
819}
820
821/**
822 * Load a queue state.
823 *
824 * @param pHlp The device helpers.
825 * @param pSSM SSM handle to read the state from.
826 * @param pQ Pointer to the queue.
827 *
828 * @returns VBox status/error code.
829 */
830int PS2CmnR3LoadQueue(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, GeneriQ *pQ)
831{
832 int rc;
833
834 /* On load, always put the read pointer at zero. */
835 rc = pHlp->pfnSSMGetU32(pSSM, &pQ->cUsed);
836 AssertRCReturn(rc, rc);
837
838 LogFlow(("Loading %d items to queue %p\n", pQ->cUsed, pQ));
839
840 AssertMsgReturn(pQ->cUsed <= pQ->cSize, ("Saved size=%u, actual=%u\n", pQ->cUsed, pQ->cSize),
841 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
842
843 /* Recalculate queue positions and load data in one go. */
844 pQ->rpos = 0;
845 pQ->wpos = pQ->cUsed;
846 return pHlp->pfnSSMGetMem(pSSM, pQ->abQueue, pQ->cUsed);
847}
848
849
850/**
851 * @callback_method_impl{FNSSMDEVSAVEEXEC, Saves a state of the keyboard device.}
852 *
853 * @returns VBox status code.
854 * @param pDevIns The device instance.
855 * @param pSSM The handle to save the state to.
856 */
857static DECLCALLBACK(int) kbdR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
858{
859 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
860 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
861
862 pHlp->pfnSSMPutU8(pSSM, pThis->write_cmd);
863 pHlp->pfnSSMPutU8(pSSM, pThis->status);
864 pHlp->pfnSSMPutU8(pSSM, pThis->mode);
865 pHlp->pfnSSMPutU8(pSSM, pThis->dbbout);
866 /* terminator */
867 pHlp->pfnSSMPutU32(pSSM, UINT32_MAX);
868
869 PS2KR3SaveState(pDevIns, &pThis->Kbd, pSSM);
870 PS2MR3SaveState(pDevIns, &pThis->Aux, pSSM);
871 return VINF_SUCCESS;
872}
873
874
875/**
876 * @callback_method_impl{FNSSMDEVLOADEXEC, Loads a saved keyboard device state.}
877 */
878static DECLCALLBACK(int) kbdR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
879{
880 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
881 int rc;
882
883 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
884 rc = kbd_load(pDevIns->pHlpR3, pSSM, pThis, uVersion);
885 AssertRCReturn(rc, rc);
886
887 if (uVersion >= 6)
888 rc = PS2KR3LoadState(pDevIns, &pThis->Kbd, pSSM, uVersion);
889 AssertRCReturn(rc, rc);
890
891 if (uVersion >= 8)
892 rc = PS2MR3LoadState(pDevIns, &pThis->Aux, pSSM, uVersion);
893 AssertRCReturn(rc, rc);
894 return rc;
895}
896
897/**
898 * @callback_method_impl{FNSSMDEVLOADDONE, Key state fix-up after loading}
899 */
900static DECLCALLBACK(int) kbdR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
901{
902 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
903 RT_NOREF(pSSM);
904 return PS2KR3LoadDone(pDevIns, &pThis->Kbd);
905}
906
907/**
908 * Reset notification.
909 *
910 * @returns VBox status code.
911 * @param pDevIns The device instance data.
912 */
913static DECLCALLBACK(void) kbdR3Reset(PPDMDEVINS pDevIns)
914{
915 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
916
917 pThis->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
918 pThis->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
919 /* Resetting everything, keyword was not working right on NT4 reboot. */
920 pThis->write_cmd = 0;
921 pThis->translate = 0;
922
923 PS2KR3Reset(pDevIns, &pThis->Kbd);
924 PS2MR3Reset(&pThis->Aux);
925}
926
927
928/* -=-=-=-=-=- real code -=-=-=-=-=- */
929
930
931/**
932 * @interface_method_impl{PDMDEVREGR3,pfnAttach}
933 *
934 * @remark The keyboard controller doesn't support this action, this is just
935 * implemented to try out the driver<->device structure.
936 */
937static DECLCALLBACK(int) kbdR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
938{
939 int rc;
940 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
941
942 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
943 ("PS/2 device does not support hotplugging\n"),
944 VERR_INVALID_PARAMETER);
945
946 switch (iLUN)
947 {
948 /* LUN #0: keyboard */
949 case 0:
950 rc = PS2KR3Attach(&pThis->Kbd, pDevIns, iLUN, fFlags);
951 break;
952
953 /* LUN #1: aux/mouse */
954 case 1:
955 rc = PS2MR3Attach(&pThis->Aux, pDevIns, iLUN, fFlags);
956 break;
957
958 default:
959 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
960 return VERR_PDM_NO_SUCH_LUN;
961 }
962
963 return rc;
964}
965
966
967/**
968 * @interface_method_impl{PDMDEVREGR3,pfnDetach}
969 * @remark The keyboard controller doesn't support this action, this is just
970 * implemented to try out the driver<->device structure.
971 */
972static DECLCALLBACK(void) kbdR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
973{
974#if 0
975 /*
976 * Reset the interfaces and update the controller state.
977 */
978 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
979 switch (iLUN)
980 {
981 /* LUN #0: keyboard */
982 case 0:
983 pThis->Keyboard.pDrv = NULL;
984 pThis->Keyboard.pDrvBase = NULL;
985 break;
986
987 /* LUN #1: aux/mouse */
988 case 1:
989 pThis->Mouse.pDrv = NULL;
990 pThis->Mouse.pDrvBase = NULL;
991 break;
992
993 default:
994 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
995 break;
996 }
997#else
998 NOREF(pDevIns); NOREF(iLUN); NOREF(fFlags);
999#endif
1000}
1001
1002
1003/**
1004 * @interface_method_impl{PDMDEVREGR3,pfnConstruct}
1005 */
1006static DECLCALLBACK(int) kbdR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1007{
1008 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1009 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
1010 int rc;
1011 Assert(iInstance == 0);
1012
1013 /*
1014 * Validate and read the configuration.
1015 */
1016 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "KbdThrottleEnabled", "");
1017 Log(("pckbd: fRCEnabled=%RTbool fR0Enabled=%RTbool\n", pDevIns->fRCEnabled, pDevIns->fR0Enabled));
1018
1019 /*
1020 * Initialize the sub-components.
1021 */
1022 rc = PS2KR3Construct(&pThis->Kbd, pDevIns, pThis, iInstance, pCfg);
1023 AssertRCReturn(rc, rc);
1024
1025 rc = PS2MR3Construct(&pThis->Aux, pDevIns, pThis, iInstance);
1026 AssertRCReturn(rc, rc);
1027
1028 /*
1029 * Register I/O ports.
1030 */
1031 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x60 /*uPort*/, 1 /*cPorts*/, kbdIOPortDataWrite, kbdIOPortDataRead,
1032 "PC Keyboard - Data", NULL /*pExtDescs*/, &pThis->hIoPortData);
1033 AssertRCReturn(rc, rc);
1034 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x64 /*uPort*/, 1 /*cPorts*/, kbdIOPortCommandWrite, kbdIOPortStatusRead,
1035 "PC Keyboard - Command / Status", NULL /*pExtDescs*/, &pThis->hIoPortCmdStatus);
1036 AssertRCReturn(rc, rc);
1037
1038 /*
1039 * Saved state.
1040 */
1041 rc = PDMDevHlpSSMRegisterEx(pDevIns, PCKBD_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
1042 NULL, NULL, NULL,
1043 NULL, kbdR3SaveExec, NULL,
1044 NULL, kbdR3LoadExec, kbdR3LoadDone);
1045 AssertRCReturn(rc, rc);
1046
1047 /*
1048 * Attach to the keyboard and mouse drivers.
1049 */
1050 rc = kbdR3Attach(pDevIns, 0 /* keyboard LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
1051 AssertRCReturn(rc, rc);
1052 rc = kbdR3Attach(pDevIns, 1 /* aux/mouse LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
1053 AssertRCReturn(rc, rc);
1054
1055 /*
1056 * Initialize the device state.
1057 */
1058 kbdR3Reset(pDevIns);
1059
1060 return VINF_SUCCESS;
1061}
1062
1063#else /* !IN_RING3 */
1064
1065/**
1066 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1067 */
1068static DECLCALLBACK(int) kbdRZConstruct(PPDMDEVINS pDevIns)
1069{
1070 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1071 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
1072
1073 int rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortData, kbdIOPortDataWrite, kbdIOPortDataRead, NULL /*pvUser*/);
1074 AssertRCReturn(rc, rc);
1075 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortCmdStatus, kbdIOPortCommandWrite, kbdIOPortStatusRead, NULL /*pvUser*/);
1076 AssertRCReturn(rc, rc);
1077
1078 return VINF_SUCCESS;
1079}
1080
1081#endif /* !IN_RING3 */
1082
1083/**
1084 * The device registration structure.
1085 */
1086const PDMDEVREG g_DevicePS2KeyboardMouse =
1087{
1088 /* .u32Version = */ PDM_DEVREG_VERSION,
1089 /* .uReserved0 = */ 0,
1090 /* .szName = */ "pckbd",
1091 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ,
1092 /* .fClass = */ PDM_DEVREG_CLASS_INPUT,
1093 /* .cMaxInstances = */ 1,
1094 /* .uSharedVersion = */ 42,
1095 /* .cbInstanceShared = */ sizeof(KBDSTATE),
1096 /* .cbInstanceCC = */ 0,
1097 /* .cbInstanceRC = */ 0,
1098 /* .cMaxPciDevices = */ 0,
1099 /* .cMaxMsixVectors = */ 0,
1100 /* .pszDescription = */ "PS/2 Keyboard and Mouse device. Emulates both the keyboard, mouse and the keyboard controller.\n"
1101 "LUN #0 is the keyboard connector.\n"
1102 "LUN #1 is the aux/mouse connector.",
1103#if defined(IN_RING3)
1104 /* .pszRCMod = */ "VBoxDDRC.rc",
1105 /* .pszR0Mod = */ "VBoxDDR0.r0",
1106 /* .pfnConstruct = */ kbdR3Construct,
1107 /* .pfnDestruct = */ NULL,
1108 /* .pfnRelocate = */ NULL,
1109 /* .pfnMemSetup = */ NULL,
1110 /* .pfnPowerOn = */ NULL,
1111 /* .pfnReset = */ kbdR3Reset,
1112 /* .pfnSuspend = */ NULL,
1113 /* .pfnResume = */ NULL,
1114 /* .pfnAttach = */ kbdR3Attach,
1115 /* .pfnDetach = */ kbdR3Detach,
1116 /* .pfnQueryInterface = */ NULL,
1117 /* .pfnInitComplete = */ NULL,
1118 /* .pfnPowerOff = */ NULL,
1119 /* .pfnSoftReset = */ NULL,
1120 /* .pfnReserved0 = */ NULL,
1121 /* .pfnReserved1 = */ NULL,
1122 /* .pfnReserved2 = */ NULL,
1123 /* .pfnReserved3 = */ NULL,
1124 /* .pfnReserved4 = */ NULL,
1125 /* .pfnReserved5 = */ NULL,
1126 /* .pfnReserved6 = */ NULL,
1127 /* .pfnReserved7 = */ NULL,
1128#elif defined(IN_RING0)
1129 /* .pfnEarlyConstruct = */ NULL,
1130 /* .pfnConstruct = */ kbdRZConstruct,
1131 /* .pfnDestruct = */ NULL,
1132 /* .pfnFinalDestruct = */ NULL,
1133 /* .pfnRequest = */ NULL,
1134 /* .pfnReserved0 = */ NULL,
1135 /* .pfnReserved1 = */ NULL,
1136 /* .pfnReserved2 = */ NULL,
1137 /* .pfnReserved3 = */ NULL,
1138 /* .pfnReserved4 = */ NULL,
1139 /* .pfnReserved5 = */ NULL,
1140 /* .pfnReserved6 = */ NULL,
1141 /* .pfnReserved7 = */ NULL,
1142#elif defined(IN_RC)
1143 /* .pfnConstruct = */ kbdRZConstruct,
1144 /* .pfnReserved0 = */ NULL,
1145 /* .pfnReserved1 = */ NULL,
1146 /* .pfnReserved2 = */ NULL,
1147 /* .pfnReserved3 = */ NULL,
1148 /* .pfnReserved4 = */ NULL,
1149 /* .pfnReserved5 = */ NULL,
1150 /* .pfnReserved6 = */ NULL,
1151 /* .pfnReserved7 = */ NULL,
1152#else
1153# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1154#endif
1155 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1156};
1157
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