VirtualBox

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

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

DevPS2: ps2kRemoveQueue is common to both DevPS2M.cpp and DevPS2K.cpp, share it! bugref:9218

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