VirtualBox

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

Last change on this file was 99739, checked in by vboxsync, 12 months ago

*: doxygen corrections (mostly about removing @returns from functions returning void).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.6 KB
RevLine 
[22909]1/* $Id: DevPS2.cpp 99739 2023-05-11 01:01:08Z vboxsync $ */
[1]2/** @file
[11194]3 * DevPS2 - PS/2 keyboard & mouse controller device.
[1]4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[1]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
[69498]26 * --------------------------------------------------------------------
[1]27 *
28 * This code is based on:
29 *
30 * QEMU PC keyboard emulation (revision 1.12)
31 *
32 * Copyright (c) 2003 Fabrice Bellard
33 *
34 * Permission is hereby granted, free of charge, to any person obtaining a copy
35 * of this software and associated documentation files (the "Software"), to deal
36 * in the Software without restriction, including without limitation the rights
37 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38 * copies of the Software, and to permit persons to whom the Software is
39 * furnished to do so, subject to the following conditions:
40 *
41 * The above copyright notice and this permission notice shall be included in
42 * all copies or substantial portions of the Software.
43 *
44 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
47 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
49 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
50 * THE SOFTWARE.
51 *
52 */
53
[57358]54
55/*********************************************************************************************************************************
56* Header Files *
57*********************************************************************************************************************************/
[1]58#define LOG_GROUP LOG_GROUP_DEV_KBD
[35346]59#include <VBox/vmm/pdmdev.h>
[82201]60#include <VBox/AssertGuest.h>
[1]61#include <iprt/assert.h>
[25966]62#include <iprt/uuid.h>
[1]63
[35353]64#include "VBoxDD.h"
[82170]65#include "DevPS2.h"
[1]66
[82191]67
68/*********************************************************************************************************************************
69* Defined Constants And Macros *
70*********************************************************************************************************************************/
[50965]71/* Do not remove this (unless eliminating the corresponding ifdefs), it will
[49886]72 * cause instant triple faults when booting Windows VMs. */
73#define TARGET_I386
74
[50965]75#define PCKBD_SAVED_STATE_VERSION 8
[1]76
77/* debug PC keyboard */
78#define DEBUG_KBD
79
80/* debug PC keyboard : only mouse */
81#define DEBUG_MOUSE
82
[22584]83/* Keyboard Controller Commands */
84#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
85#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
86#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
87#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
88#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
89#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
90#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
91#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
92#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
93#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
[1]94#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */
[22584]95#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */
96#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */
97#define KBD_CCMD_WRITE_OBUF 0xD2
98#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
99 initiated by the auxiliary device */
100#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
[1]101#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */
102#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */
[6102]103#define KBD_CCMD_READ_TSTINP 0xE0 /* Read test inputs T0, T1 */
[48033]104#define KBD_CCMD_RESET_ALT 0xF0
[22584]105#define KBD_CCMD_RESET 0xFE
[1]106
107/* Status Register Bits */
[22584]108#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
109#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
110#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
111#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
112#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
113#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
114#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
115#define KBD_STAT_PERR 0x80 /* Parity error */
[1]116
117/* Controller Mode Register Bits */
[22584]118#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
119#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
120#define KBD_MODE_SYS 0x04 /* The system flag (?) */
121#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
122#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
123#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
124#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
125#define KBD_MODE_RFU 0x80
[1]126
127
[82191]128/*********************************************************************************************************************************
129* Structures and Typedefs *
130*********************************************************************************************************************************/
131/** AT to PC scancode translator state. */
132typedef enum
133{
134 XS_IDLE, /**< Starting state. */
135 XS_BREAK, /**< F0 break byte was received. */
136 XS_HIBIT /**< Break code still active. */
137} xlat_state_t;
[1]138
[82191]139
140/*********************************************************************************************************************************
141* Global Variables *
142*********************************************************************************************************************************/
143/* Table used by the keyboard controller to optionally translate the incoming
144 * keyboard data. Note that the translation is designed for essentially taking
145 * Scan Set 2 input and producing Scan Set 1 output, but can be turned on and
146 * off regardless of what the keyboard is sending.
147 */
148static uint8_t const g_aAT2PC[128] =
149{
150 0xff,0x43,0x41,0x3f,0x3d,0x3b,0x3c,0x58,0x64,0x44,0x42,0x40,0x3e,0x0f,0x29,0x59,
151 0x65,0x38,0x2a,0x70,0x1d,0x10,0x02,0x5a,0x66,0x71,0x2c,0x1f,0x1e,0x11,0x03,0x5b,
152 0x67,0x2e,0x2d,0x20,0x12,0x05,0x04,0x5c,0x68,0x39,0x2f,0x21,0x14,0x13,0x06,0x5d,
153 0x69,0x31,0x30,0x23,0x22,0x15,0x07,0x5e,0x6a,0x72,0x32,0x24,0x16,0x08,0x09,0x5f,
154 0x6b,0x33,0x25,0x17,0x18,0x0b,0x0a,0x60,0x6c,0x34,0x35,0x26,0x27,0x19,0x0c,0x61,
155 0x6d,0x73,0x28,0x74,0x1a,0x0d,0x62,0x6e,0x3a,0x36,0x1c,0x1b,0x75,0x2b,0x63,0x76,
156 0x55,0x56,0x77,0x78,0x79,0x7a,0x0e,0x7b,0x7c,0x4f,0x7d,0x4b,0x47,0x7e,0x7f,0x6f,
157 0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x54
158};
159
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
[82195]219/** update irq and KBD_STAT_[MOUSE_]OBF */
[82204]220static void kbd_update_irq(PPDMDEVINS pDevIns, PKBDSTATE s)
[1]221{
222 int irq12_level, irq1_level;
[39959]223 uint8_t val;
[1]224
225 irq1_level = 0;
226 irq12_level = 0;
[30013]227
[28455]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. */
[82195]235 if (!(s->mode & KBD_MODE_DISABLE_KBD) && PS2KByteFromKbd(pDevIns, &s->Kbd, &val) == VINF_SUCCESS)
[28455]236 {
[39959]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
[82191]244 s->xlat_state = kbcXlateAT2PC(s->xlat_state, val, &xlated_val);
[39959]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 */
[82195]250 while (s->xlat_state == XS_BREAK && PS2KByteFromKbd(pDevIns, &s->Kbd, &val) == VINF_SUCCESS)
[39959]251 {
[82191]252 s->xlat_state = kbcXlateAT2PC(s->xlat_state, val, &xlated_val);
[39959]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 }
[48214]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 }
[1]270 }
[28455]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;
[30013]277 }
278 else
[28455]279 { /* KBD_STAT_OBF set but KBD_STAT_MOUSE_OBF isn't. */
[34371]280 if (s->mode & KBD_MODE_KBD_INT)
[28455]281 irq1_level = 1;
282 }
[1]283 }
[82203]284 PDMDevHlpISASetIrq(pDevIns, 1, irq1_level);
285 PDMDevHlpISASetIrq(pDevIns, 12, irq12_level);
[1]286}
287
[82195]288void KBCUpdateInterrupts(PPDMDEVINS pDevIns)
[39959]289{
[82195]290 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
291 kbd_update_irq(pDevIns, pThis);
[39959]292}
293
[82203]294static void kbc_dbb_out(PPDMDEVINS pDevIns, PKBDSTATE s, uint8_t val)
[38377]295{
296 s->dbbout = val;
297 /* Set the OBF and raise IRQ. */
298 s->status |= KBD_STAT_OBF;
299 if (s->mode & KBD_MODE_KBD_INT)
[82203]300 PDMDevHlpISASetIrq(pDevIns, 1, 1);
[38377]301}
302
[82203]303static void kbc_dbb_out_aux(PPDMDEVINS pDevIns, PKBDSTATE s, uint8_t val)
[48214]304{
305 s->dbbout = val;
306 /* Set the aux OBF and raise IRQ. */
307 s->status |= KBD_STAT_OBF | KBD_STAT_MOUSE_OBF;
308 if (s->mode & KBD_MODE_MOUSE_INT)
[82203]309 PDMDevHlpISASetIrq(pDevIns, 12, PDM_IRQ_LEVEL_HIGH);
[48214]310}
311
[82201]312static VBOXSTRICTRC kbd_write_command(PPDMDEVINS pDevIns, PKBDSTATE s, uint32_t val)
[1]313{
314#ifdef DEBUG_KBD
315 Log(("kbd: write cmd=0x%02x\n", val));
316#endif
317 switch(val) {
318 case KBD_CCMD_READ_MODE:
[82203]319 kbc_dbb_out(pDevIns, s, s->mode);
[1]320 break;
321 case KBD_CCMD_WRITE_MODE:
322 case KBD_CCMD_WRITE_OBUF:
323 case KBD_CCMD_WRITE_AUX_OBUF:
324 case KBD_CCMD_WRITE_MOUSE:
325 case KBD_CCMD_WRITE_OUTPORT:
326 s->write_cmd = val;
327 break;
328 case KBD_CCMD_MOUSE_DISABLE:
329 s->mode |= KBD_MODE_DISABLE_MOUSE;
[83299]330 PS2MLineDisable(&s->Aux);
[1]331 break;
332 case KBD_CCMD_MOUSE_ENABLE:
[83299]333 PS2MLineEnable(&s->Aux);
[1]334 s->mode &= ~KBD_MODE_DISABLE_MOUSE;
[38377]335 /* Check for queued input. */
[83300]336 /// @todo Can there actually be any?
[82195]337 kbd_update_irq(pDevIns, s);
[1]338 break;
339 case KBD_CCMD_TEST_MOUSE:
[82203]340 kbc_dbb_out(pDevIns, s, 0x00);
[1]341 break;
342 case KBD_CCMD_SELF_TEST:
[38377]343 /* Enable the A20 line - that is the power-on state(!). */
344# ifndef IN_RING3
[82203]345 if (!PDMDevHlpA20IsEnabled(pDevIns))
[82201]346 return VINF_IOM_R3_IOPORT_WRITE;
347# else /* IN_RING3 */
[82203]348 PDMDevHlpA20Set(pDevIns, true);
[38377]349# endif /* IN_RING3 */
[1]350 s->status |= KBD_STAT_SELFTEST;
[38377]351 s->mode |= KBD_MODE_DISABLE_KBD;
[82203]352 kbc_dbb_out(pDevIns, s, 0x55);
[1]353 break;
354 case KBD_CCMD_KBD_TEST:
[82203]355 kbc_dbb_out(pDevIns, s, 0x00);
[1]356 break;
357 case KBD_CCMD_KBD_DISABLE:
358 s->mode |= KBD_MODE_DISABLE_KBD;
359 break;
360 case KBD_CCMD_KBD_ENABLE:
361 s->mode &= ~KBD_MODE_DISABLE_KBD;
[38377]362 /* Check for queued input. */
[82195]363 kbd_update_irq(pDevIns, s);
[1]364 break;
365 case KBD_CCMD_READ_INPORT:
[82203]366 kbc_dbb_out(pDevIns, s, 0xBF);
[1]367 break;
368 case KBD_CCMD_READ_OUTPORT:
369 /* XXX: check that */
370#ifdef TARGET_I386
[82203]371 val = 0x01 | (PDMDevHlpA20IsEnabled(pDevIns) << 1);
[1]372#else
373 val = 0x01;
374#endif
375 if (s->status & KBD_STAT_OBF)
376 val |= 0x10;
377 if (s->status & KBD_STAT_MOUSE_OBF)
378 val |= 0x20;
[82203]379 kbc_dbb_out(pDevIns, s, val);
[1]380 break;
381#ifdef TARGET_I386
382 case KBD_CCMD_ENABLE_A20:
383# ifndef IN_RING3
[82203]384 if (!PDMDevHlpA20IsEnabled(pDevIns))
[82201]385 return VINF_IOM_R3_IOPORT_WRITE;
386# else /* IN_RING3 */
[82203]387 PDMDevHlpA20Set(pDevIns, true);
[1]388# endif /* IN_RING3 */
389 break;
390 case KBD_CCMD_DISABLE_A20:
391# ifndef IN_RING3
[82203]392 if (PDMDevHlpA20IsEnabled(pDevIns))
[82201]393 return VINF_IOM_R3_IOPORT_WRITE;
394# else /* IN_RING3 */
[82203]395 PDMDevHlpA20Set(pDevIns, false);
[82201]396# endif /* IN_RING3 */
[1]397 break;
398#endif
[6102]399 case KBD_CCMD_READ_TSTINP:
400 /* Keyboard clock line is zero IFF keyboard is disabled */
401 val = (s->mode & KBD_MODE_DISABLE_KBD) ? 0 : 1;
[82203]402 kbc_dbb_out(pDevIns, s, val);
[6102]403 break;
[1]404 case KBD_CCMD_RESET:
[48033]405 case KBD_CCMD_RESET_ALT:
[22858]406#ifndef IN_RING3
[82201]407 return VINF_IOM_R3_IOPORT_WRITE;
408#else /* IN_RING3 */
[41560]409 LogRel(("Reset initiated by keyboard controller\n"));
[82203]410 return PDMDevHlpVMReset(pDevIns, PDMVMRESET_F_KBD);
[82201]411#endif /* IN_RING3 */
[1]412 case 0xff:
413 /* ignore that - I don't know what is its use */
414 break;
[22858]415 /* Make OS/2 happy. */
[33540]416 /* The 8042 RAM is readable using commands 0x20 thru 0x3f, and writable
[60404]417 by 0x60 thru 0x7f. Now days only the first byte, the mode, is used.
[3265]418 We'll ignore the writes (0x61..7f) and return 0 for all the reads
419 just to make some OS/2 debug stuff a bit happier. */
420 case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
421 case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
422 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
423 case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
[82203]424 kbc_dbb_out(pDevIns, s, 0);
[3265]425 Log(("kbd: reading non-standard RAM addr %#x\n", val & 0x1f));
426 break;
[1]427 default:
428 Log(("kbd: unsupported keyboard cmd=0x%02x\n", val));
429 break;
430 }
[82201]431 return VINF_SUCCESS;
[1]432}
433
[82201]434static uint32_t kbd_read_data(PPDMDEVINS pDevIns, PKBDSTATE s)
[1]435{
[38377]436 uint32_t val;
[1]437
[38377]438 /* Return the current DBB contents. */
439 val = s->dbbout;
440
441 /* Reading the DBB deasserts IRQs... */
442 if (s->status & KBD_STAT_MOUSE_OBF)
[82203]443 PDMDevHlpISASetIrq(pDevIns, 12, 0);
[38377]444 else
[82203]445 PDMDevHlpISASetIrq(pDevIns, 1, 0);
[38377]446 /* ...and clears the OBF bits. */
447 s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
448
449 /* Check if more data is available. */
[82195]450 kbd_update_irq(pDevIns, s);
[1]451#ifdef DEBUG_KBD
452 Log(("kbd: read data=0x%02x\n", val));
453#endif
454 return val;
455}
456
[82202]457static VBOXSTRICTRC kbd_write_data(PPDMDEVINS pDevIns, PKBDSTATE s, uint32_t val)
[1]458{
[82202]459 VBOXSTRICTRC rc = VINF_SUCCESS;
[1]460
461#ifdef DEBUG_KBD
462 Log(("kbd: write data=0x%02x\n", val));
463#endif
464
465 switch(s->write_cmd) {
466 case 0:
[38377]467 /* Automatically enables keyboard interface. */
468 s->mode &= ~KBD_MODE_DISABLE_KBD;
[82195]469 rc = PS2KByteToKbd(pDevIns, &s->Kbd, val);
[39959]470 if (rc == VINF_SUCCESS)
[82195]471 kbd_update_irq(pDevIns, s);
[1]472 break;
473 case KBD_CCMD_WRITE_MODE:
474 s->mode = val;
[24396]475 s->translate = (s->mode & KBD_MODE_KCC) == KBD_MODE_KCC;
[82195]476 kbd_update_irq(pDevIns, s);
[1]477 break;
478 case KBD_CCMD_WRITE_OBUF:
[82203]479 kbc_dbb_out(pDevIns, s, val);
[1]480 break;
481 case KBD_CCMD_WRITE_AUX_OBUF:
[82203]482 kbc_dbb_out_aux(pDevIns, s, val);
[1]483 break;
484 case KBD_CCMD_WRITE_OUTPORT:
485#ifdef TARGET_I386
486# ifndef IN_RING3
[82203]487 if (PDMDevHlpA20IsEnabled(pDevIns) != !!(val & 2))
[40280]488 rc = VINF_IOM_R3_IOPORT_WRITE;
[1]489# else /* IN_RING3 */
[82203]490 PDMDevHlpA20Set(pDevIns, !!(val & 2));
[82202]491# endif /* IN_RING3 */
[1]492#endif
493 if (!(val & 1)) {
494# ifndef IN_RING3
[40280]495 rc = VINF_IOM_R3_IOPORT_WRITE;
[1]496# else
[82203]497 rc = PDMDevHlpVMReset(pDevIns, PDMVMRESET_F_KBD);
[1]498# endif
499 }
500 break;
501 case KBD_CCMD_WRITE_MOUSE:
[39959]502 /* Automatically enables aux interface. */
[83299]503 if (s->mode & KBD_MODE_DISABLE_MOUSE)
504 {
505 PS2MLineEnable(&s->Aux);
506 s->mode &= ~KBD_MODE_DISABLE_MOUSE;
507 }
[82195]508 rc = PS2MByteToAux(pDevIns, &s->Aux, val);
[48214]509 if (rc == VINF_SUCCESS)
[82195]510 kbd_update_irq(pDevIns, s);
[1]511 break;
512 default:
513 break;
514 }
[40280]515 if (rc != VINF_IOM_R3_IOPORT_WRITE)
[27060]516 s->write_cmd = 0;
[1]517 return rc;
518}
519
520#ifdef IN_RING3
521
[82206]522static int kbd_load(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, PKBDSTATE s, PKBDSTATER3 pThisCC, uint32_t version_id)
[1]523{
524 uint32_t u32, i;
[82206]525 uint8_t u8Dummy;
526 uint32_t u32Dummy;
[1]527 int rc;
528
[26925]529#if 0
530 /** @todo enable this and remove the "if (version_id == 4)" code at some
531 * later time */
532 /* Version 4 was never created by any publicly released version of VBox */
533 AssertReturn(version_id != 4, VERR_NOT_SUPPORTED);
534#endif
[22810]535 if (version_id < 2 || version_id > PCKBD_SAVED_STATE_VERSION)
[1]536 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
[82189]537 pHlp->pfnSSMGetU8(pSSM, &s->write_cmd);
538 pHlp->pfnSSMGetU8(pSSM, &s->status);
539 pHlp->pfnSSMGetU8(pSSM, &s->mode);
[39959]540 if (version_id <= 5)
541 {
[82189]542 pHlp->pfnSSMGetU32(pSSM, &u32Dummy);
543 pHlp->pfnSSMGetU32(pSSM, &u32Dummy);
[39959]544 }
545 else
546 {
[82189]547 pHlp->pfnSSMGetU8(pSSM, &s->dbbout);
[39959]548 }
[50965]549 if (version_id <= 7)
550 {
551 int32_t i32Dummy;
[54240]552 uint8_t u8State;
553 uint8_t u8Rate;
554 uint8_t u8Proto;
555
[82189]556 pHlp->pfnSSMGetU32(pSSM, &u32Dummy);
557 pHlp->pfnSSMGetU8(pSSM, &u8State);
558 pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
559 pHlp->pfnSSMGetU8(pSSM, &u8Rate);
560 pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
561 pHlp->pfnSSMGetU8(pSSM, &u8Proto);
562 pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
563 pHlp->pfnSSMGetS32(pSSM, &i32Dummy);
564 pHlp->pfnSSMGetS32(pSSM, &i32Dummy);
565 pHlp->pfnSSMGetS32(pSSM, &i32Dummy);
[50965]566 if (version_id > 2)
567 {
[82189]568 pHlp->pfnSSMGetS32(pSSM, &i32Dummy);
569 pHlp->pfnSSMGetS32(pSSM, &i32Dummy);
[50965]570 }
[82189]571 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
[50965]572 if (version_id == 4)
573 {
[82189]574 pHlp->pfnSSMGetU32(pSSM, &u32Dummy);
575 rc = pHlp->pfnSSMGetU32(pSSM, &u32Dummy);
[50965]576 }
577 if (version_id > 3)
[82189]578 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
[50965]579 if (version_id == 4)
[82189]580 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
[54735]581 AssertLogRelRCReturn(rc, rc);
[54240]582
[82206]583 PS2MR3FixupState(&s->Aux, &pThisCC->Aux, u8State, u8Rate, u8Proto);
[50965]584 }
[1]585
[24396]586 /* Determine the translation state. */
587 s->translate = (s->mode & KBD_MODE_KCC) == KBD_MODE_KCC;
588
[1]589 /*
590 * Load the queues
591 */
[39959]592 if (version_id <= 5)
[1]593 {
[82189]594 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
[11266]595 if (RT_FAILURE(rc))
[1]596 return rc;
[39959]597 for (i = 0; i < u32; i++)
598 {
[82189]599 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
[39959]600 if (RT_FAILURE(rc))
601 return rc;
602 }
[40040]603 Log(("kbd_load: %d keyboard queue items discarded from old saved state\n", u32));
[1]604 }
605
[50965]606 if (version_id <= 7)
[48214]607 {
[82189]608 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
[48214]609 if (RT_FAILURE(rc))
610 return rc;
611 for (i = 0; i < u32; i++)
612 {
[82189]613 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
[48214]614 if (RT_FAILURE(rc))
615 return rc;
616 }
617 Log(("kbd_load: %d mouse event queue items discarded from old saved state\n", u32));
[50965]618
[82189]619 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
[50965]620 if (RT_FAILURE(rc))
621 return rc;
622 for (i = 0; i < u32; i++)
623 {
[82189]624 rc = pHlp->pfnSSMGetU8(pSSM, &u8Dummy);
[50965]625 if (RT_FAILURE(rc))
626 return rc;
627 }
628 Log(("kbd_load: %d mouse command queue items discarded from old saved state\n", u32));
[48214]629 }
[1]630
631 /* terminator */
[82189]632 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
[11266]633 if (RT_FAILURE(rc))
[1]634 return rc;
[2246]635 if (u32 != ~0U)
[1]636 {
637 AssertMsgFailed(("u32=%#x\n", u32));
638 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
639 }
640 return 0;
641}
[82189]642
[1]643#endif /* IN_RING3 */
644
645
[22858]646/* VirtualBox code start */
[1]647
648/* -=-=-=-=-=- wrappers -=-=-=-=-=- */
649
[82202]650/** Fluff bits indexed by size (1,2,4). */
651static uint32_t const g_afFluff[5] =
652{
653 /* [0] = */ 0,
654 /* [1] = */ 0,
655 /* [2] = */ UINT32_C(0xff00),
656 /* [3] = */ 0,
657 /* [4] = */ UINT32_C(0xffffff00) /* Crazy Apple (Darwin 6.0.2 and earlier). */
658};
659
[1]660/**
[82201]661 * @callback_method_impl{FNIOMIOPORTNEWIN,
662 * Port I/O Handler for keyboard data IN operations.}
[1]663 */
[82201]664static DECLCALLBACK(VBOXSTRICTRC) kbdIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
[1]665{
[82201]666 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
667 RT_NOREF(pvUser, offPort);
668 Assert(offPort == 0);
[82202]669 Assert(cb == 1 || cb == 2 || cb == 4);
[69704]670
[82202]671 *pu32 = kbd_read_data(pDevIns, pThis) | g_afFluff[cb];
672 Log2(("kbdIOPortDataRead: cb=%u *pu32=%#x\n", cb, *pu32));
673 return VINF_SUCCESS;
[1]674}
675
676/**
[82201]677 * @callback_method_impl{FNIOMIOPORTNEWOUT,
678 * Port I/O Handler for keyboard data OUT operations.}
[1]679 */
[82201]680static DECLCALLBACK(VBOXSTRICTRC) kbdIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
[1]681{
[82201]682 RT_NOREF(offPort, pvUser);
683 Assert(offPort == 0);
684
[54877]685 if (cb == 1 || cb == 2)
[1]686 {
[82195]687 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
[82202]688 VBOXSTRICTRC rc = kbd_write_data(pDevIns, pThis, (uint8_t)u32);
689 Log2(("kbdIOPortDataWrite: Port=0x60+%x cb=%d u32=%#x rc=%Rrc\n", offPort, cb, u32, VBOXSTRICTRC_VAL(rc)));
690 return rc;
[1]691 }
[82202]692 Assert(cb == 4);
693 ASSERT_GUEST_MSG_FAILED(("Port=0x60+%x cb=%d\n", offPort, cb));
694 return VINF_SUCCESS;
[1]695}
696
697/**
[82201]698 * @callback_method_impl{FNIOMIOPORTNEWIN,
699 * Port I/O Handler for keyboard status IN operations.}
[1]700 */
[82201]701static DECLCALLBACK(VBOXSTRICTRC) kbdIOPortStatusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
[1]702{
[82201]703 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
704 RT_NOREF(offPort, pvUser);
705 Assert(offPort == 0);
[82202]706 Assert(cb == 1 || cb == 2 || cb == 4);
[55873]707
[82202]708 *pu32 = pThis->status | g_afFluff[cb];
709 Log2(("kbdIOPortStatusRead: cb=%u -> *pu32=%#x\n", cb, *pu32));
710 return VINF_SUCCESS;
[1]711}
712
713/**
[82201]714 * @callback_method_impl{FNIOMIOPORTNEWIN,
715 * Port I/O Handler for keyboard command OUT operations.}
[1]716 */
[82201]717static DECLCALLBACK(VBOXSTRICTRC) kbdIOPortCommandWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
[1]718{
[82201]719 RT_NOREF(offPort, pvUser);
720 Assert(offPort == 0);
721
[54877]722 if (cb == 1 || cb == 2)
[1]723 {
[82201]724 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
725 VBOXSTRICTRC rc = kbd_write_command(pDevIns, pThis, (uint8_t)u32);
726 Log2(("kbdIOPortCommandWrite: cb=%d u32=%#x rc=%Rrc\n", cb, u32, VBOXSTRICTRC_VAL(rc)));
727 return rc;
[1]728 }
[82202]729 Assert(cb == 4);
[82201]730 ASSERT_GUEST_MSG_FAILED(("offPort=0x64+%x cb=%d\n", offPort, cb));
731 return VINF_SUCCESS;
[1]732}
733
[82189]734/**
735 * Clear a queue.
736 *
[82208]737 * @param pQHdr The queue header.
738 * @param cElements The queue size.
[82189]739 */
[82208]740void PS2CmnClearQueue(PPS2QHDR pQHdr, size_t cElements)
[82189]741{
[82208]742 Assert(cElements > 0);
[90198]743 LogFlowFunc(("Clearing %s queue %p\n", R3STRING(pQHdr->pszDescR3), pQHdr));
[82208]744 pQHdr->wpos = pQHdr->rpos = pQHdr->rpos % cElements;
745 pQHdr->cUsed = 0;
[82189]746}
747
748
749/**
750 * Add a byte to a queue.
751 *
[82208]752 * @param pQHdr The queue header.
753 * @param cElements The queue size.
[82213]754 * @param pbElements The queue element array.
[82208]755 * @param bValue The byte to store.
[82189]756 */
[82208]757void PS2CmnInsertQueue(PPS2QHDR pQHdr, size_t cElements, uint8_t *pbElements, uint8_t bValue)
[82189]758{
[82208]759 Assert(cElements > 0);
760
761 /* Check that the queue is not full. */
762 uint32_t cUsed = pQHdr->cUsed;
763 if (cUsed < cElements)
[82189]764 {
[82208]765 /* Insert data and update circular buffer write position. */
766 uint32_t wpos = pQHdr->wpos % cElements;
767 pbElements[wpos] = bValue;
768
769 wpos += 1;
770 if (wpos < cElements)
771 pQHdr->wpos = wpos;
772 else
773 pQHdr->wpos = 0; /* Roll over. */
774 pQHdr->cUsed = cUsed + 1;
775
[90198]776 LogRelFlowFunc(("inserted %#04x into %s queue %p\n", bValue, R3STRING(pQHdr->pszDescR3), pQHdr));
[82189]777 }
[82208]778 else
779 {
780 Assert(cUsed == cElements);
[90198]781 LogRelFlowFunc(("%s queue %p full (%zu entries)\n", R3STRING(pQHdr->pszDescR3), pQHdr, cElements));
[82208]782 }
[82189]783}
784
[82190]785/**
786 * Retrieve a byte from a queue.
787 *
[82208]788 * @param pQHdr The queue header.
789 * @param cElements The queue size.
[82213]790 * @param pbElements The queue element array.
[82208]791 * @param pbValue Where to return the byte on success.
[82190]792 *
793 * @retval VINF_TRY_AGAIN if queue is empty,
794 * @retval VINF_SUCCESS if a byte was read.
795 */
[82208]796int PS2CmnRemoveQueue(PPS2QHDR pQHdr, size_t cElements, uint8_t const *pbElements, uint8_t *pbValue)
[82190]797{
798 int rc;
799
[82208]800 Assert(cElements > 0);
801 Assert(pbValue);
802
803 uint32_t cUsed = (uint32_t)RT_MIN(pQHdr->cUsed, cElements);
804 if (cUsed > 0)
[82190]805 {
[82208]806 uint32_t rpos = pQHdr->rpos % cElements;
807 *pbValue = pbElements[rpos];
808
809 rpos += 1;
810 if (rpos < cElements)
811 pQHdr->rpos = rpos;
812 else
813 pQHdr->rpos = 0; /* Roll over. */
814 pQHdr->cUsed = cUsed - 1;
815
[90198]816 LogFlowFunc(("removed 0x%02X from %s queue %p\n", *pbValue, R3STRING(pQHdr->pszDescR3), pQHdr));
[82190]817 rc = VINF_SUCCESS;
818 }
819 else
820 {
[90198]821 LogFlowFunc(("%s queue %p empty\n", R3STRING(pQHdr->pszDescR3), pQHdr));
[82190]822 rc = VINF_TRY_AGAIN;
823 }
824 return rc;
825}
826
[1]827#ifdef IN_RING3
828
829/**
[82189]830 * Save a queue state.
[1]831 *
[82208]832 * @param pHlp The device helpers.
833 * @param pSSM SSM handle to write the state to.
834 * @param pQHdr The queue header.
835 * @param cElements The queue size.
[82213]836 * @param pbElements The queue element array.
[82189]837 */
[82208]838void PS2CmnR3SaveQueue(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, PPS2QHDR pQHdr, size_t cElements, uint8_t const *pbElements)
[82189]839{
[82208]840 uint32_t cItems = (uint32_t)RT_MIN(pQHdr->cUsed, cElements);
[82189]841
842 /* Only save the number of items. Note that the read/write
843 * positions aren't saved as they will be rebuilt on load.
844 */
845 pHlp->pfnSSMPutU32(pSSM, cItems);
846
[90198]847 LogFlow(("Storing %u items from %s queue %p\n", cItems, pQHdr->pszDescR3, pQHdr));
[82189]848
849 /* Save queue data - only the bytes actually used (typically zero). */
[82208]850 for (uint32_t i = pQHdr->rpos % cElements; cItems-- > 0; i = (i + 1) % cElements)
851 pHlp->pfnSSMPutU8(pSSM, pbElements[i]);
[82189]852}
853
854/**
855 * Load a queue state.
856 *
[82208]857 * @param pHlp The device helpers.
858 * @param pSSM SSM handle to read the state from.
859 * @param pQHdr The queue header.
860 * @param cElements The queue size.
[82213]861 * @param pbElements The queue element array.
[82189]862 *
[82190]863 * @returns VBox status/error code.
[82189]864 */
[82208]865int PS2CmnR3LoadQueue(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, PPS2QHDR pQHdr, size_t cElements, uint8_t *pbElements)
[82189]866{
867 /* On load, always put the read pointer at zero. */
[82208]868 uint32_t cUsed;
869 int rc = pHlp->pfnSSMGetU32(pSSM, &cUsed);
[82189]870 AssertRCReturn(rc, rc);
871
[90198]872 LogFlow(("Loading %u items to %s queue %p\n", cUsed, pQHdr->pszDescR3, pQHdr));
[82189]873
[82208]874 AssertMsgReturn(cUsed <= cElements, ("Saved size=%u, actual=%zu\n", cUsed, cElements),
[82189]875 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
876
877 /* Recalculate queue positions and load data in one go. */
[82208]878 pQHdr->rpos = 0;
879 pQHdr->wpos = cUsed;
880 pQHdr->cUsed = cUsed;
881 return pHlp->pfnSSMGetMem(pSSM, pbElements, cUsed);
[82189]882}
883
884
885/**
886 * @callback_method_impl{FNSSMDEVSAVEEXEC, Saves a state of the keyboard device.}
887 *
[1]888 * @returns VBox status code.
889 * @param pDevIns The device instance.
[44806]890 * @param pSSM The handle to save the state to.
[1]891 */
[82189]892static DECLCALLBACK(int) kbdR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
[1]893{
[82189]894 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
895 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
896
897 pHlp->pfnSSMPutU8(pSSM, pThis->write_cmd);
898 pHlp->pfnSSMPutU8(pSSM, pThis->status);
899 pHlp->pfnSSMPutU8(pSSM, pThis->mode);
900 pHlp->pfnSSMPutU8(pSSM, pThis->dbbout);
901 /* terminator */
902 pHlp->pfnSSMPutU32(pSSM, UINT32_MAX);
903
904 PS2KR3SaveState(pDevIns, &pThis->Kbd, pSSM);
905 PS2MR3SaveState(pDevIns, &pThis->Aux, pSSM);
[1]906 return VINF_SUCCESS;
907}
908
909
910/**
[82189]911 * @callback_method_impl{FNSSMDEVLOADEXEC, Loads a saved keyboard device state.}
[1]912 */
[82189]913static DECLCALLBACK(int) kbdR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
[1]914{
[82206]915 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
916 PKBDSTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PKBDSTATER3);
[39959]917 int rc;
918
[22793]919 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
[82206]920 rc = kbd_load(pDevIns->pHlpR3, pSSM, pThis, pThisCC, uVersion);
[82189]921 AssertRCReturn(rc, rc);
922
[39959]923 if (uVersion >= 6)
[82189]924 rc = PS2KR3LoadState(pDevIns, &pThis->Kbd, pSSM, uVersion);
925 AssertRCReturn(rc, rc);
926
[50965]927 if (uVersion >= 8)
[82206]928 rc = PS2MR3LoadState(pDevIns, &pThis->Aux, &pThisCC->Aux, pSSM, uVersion);
[82189]929 AssertRCReturn(rc, rc);
[39959]930 return rc;
[1]931}
932
[82234]933
[1]934/**
[64368]935 * @callback_method_impl{FNSSMDEVLOADDONE, Key state fix-up after loading}
[49469]936 */
[82189]937static DECLCALLBACK(int) kbdR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
[49469]938{
[82206]939 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
940 PKBDSTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PKBDSTATER3);
[82195]941 RT_NOREF(pSSM);
[83299]942 if (pThis->mode & KBD_MODE_DISABLE_MOUSE)
943 PS2MLineDisable(&pThis->Aux);
944 if (pThis->mode & KBD_MODE_DISABLE_KBD)
945 PS2KLineDisable(&pThis->Kbd);
[82206]946 return PS2KR3LoadDone(pDevIns, &pThis->Kbd, &pThisCC->Kbd);
[49469]947}
948
[82234]949
[83299]950/**
951 * Debug device info handler. Prints basic auxiliary device state.
952 *
953 * @param pDevIns Device instance which registered the info.
954 * @param pHlp Callback functions for doing output.
955 * @param pszArgs Argument string. Optional and specific to the handler.
956 */
957static DECLCALLBACK(void) kbdR3InfoState(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
958{
959 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
960 NOREF(pszArgs);
961
962 pHlp->pfnPrintf(pHlp, "Keyboard controller: Active command %02X, DBB out %02X, translation %s\n",
963 pThis->write_cmd, pThis->dbbout, pThis->translate ? "on" : "off");
964
965 pHlp->pfnPrintf(pHlp, "Mode: %02X ( ", pThis->mode);
966 if (pThis->mode & KBD_MODE_DISABLE_KBD)
967 pHlp->pfnPrintf(pHlp, "DISABLE_KBD ");
968 if (pThis->mode & KBD_MODE_KBD_INT)
969 pHlp->pfnPrintf(pHlp, "KBD_INT ");
970 if (pThis->mode & KBD_MODE_MOUSE_INT)
971 pHlp->pfnPrintf(pHlp, "AUX_INT ");
972 if (pThis->mode & KBD_MODE_SYS)
973 pHlp->pfnPrintf(pHlp, "SYS ");
974 if (pThis->mode & KBD_MODE_NO_KEYLOCK)
975 pHlp->pfnPrintf(pHlp, "NO_KEYLOCK ");
976 if (pThis->mode & KBD_MODE_DISABLE_KBD)
977 pHlp->pfnPrintf(pHlp, "DISABLE_KBD ");
978 if (pThis->mode & KBD_MODE_DISABLE_MOUSE)
979 pHlp->pfnPrintf(pHlp, "DISABLE_AUX ");
980 if (pThis->mode & KBD_MODE_KCC)
981 pHlp->pfnPrintf(pHlp, "KCC ");
982 if (pThis->mode & KBD_MODE_RFU)
983 pHlp->pfnPrintf(pHlp, "RFU ");
984 pHlp->pfnPrintf(pHlp, " )\n");
985
986 pHlp->pfnPrintf(pHlp, "Status: %02X ( ", pThis->status);
987 if (pThis->status & KBD_STAT_OBF)
988 pHlp->pfnPrintf(pHlp, "OBF ");
989 if (pThis->status & KBD_STAT_IBF)
990 pHlp->pfnPrintf(pHlp, "IBF ");
991 if (pThis->status & KBD_STAT_SELFTEST)
992 pHlp->pfnPrintf(pHlp, "SELFTEST ");
993 if (pThis->status & KBD_STAT_CMD)
994 pHlp->pfnPrintf(pHlp, "CMD ");
995 if (pThis->status & KBD_STAT_UNLOCKED)
996 pHlp->pfnPrintf(pHlp, "UNLOCKED ");
997 if (pThis->status & KBD_STAT_MOUSE_OBF)
998 pHlp->pfnPrintf(pHlp, "AUX_OBF ");
999 if (pThis->status & KBD_STAT_GTO)
1000 pHlp->pfnPrintf(pHlp, "GTO ");
1001 if (pThis->status & KBD_STAT_PERR)
1002 pHlp->pfnPrintf(pHlp, "PERR ");
1003 pHlp->pfnPrintf(pHlp, " )\n");
1004}
1005
1006
[82234]1007/* -=-=-=-=-=- real code -=-=-=-=-=- */
1008
[49469]1009/**
[1]1010 * Reset notification.
1011 *
1012 * @param pDevIns The device instance data.
1013 */
[82189]1014static DECLCALLBACK(void) kbdR3Reset(PPDMDEVINS pDevIns)
[1]1015{
[82206]1016 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
1017 PKBDSTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PKBDSTATER3);
[28909]1018
[82189]1019 pThis->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
1020 pThis->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
1021 /* Resetting everything, keyword was not working right on NT4 reboot. */
1022 pThis->write_cmd = 0;
1023 pThis->translate = 0;
1024
[82206]1025 PS2KR3Reset(pDevIns, &pThis->Kbd, &pThisCC->Kbd);
[82189]1026 PS2MR3Reset(&pThis->Aux);
[1]1027}
1028
1029
1030/**
[82189]1031 * @interface_method_impl{PDMDEVREGR3,pfnAttach}
[1]1032 *
1033 * @remark The keyboard controller doesn't support this action, this is just
1034 * implemented to try out the driver<->device structure.
1035 */
[82189]1036static DECLCALLBACK(int) kbdR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
[1]1037{
[82206]1038 PKBDSTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PKBDSTATER3);
[1]1039 int rc;
[21188]1040
[22277]1041 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
[21188]1042 ("PS/2 device does not support hotplugging\n"),
1043 VERR_INVALID_PARAMETER);
1044
[1]1045 switch (iLUN)
1046 {
1047 /* LUN #0: keyboard */
1048 case 0:
[82206]1049 rc = PS2KR3Attach(pDevIns, &pThisCC->Kbd, iLUN, fFlags);
[1]1050 break;
1051
1052 /* LUN #1: aux/mouse */
1053 case 1:
[82206]1054 rc = PS2MR3Attach(pDevIns, &pThisCC->Aux, iLUN, fFlags);
[1]1055 break;
1056
1057 default:
1058 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
1059 return VERR_PDM_NO_SUCH_LUN;
1060 }
1061
1062 return rc;
1063}
1064
1065
1066/**
[82189]1067 * @interface_method_impl{PDMDEVREGR3,pfnDetach}
[1]1068 * @remark The keyboard controller doesn't support this action, this is just
1069 * implemented to try out the driver<->device structure.
1070 */
[82189]1071static DECLCALLBACK(void) kbdR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
[1]1072{
1073#if 0
1074 /*
1075 * Reset the interfaces and update the controller state.
1076 */
[82189]1077 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
[1]1078 switch (iLUN)
1079 {
1080 /* LUN #0: keyboard */
1081 case 0:
[82206]1082 pThisCC->Keyboard.pDrv = NULL;
1083 pThisCC->Keyboard.pDrvBase = NULL;
[1]1084 break;
1085
1086 /* LUN #1: aux/mouse */
1087 case 1:
[82206]1088 pThisCC->Mouse.pDrv = NULL;
1089 pThisCC->Mouse.pDrvBase = NULL;
[1]1090 break;
1091
1092 default:
1093 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
1094 break;
1095 }
[39091]1096#else
1097 NOREF(pDevIns); NOREF(iLUN); NOREF(fFlags);
[1]1098#endif
1099}
1100
[22480]1101
[1]1102/**
[82189]1103 * @interface_method_impl{PDMDEVREGR3,pfnConstruct}
[1]1104 */
[82189]1105static DECLCALLBACK(int) kbdR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
[1]1106{
[82189]1107 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
[82206]1108 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
1109 PKBDSTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PKBDSTATER3);
[1]1110 int rc;
[82208]1111 RT_NOREF(iInstance);
1112
[1]1113 Assert(iInstance == 0);
1114
1115 /*
1116 * Validate and read the configuration.
1117 */
[82189]1118 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "KbdThrottleEnabled", "");
1119 Log(("pckbd: fRCEnabled=%RTbool fR0Enabled=%RTbool\n", pDevIns->fRCEnabled, pDevIns->fR0Enabled));
[1]1120
1121 /*
[82203]1122 * Initialize the sub-components.
[1]1123 */
[82208]1124 rc = PS2KR3Construct(pDevIns, &pThis->Kbd, &pThisCC->Kbd, pCfg);
[82189]1125 AssertRCReturn(rc, rc);
[1]1126
[82208]1127 rc = PS2MR3Construct(pDevIns, &pThis->Aux, &pThisCC->Aux);
[82189]1128 AssertRCReturn(rc, rc);
[1]1129
1130 /*
[82189]1131 * Register I/O ports.
[1]1132 */
[82201]1133 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x60 /*uPort*/, 1 /*cPorts*/, kbdIOPortDataWrite, kbdIOPortDataRead,
1134 "PC Keyboard - Data", NULL /*pExtDescs*/, &pThis->hIoPortData);
[82189]1135 AssertRCReturn(rc, rc);
[82201]1136 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x64 /*uPort*/, 1 /*cPorts*/, kbdIOPortCommandWrite, kbdIOPortStatusRead,
1137 "PC Keyboard - Command / Status", NULL /*pExtDescs*/, &pThis->hIoPortCmdStatus);
[82189]1138 AssertRCReturn(rc, rc);
1139
1140 /*
1141 * Saved state.
1142 */
[49469]1143 rc = PDMDevHlpSSMRegisterEx(pDevIns, PCKBD_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
1144 NULL, NULL, NULL,
[82189]1145 NULL, kbdR3SaveExec, NULL,
1146 NULL, kbdR3LoadExec, kbdR3LoadDone);
1147 AssertRCReturn(rc, rc);
[1]1148
1149 /*
[83299]1150 * Register debugger info callbacks.
1151 */
1152 PDMDevHlpDBGFInfoRegister(pDevIns, "ps2c", "Display keyboard/mouse controller state.", kbdR3InfoState);
1153
1154 /*
[1]1155 * Attach to the keyboard and mouse drivers.
1156 */
[82189]1157 rc = kbdR3Attach(pDevIns, 0 /* keyboard LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
1158 AssertRCReturn(rc, rc);
1159 rc = kbdR3Attach(pDevIns, 1 /* aux/mouse LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
1160 AssertRCReturn(rc, rc);
[1]1161
1162 /*
1163 * Initialize the device state.
1164 */
[82189]1165 kbdR3Reset(pDevIns);
[1]1166
1167 return VINF_SUCCESS;
1168}
1169
[82201]1170#else /* !IN_RING3 */
[1]1171
1172/**
[82201]1173 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1174 */
1175static DECLCALLBACK(int) kbdRZConstruct(PPDMDEVINS pDevIns)
1176{
1177 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1178 PKBDSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PKBDSTATE);
1179
1180 int rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortData, kbdIOPortDataWrite, kbdIOPortDataRead, NULL /*pvUser*/);
1181 AssertRCReturn(rc, rc);
1182 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortCmdStatus, kbdIOPortCommandWrite, kbdIOPortStatusRead, NULL /*pvUser*/);
1183 AssertRCReturn(rc, rc);
1184
1185 return VINF_SUCCESS;
1186}
1187
1188#endif /* !IN_RING3 */
1189
1190/**
[1]1191 * The device registration structure.
1192 */
1193const PDMDEVREG g_DevicePS2KeyboardMouse =
1194{
[80531]1195 /* .u32Version = */ PDM_DEVREG_VERSION,
1196 /* .uReserved0 = */ 0,
1197 /* .szName = */ "pckbd",
[82206]1198 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
[80531]1199 /* .fClass = */ PDM_DEVREG_CLASS_INPUT,
1200 /* .cMaxInstances = */ 1,
1201 /* .uSharedVersion = */ 42,
[82204]1202 /* .cbInstanceShared = */ sizeof(KBDSTATE),
[82206]1203 /* .cbInstanceCC = */ CTX_EXPR(sizeof(KBDSTATER3), 0, 0),
[80531]1204 /* .cbInstanceRC = */ 0,
[80703]1205 /* .cMaxPciDevices = */ 0,
[80704]1206 /* .cMaxMsixVectors = */ 0,
[80531]1207 /* .pszDescription = */ "PS/2 Keyboard and Mouse device. Emulates both the keyboard, mouse and the keyboard controller.\n"
1208 "LUN #0 is the keyboard connector.\n"
1209 "LUN #1 is the aux/mouse connector.",
1210#if defined(IN_RING3)
1211 /* .pszRCMod = */ "VBoxDDRC.rc",
1212 /* .pszR0Mod = */ "VBoxDDR0.r0",
[82189]1213 /* .pfnConstruct = */ kbdR3Construct,
[80531]1214 /* .pfnDestruct = */ NULL,
[82195]1215 /* .pfnRelocate = */ NULL,
[80531]1216 /* .pfnMemSetup = */ NULL,
1217 /* .pfnPowerOn = */ NULL,
[82189]1218 /* .pfnReset = */ kbdR3Reset,
[80531]1219 /* .pfnSuspend = */ NULL,
1220 /* .pfnResume = */ NULL,
[82189]1221 /* .pfnAttach = */ kbdR3Attach,
1222 /* .pfnDetach = */ kbdR3Detach,
[80531]1223 /* .pfnQueryInterface = */ NULL,
1224 /* .pfnInitComplete = */ NULL,
1225 /* .pfnPowerOff = */ NULL,
1226 /* .pfnSoftReset = */ NULL,
1227 /* .pfnReserved0 = */ NULL,
1228 /* .pfnReserved1 = */ NULL,
1229 /* .pfnReserved2 = */ NULL,
1230 /* .pfnReserved3 = */ NULL,
1231 /* .pfnReserved4 = */ NULL,
1232 /* .pfnReserved5 = */ NULL,
1233 /* .pfnReserved6 = */ NULL,
1234 /* .pfnReserved7 = */ NULL,
1235#elif defined(IN_RING0)
1236 /* .pfnEarlyConstruct = */ NULL,
[82201]1237 /* .pfnConstruct = */ kbdRZConstruct,
[80531]1238 /* .pfnDestruct = */ NULL,
1239 /* .pfnFinalDestruct = */ NULL,
1240 /* .pfnRequest = */ NULL,
1241 /* .pfnReserved0 = */ NULL,
1242 /* .pfnReserved1 = */ NULL,
1243 /* .pfnReserved2 = */ NULL,
1244 /* .pfnReserved3 = */ NULL,
1245 /* .pfnReserved4 = */ NULL,
1246 /* .pfnReserved5 = */ NULL,
1247 /* .pfnReserved6 = */ NULL,
1248 /* .pfnReserved7 = */ NULL,
1249#elif defined(IN_RC)
[82201]1250 /* .pfnConstruct = */ kbdRZConstruct,
[80531]1251 /* .pfnReserved0 = */ NULL,
1252 /* .pfnReserved1 = */ NULL,
1253 /* .pfnReserved2 = */ NULL,
1254 /* .pfnReserved3 = */ NULL,
1255 /* .pfnReserved4 = */ NULL,
1256 /* .pfnReserved5 = */ NULL,
1257 /* .pfnReserved6 = */ NULL,
1258 /* .pfnReserved7 = */ NULL,
1259#else
1260# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1261#endif
1262 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
[1]1263};
1264
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use