VirtualBox

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

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

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

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