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 *******************************************************************/
16 #include "kbdbios32.h"
17 #include "../kbdbios.h"
21 #include "hardware/ps2.h"
23 /* PRIVATE VARIABLES **********************************************************/
25 static BYTE BiosKeyboardMap
[256];
27 /* PRIVATE FUNCTIONS **********************************************************/
29 static BOOLEAN
BiosKbdBufferPush(WORD Data
)
31 /* Get the location of the element after the tail */
32 WORD NextElement
= Bda
->KeybdBufferTail
+ sizeof(WORD
);
34 /* Wrap it around if it's at or beyond the end */
35 if (NextElement
>= Bda
->KeybdBufferEnd
) NextElement
= Bda
->KeybdBufferStart
;
37 /* If it's full, fail */
38 if (NextElement
== Bda
->KeybdBufferHead
)
40 DPRINT1("BIOS keyboard buffer full.\n");
44 /* Put the value in the queue */
45 *((LPWORD
)((ULONG_PTR
)Bda
+ Bda
->KeybdBufferTail
)) = Data
;
46 Bda
->KeybdBufferTail
= NextElement
;
52 static BOOLEAN
BiosKbdBufferTop(LPWORD Data
)
54 /* If it's empty, fail */
55 if (Bda
->KeybdBufferHead
== Bda
->KeybdBufferTail
) return FALSE
;
57 /* Otherwise, get the value and return success */
58 *Data
= *((LPWORD
)((ULONG_PTR
)Bda
+ Bda
->KeybdBufferHead
));
63 static BOOLEAN
BiosKbdBufferPop(VOID
)
65 /* If it's empty, fail */
66 if (Bda
->KeybdBufferHead
== Bda
->KeybdBufferTail
) return FALSE
;
68 /* Remove the value from the queue */
69 Bda
->KeybdBufferHead
+= sizeof(WORD
);
71 /* Check if we are at, or have passed, the end of the buffer */
72 if (Bda
->KeybdBufferHead
>= Bda
->KeybdBufferEnd
)
74 /* Return it to the beginning */
75 Bda
->KeybdBufferHead
= Bda
->KeybdBufferStart
;
82 static WORD
BiosPeekCharacter(VOID
)
84 WORD CharacterData
= 0;
86 /* Get the key from the queue, but don't remove it */
87 if (BiosKbdBufferTop(&CharacterData
)) return CharacterData
;
91 static WORD
BiosGetCharacter(VOID
)
93 WORD CharacterData
= 0;
95 /* Check if there is a key available, and if so, remove it from the queue */
96 if (BiosKbdBufferTop(&CharacterData
)) BiosKbdBufferPop();
97 else CharacterData
= 0xFFFF;
102 static VOID WINAPI
BiosKeyboardService(LPWORD Stack
)
106 /* Wait for keystroke and read */
108 /* Wait for extended keystroke and read */
109 case 0x10: // FIXME: Temporarily do the same as INT 16h, 00h
111 /* Read the character (and wait if necessary) */
112 WORD Character
= BiosGetCharacter();
114 if (Character
== 0xFFFF)
116 /* No key available. Set the handler CF to repeat the BOP */
126 /* Get keystroke status */
128 /* Get extended keystroke status */
129 case 0x11: // FIXME: Temporarily do the same as INT 16h, 01h
131 WORD Character
= BiosPeekCharacter();
133 if (Character
!= 0xFFFF)
135 /* There is a character, clear ZF and return it */
136 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_ZF
;
141 /* No character, set ZF */
142 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_ZF
;
148 /* Get shift status */
151 /* Return the lower byte of the keyboard shift status word */
152 setAL(LOBYTE(Bda
->KeybdShiftFlags
));
159 DPRINT1("BIOS Function INT 16h, AH = 0x04 is RESERVED\n");
166 /* Return 0 if success, 1 if failure */
167 setAL(BiosKbdBufferPush(getCX()) == FALSE
);
171 /* Get extended shift status */
175 * Be careful! The returned word is similar to Bda->KeybdShiftFlags
176 * but the high byte is organized differently:
177 * the bytes 2 and 3 of the high byte are not the same...
179 WORD KeybdShiftFlags
= (Bda
->KeybdShiftFlags
& 0xF3FF);
181 /* Return the extended keyboard shift status word */
182 setAX(KeybdShiftFlags
);
188 DPRINT1("BIOS Function INT 16h, AH = 0x%02X NOT IMPLEMENTED\n",
195 static VOID WINAPI
BiosKeyboardIrq(LPWORD Stack
)
197 BYTE ScanCode
, VirtualKey
;
200 /* Get the scan code and virtual key code */
201 ScanCode
= IOReadB(PS2_DATA_PORT
);
202 VirtualKey
= MapVirtualKey(ScanCode
& 0x7F, MAPVK_VSC_TO_VK
);
204 /* Check if this is a key press or release */
205 if (!(ScanCode
& (1 << 7)))
208 if (VirtualKey
== VK_NUMLOCK
||
209 VirtualKey
== VK_CAPITAL
||
210 VirtualKey
== VK_SCROLL
||
211 VirtualKey
== VK_INSERT
)
213 /* For toggle keys, toggle the lowest bit in the keyboard map */
214 BiosKeyboardMap
[VirtualKey
] ^= ~(1 << 0);
217 /* Set the highest bit */
218 BiosKeyboardMap
[VirtualKey
] |= (1 << 7);
220 /* Find out which character this is */
222 if (ToAscii(VirtualKey
, ScanCode
, BiosKeyboardMap
, &Character
, 0) == 0)
228 /* Push it onto the BIOS keyboard queue */
229 BiosKbdBufferPush(MAKEWORD(Character
, ScanCode
));
233 /* Key release, unset the highest bit */
234 BiosKeyboardMap
[VirtualKey
] &= ~(1 << 7);
237 /* Clear the keyboard flags */
238 Bda
->KeybdShiftFlags
= 0;
240 /* Set the appropriate flags based on the state */
241 if (BiosKeyboardMap
[VK_RSHIFT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_RSHIFT
;
242 if (BiosKeyboardMap
[VK_LSHIFT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_LSHIFT
;
243 if (BiosKeyboardMap
[VK_CONTROL
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_CTRL
;
244 if (BiosKeyboardMap
[VK_MENU
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_ALT
;
245 if (BiosKeyboardMap
[VK_SCROLL
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_SCROLL_ON
;
246 if (BiosKeyboardMap
[VK_NUMLOCK
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_NUMLOCK_ON
;
247 if (BiosKeyboardMap
[VK_CAPITAL
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_CAPSLOCK_ON
;
248 if (BiosKeyboardMap
[VK_INSERT
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_INSERT_ON
;
249 if (BiosKeyboardMap
[VK_RMENU
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_RALT
;
250 if (BiosKeyboardMap
[VK_LMENU
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_LALT
;
251 if (BiosKeyboardMap
[VK_SNAPSHOT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_SYSRQ
;
252 if (BiosKeyboardMap
[VK_PAUSE
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_PAUSE
;
253 if (BiosKeyboardMap
[VK_SCROLL
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_SCROLL
;
254 if (BiosKeyboardMap
[VK_NUMLOCK
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_NUMLOCK
;
255 if (BiosKeyboardMap
[VK_CAPITAL
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_CAPSLOCK
;
256 if (BiosKeyboardMap
[VK_INSERT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_INSERT
;
258 PicIRQComplete(Stack
);
261 /* PUBLIC FUNCTIONS ***********************************************************/
263 BOOLEAN
KbdBios32Initialize(VOID
)
265 /* Initialize the common Keyboard BIOS Support Library */
266 if (!KbdBiosInitialize()) return FALSE
;
268 /* Initialize the BDA */
269 Bda
->KeybdBufferStart
= FIELD_OFFSET(BIOS_DATA_AREA
, KeybdBuffer
);
270 Bda
->KeybdBufferEnd
= Bda
->KeybdBufferStart
+ BIOS_KBD_BUFFER_SIZE
* sizeof(WORD
);
271 Bda
->KeybdBufferHead
= Bda
->KeybdBufferTail
= Bda
->KeybdBufferStart
;
273 // FIXME: Fill the keyboard buffer with invalid values, for diagnostic purposes...
274 RtlFillMemory(((LPVOID
)((ULONG_PTR
)Bda
+ Bda
->KeybdBufferStart
)), BIOS_KBD_BUFFER_SIZE
* sizeof(WORD
), 'A');
276 /* Register the BIOS 32-bit Interrupts */
278 /* Initialize software vector handlers */
279 RegisterBiosInt32(BIOS_KBD_INTERRUPT
, BiosKeyboardService
);
281 /* Set up the HW vector interrupts */
282 EnableHwIRQ(1, BiosKeyboardIrq
);
283 // EnableHwIRQ(12, BiosMouseIrq);
288 VOID
KbdBios32Cleanup(VOID
)
290 /* Cleanup the common Keyboard BIOS Support Library */