VirtualBox

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

Last change on this file since 50962 was 50962, checked in by vboxsync, 11 years ago

Send HID usage codes rather than XT scan codes to keyboard devices, with conversion in driver. See #6026.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.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 /* Also a 'release keys' signal. */
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 (Note 3) */
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/*
436 * Note 1: The behavior of these keys depends on the state of modifier keys
437 * at the time the key was pressed.
438 *
439 * Note 2: The key label depends on the national version of the keyboard.
440 *
441 * Note 3: Certain keys which have their own PS/2 scancodes do not exist on
442 * USB keyboards; the SysReq key is an example. The SysReq key scancode needs
443 * to be translated to the Print Screen HID usage code. The HID usage to PS/2
444 * scancode conversion then generates the correct sequence depending on the
445 * keyboard state.
446 */
447
448/* USB to PS/2 conversion table for modifier keys. */
449static const key_def aPS2ModKeys[] = {
450 /* E0 */ {0x1D, 0x14, 0x11, 0, T_B }, /* Key 58: Left Control */
451 /* E1 */ {0x2A, 0x12, 0x12, 0, T_B }, /* Key 44: Left Shift */
452 /* E2 */ {0x38, 0x11, 0x19, 0, T_B }, /* Key 60: Left Alt */
453 /* E3 */ {0x5B, 0x1F, UNKN, KF_E0, T_U }, /* Key 127: Left GUI */
454 /* E4 */ {0x1D, 0x14, 0x58, KF_E0, T_M }, /* Key 64: Right Control */
455 /* E5 */ {0x36, 0x59, 0x59, 0, T_B }, /* Key 57: Right Shift */
456 /* E6 */ {0x38, 0x11, 0x39, KF_E0, T_M }, /* Key 62: Right Alt */
457 /* E7 */ {0x5C, 0x27, UNKN, KF_E0, T_U }, /* Key 128: Right GUI */
458};
459
460/*******************************************************************************
461* Global Variables *
462*******************************************************************************/
463
464/*******************************************************************************
465* Internal Functions *
466*******************************************************************************/
467
468
469/**
470 * Clear a queue.
471 *
472 * @param pQ Pointer to the queue.
473 */
474static void ps2kClearQueue(GeneriQ *pQ)
475{
476 LogFlowFunc(("Clearing queue %p\n", pQ));
477 pQ->wpos = pQ->rpos;
478 pQ->cUsed = 0;
479}
480
481
482/**
483 * Add a byte to a queue.
484 *
485 * @param pQ Pointer to the queue.
486 * @param val The byte to store.
487 */
488static void ps2kInsertQueue(GeneriQ *pQ, uint8_t val)
489{
490 /* Check if queue is full. */
491 if (pQ->cUsed >= pQ->cSize)
492 {
493 LogFlowFunc(("queue %p full (%d entries)\n", pQ, pQ->cUsed));
494 return;
495 }
496 /* Insert data and update circular buffer write position. */
497 pQ->abQueue[pQ->wpos] = val;
498 if (++pQ->wpos == pQ->cSize)
499 pQ->wpos = 0; /* Roll over. */
500 ++pQ->cUsed;
501 LogFlowFunc(("inserted 0x%02X into queue %p\n", val, pQ));
502}
503
504#ifdef IN_RING3
505
506/**
507 * Save a queue state.
508 *
509 * @param pSSM SSM handle to write the state to.
510 * @param pQ Pointer to the queue.
511 */
512static void ps2kSaveQueue(PSSMHANDLE pSSM, GeneriQ *pQ)
513{
514 uint32_t cItems = pQ->cUsed;
515 int i;
516
517 /* Only save the number of items. Note that the read/write
518 * positions aren't saved as they will be rebuilt on load.
519 */
520 SSMR3PutU32(pSSM, cItems);
521
522 LogFlow(("Storing %d items from queue %p\n", cItems, pQ));
523
524 /* Save queue data - only the bytes actually used (typically zero). */
525 for (i = pQ->rpos; cItems-- > 0; i = (i + 1) % pQ->cSize)
526 SSMR3PutU8(pSSM, pQ->abQueue[i]);
527}
528
529/**
530 * Load a queue state.
531 *
532 * @param pSSM SSM handle to read the state from.
533 * @param pQ Pointer to the queue.
534 *
535 * @return int VBox status/error code.
536 */
537static int ps2kLoadQueue(PSSMHANDLE pSSM, GeneriQ *pQ)
538{
539 int rc;
540
541 /* On load, always put the read pointer at zero. */
542 SSMR3GetU32(pSSM, &pQ->cUsed);
543
544 LogFlow(("Loading %d items to queue %p\n", pQ->cUsed, pQ));
545
546 if (pQ->cUsed > pQ->cSize)
547 {
548 AssertMsgFailed(("Saved size=%u, actual=%u\n", pQ->cUsed, pQ->cSize));
549 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
550 }
551
552 /* Recalculate queue positions and load data in one go. */
553 pQ->rpos = 0;
554 pQ->wpos = pQ->cUsed;
555 rc = SSMR3GetMem(pSSM, pQ->abQueue, pQ->cUsed);
556
557 return rc;
558}
559
560#endif /* IN_RING3 */
561
562/**
563 * Retrieve a byte from a queue.
564 *
565 * @param pQ Pointer to the queue.
566 * @param pVal Pointer to storage for the byte.
567 *
568 * @return int VINF_TRY_AGAIN if queue is empty,
569 * VINF_SUCCESS if a byte was read.
570 */
571static int ps2kRemoveQueue(GeneriQ *pQ, uint8_t *pVal)
572{
573 int rc = VINF_TRY_AGAIN;
574
575 Assert(pVal);
576 if (pQ->cUsed)
577 {
578 *pVal = pQ->abQueue[pQ->rpos];
579 if (++pQ->rpos == pQ->cSize)
580 pQ->rpos = 0; /* Roll over. */
581 --pQ->cUsed;
582 rc = VINF_SUCCESS;
583 LogFlowFunc(("removed 0x%02X from queue %p\n", *pVal, pQ));
584 } else
585 LogFlowFunc(("queue %p empty\n", pQ));
586 return rc;
587}
588
589/* Convert encoded typematic value to milliseconds. Note that the values are rated
590 * with +/- 20% accuracy, so there's no need for high precision.
591 */
592static void ps2kSetupTypematic(PPS2K pThis, uint8_t val)
593{
594 int A, B;
595 unsigned period;
596
597 pThis->u8Typematic = val;
598 /* The delay is easy: (1 + value) * 250 ms */
599 pThis->uTypematicDelay = (1 + ((val >> 5) & 3)) * 250;
600 /* The rate is more complicated: (8 + A) * 2^B * 4.17 ms */
601 A = val & 7;
602 B = (val >> 3) & 3;
603 period = (8 + A) * (1 << B) * 417 / 100;
604 pThis->uTypematicRepeat = period;
605 Log(("Typematic delay %u ms, repeat period %u ms\n",
606 pThis->uTypematicDelay, pThis->uTypematicRepeat));
607}
608
609static void ps2kSetDefaults(PPS2K pThis)
610{
611 LogFlowFunc(("Set keyboard defaults\n"));
612 ps2kClearQueue((GeneriQ *)&pThis->keyQ);
613 /* Set default Scan Set 3 typematic values. */
614 /* Set default typematic rate/delay. */
615 ps2kSetupTypematic(pThis, KBD_DFL_RATE_DELAY);
616 /* Clear last typematic key?? */
617}
618
619/**
620 * Receive and process a byte sent by the keyboard controller.
621 *
622 * @param pThis The PS/2 keyboard instance data.
623 * @param cmd The command (or data) byte.
624 */
625int PS2KByteToKbd(PPS2K pThis, uint8_t cmd)
626{
627 bool fHandled = true;
628
629 LogFlowFunc(("new cmd=0x%02X, active cmd=0x%02X\n", cmd, pThis->u8CurrCmd));
630
631 switch (cmd)
632 {
633 case KCMD_ECHO:
634 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ECHO);
635 pThis->u8CurrCmd = 0;
636 break;
637 case KCMD_READ_ID:
638 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
639 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ID1);
640 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ID2);
641 pThis->u8CurrCmd = 0;
642 break;
643 case KCMD_ENABLE:
644 pThis->fScanning = true;
645 ps2kClearQueue((GeneriQ *)&pThis->keyQ);
646 /* Clear last typematic key?? */
647 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
648 pThis->u8CurrCmd = 0;
649 break;
650 case KCMD_DFLT_DISABLE:
651 pThis->fScanning = false;
652 ps2kSetDefaults(pThis);
653 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
654 pThis->u8CurrCmd = 0;
655 break;
656 case KCMD_SET_DEFAULT:
657 ps2kSetDefaults(pThis);
658 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
659 pThis->u8CurrCmd = 0;
660 break;
661 case KCMD_ALL_TYPEMATIC:
662 case KCMD_ALL_MK_BRK:
663 case KCMD_ALL_MAKE:
664 case KCMD_ALL_TMB:
665 ///@todo Set the key types here.
666 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
667 pThis->u8CurrCmd = 0;
668 break;
669 case KCMD_RESEND:
670 pThis->u8CurrCmd = 0;
671 break;
672 case KCMD_RESET:
673 pThis->u8ScanSet = 2;
674 ps2kSetDefaults(pThis);
675 ///@todo reset more?
676 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
677 pThis->u8CurrCmd = cmd;
678 /* Delay BAT completion; the test may take hundreds of ms. */
679 TMTimerSetMillies(pThis->CTX_SUFF(pKbdDelayTimer), 2);
680 break;
681 /* The following commands need a parameter. */
682 case KCMD_LEDS:
683 case KCMD_SCANSET:
684 case KCMD_RATE_DELAY:
685 case KCMD_TYPE_MATIC:
686 case KCMD_TYPE_MK_BRK:
687 case KCMD_TYPE_MAKE:
688 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
689 pThis->u8CurrCmd = cmd;
690 break;
691 default:
692 /* Sending a command instead of a parameter starts the new command. */
693 switch (pThis->u8CurrCmd)
694 {
695 case KCMD_LEDS:
696#ifndef IN_RING3
697 return VINF_IOM_R3_IOPORT_WRITE;
698#else
699 {
700 PDMKEYBLEDS enmLeds = PDMKEYBLEDS_NONE;
701
702 if (cmd & 0x01)
703 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_SCROLLLOCK);
704 if (cmd & 0x02)
705 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_NUMLOCK);
706 if (cmd & 0x04)
707 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_CAPSLOCK);
708 pThis->Keyboard.pDrv->pfnLedStatusChange(pThis->Keyboard.pDrv, enmLeds);
709 pThis->fNumLockOn = !!(cmd & 0x02); /* Sync internal Num Lock state. */
710 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
711 pThis->u8LEDs = cmd;
712 pThis->u8CurrCmd = 0;
713 }
714#endif
715 break;
716 case KCMD_SCANSET:
717 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
718 if (cmd == 0)
719 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, pThis->u8ScanSet);
720 else if (cmd < 4)
721 {
722 pThis->u8ScanSet = cmd;
723 LogRel(("PS2K: Selected scan set %d.\n", cmd));
724 }
725 /* Other values are simply ignored. */
726 pThis->u8CurrCmd = 0;
727 break;
728 case KCMD_RATE_DELAY:
729 ps2kSetupTypematic(pThis, cmd);
730 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_ACK);
731 pThis->u8CurrCmd = 0;
732 break;
733 default:
734 fHandled = false;
735 }
736 /* Fall through only to handle unrecognized commands. */
737 if (fHandled)
738 break;
739
740 case KCMD_INVALID_1:
741 case KCMD_INVALID_2:
742 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_RESEND);
743 pThis->u8CurrCmd = 0;
744 break;
745 }
746 LogFlowFunc(("Active cmd now 0x%02X; updating interrupts\n", pThis->u8CurrCmd));
747// KBCUpdateInterrupts(pThis->pParent);
748 return VINF_SUCCESS;
749}
750
751/**
752 * Send a byte (keystroke or command response) to the keyboard controller.
753 *
754 * @returns VINF_SUCCESS or VINF_TRY_AGAIN.
755 * @param pThis The PS/2 keyboard instance data.
756 * @param pb Where to return the byte we've read.
757 * @remarks Caller must have entered the device critical section.
758 */
759int PS2KByteFromKbd(PPS2K pThis, uint8_t *pb)
760{
761 int rc;
762
763 AssertPtr(pb);
764
765 /* Anything in the command queue has priority over data
766 * in the keystroke queue. Additionally, keystrokes are
767 * blocked if a command is currently in progress, even if
768 * the command queue is empty.
769 */
770 rc = ps2kRemoveQueue((GeneriQ *)&pThis->cmdQ, pb);
771 if (rc != VINF_SUCCESS && !pThis->u8CurrCmd && pThis->fScanning)
772 rc = ps2kRemoveQueue((GeneriQ *)&pThis->keyQ, pb);
773
774 LogFlowFunc(("keyboard sends 0x%02x (%svalid data)\n", *pb, rc == VINF_SUCCESS ? "" : "not "));
775 return rc;
776}
777
778#ifdef IN_RING3
779
780static int ps2kProcessKeyEvent(PPS2K pThis, uint8_t u8HidCode, bool fKeyDown)
781{
782 unsigned int i = 0;
783 key_def const *pKeyDef;
784 uint8_t abCodes[16];
785 uint8_t u8MakeCode;
786
787 LogFlowFunc(("key %s: 0x%02x (set %d)\n", fKeyDown ? "down" : "up", u8HidCode, pThis->u8ScanSet));
788
789 /* Find the key definition in somewhat sparse storage. */
790 pKeyDef = u8HidCode >= HID_MODIFIER_FIRST ? &aPS2ModKeys[u8HidCode - HID_MODIFIER_FIRST] : &aPS2Keys[u8HidCode];
791
792 /* Some keys are not processed at all; early return. */
793 if (pKeyDef->makeS1 == NONE)
794 {
795 LogFlow(("Skipping key processing.\n"));
796 return VINF_SUCCESS;
797 }
798
799 /* Handle modifier keys (Ctrl/Alt/Shift/GUI). We need to keep track
800 * of their state in addition to sending the scan code.
801 */
802 if (u8HidCode >= HID_MODIFIER_FIRST)
803 {
804 unsigned mod_bit = 1 << (u8HidCode - HID_MODIFIER_FIRST);
805
806 Assert((u8HidCode <= HID_MODIFIER_LAST));
807 if (fKeyDown)
808 pThis->u8Modifiers |= mod_bit;
809 else
810 pThis->u8Modifiers &= ~mod_bit;
811 }
812
813 /* Toggle NumLock state. */
814 if ((pKeyDef->keyFlags & KF_NL) && fKeyDown)
815 pThis->fNumLockOn ^= true;
816
817 if (pThis->u8ScanSet == 1 || pThis->u8ScanSet == 2)
818 {
819 /* The basic scan set 1 and 2 logic is the same, only the scan codes differ.
820 * Since scan set 2 is used almost all the time, that case is handled first.
821 */
822 abCodes[0] = 0;
823 if (fKeyDown)
824 {
825 /* Process key down event. */
826 if (pKeyDef->keyFlags & KF_PB)
827 {
828 /* Pause/Break sends different data if either Ctrl is held. */
829 if (pThis->u8Modifiers & (MOD_LCTRL | MOD_RCTRL))
830 strcpy((char *)abCodes, pThis->u8ScanSet == 2 ?
831 "\xE0\x7E\xE0\xF0\x7E" : "\xE0\x46\xE0\xC6");
832 else
833 strcpy((char *)abCodes, pThis->u8ScanSet == 2 ?
834 "\xE1\x14\x77\xE1\xF0\x14\xF0\x77" : "\xE1\x1D\x45\xE1\x9D\xC5");
835 }
836 else if (pKeyDef->keyFlags & KF_PS)
837 {
838 /* Print Screen depends on all of Ctrl, Shift, *and* Alt! */
839 if (pThis->u8Modifiers & (MOD_LALT | MOD_RALT))
840 strcpy((char *)abCodes, pThis->u8ScanSet == 2 ?
841 "\x84" : "\x54");
842 else if (pThis->u8Modifiers & (MOD_LSHIFT | MOD_RSHIFT))
843 strcpy((char *)abCodes, pThis->u8ScanSet == 2 ?
844 "\xE0\x7C" : "\xE0\x37");
845 else
846 strcpy((char *)abCodes, pThis->u8ScanSet == 2 ?
847 "\xE0\x12\xE0\x7C" : "\xE0\x2A\xE0\x37");
848 }
849 else if (pKeyDef->keyFlags & (KF_GK | KF_NS))
850 {
851 /* The numeric pad keys fake Shift presses or releases
852 * depending on Num Lock and Shift key state. The '/'
853 * key behaves in a similar manner but does not depend on
854 * the Num Lock state.
855 */
856 if (!pThis->fNumLockOn || (pKeyDef->keyFlags & KF_NS))
857 {
858 if (pThis->u8Modifiers & MOD_LSHIFT)
859 strcat((char *)abCodes, pThis->u8ScanSet == 2 ?
860 "\xE0\xF0\x12" : "\xE0\xAA");
861 if (pThis->u8Modifiers & MOD_RSHIFT)
862 strcat((char *)abCodes, pThis->u8ScanSet == 2 ?
863 "\xE0\xF0\x59" : "\xE0\xB6");
864 }
865 else
866 {
867 Assert(pThis->fNumLockOn); /* Not for KF_NS! */
868 if ((pThis->u8Modifiers & (MOD_LSHIFT | MOD_RSHIFT)) == 0)
869 strcpy((char *)abCodes, pThis->u8ScanSet == 2 ?
870 "\xE0\x12" : "\xE0\x2A");
871 /* Else Shift cancels NumLock, so no prefix! */
872 }
873 }
874 /* Feed the bytes to the queue if there is room. */
875 ///@todo check empty space!
876 while (abCodes[i])
877 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, abCodes[i++]);
878 Assert(i < sizeof(abCodes));
879
880 /* Standard processing for regular keys only. */
881 u8MakeCode = pThis->u8ScanSet == 2 ? pKeyDef->makeS2 : pKeyDef->makeS1;
882 if (!(pKeyDef->keyFlags & (KF_PB | KF_PS)))
883 {
884 if (pKeyDef->keyFlags & (KF_E0 | KF_GK | KF_NS))
885 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, 0xE0);
886 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, u8MakeCode);
887 }
888 }
889 else if (!(pKeyDef->keyFlags & (KF_NB | KF_PB)))
890 {
891 /* Process key up event except for keys which produce none. */
892
893 /* Handle Print Screen release. */
894 if (pKeyDef->keyFlags & KF_PS)
895 {
896 /* Undo faked Print Screen state as needed. */
897 if (pThis->u8Modifiers & (MOD_LALT | MOD_RALT))
898 strcpy((char *)abCodes, pThis->u8ScanSet == 2 ?
899 "\xF0\x84" : "\xD4");
900 else if (pThis->u8Modifiers & (MOD_LSHIFT | MOD_RSHIFT))
901 strcpy((char *)abCodes, pThis->u8ScanSet == 2 ?
902 "\xE0\xF0\x7C" : "\xE0\xB7");
903 else
904 strcpy((char *)abCodes, pThis->u8ScanSet == 2 ?
905 "\xE0\xF0\x7C\xE0\xF0\x12" : "\xE0\xB7\xE0\xAA");
906 }
907 else
908 {
909 /* Process base scan code for less unusual keys. */
910 if (pKeyDef->keyFlags & (KF_E0 | KF_GK | KF_NS))
911 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, 0xE0);
912 if (pThis->u8ScanSet == 2) {
913 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, 0xF0);
914 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS2);
915 } else {
916 Assert(pThis->u8ScanSet == 1);
917 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS1 | 0x80);
918 }
919
920 /* Restore shift state for gray keys. */
921 if (pKeyDef->keyFlags & (KF_GK | KF_NS))
922 {
923 if (!pThis->fNumLockOn || (pKeyDef->keyFlags & KF_NS))
924 {
925 if (pThis->u8Modifiers & MOD_LSHIFT)
926 strcat((char *)abCodes, pThis->u8ScanSet == 2 ?
927 "\xE0\x12" : "\xE0\x2A");
928 if (pThis->u8Modifiers & MOD_RSHIFT)
929 strcat((char *)abCodes, pThis->u8ScanSet == 2 ?
930 "\xE0\x59" : "\xE0\x36");
931 }
932 else
933 {
934 Assert(pThis->fNumLockOn); /* Not for KF_NS! */
935 if ((pThis->u8Modifiers & (MOD_LSHIFT | MOD_RSHIFT)) == 0)
936 strcpy((char *)abCodes, pThis->u8ScanSet == 2 ?
937 "\xE0\xF0\x12" : "\xE0\xAA");
938 }
939 }
940 }
941
942 /* Feed any additional bytes to the queue if there is room. */
943 ///@todo check empty space!
944 while (abCodes[i])
945 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, abCodes[i++]);
946 Assert(i < sizeof(abCodes));
947 }
948 }
949 else
950 {
951 /* Handle Scan Set 3 - very straightforward. */
952 Assert(pThis->u8ScanSet == 3);
953 if (fKeyDown)
954 {
955 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS3);
956 }
957 else
958 {
959 /* Send a key release code unless it's a make only key. */
960 ///@todo Look up the current typematic setting, not the default!
961 if (pKeyDef->keyMatic != T_M)
962 {
963 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, 0xF0);
964 ps2kInsertQueue((GeneriQ *)&pThis->keyQ, pKeyDef->makeS3);
965 }
966 }
967 }
968
969 /* Set up or cancel typematic key repeat. */
970 if (fKeyDown)
971 {
972 if (pThis->u8TypematicKey != u8HidCode)
973 {
974 pThis->enmTypematicState = KBD_TMS_DELAY;
975 pThis->u8TypematicKey = u8HidCode;
976 TMTimerSetMillies(pThis->CTX_SUFF(pKbdTypematicTimer), pThis->uTypematicDelay);
977 Log(("Typematic delay %u ms, key %02X\n", pThis->uTypematicDelay, u8HidCode));
978 }
979 }
980 else
981 {
982 pThis->u8TypematicKey = 0;
983 pThis->enmTypematicState = KBD_TMS_IDLE;
984 ///@todo Cancel timer right away?
985 ///@todo Cancel timer before pushing key up code!?
986 }
987
988 /* Poke the KBC to update its state. */
989 KBCUpdateInterrupts(pThis->pParent);
990
991 return VINF_SUCCESS;
992}
993
994/* Timer handler for emulating typematic keys. Note that only the last key
995 * held down repeats (if typematic).
996 */
997static DECLCALLBACK(void) ps2kTypematicTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
998{
999 PPS2K pThis = (PS2K *)pvUser; NOREF(pDevIns);
1000 LogFlowFunc(("Typematic state=%d, key %02X\n", pThis->enmTypematicState, pThis->u8TypematicKey));
1001
1002 /* If the current typematic key is zero, the repeat was canceled just when
1003 * the timer was about to run. In that case, do nothing.
1004 */
1005 if (pThis->u8TypematicKey)
1006 {
1007 if (pThis->enmTypematicState == KBD_TMS_DELAY)
1008 pThis->enmTypematicState = KBD_TMS_REPEAT;
1009
1010 if (pThis->enmTypematicState == KBD_TMS_REPEAT)
1011 {
1012 ps2kProcessKeyEvent(pThis, pThis->u8TypematicKey, true /* Key down */ );
1013 TMTimerSetMillies(pThis->CTX_SUFF(pKbdTypematicTimer), pThis->uTypematicRepeat);
1014 }
1015 }
1016}
1017
1018/* The keyboard BAT is specified to take several hundred milliseconds. We need
1019 * to delay sending the result to the host for at least a tiny little while.
1020 */
1021static DECLCALLBACK(void) ps2kDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1022{
1023 PPS2K pThis = (PS2K *)pvUser; NOREF(pDevIns);
1024
1025 LogFlowFunc(("Delay timer: cmd %02X\n", pThis->u8CurrCmd));
1026
1027 Assert(pThis->u8CurrCmd == KCMD_RESET);
1028 ps2kInsertQueue((GeneriQ *)&pThis->cmdQ, KRSP_BAT_OK);
1029 pThis->fScanning = true; /* BAT completion enables scanning! */
1030 pThis->u8CurrCmd = 0;
1031
1032 ///@todo Might want a PS2KCompleteCommand() to push last response, clear command, and kick the KBC...
1033 /* Give the KBC a kick. */
1034 KBCUpdateInterrupts(pThis->pParent);
1035}
1036
1037/* Release any and all currently depressed keys. Used whenever the guest keyboard
1038 * is likely to be out of sync with the host, such as when loading a saved state
1039 * or resuming a suspended host.
1040 */
1041static void ps2kReleaseKeys(PPS2K pThis)
1042{
1043 LogFlowFunc(("Releasing keys...\n"));
1044
1045 for (unsigned uKey = 0; uKey < sizeof(pThis->abDepressedKeys); ++uKey)
1046 if (pThis->abDepressedKeys[uKey])
1047 {
1048 ps2kProcessKeyEvent(pThis, uKey, false /* key up */);
1049 pThis->abDepressedKeys[uKey] = 0;
1050 }
1051 LogFlowFunc(("Done releasing keys\n"));
1052}
1053
1054
1055/**
1056 * Debug device info handler. Prints basic keyboard state.
1057 *
1058 * @param pDevIns Device instance which registered the info.
1059 * @param pHlp Callback functions for doing output.
1060 * @param pszArgs Argument string. Optional and specific to the handler.
1061 */
1062static DECLCALLBACK(void) ps2kInfoState(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
1063{
1064 PPS2K pThis = KBDGetPS2KFromDevIns(pDevIns);
1065 NOREF(pszArgs);
1066
1067 pHlp->pfnPrintf(pHlp, "PS/2 Keyboard: scan set %d, scanning %s\n",
1068 pThis->u8ScanSet, pThis->fScanning ? "enabled" : "disabled");
1069 pHlp->pfnPrintf(pHlp, "Active command %02X\n", pThis->u8CurrCmd);
1070 pHlp->pfnPrintf(pHlp, "LED state %02X, Num Lock %s\n", pThis->u8LEDs,
1071 pThis->fNumLockOn ? "on" : "off");
1072 pHlp->pfnPrintf(pHlp, "Typematic delay %ums, repeat period %ums\n",
1073 pThis->uTypematicDelay, pThis->uTypematicRepeat);
1074 pHlp->pfnPrintf(pHlp, "Command queue: %d items (%d max)\n",
1075 pThis->cmdQ.cUsed, pThis->cmdQ.cSize);
1076 pHlp->pfnPrintf(pHlp, "Input queue : %d items (%d max)\n",
1077 pThis->keyQ.cUsed, pThis->keyQ.cSize);
1078 if (pThis->enmTypematicState != KBD_TMS_IDLE)
1079 pHlp->pfnPrintf(pHlp, "Active typematic key %02X (%s)\n", pThis->u8Typematic,
1080 pThis->enmTypematicState == KBD_TMS_DELAY ? "delay" : "repeat");
1081}
1082
1083/* -=-=-=-=-=- Keyboard: IBase -=-=-=-=-=- */
1084
1085/**
1086 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1087 */
1088static DECLCALLBACK(void *) ps2kQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1089{
1090 PPS2K pThis = RT_FROM_MEMBER(pInterface, PS2K, Keyboard.IBase);
1091 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Keyboard.IBase);
1092 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIKEYBOARDPORT, &pThis->Keyboard.IPort);
1093 return NULL;
1094}
1095
1096
1097/* -=-=-=-=-=- Keyboard: IKeyboardPort -=-=-=-=-=- */
1098
1099/**
1100 * Keyboard event handler.
1101 *
1102 * @returns VBox status code.
1103 * @param pThis The PS2 keyboard instance data.
1104 * @param u32Usage USB HID usage code with key
1105 * press/release flag.
1106 */
1107static int ps2kPutEventWorker(PPS2K pThis, uint32_t u32Usage)
1108{
1109 uint8_t u8HidCode;
1110 bool fKeyDown;
1111 bool fHaveEvent = true;
1112 int rc = VINF_SUCCESS;
1113
1114 /* Extract the usage code and ensure it's valid. */
1115 fKeyDown = !(u32Usage & 0x80000000);
1116 u8HidCode = u32Usage & 0xFF;
1117 AssertReturn(u8HidCode <= VBOX_USB_MAX_USAGE_CODE, VERR_INTERNAL_ERROR);
1118
1119 if (fKeyDown)
1120 {
1121 /* Due to host key repeat, we can get key events for keys which are
1122 * already depressed. We need to ignore those. */
1123 if (pThis->abDepressedKeys[u8HidCode])
1124 fHaveEvent = false;
1125 pThis->abDepressedKeys[u8HidCode] = 1;
1126 }
1127 else
1128 {
1129 /* NB: We allow key release events for keys which aren't depressed.
1130 * That is unlikely to happen and should not cause trouble.
1131 */
1132 pThis->abDepressedKeys[u8HidCode] = 0;
1133 }
1134
1135 /* Unless this is a new key press/release, don't even bother. */
1136 if (fHaveEvent)
1137 {
1138 rc = PDMCritSectEnter(pThis->pCritSectR3, VERR_SEM_BUSY);
1139 AssertReleaseRC(rc);
1140
1141 rc = ps2kProcessKeyEvent(pThis, u8HidCode, fKeyDown);
1142
1143 PDMCritSectLeave(pThis->pCritSectR3);
1144 }
1145
1146 return rc;
1147}
1148
1149static DECLCALLBACK(int) ps2kPutEventWrapper(PPDMIKEYBOARDPORT pInterface, uint32_t u32UsageCode)
1150{
1151 PPS2K pThis = RT_FROM_MEMBER(pInterface, PS2K, Keyboard.IPort);
1152 int rc;
1153
1154 LogFlowFunc(("key code %08X\n", u32UsageCode));
1155
1156 rc = PDMCritSectEnter(pThis->pCritSectR3, VERR_SEM_BUSY);
1157 AssertReleaseRC(rc);
1158
1159 /* The 'BAT fail' scancode is reused as a signal to release keys. No actual
1160 * key is allowed to use this scancode.
1161 */
1162 if (RT_UNLIKELY(u32UsageCode == KRSP_BAT_FAIL))
1163 {
1164 ps2kReleaseKeys(pThis);
1165 }
1166 else
1167 {
1168 /* Stupid Korean key hack: convert a lone break key into a press/release sequence. */
1169 if (u32UsageCode == 0x80000090 || u32UsageCode == 0x80000091)
1170 ps2kPutEventWorker(pThis, u32UsageCode & ~0x80000000);
1171
1172 ps2kPutEventWorker(pThis, u32UsageCode);
1173 }
1174
1175 PDMCritSectLeave(pThis->pCritSectR3);
1176
1177 return VINF_SUCCESS;
1178}
1179
1180
1181/**
1182 * Attach command.
1183 *
1184 * This is called to let the device attach to a driver for a
1185 * specified LUN.
1186 *
1187 * This is like plugging in the keyboard after turning on the
1188 * system.
1189 *
1190 * @returns VBox status code.
1191 * @param pThis The PS/2 keyboard instance data.
1192 * @param pDevIns The device instance.
1193 * @param iLUN The logical unit which is being detached.
1194 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1195 */
1196int PS2KAttach(PPS2K pThis, PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1197{
1198 int rc;
1199
1200 /* The LUN must be 0, i.e. keyboard. */
1201 Assert(iLUN == 0);
1202 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
1203 ("PS/2 keyboard does not support hotplugging\n"),
1204 VERR_INVALID_PARAMETER);
1205
1206 LogFlowFunc(("iLUN=%d\n", iLUN));
1207
1208 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->Keyboard.IBase, &pThis->Keyboard.pDrvBase, "Keyboard Port");
1209 if (RT_SUCCESS(rc))
1210 {
1211 pThis->Keyboard.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Keyboard.pDrvBase, PDMIKEYBOARDCONNECTOR);
1212 if (!pThis->Keyboard.pDrv)
1213 {
1214 AssertLogRelMsgFailed(("LUN #0 doesn't have a keyboard interface! rc=%Rrc\n", rc));
1215 rc = VERR_PDM_MISSING_INTERFACE;
1216 }
1217 }
1218 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1219 {
1220 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pReg->szName, pDevIns->iInstance));
1221 rc = VINF_SUCCESS;
1222 }
1223 else
1224 AssertLogRelMsgFailed(("Failed to attach LUN #0! rc=%Rrc\n", rc));
1225
1226 return rc;
1227}
1228
1229void PS2KSaveState(PPS2K pThis, PSSMHANDLE pSSM)
1230{
1231 uint32_t cPressed = 0;
1232 uint32_t cbTMSSize = 0;
1233
1234 LogFlowFunc(("Saving PS2K state\n"));
1235
1236 /* Save the basic keyboard state. */
1237 SSMR3PutU8(pSSM, pThis->u8CurrCmd);
1238 SSMR3PutU8(pSSM, pThis->u8LEDs);
1239 SSMR3PutU8(pSSM, pThis->u8Typematic);
1240 SSMR3PutU8(pSSM, pThis->u8TypematicKey);
1241 SSMR3PutU8(pSSM, pThis->u8Modifiers);
1242 SSMR3PutU8(pSSM, pThis->u8ScanSet);
1243 SSMR3PutU8(pSSM, pThis->enmTypematicState);
1244 SSMR3PutBool(pSSM, pThis->fNumLockOn);
1245 SSMR3PutBool(pSSM, pThis->fScanning);
1246
1247 /* Save the command and keystroke queues. */
1248 ps2kSaveQueue(pSSM, (GeneriQ *)&pThis->cmdQ);
1249 ps2kSaveQueue(pSSM, (GeneriQ *)&pThis->keyQ);
1250
1251 /* Save the command delay timer. Note that the typematic repeat
1252 * timer is *not* saved.
1253 */
1254 TMR3TimerSave(pThis->CTX_SUFF(pKbdDelayTimer), pSSM);
1255
1256 /* Save any pressed keys. This is necessary to avoid "stuck"
1257 * keys after a restore. Needs two passes.
1258 */
1259 for (unsigned i = 0; i < sizeof(pThis->abDepressedKeys); ++i)
1260 if (pThis->abDepressedKeys[i])
1261 ++cPressed;
1262
1263 SSMR3PutU32(pSSM, cPressed);
1264
1265 for (unsigned uKey = 0; uKey < sizeof(pThis->abDepressedKeys); ++uKey)
1266 if (pThis->abDepressedKeys[uKey])
1267 SSMR3PutU8(pSSM, uKey);
1268
1269 /* Save the typematic settings for Scan Set 3. */
1270 SSMR3PutU32(pSSM, cbTMSSize);
1271 /* Currently not implemented. */
1272}
1273
1274int PS2KLoadState(PPS2K pThis, PSSMHANDLE pSSM, uint32_t uVersion)
1275{
1276 uint8_t u8;
1277 uint32_t cPressed;
1278 uint32_t cbTMSSize;
1279 int rc;
1280
1281 NOREF(uVersion);
1282 LogFlowFunc(("Loading PS2K state version %u\n", uVersion));
1283
1284 /* Load the basic keyboard state. */
1285 SSMR3GetU8(pSSM, &pThis->u8CurrCmd);
1286 SSMR3GetU8(pSSM, &pThis->u8LEDs);
1287 SSMR3GetU8(pSSM, &pThis->u8Typematic);
1288 SSMR3GetU8(pSSM, &pThis->u8TypematicKey);
1289 SSMR3GetU8(pSSM, &pThis->u8Modifiers);
1290 SSMR3GetU8(pSSM, &pThis->u8ScanSet);
1291 SSMR3GetU8(pSSM, &u8);
1292 pThis->enmTypematicState = (tmatic_state_t)u8;
1293 SSMR3GetBool(pSSM, &pThis->fNumLockOn);
1294 SSMR3GetBool(pSSM, &pThis->fScanning);
1295
1296 /* Load the command and keystroke queues. */
1297 rc = ps2kLoadQueue(pSSM, (GeneriQ *)&pThis->cmdQ);
1298 AssertRCReturn(rc, rc);
1299 rc = ps2kLoadQueue(pSSM, (GeneriQ *)&pThis->keyQ);
1300 AssertRCReturn(rc, rc);
1301
1302 /* Load the command delay timer, just in case. */
1303 rc = TMR3TimerLoad(pThis->CTX_SUFF(pKbdDelayTimer), pSSM);
1304 AssertRCReturn(rc, rc);
1305
1306 /* Recalculate the typematic delay/rate. */
1307 ps2kSetupTypematic(pThis, pThis->u8Typematic);
1308
1309 /* Fake key up events for keys that were held down at the time the state was saved. */
1310 rc = SSMR3GetU32(pSSM, &cPressed);
1311 AssertRCReturn(rc, rc);
1312
1313 /* If any keys were down, load and then release them. */
1314 if (cPressed)
1315 {
1316 for (unsigned i = 0; i < cPressed; ++i)
1317 {
1318 rc = SSMR3GetU8(pSSM, &u8);
1319 AssertRCReturn(rc, rc);
1320 pThis->abDepressedKeys[u8] = 1;
1321 }
1322 }
1323
1324 /* Load typematic settings for Scan Set 3. */
1325 rc = SSMR3GetU32(pSSM, &cbTMSSize);
1326 AssertRCReturn(rc, rc);
1327
1328 while (cbTMSSize--)
1329 {
1330 rc = SSMR3GetU8(pSSM, &u8);
1331 AssertRCReturn(rc, rc);
1332 }
1333
1334 return rc;
1335}
1336
1337int PS2KLoadDone(PPS2K pThis, PSSMHANDLE pSSM)
1338{
1339 /* This *must* be done after the inital load because it may trigger
1340 * interrupts and change the interrupt controller state.
1341 */
1342 ps2kReleaseKeys(pThis);
1343 return VINF_SUCCESS;
1344}
1345
1346void PS2KReset(PPS2K pThis)
1347{
1348 LogFlowFunc(("Resetting PS2K\n"));
1349
1350 pThis->fScanning = true;
1351 pThis->u8ScanSet = 2;
1352 pThis->u8CurrCmd = 0;
1353 pThis->u8Modifiers = 0;
1354 pThis->u8TypematicKey = 0;
1355 pThis->enmTypematicState = KBD_TMS_IDLE;
1356
1357 /* Clear queues and any pressed keys. */
1358 memset(pThis->abDepressedKeys, 0, sizeof(pThis->abDepressedKeys));
1359 ps2kClearQueue((GeneriQ *)&pThis->cmdQ);
1360 ps2kSetDefaults(pThis); /* Also clears keystroke queue. */
1361
1362 /* Activate the PS/2 keyboard by default. */
1363 if (pThis->Keyboard.pDrv)
1364 pThis->Keyboard.pDrv->pfnSetActive(pThis->Keyboard.pDrv, true);
1365}
1366
1367void PS2KRelocate(PPS2K pThis, RTGCINTPTR offDelta, PPDMDEVINS pDevIns)
1368{
1369 LogFlowFunc(("Relocating PS2K\n"));
1370 pThis->pKbdDelayTimerRC = TMTimerRCPtr(pThis->pKbdDelayTimerR3);
1371 pThis->pKbdTypematicTimerRC = TMTimerRCPtr(pThis->pKbdTypematicTimerR3);
1372 NOREF(offDelta);
1373}
1374
1375int PS2KConstruct(PPS2K pThis, PPDMDEVINS pDevIns, void *pParent, int iInstance)
1376{
1377 int rc;
1378
1379 LogFlowFunc(("iInstance=%d\n", iInstance));
1380
1381 pThis->pParent = pParent;
1382
1383 /* Initialize the queues. */
1384 pThis->keyQ.cSize = KBD_KEY_QUEUE_SIZE;
1385 pThis->cmdQ.cSize = KBD_CMD_QUEUE_SIZE;
1386
1387 pThis->Keyboard.IBase.pfnQueryInterface = ps2kQueryInterface;
1388 pThis->Keyboard.IPort.pfnPutEventHid = ps2kPutEventWrapper;
1389
1390 /*
1391 * Initialize the critical section pointer(s).
1392 */
1393 pThis->pCritSectR3 = pDevIns->pCritSectRoR3;
1394
1395 /*
1396 * Create the typematic delay/repeat timer. Does not use virtual time!
1397 */
1398 PTMTIMER pTimer;
1399 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_REAL, ps2kTypematicTimer, pThis,
1400 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "PS2K Typematic Timer", &pTimer);
1401 if (RT_FAILURE(rc))
1402 return rc;
1403
1404 pThis->pKbdTypematicTimerR3 = pTimer;
1405 pThis->pKbdTypematicTimerR0 = TMTimerR0Ptr(pTimer);
1406 pThis->pKbdTypematicTimerRC = TMTimerRCPtr(pTimer);
1407
1408 /*
1409 * Create the command delay timer.
1410 */
1411 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ps2kDelayTimer, pThis,
1412 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "PS2K Delay Timer", &pTimer);
1413 if (RT_FAILURE(rc))
1414 return rc;
1415
1416 pThis->pKbdDelayTimerR3 = pTimer;
1417 pThis->pKbdDelayTimerR0 = TMTimerR0Ptr(pTimer);
1418 pThis->pKbdDelayTimerRC = TMTimerRCPtr(pTimer);
1419
1420 /*
1421 * Register debugger info callbacks.
1422 */
1423 PDMDevHlpDBGFInfoRegister(pDevIns, "ps2k", "Display PS/2 keyboard state.", ps2kInfoState);
1424
1425 return rc;
1426}
1427
1428#endif
1429
1430///@todo The following should live with the KBC implementation.
1431
1432/* Table used by the keyboard controller to optionally translate the incoming
1433 * keyboard data. Note that the translation is designed for essentially taking
1434 * Scan Set 2 input and producing Scan Set 1 output, but can be turned on and
1435 * off regardless of what the keyboard is sending.
1436 */
1437static uint8_t aAT2PC[128] = {
1438 0xff,0x43,0x41,0x3f,0x3d,0x3b,0x3c,0x58,0x64,0x44,0x42,0x40,0x3e,0x0f,0x29,0x59,
1439 0x65,0x38,0x2a,0x70,0x1d,0x10,0x02,0x5a,0x66,0x71,0x2c,0x1f,0x1e,0x11,0x03,0x5b,
1440 0x67,0x2e,0x2d,0x20,0x12,0x05,0x04,0x5c,0x68,0x39,0x2f,0x21,0x14,0x13,0x06,0x5d,
1441 0x69,0x31,0x30,0x23,0x22,0x15,0x07,0x5e,0x6a,0x72,0x32,0x24,0x16,0x08,0x09,0x5f,
1442 0x6b,0x33,0x25,0x17,0x18,0x0b,0x0a,0x60,0x6c,0x34,0x35,0x26,0x27,0x19,0x0c,0x61,
1443 0x6d,0x73,0x28,0x74,0x1a,0x0d,0x62,0x6e,0x3a,0x36,0x1c,0x1b,0x75,0x2b,0x63,0x76,
1444 0x55,0x56,0x77,0x78,0x79,0x7a,0x0e,0x7b,0x7c,0x4f,0x7d,0x4b,0x47,0x7e,0x7f,0x6f,
1445 0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x54
1446};
1447
1448/**
1449 * Convert an AT (Scan Set 2) scancode to PC (Scan Set 1).
1450 *
1451 * @param state Current state of the translator
1452 * (xlat_state_t).
1453 * @param scanIn Incoming scan code.
1454 * @param pScanOut Pointer to outgoing scan code. The
1455 * contents are only valid if returned
1456 * state is not XS_BREAK.
1457 *
1458 * @return xlat_state_t New state of the translator.
1459 */
1460int32_t XlateAT2PC(int32_t state, uint8_t scanIn, uint8_t *pScanOut)
1461{
1462 uint8_t scan_in;
1463 uint8_t scan_out;
1464
1465 Assert(pScanOut);
1466 Assert(state == XS_IDLE || state == XS_BREAK || state == XS_HIBIT);
1467
1468 /* Preprocess the scan code for a 128-entry translation table. */
1469 if (scanIn == 0x83) /* Check for F7 key. */
1470 scan_in = 0x02;
1471 else if (scanIn == 0x84) /* Check for SysRq key. */
1472 scan_in = 0x7f;
1473 else
1474 scan_in = scanIn;
1475
1476 /* Values 0x80 and above are passed through, except for 0xF0
1477 * which indicates a key release.
1478 */
1479 if (scan_in < 0x80)
1480 {
1481 scan_out = aAT2PC[scan_in];
1482 /* Turn into break code if required. */
1483 if (state == XS_BREAK || state == XS_HIBIT)
1484 scan_out |= 0x80;
1485
1486 state = XS_IDLE;
1487 }
1488 else
1489 {
1490 /* NB: F0 E0 10 will be translated to E0 E5 (high bit set on last byte)! */
1491 if (scan_in == 0xF0) /* Check for break code. */
1492 state = XS_BREAK;
1493 else if (state == XS_BREAK)
1494 state = XS_HIBIT; /* Remember the break bit. */
1495 scan_out = scan_in;
1496 }
1497 LogFlowFunc(("scan code %02X translated to %02X; new state is %d\n",
1498 scanIn, scan_out, state));
1499
1500 *pScanOut = scan_out;
1501 return state;
1502}
1503
1504#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette