bec4fde71bce9681b4ded13d8090177757ca8f91
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: VDM Keyboard 32-bit BIOS
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
15 #include "kbdbios32.h"
16 #include <bios/kbdbios.h>
20 #include "cpu/cpu.h" // for EMULATOR_FLAG_ZF
22 #include "hardware/ps2.h"
24 /* PRIVATE VARIABLES **********************************************************/
26 static BYTE BiosKeyboardMap
[256];
28 /* PRIVATE FUNCTIONS **********************************************************/
30 static BOOLEAN
BiosKbdBufferPush(WORD Data
)
32 /* Get the location of the element after the tail */
33 WORD NextElement
= Bda
->KeybdBufferTail
+ sizeof(WORD
);
35 /* Wrap it around if it's at or beyond the end */
36 if (NextElement
>= Bda
->KeybdBufferEnd
) NextElement
= Bda
->KeybdBufferStart
;
38 /* If it's full, fail */
39 if (NextElement
== Bda
->KeybdBufferHead
)
41 DPRINT1("BIOS keyboard buffer full.\n");
45 /* Put the value in the queue */
46 *((LPWORD
)((ULONG_PTR
)Bda
+ Bda
->KeybdBufferTail
)) = Data
;
47 Bda
->KeybdBufferTail
= NextElement
;
53 static BOOLEAN
BiosKbdBufferTop(LPWORD Data
)
55 /* If it's empty, fail */
56 if (Bda
->KeybdBufferHead
== Bda
->KeybdBufferTail
) return FALSE
;
58 /* Otherwise, get the value and return success */
59 *Data
= *((LPWORD
)((ULONG_PTR
)Bda
+ Bda
->KeybdBufferHead
));
64 static BOOLEAN
BiosKbdBufferPop(VOID
)
66 /* If it's empty, fail */
67 if (Bda
->KeybdBufferHead
== Bda
->KeybdBufferTail
) return FALSE
;
69 /* Remove the value from the queue */
70 Bda
->KeybdBufferHead
+= sizeof(WORD
);
72 /* Check if we are at, or have passed, the end of the buffer */
73 if (Bda
->KeybdBufferHead
>= Bda
->KeybdBufferEnd
)
75 /* Return it to the beginning */
76 Bda
->KeybdBufferHead
= Bda
->KeybdBufferStart
;
83 static VOID WINAPI
BiosKeyboardService(LPWORD Stack
)
87 /* Wait for keystroke and read */
89 /* Wait for extended keystroke and read */
94 /* Read the character (and wait if necessary) */
95 if (!BiosKbdBufferTop(&Character
))
97 /* No key available. Set the handler CF to repeat the BOP */
102 if (getAH() == 0x00 && LOBYTE(Character
) == 0xE0)
104 /* Clear the extended code */
115 /* Get keystroke status */
117 /* Get extended keystroke status */
122 if (BiosKbdBufferTop(&Character
))
124 /* There is a character, clear ZF and return it */
125 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_ZF
;
127 if (getAH() == 0x01 && LOBYTE(Character
) == 0xE0)
129 /* Clear the extended code */
137 /* No character, set ZF */
138 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_ZF
;
144 /* Get shift status */
147 /* Return the lower byte of the keyboard shift status word */
148 setAL(LOBYTE(Bda
->KeybdShiftFlags
));
155 DPRINT1("BIOS Function INT 16h, AH = 0x04 is RESERVED\n");
162 /* Return 0 if success, 1 if failure */
163 setAL(BiosKbdBufferPush(getCX()) == FALSE
);
167 /* Get extended shift status */
171 * Be careful! The returned word is similar to Bda->KeybdShiftFlags
172 * but the high byte is organized differently:
173 * the bytes 2 and 3 of the high byte are not the same...
175 WORD KeybdShiftFlags
= (Bda
->KeybdShiftFlags
& 0xF3FF);
177 /* Return the extended keyboard shift status word */
178 setAX(KeybdShiftFlags
);
184 DPRINT1("BIOS Function INT 16h, AH = 0x%02X NOT IMPLEMENTED\n",
191 static VOID WINAPI
BiosKeyboardIrq(LPWORD Stack
)
193 static BOOLEAN Extended
= FALSE
;
194 BOOLEAN SkipScanCode
;
195 BYTE ScanCode
, VirtualKey
;
199 * Get the scan code from the PS/2 port, then call the
200 * INT 15h, AH=4Fh Keyboard Intercept function to try to
201 * translate the scan code. CF must be set before the call.
202 * In return, if CF is set we continue processing the scan code
203 * stored in AL, and if not, we skip it.
211 setAL(IOReadB(PS2_DATA_PORT
));
213 Int32Call(&BiosContext
, BIOS_MISC_INTERRUPT
);
215 /* Retrieve the modified scan code in AL */
216 SkipScanCode
= (getCF() == 0);
222 if (ScanCode
== 0xE0)
228 /* Check whether CF is clear. If so, skip the scan code. */
229 if (SkipScanCode
) goto Quit
;
231 /* Get the corresponding virtual key code */
232 VirtualKey
= MapVirtualKey(ScanCode
& 0x7F, MAPVK_VSC_TO_VK
);
234 /* Check if this is a key press or release */
235 if (!(ScanCode
& (1 << 7)))
237 /* Key press, set the highest bit */
238 BiosKeyboardMap
[VirtualKey
] |= (1 << 7);
247 /* For toggle keys, toggle the lowest bit in the keyboard map */
248 BiosKeyboardMap
[VirtualKey
] ^= ~(1 << 0);
260 /* Modifier keys don't go in the buffer */
266 Character
= Extended
? 0xE0 : 0x00;
268 /* If this is not an extended scancode, and ALT isn't held down, find out which character this is */
269 if (!Extended
&& !(Bda
->KeybdShiftFlags
& (BDA_KBDFLAG_ALT
| BDA_KBDFLAG_LALT
| BDA_KBDFLAG_RALT
)))
271 if (ToAscii(VirtualKey
, ScanCode
, BiosKeyboardMap
, &Character
, 0) == 0)
278 /* Push it onto the BIOS keyboard queue */
279 BiosKbdBufferPush(MAKEWORD(Character
, ScanCode
));
285 /* Key release, unset the highest bit */
286 BiosKeyboardMap
[VirtualKey
] &= ~(1 << 7);
289 /* Clear the keyboard flags */
290 Bda
->KeybdShiftFlags
= 0;
292 /* Set the appropriate flags based on the state */
293 if (BiosKeyboardMap
[VK_SHIFT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_LSHIFT
;
294 if (BiosKeyboardMap
[VK_RSHIFT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_RSHIFT
;
295 if (BiosKeyboardMap
[VK_LSHIFT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_LSHIFT
;
296 if (BiosKeyboardMap
[VK_CONTROL
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_CTRL
;
297 if (BiosKeyboardMap
[VK_MENU
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_ALT
;
298 if (BiosKeyboardMap
[VK_SCROLL
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_SCROLL_ON
;
299 if (BiosKeyboardMap
[VK_NUMLOCK
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_NUMLOCK_ON
;
300 if (BiosKeyboardMap
[VK_CAPITAL
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_CAPSLOCK_ON
;
301 if (BiosKeyboardMap
[VK_INSERT
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_INSERT_ON
;
302 if (BiosKeyboardMap
[VK_RMENU
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_RALT
;
303 if (BiosKeyboardMap
[VK_LMENU
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_LALT
;
304 if (BiosKeyboardMap
[VK_SNAPSHOT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_SYSRQ
;
305 if (BiosKeyboardMap
[VK_PAUSE
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_PAUSE
;
306 if (BiosKeyboardMap
[VK_SCROLL
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_SCROLL
;
307 if (BiosKeyboardMap
[VK_NUMLOCK
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_NUMLOCK
;
308 if (BiosKeyboardMap
[VK_CAPITAL
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_CAPSLOCK
;
309 if (BiosKeyboardMap
[VK_INSERT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_INSERT
;
311 /* Clear the extended key flag */
314 DPRINT("BiosKeyboardIrq - Character = 0x%X, ScanCode = 0x%X, KeybdShiftFlags = 0x%X\n",
315 Character
, ScanCode
, Bda
->KeybdShiftFlags
);
318 PicIRQComplete(Stack
);
321 /* PUBLIC FUNCTIONS ***********************************************************/
323 BOOLEAN
KbdBios32Initialize(VOID
)
325 /* Initialize the common Keyboard BIOS Support Library */
326 if (!KbdBiosInitialize()) return FALSE
;
328 /* Initialize the BDA */
329 Bda
->KeybdBufferStart
= FIELD_OFFSET(BIOS_DATA_AREA
, KeybdBuffer
);
330 Bda
->KeybdBufferEnd
= Bda
->KeybdBufferStart
+ BIOS_KBD_BUFFER_SIZE
* sizeof(WORD
);
331 Bda
->KeybdBufferHead
= Bda
->KeybdBufferTail
= Bda
->KeybdBufferStart
;
333 // FIXME: Fill the keyboard buffer with invalid values for diagnostic purposes...
334 RtlFillMemory(((LPVOID
)((ULONG_PTR
)Bda
+ Bda
->KeybdBufferStart
)),
335 BIOS_KBD_BUFFER_SIZE
* sizeof(WORD
), 'A');
338 * Register the BIOS 32-bit Interrupts:
339 * - Software vector handler
340 * - HW vector interrupt
342 RegisterBiosInt32(BIOS_KBD_INTERRUPT
, BiosKeyboardService
);
343 EnableHwIRQ(1, BiosKeyboardIrq
);
348 VOID
KbdBios32Cleanup(VOID
)
350 /* Cleanup the common Keyboard BIOS Support Library */