ReactOS 0.4.16-dev-338-g34e76ad
kbdbios32.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/bios/bios32/kbdbios32.c
5 * PURPOSE: VDM 32-bit PS/2 Keyboard BIOS
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9/* INCLUDES *******************************************************************/
10
11#include "ntvdm.h"
12
13#define NDEBUG
14#include <debug.h>
15
16#include "kbdbios32.h"
17#include <bios/kbdbios.h>
18#include "bios32p.h"
19
20#include "int32.h"
21#include "cpu/cpu.h" // for EMULATOR_FLAG_ZF
22#include "io.h"
23#include "hardware/ps2.h"
24
25/* PRIVATE VARIABLES **********************************************************/
26
28
29/* PRIVATE FUNCTIONS **********************************************************/
30
32{
33 /* Get the location of the element after the tail */
34 WORD NextElement = Bda->KeybdBufferTail + sizeof(WORD);
35
36 /* Wrap it around if it's at or beyond the end */
37 if (NextElement >= Bda->KeybdBufferEnd) NextElement = Bda->KeybdBufferStart;
38
39 /* If it's full, fail */
40 if (NextElement == Bda->KeybdBufferHead)
41 {
42 DPRINT1("BIOS keyboard buffer full.\n");
43 return FALSE;
44 }
45
46 /* Put the value in the queue */
48 Bda->KeybdBufferTail = NextElement;
49
50 /* Return success */
51 return TRUE;
52}
53
55{
56 /* If it's empty, fail */
58
59 /* Otherwise, get the value and return success */
61
62 return TRUE;
63}
64
66{
67 /* If it's empty, fail */
69
70 /* Remove the value from the queue */
71 Bda->KeybdBufferHead += sizeof(WORD);
72
73 /* Check if we are at, or have passed, the end of the buffer */
75 {
76 /* Return it to the beginning */
78 }
79
80 /* Return success */
81 return TRUE;
82}
83
84/* static */
86{
87 switch (getAH())
88 {
89 /* Wait for keystroke and read */
90 case 0x00:
91 /* Wait for extended keystroke and read */
92 case 0x10:
93 {
94 WORD Character;
95
96 /* Read the character (and wait if necessary) */
97 if (!BiosKbdBufferTop(&Character))
98 {
99 /* No key available. Set the handler CF to repeat the BOP */
100 setCF(1);
101 break;
102 }
103
104 if (getAH() == 0x00 && LOBYTE(Character) == 0xE0)
105 {
106 /* Clear the extended code */
107 Character &= 0xFF00;
108 }
109
111 setAX(Character);
112 setCF(0);
113
114 break;
115 }
116
117 /* Get keystroke status */
118 case 0x01:
119 /* Get extended keystroke status */
120 case 0x11:
121 {
122 WORD Character;
123
124 if (BiosKbdBufferTop(&Character))
125 {
126 /* There is a character, clear ZF and return it */
127 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
128
129 if (getAH() == 0x01 && LOBYTE(Character) == 0xE0)
130 {
131 /* Clear the extended code */
132 Character &= 0xFF00;
133 }
134
135 setAX(Character);
136 }
137 else
138 {
139 /* No character, set ZF */
141 }
142
143 break;
144 }
145
146 /* Get shift status */
147 case 0x02:
148 {
149 /* Return the lower byte of the keyboard shift status word */
151 break;
152 }
153
154 /* Reserved */
155 case 0x04:
156 {
157 DPRINT1("BIOS Function INT 16h, AH = 0x04 is RESERVED\n");
158 break;
159 }
160
161 /* Push keystroke */
162 case 0x05:
163 {
164 /* Return 0 if success, 1 if failure */
166 break;
167 }
168
169 /* Get extended shift status */
170 case 0x12:
171 {
172 /*
173 * Be careful! The returned word is similar to 'Bda->KeybdShiftFlags'
174 * but the high byte is organized differently:
175 * the bits 2 and 3 of the high byte are not the same:
176 * instead they correspond to the right CTRL and ALT keys as specified
177 * in bits 2 and 3 of LOBYTE(Bda->KeybdStatusFlags).
178 */
179 // Bda->KeybdShiftFlags & 0xF3FF;
180 WORD KeybdShiftFlags = MAKEWORD(LOBYTE(Bda->KeybdShiftFlags),
181 (HIBYTE(Bda->KeybdShiftFlags ) & 0xF3) |
182 (LOBYTE(Bda->KeybdStatusFlags) & 0x0C));
183
184 /* Return the extended keyboard shift status word */
185 setAX(KeybdShiftFlags);
186 break;
187 }
188
189 default:
190 {
191 DPRINT1("BIOS Function INT 16h, AH = 0x%02X NOT IMPLEMENTED\n",
192 getAH());
193 }
194 }
195}
196
197// Keyboard IRQ 1
198/* static */
200{
201 static BOOLEAN Extended = FALSE;
202 BOOLEAN SkipScanCode;
203 BYTE ScanCode, VirtualKey;
204 WORD Character;
205
206 /*
207 * Get the scan code from the PS/2 port, then call the
208 * INT 15h, AH=4Fh Keyboard Intercept function to try to
209 * translate the scan code. CF must be set before the call.
210 * In return, if CF is set we continue processing the scan code
211 * stored in AL, and if not, we skip it.
212 */
213 WORD AX = getAX();
214 WORD CX = getCX();
215 WORD DX = getDX();
216 WORD BX = getBX();
217 WORD BP = getBP();
218 WORD SI = getSI();
219 WORD DI = getDI();
220 WORD DS = getDS();
221 WORD ES = getES();
222
223 setCF(1);
225 setAH(0x4F);
227
228 /* Retrieve the modified scan code in AL */
229 SkipScanCode = (getCF() == 0);
230 ScanCode = getAL();
231
232 setAX(AX);
233 setCX(CX);
234 setDX(DX);
235 setBX(BX);
236 setBP(BP);
237 setSI(SI);
238 setDI(DI);
239 setDS(DS);
240 setES(ES);
241 setCF(0);
242
243 if (ScanCode == 0xE0)
244 {
245 Extended = TRUE;
246 Bda->KeybdStatusFlags |= 0x02;
247 goto Quit;
248 }
249
250 // FIXME: For diagnostic purposes. We should decide what to do then!!
251 if (ScanCode == 0xE1)
252 DPRINT1("BiosKeyboardIrq, ScanCode == 0xE1\n");
253
254 /* Check whether CF is clear. If so, skip the scan code. */
255 if (SkipScanCode) goto Quit;
256
257 /* Get the corresponding virtual key code */
258 VirtualKey = MapVirtualKey(ScanCode & 0x7F, MAPVK_VSC_TO_VK);
259
260 /* Check if this is a key press or release */
261 if (!(ScanCode & (1 << 7)))
262 {
263 /* Key press, set the highest bit */
264 BiosKeyboardMap[VirtualKey] |= (1 << 7);
265
266 switch (VirtualKey)
267 {
268 case VK_NUMLOCK:
269 case VK_CAPITAL:
270 case VK_SCROLL:
271 case VK_INSERT:
272 {
273 /* For toggle keys, toggle the lowest bit in the keyboard map */
274 BiosKeyboardMap[VirtualKey] ^= ~(1 << 0);
275 break;
276 }
277
278 case VK_SHIFT:
279 case VK_LSHIFT:
280 case VK_RSHIFT:
281 case VK_CONTROL:
282 case VK_RCONTROL:
283 case VK_LCONTROL:
284 case VK_MENU:
285 case VK_LMENU:
286 case VK_RMENU:
287 {
288 /* Modifier keys don't go in the buffer */
289 break;
290 }
291
292 default:
293 {
294 Character = Extended ? 0xE0 : 0x00;
295
296 /* If this is not an extended scancode, and ALT isn't held down, find out which character this is */
298 {
299 if (ToAscii(VirtualKey, ScanCode, BiosKeyboardMap, &Character, 0) == 0)
300 {
301 /* Not ASCII */
302 Character = 0;
303 }
304 }
305
306 /* Push it onto the BIOS keyboard queue */
308 }
309 }
310 }
311 else
312 {
313 /* Key release, unset the highest bit */
314 BiosKeyboardMap[VirtualKey] &= ~(1 << 7);
315 }
316
317 /* Clear the keyboard flags */
318 Bda->KeybdShiftFlags = 0;
319 // Release right CTRL and ALT keys
321
322 /* Set the appropriate flags based on the state */
323 // SHIFT
327 // CTRL
331 // ALT
335 // Others
346
347 /* Clear the extended key flag */
348 Extended = FALSE;
349 Bda->KeybdStatusFlags &= ~0x02; // Remove the 0xE0 code flag
350 // Bda->KeybdStatusFlags &= ~0x01; // Remove the 0xE1 code flag
351
352 DPRINT("BiosKeyboardIrq - Character = 0x%X, ScanCode = 0x%X, KeybdShiftFlags = 0x%X\n",
353 Character, ScanCode, Bda->KeybdShiftFlags);
354
355Quit:
357}
358
359/* PUBLIC FUNCTIONS ***********************************************************/
360
362{
363 /* Initialize the BDA */
367
368 // FIXME: Fill the keyboard buffer with invalid values for diagnostic purposes...
370 BIOS_KBD_BUFFER_SIZE * sizeof(WORD), 'A');
371
372 Bda->KeybdShiftFlags = 0;
373 Bda->KeybdStatusFlags = (1 << 4); // 101/102 enhanced keyboard installed
374 Bda->KeybdLedFlags = 0;
375
376 /*
377 * Register the BIOS 32-bit Interrupts:
378 * - Software vector handler
379 * - HW vector interrupt
380 */
383}
384
385/* EOF */
unsigned char BOOLEAN
UINT ScanCode
Definition: VirtualKey.c:24
@ DS
Definition: amd64_sup.c:16
#define DPRINT1
Definition: precomp.h:8
VOID PicIRQComplete(BYTE IntNum)
Definition: bios32.c:816
CALLBACK16 BiosContext
Definition: bios32.c:45
VOID EnableHwIRQ(UCHAR hwirq, EMULATOR_INT32_PROC func)
Definition: bios32.c:802
#define RegisterBiosInt32(IntNumber, IntHandler)
Definition: bios32p.h:34
#define BIOS_MISC_INTERRUPT
Definition: bios32p.h:25
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
unsigned short WORD
Definition: ntddk_ex.h:93
#define DX
Definition: i386-dis.c:425
#define AX
Definition: i386-dis.c:424
#define RtlFillMemory(Dest, Length, Fill)
Definition: winternl.h:599
VOID Int32Call(IN PCALLBACK16 Context, IN BYTE IntNumber)
Definition: int32.c:151
#define STACK_FLAGS
Definition: int32.h:35
#define STACK_INT_NUM
Definition: int32.h:30
#define LOBYTE(W)
Definition: jmemdos.c:487
#define HIBYTE(W)
Definition: jmemdos.c:486
VOID WINAPI BiosKeyboardIrq(LPWORD Stack)
Definition: kbdbios32.c:199
static BOOLEAN BiosKbdBufferPop(VOID)
Definition: kbdbios32.c:65
static BOOLEAN BiosKbdBufferTop(LPWORD Data)
Definition: kbdbios32.c:54
static BYTE BiosKeyboardMap[256]
Definition: kbdbios32.c:27
VOID KbdBios32Post(VOID)
Definition: kbdbios32.c:361
VOID WINAPI BiosKeyboardService(LPWORD Stack)
Definition: kbdbios32.c:85
static BOOLEAN BiosKbdBufferPush(WORD Data)
Definition: kbdbios32.c:31
#define BDA_KBDFLAG_LCTRL
Definition: kbdbios32.h:28
#define BDA_KBDFLAG_NUMLOCK_ON
Definition: kbdbios32.h:25
#define BIOS_KBD_BUFFER_SIZE
Definition: kbdbios32.h:16
#define BDA_KBDFLAG_PAUSE
Definition: kbdbios32.h:31
#define BDA_KBDFLAG_RCTRL
Definition: kbdbios32.h:21
#define BDA_KBDFLAG_LALT
Definition: kbdbios32.h:29
#define BDA_KBDFLAG_INSERT_ON
Definition: kbdbios32.h:27
#define BDA_KBDFLAG_NUMLOCK
Definition: kbdbios32.h:33
#define BDA_KBDFLAG_SYSRQ
Definition: kbdbios32.h:30
#define BDA_KBDFLAG_CAPSLOCK_ON
Definition: kbdbios32.h:26
#define BDA_KBDFLAG_CAPSLOCK
Definition: kbdbios32.h:34
#define BDA_KBDFLAG_INSERT
Definition: kbdbios32.h:35
#define BDA_KBDFLAG_CTRL
Definition: kbdbios32.h:20
#define BDA_KBDFLAG_RSHIFT
Definition: kbdbios32.h:18
#define BDA_KBDFLAG_RALT
Definition: kbdbios32.h:23
#define BDA_KBDFLAG_LSHIFT
Definition: kbdbios32.h:19
#define BDA_KBDFLAG_SCROLL
Definition: kbdbios32.h:32
#define BDA_KBDFLAG_ALT
Definition: kbdbios32.h:22
#define BDA_KBDFLAG_SCROLL_ON
Definition: kbdbios32.h:24
#define BIOS_KBD_INTERRUPT
Definition: kbdbios.h:14
if(dx< 0)
Definition: linetemp.h:194
@ ES
Definition: bidi.c:78
#define PS2_DATA_PORT
Definition: ps2.h:16
#define DPRINT
Definition: sndvol32.h:73
WORD KeybdBufferEnd
Definition: bios.h:88
BYTE KeybdStatusFlags
Definition: bios.h:100
WORD KeybdBufferHead
Definition: bios.h:51
WORD KeybdBufferTail
Definition: bios.h:52
BYTE KeybdLedFlags
Definition: bios.h:101
WORD KeybdShiftFlags
Definition: bios.h:49
WORD KeybdBufferStart
Definition: bios.h:87
PBIOS_DATA_AREA Bda
Definition: bios.c:42
#define EMULATOR_FLAG_ZF
Definition: cpu.h:22
UCHAR IOReadB(USHORT Port)
Definition: io.c:64
#define MAKEWORD(a, b)
Definition: typedefs.h:248
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
uint16_t * LPWORD
Definition: typedefs.h:56
uint32_t ULONG_PTR
Definition: typedefs.h:65
VOID WINAPI setBX(USHORT)
Definition: registers.c:177
VOID WINAPI setCX(USHORT)
Definition: registers.c:235
VOID WINAPI setDX(USHORT)
Definition: registers.c:293
ULONG WINAPI getCF(VOID)
Definition: registers.c:566
USHORT WINAPI getBX(VOID)
Definition: registers.c:170
VOID WINAPI setAL(UCHAR)
Definition: registers.c:149
USHORT WINAPI getDS(VOID)
Definition: registers.c:508
UCHAR WINAPI getAL(VOID)
Definition: registers.c:142
VOID WINAPI setCF(ULONG)
Definition: registers.c:573
VOID WINAPI setAH(UCHAR)
Definition: registers.c:135
USHORT WINAPI getCX(VOID)
Definition: registers.c:228
USHORT WINAPI getSI(VOID)
Definition: registers.c:404
USHORT WINAPI getDX(VOID)
Definition: registers.c:286
VOID WINAPI setDS(USHORT)
Definition: registers.c:515
USHORT WINAPI getAX(VOID)
Definition: registers.c:114
USHORT WINAPI getES(VOID)
Definition: registers.c:522
USHORT WINAPI getBP(VOID)
Definition: registers.c:374
USHORT WINAPI getDI(VOID)
Definition: registers.c:434
VOID WINAPI setBP(USHORT)
Definition: registers.c:381
VOID WINAPI setAX(USHORT)
Definition: registers.c:121
VOID WINAPI setES(USHORT)
Definition: registers.c:529
UCHAR WINAPI getAH(VOID)
Definition: registers.c:128
VOID WINAPI setSI(USHORT)
Definition: registers.c:411
VOID WINAPI setDI(USHORT)
Definition: registers.c:441
_In_ WDFREQUEST _In_ PIO_STACK_LOCATION Stack
Definition: wdfrequest.h:639
#define WINAPI
Definition: msvc.h:6
#define VK_SNAPSHOT
Definition: winuser.h:2234
#define MapVirtualKey
Definition: winuser.h:5832
#define VK_CAPITAL
Definition: winuser.h:2209
int WINAPI ToAscii(_In_ UINT, _In_ UINT, _In_reads_opt_(256) CONST BYTE *, _Out_ LPWORD, _In_ UINT)
#define VK_SCROLL
Definition: winuser.h:2283
#define VK_CONTROL
Definition: winuser.h:2206
#define VK_RSHIFT
Definition: winuser.h:2286
#define VK_LSHIFT
Definition: winuser.h:2285
#define VK_LCONTROL
Definition: winuser.h:2287
#define VK_PAUSE
Definition: winuser.h:2208
#define MAPVK_VSC_TO_VK
Definition: winuser.h:2359
#define VK_RCONTROL
Definition: winuser.h:2288
#define VK_RMENU
Definition: winuser.h:2290
#define VK_NUMLOCK
Definition: winuser.h:2282
#define VK_SHIFT
Definition: winuser.h:2205
#define VK_INSERT
Definition: winuser.h:2235
#define VK_LMENU
Definition: winuser.h:2289
#define VK_MENU
Definition: winuser.h:2207
unsigned char BYTE
Definition: xxhash.c:193