VirtualBox

source: vbox/trunk/src/VBox/Devices/Input/PS2K.cpp@ 44827

Last change on this file since 44827 was 44806, checked in by vboxsync, 12 years ago

DevPS2.cpp++: Drop two critsects in favor of the default device critsect. This is simpler and avoid confusion as to the locking saftety of the PS2KByteFromKbd and PS2KByteToKbd interfaces exposed by PS2K and used by DevPS2. Misc cleanups (didn't do a full cleanup, sorry).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 58.8 KB
Line 
1/** @file
2 * PS2K - PS/2 keyboard emulation.
3 */
4
5/*
6 * Copyright (C) 2007-2012 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17/*
18 * References:
19 *
20 * IBM PS/2 Technical Reference, Keyboards (101- and 102-Key), 1990
21 * Keyboard Scan Code Specification, Microsoft, 2000
22 *
23 * Notes:
24 * - The keyboard never sends partial scan-code sequences; if there isn't enough
25 * room left in the buffer for the entire sequence, the keystroke is discarded
26 * and an overrun code is sent instead.
27 * - Command responses do not disturb stored keystrokes and always have priority.
28 * - Caps Lock and Scroll Lock are normal keys from the keyboard's point of view.
29 * However, Num Lock is not and the keyboard internally tracks its state.
30 * - The way Print Screen works in scan set 1/2 is totally insane.
31 */
32
33
34/*******************************************************************************
35* Header Files *
36*******************************************************************************/
37#define LOG_GROUP LOG_GROUP_DEV_KBD
38#include <VBox/vmm/pdmdev.h>
39#include <VBox/err.h>
40#include <iprt/assert.h>
41#include <iprt/uuid.h>
42#include "VBoxDD.h"
43#define IN_PS2K
44#include "PS2Dev.h"
45
46/*******************************************************************************
47* Defined Constants And Macros *
48*******************************************************************************/
49/** @name Keyboard commands sent by the system.
50 * @{ */
51#define KCMD_LEDS 0xED
52#define KCMD_ECHO 0xEE
53#define KCMD_INVALID_1 0xEF
54#define KCMD_SCANSET 0xF0
55#define KCMD_INVALID_2 0xF1
56#define KCMD_READ_ID 0xF2
57#define KCMD_RATE_DELAY 0xF3
58#define KCMD_ENABLE 0xF4
59#define KCMD_DFLT_DISABLE 0xF5
60#define KCMD_SET_DEFAULT 0xF6
61#define KCMD_ALL_TYPEMATIC 0xF7
62#define KCMD_ALL_MK_BRK 0xF8
63#define KCMD_ALL_MAKE 0xF9
64#define KCMD_ALL_TMB 0xFA
65#define KCMD_TYPE_MATIC 0xFB
66#define KCMD_TYPE_MK_BRK 0xFC
67#define KCMD_TYPE_MAKE 0xFD
68#define KCMD_RESEND 0xFE
69#define KCMD_RESET 0xFF
70/** @} */
71
72/** @name Keyboard responses sent to the system.
73 * @{ */
74#define KRSP_ID1 0xAB
75#define KRSP_ID2 0x83
76#define KRSP_BAT_OK 0xAA
77#define KRSP_BAT_FAIL 0xFC
78#define KRSP_ECHO 0xEE
79#define KRSP_ACK 0xFA
80#define KRSP_RESEND 0xFE
81/** @} */
82
83/** @name HID modifier range.
84 * @{ */
85#define HID_MODIFIER_FIRST 0xE0
86#define HID_MODIFIER_LAST 0xE8
87/** @} */
88
89/** @name USB HID additional constants
90 * @{ */
91/** The highest USB usage code reported by VirtualBox. */
92#define VBOX_USB_MAX_USAGE_CODE 0xE7
93/** The size of an array needed to store all USB usage codes */
94#define VBOX_USB_USAGE_ARRAY_SIZE (VBOX_USB_MAX_USAGE_CODE + 1)
95/** @} */
96
97/** @name Modifier key states. Sorted in USB HID code order.
98 * @{ */
99#define MOD_LCTRL 0x01
100#define MOD_LSHIFT 0x02
101#define MOD_LALT 0x04
102#define MOD_LGUI 0x08
103#define MOD_RCTRL 0x10
104#define MOD_RSHIFT 0x20
105#define MOD_RALT 0x40
106#define MOD_RGUI 0x80
107/** @} */
108
109/* Default typematic value. */
110#define KBD_DFL_RATE_DELAY 0x2B
111
112/** Define a simple PS/2 input device queue. */
113#define DEF_PS2Q_TYPE(name, size) \
114 typedef struct { \
115 uint32_t rpos; \
116 uint32_t wpos; \
117 uint32_t cUsed; \
118 uint32_t cSize; \
119 uint8_t abQueue[size]; \
120 } name
121
122/* Internal keyboard queue sizes. The input queue doesn't need to be
123 * extra huge and the command queue only needs to handle a few bytes.
124 */
125#define KBD_KEY_QUEUE_SIZE 64
126#define KBD_CMD_QUEUE_SIZE 4
127
128/*******************************************************************************
129* Structures and Typedefs *
130*******************************************************************************/
131
132/** Scancode translator state. */
133typedef enum {
134 SS_IDLE, /**< Starting state. */
135 SS_EXT, /**< E0 byte was received. */
136 SS_EXT1 /**< E1 byte was received. */
137} scan_state_t;
138
139/** Typematic state. */
140typedef enum {
141 KBD_TMS_IDLE = 0, /* No typematic key active. */
142 KBD_TMS_DELAY = 1, /* In the initial delay period. */
143 KBD_TMS_REPEAT = 2, /* Key repeating at set rate. */
144 KBD_TMS_32BIT_HACK = 0x7fffffff
145} tmatic_state_t;
146
147
148DEF_PS2Q_TYPE(KbdKeyQ, KBD_KEY_QUEUE_SIZE);
149DEF_PS2Q_TYPE(KbdCmdQ, KBD_CMD_QUEUE_SIZE);
150DEF_PS2Q_TYPE(GeneriQ, 1);
151
152/**
153 * The PS/2 keyboard instance data.
154 */
155typedef struct PS2K
156{
157 /** Pointer to parent device (keyboard controller). */
158 R3PTRTYPE(void *) pParent;
159 /** Set if keyboard is enabled ('scans' for input). */
160 bool fScanning;
161 /** Set NumLock is on. */
162 bool fNumLockOn;
163 /** Selected scan set. */
164 uint8_t u8ScanSet;
165 /** Modifier key state. */
166 uint8_t u8Modifiers;
167 /** Currently processed command (if any). */
168 uint8_t u8CurrCmd;
169 /** Status indicator (LED) state. */
170 uint8_t u8LEDs;
171 /** Selected typematic delay/rate. */
172 uint8_t u8Typematic;
173 /** Usage code of current typematic key, if any. */
174 uint8_t u8TypematicKey;
175 /** Current typematic repeat state. */
176 tmatic_state_t enmTypematicState;
177 /** Buffer holding scan codes to be sent to the host. */
178 KbdKeyQ keyQ;
179 /** Command response queue (priority). */
180 KbdCmdQ cmdQ;
181 /** Currently depressed keys. */
182 uint8_t abDepressedKeys[VBOX_USB_USAGE_ARRAY_SIZE];
183 /** Typematic delay in milliseconds. */
184 unsigned uTypematicDelay;
185 /** Typematic repeat period in milliseconds. */
186 unsigned uTypematicRepeat;
187#if HC_ARCH_BITS == 32
188 uint32_t Alignment0;
189#endif
190
191 /** Command delay timer - RC Ptr. */
192 PTMTIMERRC pKbdDelayTimerRC;
193 /** Typematic timer - RC Ptr. */
194 PTMTIMERRC pKbdTypematicTimerRC;
195
196 /** The device critical section protecting everything - R3 Ptr */
197 R3PTRTYPE(PPDMCRITSECT) pCritSectR3;
198 /** Command delay timer - R3 Ptr. */
199 PTMTIMERR3 pKbdDelayTimerR3;
200 /** Typematic timer - R3 Ptr. */
201 PTMTIMERR3 pKbdTypematicTimerR3;
202 RTR3PTR Alignment2;
203
204 /** Command delay timer - R0 Ptr. */
205 PTMTIMERR0 pKbdDelayTimerR0;
206 /** Typematic timer - R0 Ptr. */
207 PTMTIMERR0 pKbdTypematicTimerR0;
208
209 scan_state_t XlatState; ///@todo: temporary
210 uint32_t Alignment1;
211
212 /**
213 * Keyboard port - LUN#0.
214 *
215 * @implements PDMIBASE
216 * @implements PDMIKEYBOARDPORT
217 */
218 struct
219 {
220 /** The base interface for the keyboard port. */
221 PDMIBASE IBase;
222 /** The keyboard port base interface. */
223 PDMIKEYBOARDPORT IPort;
224
225 /** The base interface of the attached keyboard driver. */
226 R3PTRTYPE(PPDMIBASE) pDrvBase;
227 /** The keyboard interface of the attached keyboard driver. */
228 R3PTRTYPE(PPDMIKEYBOARDCONNECTOR) pDrv;
229 } Keyboard;
230} PS2K, *PPS2K;
231
232AssertCompile(PS2K_STRUCT_FILLER >= sizeof(PS2K));
233
234#ifndef VBOX_DEVICE_STRUCT_TESTCASE
235
236/* Key type flags. */
237#define KF_E0 0x01 /* E0 prefix. */
238#define KF_NB 0x02 /* No break code. */
239#define KF_GK 0x04 /* Gray navigation key. */
240#define KF_PS 0x08 /* Print Screen key. */
241#define KF_PB 0x10 /* Pause/Break key. */
242#define KF_NL 0x20 /* Num Lock key. */
243#define KF_NS 0x40 /* NumPad '/' key. */
244
245/* Scan Set 3 typematic defaults. */
246#define T_U 0x00 /* Unknown value. */
247#define T_T 0x01 /* Key is typematic. */
248#define T_M 0x02 /* Key is make only. */
249#define T_B 0x04 /* Key is make/break. */
250
251/* Special key values. */
252#define NONE 0x93 /* No PS/2 scan code returned. */
253#define UNAS 0x94 /* No PS/2 scan assigned to key. */
254#define RSVD 0x95 /* Reserved, do not use. */
255#define UNKN 0x96 /* Translation unknown. */
256
257/* Key definition structure. */
258typedef struct {
259 uint8_t makeS1; /* Set 1 make code. */
260 uint8_t makeS2; /* Set 2 make code. */
261 uint8_t makeS3; /* Set 3 make code. */
262 uint8_t keyFlags; /* Key flags. */
263 uint8_t keyMatic; /* Set 3 typematic default. */
264} key_def;
265
266/* USB to PS/2 conversion table for regular keys. */
267static const key_def aPS2Keys[] = {
268 /* 00 */ {NONE, NONE, NONE, KF_NB, T_U }, /* Key N/A: No Event */
269 /* 01 */ {0xFF, 0x00, 0x00, KF_NB, T_U }, /* Key N/A: Overrun Error */
270 /* 02 */ {0xFC, 0xFC, 0xFC, KF_NB, T_U }, /* Key N/A: POST Fail */
271 /* 03 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key N/A: ErrorUndefined */
272 /* 04 */ {0x1E, 0x1C, 0x1C, 0, T_T }, /* Key 31: a A */
273 /* 05 */ {0x30, 0x32, 0x32, 0, T_T }, /* Key 50: b B */
274 /* 06 */ {0x2E, 0x21, 0x21, 0, T_T }, /* Key 48: c C */
275 /* 07 */ {0x20, 0x23, 0x23, 0, T_T }, /* Key 33: d D */
276 /* 08 */ {0x12, 0x24, 0x24, 0, T_T }, /* Key 19: e E */
277 /* 09 */ {0x21, 0x2B, 0x2B, 0, T_T }, /* Key 34: f F */
278 /* 0A */ {0x22, 0x34, 0x34, 0, T_T }, /* Key 35: g G */
279 /* 0B */ {0x23, 0x33, 0x33, 0, T_T }, /* Key 36: h H */
280 /* 0C */ {0x17, 0x43, 0x43, 0, T_T }, /* Key 24: i I */
281 /* 0D */ {0x24, 0x3B, 0x3B, 0, T_T }, /* Key 37: j J */
282 /* 0E */ {0x25, 0x42, 0x42, 0, T_T }, /* Key 38: k K */
283 /* 0F */ {0x26, 0x4B, 0x4B, 0, T_T }, /* Key 39: l L */
284 /* 10 */ {0x32, 0x3A, 0x3A, 0, T_T }, /* Key 52: m M */
285 /* 11 */ {0x31, 0x31, 0x31, 0, T_T }, /* Key 51: n N */
286 /* 12 */ {0x18, 0x44, 0x44, 0, T_T }, /* Key 25: o O */
287 /* 13 */ {0x19, 0x4D, 0x4D, 0, T_T }, /* Key 26: p P */
288 /* 14 */ {0x10, 0x15, 0x15, 0, T_T }, /* Key 17: q Q */
289 /* 15 */ {0x13, 0x2D, 0x2D, 0, T_T }, /* Key 20: r R */
290 /* 16 */ {0x1F, 0x1B, 0x1B, 0, T_T }, /* Key 32: s S */
291 /* 17 */ {0x14, 0x2C, 0x2C, 0, T_T }, /* Key 21: t T */
292 /* 18 */ {0x16, 0x3C, 0x3C, 0, T_T }, /* Key 23: u U */
293 /* 19 */ {0x2F, 0x2A, 0x2A, 0, T_T }, /* Key 49: v V */
294 /* 1A */ {0x11, 0x1D, 0x1D, 0, T_T }, /* Key 18: w W */
295 /* 1B */ {0x2D, 0x22, 0x22, 0, T_T }, /* Key 47: x X */
296 /* 1C */ {0x15, 0x35, 0x35, 0, T_T }, /* Key 22: y Y */
297 /* 1D */ {0x2C, 0x1A, 0x1A, 0, T_T }, /* Key 46: z Z */
298 /* 1E */ {0x02, 0x16, 0x16, 0, T_T }, /* Key 2: 1 ! */
299 /* 1F */ {0x03, 0x1E, 0x1E, 0, T_T }, /* Key 3: 2 @ */
300 /* 20 */ {0x04, 0x26, 0x26, 0, T_T }, /* Key 4: 3 # */
301 /* 21 */ {0x05, 0x25, 0x25, 0, T_T }, /* Key 5: 4 $ */
302 /* 22 */ {0x06, 0x2E, 0x2E, 0, T_T }, /* Key 6: 5 % */
303 /* 23 */ {0x07, 0x36, 0x36, 0, T_T }, /* Key 7: 6 ^ */
304 /* 24 */ {0x08, 0x3D, 0x3D, 0, T_T }, /* Key 8: 7 & */
305 /* 25 */ {0x09, 0x3E, 0x3E, 0, T_T }, /* Key 9: 8 * */
306 /* 26 */ {0x0A, 0x46, 0x46, 0, T_T }, /* Key 10: 9 ( */
307 /* 27 */ {0x0B, 0x45, 0x45, 0, T_T }, /* Key 11: 0 ) */
308 /* 28 */ {0x1C, 0x5A, 0x5A, 0, T_T }, /* Key 43: Return */
309 /* 29 */ {0x01, 0x76, 0x08, 0, T_M }, /* Key 110: Escape */
310 /* 2A */ {0x0E, 0x66, 0x66, 0, T_T }, /* Key 15: Backspace */
311 /* 2B */ {0x0F, 0x0D, 0x0D, 0, T_T }, /* Key 16: Tab */
312 /* 2C */ {0x39, 0x29, 0x29, 0, T_T }, /* Key 61: Space */
313 /* 2D */ {0x0C, 0x4E, 0x4E, 0, T_T }, /* Key 12: - _ */
314 /* 2E */ {0x0D, 0x55, 0x55, 0, T_T }, /* Key 13: = + */
315 /* 2F */ {0x1A, 0x54, 0x54, 0, T_T }, /* Key 27: [ { */
316 /* 30 */ {0x1B, 0x5B, 0x5B, 0, T_T }, /* Key 28: ] } */
317 /* 31 */ {0x2B, 0x5D, 0x5C, 0, T_T }, /* Key 29: \ | */
318 /* 32 */ {0x2B, 0x5D, 0x5D, 0, T_T }, /* Key 42: Europe 1 (Note 2) */
319 /* 33 */ {0x27, 0x4C, 0x4C, 0, T_T }, /* Key 40: ; : */
320 /* 34 */ {0x28, 0x52, 0x52, 0, T_T }, /* Key 41: ' " */
321 /* 35 */ {0x29, 0x0E, 0x0E, 0, T_T }, /* Key 1: ` ~ */
322 /* 36 */ {0x33, 0x41, 0x41, 0, T_T }, /* Key 53: , < */
323 /* 37 */ {0x34, 0x49, 0x49, 0, T_T }, /* Key 54: . > */
324 /* 38 */ {0x35, 0x4A, 0x4A, 0, T_T }, /* Key 55: / ? */
325 /* 39 */ {0x3A, 0x58, 0x14, 0, T_B }, /* Key 30: Caps Lock */
326 /* 3A */ {0x3B, 0x05, 0x07, 0, T_M }, /* Key 112: F1 */
327 /* 3B */ {0x3C, 0x06, 0x0F, 0, T_M }, /* Key 113: F2 */
328 /* 3C */ {0x3D, 0x04, 0x17, 0, T_M }, /* Key 114: F3 */
329 /* 3D */ {0x3E, 0x0C, 0x1F, 0, T_M }, /* Key 115: F4 */
330 /* 3E */ {0x3F, 0x03, 0x27, 0, T_M }, /* Key 116: F5 */
331 /* 3F */ {0x40, 0x0B, 0x2F, 0, T_M }, /* Key 117: F6 */
332 /* 40 */ {0x41, 0x83, 0x37, 0, T_M }, /* Key 118: F7 */
333 /* 41 */ {0x42, 0x0A, 0x3F, 0, T_M }, /* Key 119: F8 */
334 /* 42 */ {0x43, 0x01, 0x47, 0, T_M }, /* Key 120: F9 */
335 /* 43 */ {0x44, 0x09, 0x4F, 0, T_M }, /* Key 121: F10 */
336 /* 44 */ {0x57, 0x78, 0x56, 0, T_M }, /* Key 122: F11 */
337 /* 45 */ {0x58, 0x07, 0x5E, 0, T_M }, /* Key 123: F12 */
338 /* 46 */ {0x37, 0x7C, 0x57, KF_PS, T_M }, /* Key 124: Print Screen (Note 1) */
339 /* 47 */ {0x46, 0x7E, 0x5F, 0, T_M }, /* Key 125: Scroll Lock */
340 /* 48 */ {RSVD, RSVD, RSVD, KF_PB, T_M }, /* Key 126: Break (Ctrl-Pause) */
341 /* 49 */ {0x52, 0x70, 0x67, KF_GK, T_M }, /* Key 75: Insert (Note 1) */
342 /* 4A */ {0x47, 0x6C, 0x6E, KF_GK, T_M }, /* Key 80: Home (Note 1) */
343 /* 4B */ {0x49, 0x7D, 0x6F, KF_GK, T_M }, /* Key 85: Page Up (Note 1) */
344 /* 4C */ {0x53, 0x71, 0x64, KF_GK, T_T }, /* Key 76: Delete (Note 1) */
345 /* 4D */ {0x4F, 0x69, 0x65, KF_GK, T_M }, /* Key 81: End (Note 1) */
346 /* 4E */ {0x51, 0x7A, 0x6D, KF_GK, T_M }, /* Key 86: Page Down (Note 1) */
347 /* 4F */ {0x4D, 0x74, 0x6A, KF_GK, T_T }, /* Key 89: Right Arrow (Note 1) */
348 /* 50 */ {0x4B, 0x6B, 0x61, KF_GK, T_T }, /* Key 79: Left Arrow (Note 1) */
349 /* 51 */ {0x50, 0x72, 0x60, KF_GK, T_T }, /* Key 84: Down Arrow (Note 1) */
350 /* 52 */ {0x48, 0x75, 0x63, KF_GK, T_T }, /* Key 83: Up Arrow (Note 1) */
351 /* 53 */ {0x45, 0x77, 0x76, KF_NL, T_M }, /* Key 90: Num Lock */
352 /* 54 */ {0x35, 0x4A, 0x77, KF_NS, T_M }, /* Key 95: Keypad / (Note 1) */
353 /* 55 */ {0x37, 0x7C, 0x7E, 0, T_M }, /* Key 100: Keypad * */
354 /* 56 */ {0x4A, 0x7B, 0x84, 0, T_M }, /* Key 105: Keypad - */
355 /* 57 */ {0x4E, 0x79, 0x7C, 0, T_T }, /* Key 106: Keypad + */
356 /* 58 */ {0x1C, 0x5A, 0x79, KF_E0, T_M }, /* Key 108: Keypad Enter */
357 /* 59 */ {0x4F, 0x69, 0x69, 0, T_M }, /* Key 93: Keypad 1 End */
358 /* 5A */ {0x50, 0x72, 0x72, 0, T_M }, /* Key 98: Keypad 2 Down */
359 /* 5B */ {0x51, 0x7A, 0x7A, 0, T_M }, /* Key 103: Keypad 3 PageDn */
360 /* 5C */ {0x4B, 0x6B, 0x6B, 0, T_M }, /* Key 92: Keypad 4 Left */
361 /* 5D */ {0x4C, 0x73, 0x73, 0, T_M }, /* Key 97: Keypad 5 */
362 /* 5E */ {0x4D, 0x74, 0x74, 0, T_M }, /* Key 102: Keypad 6 Right */
363 /* 5F */ {0x47, 0x6C, 0x6C, 0, T_M }, /* Key 91: Keypad 7 Home */
364 /* 60 */ {0x48, 0x75, 0x75, 0, T_M }, /* Key 96: Keypad 8 Up */
365 /* 61 */ {0x49, 0x7D, 0x7D, 0, T_M }, /* Key 101: Keypad 9 PageUp */
366 /* 62 */ {0x52, 0x70, 0x70, 0, T_M }, /* Key 99: Keypad 0 Insert */
367 /* 63 */ {0x53, 0x71, 0x71, 0, T_M }, /* Key 104: Keypad . Delete */
368 /* 64 */ {0x56, 0x61, 0x13, 0, T_T }, /* Key 45: Europe 2 (Note 2) */
369 /* 65 */ {0x5D, 0x2F, UNKN, KF_E0, T_U }, /* Key 129: App */
370 /* 66 */ {0x5E, 0x37, UNKN, KF_E0, T_U }, /* Key Unk: Keyboard Power */
371 /* 67 */ {0x59, 0x0F, UNKN, 0, T_U }, /* Key Unk: Keypad = */
372 /* 68 */ {0x64, 0x08, UNKN, 0, T_U }, /* Key Unk: F13 */
373 /* 69 */ {0x65, 0x10, UNKN, 0, T_U }, /* Key Unk: F14 */
374 /* 6A */ {0x66, 0x18, UNKN, 0, T_U }, /* Key Unk: F15 */
375 /* 6B */ {0x67, 0x20, UNKN, 0, T_U }, /* Key Unk: F16 */
376 /* 6C */ {0x68, 0x28, UNKN, 0, T_U }, /* Key Unk: F17 */
377 /* 6D */ {0x69, 0x30, UNKN, 0, T_U }, /* Key Unk: F18 */
378 /* 6E */ {0x6A, 0x38, UNKN, 0, T_U }, /* Key Unk: F19 */
379 /* 6F */ {0x6B, 0x40, UNKN, 0, T_U }, /* Key Unk: F20 */
380 /* 70 */ {0x6C, 0x48, UNKN, 0, T_U }, /* Key Unk: F21 */
381 /* 71 */ {0x6D, 0x50, UNKN, 0, T_U }, /* Key Unk: F22 */
382 /* 72 */ {0x6E, 0x57, UNKN, 0, T_U }, /* Key Unk: F23 */
383 /* 73 */ {0x76, 0x5F, UNKN, 0, T_U }, /* Key Unk: F24 */
384 /* 74 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Execute */
385 /* 75 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Help */
386 /* 76 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Menu */
387 /* 77 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Select */
388 /* 78 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Stop */
389 /* 79 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Again */
390 /* 7A */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Undo */
391 /* 7B */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Cut */
392 /* 7C */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Copy */
393 /* 7D */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Paste */
394 /* 7E */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Find */
395 /* 7F */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Mute */
396 /* 80 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Volume Up */
397 /* 81 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Volume Dn */
398 /* 82 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Locking Caps Lock */
399 /* 83 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Locking Num Lock */
400 /* 84 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Locking Scroll Lock */
401 /* 85 */ {0x7E, 0x6D, UNKN, 0, T_U }, /* Key Unk: Keypad , (Brazilian Keypad .) */
402 /* 86 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Equal Sign */
403 /* 87 */ {0x73, 0x51, UNKN, 0, T_U }, /* Key Unk: Keyboard Intl 1 (Ro) */
404 /* 88 */ {0x70, 0x13, UNKN, 0, T_U }, /* Key Unk: Keyboard Intl2 (K'kana/H'gana) */
405 /* 89 */ {0x7D, 0x6A, UNKN, 0, T_U }, /* Key Unk: Keyboard Intl 2 (Yen) */
406 /* 8A */ {0x79, 0x64, UNKN, 0, T_U }, /* Key Unk: Keyboard Intl 4 (Henkan) */
407 /* 8B */ {0x7B, 0x67, UNKN, 0, T_U }, /* Key Unk: Keyboard Intl 5 (Muhenkan) */
408 /* 8C */ {0x5C, 0x27, UNKN, 0, T_U }, /* Key Unk: Keyboard Intl 6 (PC9800 Pad ,) */
409 /* 8D */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Intl 7 */
410 /* 8E */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Intl 8 */
411 /* 8F */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Intl 9 */
412 /* 90 */ {0xF2, 0xF2, UNKN, KF_NB, T_U }, /* Key Unk: Keyboard Lang 1 (Hang'l/Engl) */
413 /* 91 */ {0xF1, 0xF1, UNKN, KF_NB, T_U }, /* Key Unk: Keyboard Lang 2 (Hanja) */
414 /* 92 */ {0x78, 0x63, UNKN, 0, T_U }, /* Key Unk: Keyboard Lang 3 (Katakana) */
415 /* 93 */ {0x77, 0x62, UNKN, 0, T_U }, /* Key Unk: Keyboard Lang 4 (Hiragana) */
416 /* 94 */ {0x76, 0x5F, UNKN, 0, T_U }, /* Key Unk: Keyboard Lang 5 (Zen/Han) */
417 /* 95 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Lang 6 */
418 /* 96 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Lang 7 */
419 /* 97 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Lang 8 */
420 /* 98 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Lang 9 */
421 /* 99 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Alternate Erase */
422 /* 9A */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard SysReq/Attention */
423 /* 9B */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Cancel */
424 /* 9C */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Clear */
425 /* 9D */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Prior */
426 /* 9E */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Return */
427 /* 9F */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Separator */
428 /* A0 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Out */
429 /* A1 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Oper */
430 /* A2 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard Clear/Again */
431 /* A3 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard CrSel/Props */
432 /* A4 */ {UNAS, UNAS, UNAS, 0, T_U }, /* Key Unk: Keyboard ExSel */
433};
434
435/* USB to PS/2 conversion table for modifier keys. */
436static const key_def aPS2ModKeys[] = {
437 /* E0 */ {0x1D, 0x14, 0x11, 0, T_B }, /* Key 58: Left Control */
438 /* E1 */ {0x2A, 0x12, 0x12, 0, T_B }, /* Key 44: Left Shift */
439 /* E2 */ {0x38, 0x11, 0x19, 0, T_B }, /* Key 60: Left Alt */
440 /* E3 */ {0x5B, 0x1F, UNKN, KF_E0, T_U }, /* Key 127: Left GUI */
441 /* E4 */ {0x1D, 0x14, 0x58, KF_E0, T_M }, /* Key 64: Right Control */
442 /* E5 */ {0x36, 0x59, 0x59, 0, T_B }, /* Key 57: Right Shift */
443 /* E6 */ {0x38, 0x11, 0x39, KF_E0, T_M }, /* Key 62: Right Alt */
444 /* E7 */ {0x5C, 0x27, UNKN, KF_E0, T_U }, /* Key 128: Right GUI */
445};
446
447/*******************************************************************************
448* Global Variables *
449*******************************************************************************/
450
451/*
452 * Because of historical reasons and poor design, VirtualBox internally uses BIOS
453 * PC/XT style scan codes to represent keyboard events. Each key press and release is
454 * represented as a stream of bytes, typically only one byte but up to four-byte
455 * sequences are possible. In the typical case, the GUI front end generates the stream
456 * of scan codes which we need to translate back to a single up/down event.
457 *
458 * This function could possibly live somewhere else.
459 */
460
461/** Lookup table for converting PC/XT scan codes to USB HID usage codes. */
462static uint8_t aScancode2Hid[] =
463{
464 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, /* 00-07 */
465 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b, /* 08-1F */
466 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c, /* 10-17 */
467 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16, /* 18-1F */
468 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33, /* 20-27 */
469 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19, /* 28-2F */
470 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55, /* 30-37 */
471 0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, /* 38-3F */
472 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f, /* 40-47 */
473 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59, /* 48-4F */
474 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x64, 0x44, /* 50-57 */
475 0x45, 0x67, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, /* 58-5F */
476 0x00, 0x00, 0x00, 0x00, 0x68, 0x69, 0x6a, 0x6b, /* 60-67 */
477 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x00, /* 68-6F */
478 0x88, 0x91, 0x90, 0x87, 0x00, 0x00, 0x00, 0x00, /* 70-77 */
479 0x00, 0x8a, 0x00, 0x8b, 0x00, 0x89, 0x85, 0x00 /* 78-7F */
480};
481
482/** Lookup table for extended scancodes (arrow keys etc.). */
483static uint8_t aExtScan2Hid[] =
484{
485 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00-07 */
486 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 08-1F */
487 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10-17 */
488 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00, /* 18-1F */
489 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 20-27 */
490 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28-2F */
491 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46, /* 30-37 */
492 /* Sun-specific keys. Most of the XT codes are made up */
493 0xe6, 0x00, 0x00, 0x75, 0x76, 0x77, 0xA3, 0x78, /* 38-3F */
494 0x80, 0x81, 0x82, 0x79, 0x00, 0x00, 0x48, 0x4a, /* 40-47 */
495 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d, /* 48-4F */
496 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00, /* 50-57 */
497 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x66, 0x00, /* 58-5F */
498 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60-67 */
499 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 68-6F */
500 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 70-77 */
501 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 78-7F */
502};
503
504/**
505 * Convert a PC scan code to a USB HID usage byte.
506 *
507 * @param state Current state of the translator (scan_state_t).
508 * @param scanCode Incoming scan code.
509 * @param pUsage Pointer to usage; high bit set for key up events. The
510 * contents are only valid if returned state is SS_IDLE.
511 *
512 * @return scan_state_t New state of the translator.
513 */
514static scan_state_t ScancodeToHidUsage(scan_state_t state, uint8_t scanCode, uint32_t *pUsage)
515{
516 uint32_t keyUp;
517 uint8_t usage;
518
519 Assert(pUsage);
520
521 /* Isolate the scan code and key break flag. */
522 keyUp = (scanCode & 0x80) << 24;
523
524 switch (state) {
525 case SS_IDLE:
526 if (scanCode == 0xE0) {
527 state = SS_EXT;
528 } else if (scanCode == 0xE1) {
529 state = SS_EXT1;
530 } else {
531 usage = aScancode2Hid[scanCode & 0x7F];
532 *pUsage = usage | keyUp;
533 /* Remain in SS_IDLE state. */
534 }
535 break;
536 case SS_EXT:
537 usage = aExtScan2Hid[scanCode & 0x7F];
538 *pUsage = usage | keyUp;
539 state = SS_IDLE;
540 break;
541 case SS_EXT1:
542 /* The sequence is E1 1D 45 E1 9D C5. We take the easy way out and remain
543 * in the SS_EXT1 state until 45 or C5 is received.
544 */
545 if ((scanCode & 0x7F) == 0x45) {
546 *pUsage = 0x48;
547 if (scanCode == 0xC5)
548 *pUsage |= keyUp;
549 state = SS_IDLE;
550 }
551 /* Else remain in SS_EXT1 state. */
552 break;
553 }
554 return state;
555}
556
557/*******************************************************************************
558* Internal Functions *
559*******************************************************************************/
560
561
562/**
563 * Clear a queue.
564 *
565 * @param pQ Pointer to the queue.
566 */
567static void ps2kClearQueue(GeneriQ *pQ)
568{
569 LogFlowFunc(("Clearing queue %p\n", pQ));
570 pQ->wpos = pQ->rpos;
571 pQ->cUsed = 0;
572}
573
574
575/**
576 * Add a byte to a queue.
577 *
578 * @param pQ Pointer to the queue.
579 * @param val The byte to store.
580 */
581static void ps2kInsertQueue(GeneriQ *pQ, uint8_t val)
582{
583 /* Check if queue is full. */
584 if (pQ->cUsed >= pQ->cSize)
585 {
586 LogFlowFunc(("queue %p full (%d entries)\n", pQ, pQ->cUsed));
587 return;
588 }
589 /* Insert data and update circular buffer write position. */
590 pQ->abQueue[pQ->wpos] = val;
591 if (++pQ->wpos == pQ->cSize)
592 pQ->wpos = 0; /* Roll over. */
593 ++pQ->cUsed;
594 LogFlowFunc(("inserted 0x%02X into queue %p\n", val, pQ));
595}
596
597#ifdef IN_RING3
598
599/**
600 * Save a queue state.
601 *
602 * @param pSSM SSM handle to write the state to.
603 * @param pQ Pointer to the queue.
604 */
605static void ps2kSaveQueue(PSSMHANDLE pSSM, GeneriQ *pQ)
606{
607 uint32_t cItems = pQ->cUsed;
608 int i;
609
610 /* Only save the number of items. Note that the read/write
611 * positions aren't saved as they will be rebuilt on load.
612 */
613 SSMR3PutU32(pSSM, cItems);
614
615 LogFlow(("Storing %d items from queue %p\n", cItems, pQ));
616
617 /* Save queue data - only the bytes actually used (typically zero). */
618 for (i = pQ->rpos; cItems-- > 0; i = (i + 1) % pQ->cSize)
619 SSMR3PutU8(pSSM, pQ->abQueue[i]);
620}
621
622/**
623 * Load a queue state.
624 *
625 * @param pSSM SSM handle to read the state from.
626 * @param pQ Pointer to the queue.
627 *
628 * @return int VBox status/error code.
629 */
630static int ps2kLoadQueue(PSSMHANDLE pSSM, GeneriQ *pQ)
631{
632 int rc;
633
634 /* On load, always put the read pointer at zero. */
635 SSMR3GetU32(pSSM, &pQ->cUsed);
636
637 LogFlow(("Loading %d items to queue %p\n", pQ->cUsed, pQ));
638
639 if (pQ->cUsed > pQ->cSize)
640 {
641 AssertMsgFailed(("Saved size=%u, actual=%u\n", pQ->cUsed, pQ->cSize));
642 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
643 }
644
645 /* Recalculate queue positions and load data in one go. */
646 pQ->rpos = 0;
647 pQ->wpos = pQ->cUsed;
648 rc = SSMR3GetMem(pSSM, pQ->abQueue, pQ->cUsed);
649
650 return rc;
651}
652
653#endif /* IN_RING3 */
654
655/**
656 * Retrieve a byte from a queue.
657 *
658 * @param pQ Pointer to the queue.
659 * @param pVal Pointer to storage for the byte.
660 *
661 * @return int VINF_TRY_AGAIN if queue is empty,
662 * VINF_SUCCESS if a byte was read.
663 */
664static int ps2kRemoveQueue(GeneriQ *pQ, uint8_t *pVal)
665{
666 int rc = VINF_TRY_AGAIN;
667
668 Assert(pVal);
669 if (pQ->cUsed)
670 {
671 *pVal = pQ->abQueue[pQ->rpos];
672 if (++pQ->rpos == pQ->cSize)
673 pQ->rpos = 0; /* Roll over. */
674 --pQ->cUsed;
675 rc = VINF_SUCCESS;
676 LogFlowFunc(("removed 0x%02X from queue %p\n", *pVal, pQ));
677 } else
678 LogFlowFunc(("queue %p empty\n", pQ));
679 return rc;
680}
681
682/* Convert encoded typematic value to milliseconds. Note that the values are rated
683 * with +/- 20% accuracy, so there's no need for high precision.
684 */
685static void ps2kSetupTypematic(PPS2K pThis, uint8_t val)
686{
687 int A, B;
688 unsigned period;
689
690 pThis->u8Typematic = val;
691 /* The delay is easy: (1 + value) * 250 ms */
692 pThis->uTypematicDelay = (1 + ((val >> 5) & 3)) * 250;
693 /* The rate is more complicated: (8 + A) * 2^B * 4.17 ms */
694 A = val & 7;
695 B = (val >> 3) & 3;
696 period = (8 + A) * (1 << B) * 417 / 100;
697 pThis->uTypematicRepeat = period;
698 Log(("Typematic delay %u ms, repeat period %u ms\n",
699 pThis->uTypematicDelay, pThis->uTypematicRepeat));
700}
701
702static void ps2kSetDefaults(PPS2K pThis)
703{
704 LogFlowFunc(("Set keyboard defaults\n"));
705 ps2kClearQueue((GeneriQ *)&pThis->keyQ);
706 /* Set default Scan Set 3 typematic values. */
707 /* Set default typematic rate/delay. */
708 ps2kSetupTypematic(pThis, KBD_DFL_RATE_DELAY);
709 /* Clear last typematic key?? */
710}
711
712/**
713 * Receive and process a byte sent by the keyboard controller.
714 *
715 * @param pThis The PS/2 keyboard instance data.
716 * @param cmd The command (or data) byte.
717 */
718int PS2KByteToKbd(PPS2K pThis, uint8_t cmd)
719{
720 bool fHandled = true;
721
722 LogFlowFunc(("new cmd=0x%02X, active cmd=0x%02X\n", cmd, pThis->u8CurrCmd));
723
724 switch (cmd)
725 {
726 case KCMD_ECHO:
727 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ECHO);
728 pThis->u8CurrCmd = 0;
729 break;
730 case KCMD_READ_ID:
731 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
732 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ID1);
733 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ID2);
734 pThis->u8CurrCmd = 0;
735 break;
736 case KCMD_ENABLE:
737 pThis->fScanning = true;
738 ps2kClearQueue((GeneriQ *)&pThis->keyQ);
739 /* Clear last typematic key?? */
740 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
741 pThis->u8CurrCmd = 0;
742 break;
743 case KCMD_DFLT_DISABLE:
744 pThis->fScanning = false;
745 ps2kSetDefaults(pThis);
746 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
747 pThis->u8CurrCmd = 0;
748 break;
749 case KCMD_SET_DEFAULT:
750 ps2kSetDefaults(pThis);
751 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
752 pThis->u8CurrCmd = 0;
753 break;
754 case KCMD_ALL_TYPEMATIC:
755 case KCMD_ALL_MK_BRK:
756 case KCMD_ALL_MAKE:
757 case KCMD_ALL_TMB:
758 ///@todo Set the key types here.
759 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
760 pThis->u8CurrCmd = 0;
761 break;
762 case KCMD_RESEND:
763 pThis->u8CurrCmd = 0;
764 break;
765 case KCMD_RESET:
766 pThis->u8ScanSet = 2;
767 ps2kSetDefaults(pThis);
768 ///@todo reset more?
769 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
770 pThis->u8CurrCmd = cmd;
771 /* Delay BAT completion; the test may take hundreds of ms. */
772 TMTimerSetMillies(pThis->CTX_SUFF(pKbdDelayTimer), 2);
773 break;
774 /* The following commands need a parameter. */
775 case KCMD_LEDS:
776 case KCMD_SCANSET:
777 case KCMD_RATE_DELAY:
778 case KCMD_TYPE_MATIC:
779 case KCMD_TYPE_MK_BRK:
780 case KCMD_TYPE_MAKE:
781 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
782 pThis->u8CurrCmd = cmd;
783 break;
784 default:
785 /* Sending a command instead of a parameter starts the new command. */
786 switch (pThis->u8CurrCmd)
787 {
788 case KCMD_LEDS:
789#ifndef IN_RING3
790 return VINF_IOM_R3_IOPORT_WRITE;
791#else
792 {
793 PDMKEYBLEDS enmLeds = PDMKEYBLEDS_NONE;
794
795 if (cmd & 0x01)
796 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_SCROLLLOCK);
797 if (cmd & 0x02)
798 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_NUMLOCK);
799 if (cmd & 0x04)
800 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_CAPSLOCK);
801 pThis->Keyboard.pDrv->pfnLedStatusChange(pThis->Keyboard.pDrv, enmLeds);
802 pThis->fNumLockOn = !!(cmd & 0x02); /* Sync internal Num Lock state. */
803 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
804 pThis->u8LEDs = cmd;
805 pThis->u8CurrCmd = 0;
806 }
807#endif
808 break;
809 case KCMD_SCANSET:
810 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
811 if (cmd == 0)
812 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, pThis->u8ScanSet);
813 else if (cmd < 4)
814 {
815 pThis->u8ScanSet = cmd;
816 LogRel(("PS2K: Selected scan set %d.\n", cmd));
817 }
818 /* Other values are simply ignored. */
819 pThis->u8CurrCmd = 0;
820 break;
821 case KCMD_RATE_DELAY:
822 ps2kSetupTypematic(pThis, cmd);
823 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
824 pThis->u8CurrCmd = 0;
825 break;
826 default:
827 fHandled = false;
828 }
829 /* Fall through only to handle unrecognized commands. */
830 if (fHandled)
831 break;
832
833 case KCMD_INVALID_1:
834 case KCMD_INVALID_2:
835 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_RESEND);
836 pThis->u8CurrCmd = 0;
837 break;
838 }
839 LogFlowFunc(("Active cmd now 0x%02X; updating interrupts\n", pThis->u8CurrCmd));
840// KBCUpdateInterrupts(pThis->pParent);
841 return VINF_SUCCESS;
842}
843
844/**
845 * Send a byte (keystroke or command response) to the keyboard controller.
846 *
847 * @returns VINF_SUCCESS or VINF_TRY_AGAIN.
848 * @param pThis The PS/2 keyboard instance data.
849 * @param pb Where to return the byte we've read.
850 * @remarks Caller must have entered the device critical section.
851 */
852int PS2KByteFromKbd(PPS2K pThis, uint8_t *pb)
853{
854 int rc;
855
856 AssertPtr(pb);
857
858 /* Anything in the command queue has priority over data
859 * in the keystroke queue. Additionally, keystrokes are
860 * blocked if a command is currently in progress, even if
861 * the command queue is empty.
862 */
863 rc = ps2kRemoveQueue((GeneriQ *)&pThis->cmdQ, pb);
864 if (rc != VINF_SUCCESS && !pThis->u8CurrCmd && pThis->fScanning)
865 rc = ps2kRemoveQueue((GeneriQ *)&pThis->keyQ, pb);
866
867 LogFlowFunc(("keyboard sends 0x%02x (%svalid data)\n", *pb, rc == VINF_SUCCESS ? "" : "not "));
868 return rc;
869}
870
871#ifdef IN_RING3
872
873static int psk2ProcessKeyEvent(PPS2K pThis, uint8_t u8HidCode, bool fKeyDown)
874{
875 unsigned int i = 0;
876 key_def const *pKeyDef;
877 uint8_t abCodes[16];
878
879 LogFlowFunc(("key %s: 0x%02x (set %d)\n", fKeyDown ? "down" : "up", u8HidCode, pThis->u8ScanSet));
880
881 /* Find the key definition in somewhat sparse storage. */
882 pKeyDef = u8HidCode >= HID_MODIFIER_FIRST ? &aPS2ModKeys[u8HidCode - HID_MODIFIER_FIRST] : &aPS2Keys[u8HidCode];
883
884 /* Some keys are not processed at all; early return. */
885 if (pKeyDef->makeS1 == NONE)
886 {
887 LogFlow(("Skipping key processing.\n"));
888 return VINF_SUCCESS;
889 }
890
891 /* Handle modifier keys (Ctrl/Alt/Shift/GUI). We need to keep track
892 * of their state in addition to sending the scan code.
893 */
894 if (u8HidCode >= HID_MODIFIER_FIRST)
895 {
896 unsigned mod_bit = 1 << (u8HidCode - HID_MODIFIER_FIRST);
897
898 Assert((u8HidCode <= HID_MODIFIER_LAST));
899 if (fKeyDown)
900 pThis->u8Modifiers |= mod_bit;
901 else
902 pThis->u8Modifiers &= ~mod_bit;
903 }
904
905 /* Toggle NumLock state. */
906 if ((pKeyDef->keyFlags & KF_NL) && fKeyDown)
907 pThis->fNumLockOn ^= true;
908
909 if (pThis->u8ScanSet == 2)
910 {
911 /* Handle Scan Set 2 - used almost all the time. */
912 abCodes[0] = 0;
913 if (fKeyDown)
914 {
915 /* Process key down event. */
916 if (pKeyDef->keyFlags & KF_PB)
917 {
918 /* Pause/Break sends different data if either Ctrl is held. */
919 if (pThis->u8Modifiers & (MOD_LCTRL | MOD_RCTRL))
920 strcpy((char *)abCodes, "\xE0\x7E\xE0\xF0\x7E");
921 else
922 strcpy((char *)abCodes, "\xE1\x14\x77\xE1\xF0\x14\xF0\x77");
923 }
924 else if (pKeyDef->keyFlags & KF_PS)
925 {
926 /* Print Screen depends on all Ctrl, Shift, *and* Alt! */
927 if (pThis->u8Modifiers & (MOD_LALT | MOD_RALT))
928 strcpy((char *)abCodes, "\x84");
929 else if (pThis->u8Modifiers & (MOD_LSHIFT | MOD_RSHIFT))
930 strcpy((char *)abCodes, "\xE0\x7C");
931 else
932 strcpy((char *)abCodes, "\xE0\x12\xE0\x7C");
933 }
934 else if (pKeyDef->keyFlags & KF_GK)
935 {
936 if (pThis->fNumLockOn)
937 {
938 if ((pThis->u8Modifiers & (MOD_LSHIFT | MOD_RSHIFT)) == 0)
939 strcpy((char *)abCodes, "\xE0\x12");
940 }
941 else
942 {
943 if (pThis->u8Modifiers & MOD_LSHIFT)
944 strcat((char *)abCodes, "\xE0\xF0\x12");
945 if (pThis->u8Modifiers & MOD_RSHIFT)
946 strcat((char *)abCodes, "\xE0\xF0\x59");
947 }
948 }
949 /* Feed the bytes to the queue if there is room. */
950 ///@todo check empty space!
951 while (abCodes[i])
952 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, abCodes[i++]);
953 Assert(i < sizeof(abCodes));
954
955 /* Standard processing for regular keys only. */
956 if (!(pKeyDef->keyFlags & (KF_PB | KF_PS)))
957 {
958 if (pKeyDef->keyFlags & (KF_E0 | KF_GK | KF_NS))
959 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, 0xE0);
960 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS2);
961 }
962 }
963 else if (!(pKeyDef->keyFlags & (KF_NB | KF_PB)))
964 {
965 /* Process key up event except for keys which produce none. */
966
967 /* Handle Print Screen release. */
968 if (pKeyDef->keyFlags & KF_PS)
969 {
970 /* Undo faked Print Screen state as needed. */
971 if (pThis->u8Modifiers & (MOD_LALT | MOD_RALT))
972 strcpy((char *)abCodes, "\xF0\x84");
973 else if (pThis->u8Modifiers & (MOD_LSHIFT | MOD_RSHIFT))
974 strcpy((char *)abCodes, "\xE0\xF0\x7C");
975 else
976 strcpy((char *)abCodes, "\xE0\xF0\x7C\xE0\xF0\x12");
977 }
978 else
979 {
980 /* Process base scan code for less unusual keys. */
981 if (pKeyDef->keyFlags & (KF_E0 | KF_GK | KF_NS))
982 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, 0xE0);
983 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, 0xF0);
984 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS2);
985
986 /* Restore shift state for gray keys. */
987 if (pKeyDef->keyFlags & KF_GK)
988 {
989 if (pThis->fNumLockOn)
990 {
991 if ((pThis->u8Modifiers & (MOD_LSHIFT | MOD_RSHIFT)) == 0)
992 strcpy((char *)abCodes, "\xE0\xF0\x12");
993 }
994 else
995 {
996 if (pThis->u8Modifiers & MOD_RSHIFT)
997 strcat((char *)abCodes, "\xE0\x59");
998 if (pThis->u8Modifiers & MOD_LSHIFT)
999 strcat((char *)abCodes, "\xE0\x12");
1000 }
1001 }
1002 }
1003
1004 /* Feed any additional bytes to the queue if there is room. */
1005 ///@todo check empty space!
1006 while (abCodes[i])
1007 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, abCodes[i++]);
1008 Assert(i < sizeof(abCodes));
1009 }
1010 }
1011 else if (pThis->u8ScanSet == 1)
1012 {
1013 /* Handle Scan Set 1 - similar in complexity to Set 2. */
1014 if (fKeyDown)
1015 {
1016 if (pKeyDef->keyFlags & (KF_E0 | KF_GK | KF_NS | KF_PS))
1017 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, 0xE0);
1018 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS1);
1019 }
1020 else if (!(pKeyDef->keyFlags & (KF_NB | KF_PB))) {
1021 if (pKeyDef->keyFlags & (KF_E0 | KF_GK | KF_NS | KF_PS))
1022 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, 0xE0);
1023 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS1 | 0x80);
1024 }
1025 }
1026 else
1027 {
1028 /* Handle Scan Set 3 - very straightforward. */
1029 if (fKeyDown)
1030 {
1031 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS3);
1032 }
1033 else
1034 {
1035 /* Send a key release code unless it's a make only key. */
1036 ///@todo Look up the current typematic setting, not the default!
1037 if (pKeyDef->keyMatic != T_M)
1038 {
1039 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, 0xF0);
1040 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS3);
1041 }
1042 }
1043 }
1044
1045 /* Set up or cancel typematic key repeat. */
1046 if (fKeyDown)
1047 {
1048 if (pThis->u8TypematicKey != u8HidCode)
1049 {
1050 pThis->enmTypematicState = KBD_TMS_DELAY;
1051 pThis->u8TypematicKey = u8HidCode;
1052 TMTimerSetMillies(pThis->CTX_SUFF(pKbdTypematicTimer), pThis->uTypematicDelay);
1053 Log(("Typematic delay %u ms, key %02X\n", pThis->uTypematicDelay, u8HidCode));
1054 }
1055 }
1056 else
1057 {
1058 pThis->u8TypematicKey = 0;
1059 pThis->enmTypematicState = KBD_TMS_IDLE;
1060 ///@todo Cancel timer right away?
1061 ///@todo Cancel timer before pushing key up code!?
1062 }
1063
1064 /* Poke the KBC to update its state. */
1065 KBCUpdateInterrupts(pThis->pParent);
1066
1067 return VINF_SUCCESS;
1068}
1069
1070/* Timer handler for emulating typematic keys. Note that only the last key
1071 * held down repeats (if typematic).
1072 */
1073static DECLCALLBACK(void) ps2kTypematicTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1074{
1075 PPS2K pThis = (PS2K *)pvUser; NOREF(pDevIns);
1076 LogFlowFunc(("Typematic state=%d, key %02X\n", pThis->enmTypematicState, pThis->u8TypematicKey));
1077
1078 /* If the current typematic key is zero, the repeat was canceled just when
1079 * the timer was about to run. In that case, do nothing.
1080 */
1081 if (pThis->u8TypematicKey)
1082 {
1083 if (pThis->enmTypematicState == KBD_TMS_DELAY)
1084 pThis->enmTypematicState = KBD_TMS_REPEAT;
1085
1086 if (pThis->enmTypematicState == KBD_TMS_REPEAT)
1087 {
1088 psk2ProcessKeyEvent(pThis, pThis->u8TypematicKey, true /* Key down */ );
1089 TMTimerSetMillies(pThis->CTX_SUFF(pKbdTypematicTimer), pThis->uTypematicRepeat);
1090 }
1091 }
1092}
1093
1094/* The keyboard BAT is specified to take several hundred milliseconds. We need
1095 * to delay sending the result to the host for at least a tiny little while.
1096 */
1097static DECLCALLBACK(void) ps2kDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1098{
1099 PPS2K pThis = (PS2K *)pvUser; NOREF(pDevIns);
1100
1101 LogFlowFunc(("Delay timer: cmd %02X\n", pThis->u8CurrCmd));
1102
1103 Assert(pThis->u8CurrCmd == KCMD_RESET);
1104 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_BAT_OK);
1105 pThis->fScanning = true; /* BAT completion enables scanning! */
1106 pThis->u8CurrCmd = 0;
1107
1108 ///@todo Might want a PS2KCompleteCommand() to push last response, clear command, and kick the KBC...
1109 /* Give the KBC a kick. */
1110 KBCUpdateInterrupts(pThis->pParent);
1111}
1112
1113
1114/**
1115 * Debug device info handler. Prints basic keyboard state.
1116 *
1117 * @param pDevIns Device instance which registered the info.
1118 * @param pHlp Callback functions for doing output.
1119 * @param pszArgs Argument string. Optional and specific to the handler.
1120 */
1121static DECLCALLBACK(void) ps2kInfoState(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
1122{
1123 PPS2K pThis = KBDGetPS2KFromDevIns(pDevIns);
1124 NOREF(pszArgs);
1125
1126 pHlp->pfnPrintf(pHlp, "PS/2 Keyboard: scan set %d, scanning %s\n",
1127 pThis->u8ScanSet, pThis->fScanning ? "enabled" : "disabled");
1128 pHlp->pfnPrintf(pHlp, "Active command %02X\n", pThis->u8CurrCmd);
1129 pHlp->pfnPrintf(pHlp, "LED state %02X, Num Lock %s\n", pThis->u8LEDs,
1130 pThis->fNumLockOn ? "on" : "off");
1131 pHlp->pfnPrintf(pHlp, "Typematic delay %ums, repeat period %ums\n",
1132 pThis->uTypematicDelay, pThis->uTypematicRepeat);
1133 pHlp->pfnPrintf(pHlp, "Command queue: %d items (%d max)\n",
1134 pThis->cmdQ.cUsed, pThis->cmdQ.cSize);
1135 pHlp->pfnPrintf(pHlp, "Input queue : %d items (%d max)\n",
1136 pThis->keyQ.cUsed, pThis->keyQ.cSize);
1137 if (pThis->enmTypematicState != KBD_TMS_IDLE)
1138 pHlp->pfnPrintf(pHlp, "Active typematic key %02X (%s)\n", pThis->u8Typematic,
1139 pThis->enmTypematicState == KBD_TMS_DELAY ? "delay" : "repeat");
1140}
1141
1142/* -=-=-=-=-=- Keyboard: IBase -=-=-=-=-=- */
1143
1144/**
1145 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1146 */
1147static DECLCALLBACK(void *) ps2kQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1148{
1149 PPS2K pThis = RT_FROM_MEMBER(pInterface, PS2K, Keyboard.IBase);
1150 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Keyboard.IBase);
1151 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIKEYBOARDPORT, &pThis->Keyboard.IPort);
1152 return NULL;
1153}
1154
1155
1156/* -=-=-=-=-=- Keyboard: IKeyboardPort -=-=-=-=-=- */
1157
1158/**
1159 * Keyboard event handler.
1160 *
1161 * @returns VBox status code.
1162 * @param pThis The PS2 keyboard instance data.
1163 * @param u32Usage USB HID usage code with key
1164 * press/release flag.
1165 */
1166static int ps2kPutEventWorker(PPS2K pThis, uint32_t u32Usage)
1167{
1168 uint8_t u8HidCode;
1169 bool fKeyDown;
1170 bool fHaveEvent = true;
1171 int rc = VINF_SUCCESS;
1172
1173 /* Extract the usage code and ensure it's valid. */
1174 fKeyDown = !(u32Usage & 0x80000000);
1175 u8HidCode = u32Usage & 0xFF;
1176 AssertReturn(u8HidCode <= VBOX_USB_MAX_USAGE_CODE, VERR_INTERNAL_ERROR);
1177
1178 if (fKeyDown)
1179 {
1180 /* Due to host key repeat, we can get key events for keys which are
1181 * already depressed. We need to ignore those. */
1182 if (pThis->abDepressedKeys[u8HidCode])
1183 fHaveEvent = false;
1184 pThis->abDepressedKeys[u8HidCode] = 1;
1185 }
1186 else
1187 {
1188 /* NB: We allow key release events for keys which aren't depressed.
1189 * That is unlikely to happen and should not cause trouble.
1190 */
1191 pThis->abDepressedKeys[u8HidCode] = 0;
1192 }
1193
1194 /* Unless this is a new key press/release, don't even bother. */
1195 if (fHaveEvent)
1196 {
1197 rc = PDMCritSectEnter(pThis->pCritSectR3, VERR_SEM_BUSY);
1198 AssertReleaseRC(rc);
1199
1200 rc = psk2ProcessKeyEvent(pThis, u8HidCode, fKeyDown);
1201
1202 PDMCritSectLeave(pThis->pCritSectR3);
1203 }
1204
1205 return rc;
1206}
1207
1208static DECLCALLBACK(int) ps2kPutEventWrapper(PPDMIKEYBOARDPORT pInterface, uint8_t u8KeyCode)
1209{
1210 PPS2K pThis = RT_FROM_MEMBER(pInterface, PS2K, Keyboard.IPort);
1211 uint32_t u32Usage = 0;
1212
1213 LogFlowFunc(("key code %02X\n", u8KeyCode));
1214 pThis->XlatState = ScancodeToHidUsage(pThis->XlatState, u8KeyCode, &u32Usage);
1215
1216 if (pThis->XlatState == SS_IDLE)
1217 {
1218 /* Stupid Korean key hack: convert a lone break key into a press/release sequence. */
1219 if (u32Usage == 0x80000090 || u32Usage == 0x80000091)
1220 ps2kPutEventWorker(pThis, u32Usage & ~0x80000000);
1221
1222 ps2kPutEventWorker(pThis, u32Usage);
1223 }
1224
1225 return VINF_SUCCESS;
1226}
1227
1228
1229/**
1230 * Attach command.
1231 *
1232 * This is called to let the device attach to a driver for a
1233 * specified LUN.
1234 *
1235 * This is like plugging in the keyboard after turning on the
1236 * system.
1237 *
1238 * @returns VBox status code.
1239 * @param pThis The PS/2 keyboard instance data.
1240 * @param pDevIns The device instance.
1241 * @param iLUN The logical unit which is being detached.
1242 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1243 */
1244int PS2KAttach(PPS2K pThis, PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1245{
1246 int rc;
1247
1248 /* The LUN must be 0, i.e. keyboard. */
1249 Assert(iLUN == 0);
1250 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
1251 ("PS/2 keyboard does not support hotplugging\n"),
1252 VERR_INVALID_PARAMETER);
1253
1254 LogFlowFunc(("iLUN=%d\n", iLUN));
1255
1256 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->Keyboard.IBase, &pThis->Keyboard.pDrvBase, "Keyboard Port");
1257 if (RT_SUCCESS(rc))
1258 {
1259 pThis->Keyboard.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Keyboard.pDrvBase, PDMIKEYBOARDCONNECTOR);
1260 if (!pThis->Keyboard.pDrv)
1261 {
1262 AssertLogRelMsgFailed(("LUN #0 doesn't have a keyboard interface! rc=%Rrc\n", rc));
1263 rc = VERR_PDM_MISSING_INTERFACE;
1264 }
1265 }
1266 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1267 {
1268 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pReg->szName, pDevIns->iInstance));
1269 rc = VINF_SUCCESS;
1270 }
1271 else
1272 AssertLogRelMsgFailed(("Failed to attach LUN #0! rc=%Rrc\n", rc));
1273
1274 return rc;
1275}
1276
1277void PS2KSaveState(PPS2K pThis, PSSMHANDLE pSSM)
1278{
1279 uint32_t cPressed = 0;
1280 uint32_t cbTMSSize = 0;
1281
1282 LogFlowFunc(("Saving PS2K state\n"));
1283
1284 /* Save the basic keyboard state. */
1285 SSMR3PutU8(pSSM, pThis->u8CurrCmd);
1286 SSMR3PutU8(pSSM, pThis->u8LEDs);
1287 SSMR3PutU8(pSSM, pThis->u8Typematic);
1288 SSMR3PutU8(pSSM, pThis->u8TypematicKey);
1289 SSMR3PutU8(pSSM, pThis->u8Modifiers);
1290 SSMR3PutU8(pSSM, pThis->u8ScanSet);
1291 SSMR3PutU8(pSSM, pThis->enmTypematicState);
1292 SSMR3PutBool(pSSM, pThis->fNumLockOn);
1293 SSMR3PutBool(pSSM, pThis->fScanning);
1294
1295 /* Save the command and keystroke queues. */
1296 ps2kSaveQueue(pSSM, (GeneriQ *)&pThis->cmdQ);
1297 ps2kSaveQueue(pSSM, (GeneriQ *)&pThis->keyQ);
1298
1299 /* Save the command delay timer. Note that the typematic repeat
1300 * timer is *not* saved.
1301 */
1302 TMR3TimerSave(pThis->CTX_SUFF(pKbdDelayTimer), pSSM);
1303
1304 /* Save any pressed keys. This is necessary to avoid "stuck"
1305 * keys after a restore. Needs two passes.
1306 */
1307 for (unsigned i = 0; i < sizeof(pThis->abDepressedKeys); ++i)
1308 if (pThis->abDepressedKeys[i])
1309 ++cPressed;
1310
1311 SSMR3PutU32(pSSM, cPressed);
1312
1313 for (unsigned i = 0; i < sizeof(pThis->abDepressedKeys); ++i)
1314 if (pThis->abDepressedKeys[i])
1315 SSMR3PutU8(pSSM, pThis->abDepressedKeys[i]);
1316
1317 /* Save the typematic settings for Scan Set 3. */
1318 SSMR3PutU32(pSSM, cbTMSSize);
1319 /* Currently not implemented. */
1320}
1321
1322int PS2KLoadState(PPS2K pThis, PSSMHANDLE pSSM, uint32_t uVersion)
1323{
1324 uint8_t u8;
1325 uint32_t cPressed;
1326 uint32_t cbTMSSize;
1327 int rc;
1328
1329 NOREF(uVersion);
1330 LogFlowFunc(("Loading PS2K state version %u\n", uVersion));
1331
1332 /* Load the basic keyboard state. */
1333 SSMR3GetU8(pSSM, &pThis->u8CurrCmd);
1334 SSMR3GetU8(pSSM, &pThis->u8LEDs);
1335 SSMR3GetU8(pSSM, &pThis->u8Typematic);
1336 SSMR3GetU8(pSSM, &pThis->u8TypematicKey);
1337 SSMR3GetU8(pSSM, &pThis->u8Modifiers);
1338 SSMR3GetU8(pSSM, &pThis->u8ScanSet);
1339 SSMR3GetU8(pSSM, &u8);
1340 pThis->enmTypematicState = (tmatic_state_t)u8;
1341 SSMR3GetBool(pSSM, &pThis->fNumLockOn);
1342 SSMR3GetBool(pSSM, &pThis->fScanning);
1343
1344 /* Load the command and keystroke queues. */
1345 rc = ps2kLoadQueue(pSSM, (GeneriQ *)&pThis->cmdQ);
1346 AssertRCReturn(rc, rc);
1347 rc = ps2kLoadQueue(pSSM, (GeneriQ *)&pThis->keyQ);
1348 AssertRCReturn(rc, rc);
1349
1350 /* Load the command delay timer, just in case. */
1351 rc = TMR3TimerLoad(pThis->CTX_SUFF(pKbdDelayTimer), pSSM);
1352 AssertRCReturn(rc, rc);
1353
1354 /* Fake key up events for keys that were held down at the time the state was saved. */
1355 rc = SSMR3GetU32(pSSM, &cPressed);
1356 AssertRCReturn(rc, rc);
1357
1358 while (cPressed--)
1359 {
1360 rc = SSMR3GetU8(pSSM, &u8);
1361 AssertRCReturn(rc, rc);
1362 psk2ProcessKeyEvent(pThis, u8, false /* key up */);
1363 }
1364
1365 /* Load typematic settings for Scan Set 3. */
1366 rc = SSMR3GetU32(pSSM, &cbTMSSize);
1367 AssertRCReturn(rc, rc);
1368
1369 while (cbTMSSize--)
1370 {
1371 rc = SSMR3GetU8(pSSM, &u8);
1372 AssertRCReturn(rc, rc);
1373 }
1374
1375 return rc;
1376}
1377
1378void PS2KReset(PPS2K pThis)
1379{
1380 LogFlowFunc(("Resetting PS2K\n"));
1381
1382 pThis->fScanning = true;
1383 pThis->u8ScanSet = 2;
1384 pThis->u8CurrCmd = 0;
1385 pThis->u8Modifiers = 0;
1386 pThis->u8TypematicKey = 0;
1387 pThis->enmTypematicState = KBD_TMS_IDLE;
1388
1389 /* Clear queues and any pressed keys. */
1390 memset(pThis->abDepressedKeys, 0, sizeof(pThis->abDepressedKeys));
1391 ps2kClearQueue((GeneriQ *)&pThis->cmdQ);
1392 ps2kSetDefaults(pThis); /* Also clears keystroke queue. */
1393
1394 /* Activate the PS/2 keyboard by default. */
1395 if (pThis->Keyboard.pDrv)
1396 pThis->Keyboard.pDrv->pfnSetActive(pThis->Keyboard.pDrv, true);
1397}
1398
1399void PS2KRelocate(PPS2K pThis, RTGCINTPTR offDelta, PPDMDEVINS pDevIns)
1400{
1401 LogFlowFunc(("Relocating PS2K\n"));
1402 pThis->pKbdDelayTimerRC = TMTimerRCPtr(pThis->pKbdDelayTimerR3);
1403 pThis->pKbdTypematicTimerRC = TMTimerRCPtr(pThis->pKbdTypematicTimerR3);
1404 NOREF(offDelta);
1405}
1406
1407int PS2KConstruct(PPS2K pThis, PPDMDEVINS pDevIns, void *pParent, int iInstance)
1408{
1409 int rc;
1410
1411 LogFlowFunc(("iInstance=%d\n", iInstance));
1412
1413 pThis->pParent = pParent;
1414
1415 /* Initialize the queues. */
1416 pThis->keyQ.cSize = KBD_KEY_QUEUE_SIZE;
1417 pThis->cmdQ.cSize = KBD_CMD_QUEUE_SIZE;
1418
1419 pThis->Keyboard.IBase.pfnQueryInterface = ps2kQueryInterface;
1420 pThis->Keyboard.IPort.pfnPutEvent = ps2kPutEventWrapper;
1421
1422 /*
1423 * Initialize the critical section pointer(s).
1424 */
1425 pThis->pCritSectR3 = pDevIns->pCritSectRoR3;
1426
1427 /*
1428 * Create the typematic delay/repeat timer. Does not use virtual time!
1429 */
1430 PTMTIMER pTimer;
1431 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_REAL, ps2kTypematicTimer, pThis,
1432 TMTIMER_FLAGS_NO_CRIT_SECT, "PS2K Typematic Timer", &pTimer);
1433 if (RT_FAILURE(rc))
1434 return rc;
1435
1436 pThis->pKbdTypematicTimerR3 = pTimer;
1437 pThis->pKbdTypematicTimerR0 = TMTimerR0Ptr(pTimer);
1438 pThis->pKbdTypematicTimerRC = TMTimerRCPtr(pTimer);
1439
1440 /*
1441 * Create the command delay timer.
1442 */
1443 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ps2kDelayTimer, pThis,
1444 TMTIMER_FLAGS_NO_CRIT_SECT, "PS2K Delay Timer", &pTimer);
1445 if (RT_FAILURE(rc))
1446 return rc;
1447
1448 pThis->pKbdDelayTimerR3 = pTimer;
1449 pThis->pKbdDelayTimerR0 = TMTimerR0Ptr(pTimer);
1450 pThis->pKbdDelayTimerRC = TMTimerRCPtr(pTimer);
1451
1452 /*
1453 * Register debugger info callbacks.
1454 */
1455 PDMDevHlpDBGFInfoRegister(pDevIns, "ps2k", "Display PS/2 keyboard state.", ps2kInfoState);
1456
1457 return rc;
1458}
1459
1460#endif
1461
1462///@todo The following should live with the KBC implementation.
1463
1464/* Table used by the keyboard controller to optionally translate the incoming
1465 * keyboard data. Note that the translation is designed for essentially taking
1466 * Scan Set 2 input and producing Scan Set 1 output, but can be turned on and
1467 * off regardless of what the keyboard is sending.
1468 */
1469static uint8_t aAT2PC[128] = {
1470 0xff,0x43,0x41,0x3f,0x3d,0x3b,0x3c,0x58,0x64,0x44,0x42,0x40,0x3e,0x0f,0x29,0x59,
1471 0x65,0x38,0x2a,0x70,0x1d,0x10,0x02,0x5a,0x66,0x71,0x2c,0x1f,0x1e,0x11,0x03,0x5b,
1472 0x67,0x2e,0x2d,0x20,0x12,0x05,0x04,0x5c,0x68,0x39,0x2f,0x21,0x14,0x13,0x06,0x5d,
1473 0x69,0x31,0x30,0x23,0x22,0x15,0x07,0x5e,0x6a,0x72,0x32,0x24,0x16,0x08,0x09,0x5f,
1474 0x6b,0x33,0x25,0x17,0x18,0x0b,0x0a,0x60,0x6c,0x34,0x35,0x26,0x27,0x19,0x0c,0x61,
1475 0x6d,0x73,0x28,0x74,0x1a,0x0d,0x62,0x6e,0x3a,0x36,0x1c,0x1b,0x75,0x2b,0x63,0x76,
1476 0x55,0x56,0x77,0x78,0x79,0x7a,0x0e,0x7b,0x7c,0x4f,0x7d,0x4b,0x47,0x7e,0x7f,0x6f,
1477 0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x54
1478};
1479
1480/**
1481 * Convert an AT (Scan Set 2) scancode to PC (Scan Set 1).
1482 *
1483 * @param state Current state of the translator
1484 * (xlat_state_t).
1485 * @param scanIn Incoming scan code.
1486 * @param pScanOut Pointer to outgoing scan code. The
1487 * contents are only valid if returned
1488 * state is not XS_BREAK.
1489 *
1490 * @return xlat_state_t New state of the translator.
1491 */
1492int32_t XlateAT2PC(int32_t state, uint8_t scanIn, uint8_t *pScanOut)
1493{
1494 uint8_t scan_in;
1495 uint8_t scan_out;
1496
1497 Assert(pScanOut);
1498 Assert(state == XS_IDLE || state == XS_BREAK || state == XS_HIBIT);
1499
1500 /* Preprocess the scan code for a 128-entry translation table. */
1501 if (scanIn == 0x83) /* Check for F7 key. */
1502 scan_in = 0x02;
1503 else if (scanIn == 0x84) /* Check for SysRq key. */
1504 scan_in = 0x7f;
1505 else
1506 scan_in = scanIn;
1507
1508 /* Values 0x80 and above are passed through, except for 0xF0
1509 * which indicates a key release.
1510 */
1511 if (scan_in < 0x80)
1512 {
1513 scan_out = aAT2PC[scan_in];
1514 /* Turn into break code if required. */
1515 if (state == XS_BREAK || state == XS_HIBIT)
1516 scan_out |= 0x80;
1517
1518 state = XS_IDLE;
1519 }
1520 else
1521 {
1522 /* NB: F0 E0 10 will be translated to E0 E5 (high bit set on last byte)! */
1523 if (scan_in == 0xF0) /* Check for break code. */
1524 state = XS_BREAK;
1525 else if (state == XS_BREAK)
1526 state = XS_HIBIT; /* Remember the break bit. */
1527 scan_out = scan_in;
1528 }
1529 LogFlowFunc(("scan code %02X translated to %02X; new state is %d\n",
1530 scanIn, scan_out, state));
1531
1532 *pScanOut = scan_out;
1533 return state;
1534}
1535
1536#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
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