ReactOS  0.4.14-dev-606-g14ebc0b
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 
27 static BYTE BiosKeyboardMap[256];
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 */
57  if (Bda->KeybdBufferHead == Bda->KeybdBufferTail) return FALSE;
58 
59  /* Otherwise, get the value and return success */
61 
62  return TRUE;
63 }
64 
66 {
67  /* If it's empty, fail */
68  if (Bda->KeybdBufferHead == Bda->KeybdBufferTail) return FALSE;
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 */
140  Stack[STACK_FLAGS] |= EMULATOR_FLAG_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 */
307  BiosKbdBufferPush(MAKEWORD(Character, ScanCode));
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 
355 Quit:
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 */
#define BDA_KBDFLAG_ALT
Definition: kbdbios32.h:22
#define BDA_KBDFLAG_NUMLOCK_ON
Definition: kbdbios32.h:25
#define STACK_INT_NUM
Definition: int32.h:30
#define PS2_DATA_PORT
Definition: ps2.h:16
#define BDA_KBDFLAG_LALT
Definition: kbdbios32.h:29
USHORT WINAPI getBX(VOID)
Definition: registers.c:170
#define TRUE
Definition: types.h:120
ULONG ScanCode
Definition: api.c:39
USHORT WINAPI getSI(VOID)
Definition: registers.c:404
#define LOBYTE(W)
Definition: jmemdos.c:487
#define MAKEWORD(a, b)
Definition: typedefs.h:247
USHORT WINAPI getCX(VOID)
Definition: registers.c:228
VOID WINAPI setAH(UCHAR)
Definition: registers.c:135
#define VK_RMENU
Definition: winuser.h:2262
#define VK_LSHIFT
Definition: winuser.h:2257
VOID WINAPI setAX(USHORT)
Definition: registers.c:121
VOID WINAPI setDS(USHORT)
Definition: registers.c:515
VOID Int32Call(IN PCALLBACK16 Context, IN BYTE IntNumber)
Definition: int32.c:151
#define HIBYTE(W)
Definition: jmemdos.c:486
VOID WINAPI setAL(UCHAR)
Definition: registers.c:149
PBIOS_DATA_AREA Bda
Definition: bios.c:42
#define AX
Definition: i386-dis.c:415
UCHAR WINAPI getAH(VOID)
Definition: registers.c:128
#define VK_INSERT
Definition: winuser.h:2207
#define VK_MENU
Definition: winuser.h:2179
UCHAR WINAPI getAL(VOID)
Definition: registers.c:142
Definition: bidi.c:78
Definition: parse.h:75
VOID KbdBios32Post(VOID)
Definition: kbdbios32.c:361
WORD KeybdBufferStart
Definition: bios.h:87
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define RegisterBiosInt32(IntNumber, IntHandler)
Definition: bios32p.h:34
VOID WINAPI setES(USHORT)
Definition: registers.c:529
#define DX
Definition: i386-dis.c:416
WORD KeybdShiftFlags
Definition: bios.h:49
#define BDA_KBDFLAG_SYSRQ
Definition: kbdbios32.h:30
WORD KeybdBufferEnd
Definition: bios.h:88
#define EMULATOR_FLAG_ZF
Definition: cpu.h:22
#define BDA_KBDFLAG_LCTRL
Definition: kbdbios32.h:28
VOID WINAPI setCF(ULONG)
Definition: registers.c:573
VOID WINAPI setSI(USHORT)
Definition: registers.c:411
UCHAR IOReadB(USHORT Port)
Definition: io.c:64
#define BDA_KBDFLAG_RALT
Definition: kbdbios32.h:23
#define BDA_KBDFLAG_RCTRL
Definition: kbdbios32.h:21
static BYTE BiosKeyboardMap[256]
Definition: kbdbios32.c:27
#define VK_SHIFT
Definition: winuser.h:2177
#define BDA_KBDFLAG_RSHIFT
Definition: kbdbios32.h:18
#define BIOS_MISC_INTERRUPT
Definition: bios32p.h:25
unsigned char BOOLEAN
_In_ LPGUID _In_ PVOID Data
Definition: classpnp.h:778
void DPRINT(...)
Definition: polytest.cpp:61
#define STACK_FLAGS
Definition: int32.h:35
#define BDA_KBDFLAG_CAPSLOCK_ON
Definition: kbdbios32.h:26
static BOOLEAN BiosKbdBufferPop(VOID)
Definition: kbdbios32.c:65
static BOOLEAN BiosKbdBufferPush(WORD Data)
Definition: kbdbios32.c:31
#define BDA_KBDFLAG_LSHIFT
Definition: kbdbios32.h:19
#define MAPVK_VSC_TO_VK
Definition: winuser.h:2331
BYTE KeybdStatusFlags
Definition: bios.h:100
VOID EnableHwIRQ(UCHAR hwirq, EMULATOR_INT32_PROC func)
Definition: bios32.c:798
#define BDA_KBDFLAG_PAUSE
Definition: kbdbios32.h:31
if(!(yy_init))
Definition: macro.lex.yy.c:714
#define BDA_KBDFLAG_INSERT_ON
Definition: kbdbios32.h:27
USHORT WINAPI getES(VOID)
Definition: registers.c:522
VOID PicIRQComplete(BYTE IntNum)
Definition: bios32.c:812
CALLBACK16 BiosContext
Definition: bios32.c:45
#define WINAPI
Definition: msvc.h:6
WORD KeybdBufferHead
Definition: bios.h:51
unsigned short WORD
Definition: ntddk_ex.h:93
#define BDA_KBDFLAG_NUMLOCK
Definition: kbdbios32.h:33
VOID WINAPI setBP(USHORT)
Definition: registers.c:381
VOID WINAPI setDX(USHORT)
Definition: registers.c:293
#define VK_RCONTROL
Definition: winuser.h:2260
#define VK_LMENU
Definition: winuser.h:2261
USHORT WINAPI getDX(VOID)
Definition: registers.c:286
#define VK_RSHIFT
Definition: winuser.h:2258
USHORT WINAPI getAX(VOID)
Definition: registers.c:114
unsigned char BYTE
Definition: mem.h:68
WORD KeybdBufferTail
Definition: bios.h:52
VOID WINAPI setBX(USHORT)
Definition: registers.c:177
#define BDA_KBDFLAG_INSERT
Definition: kbdbios32.h:35
#define MapVirtualKey
Definition: winuser.h:5795
uint16_t * LPWORD
Definition: typedefs.h:54
VOID WINAPI setDI(USHORT)
Definition: registers.c:441
#define BDA_KBDFLAG_CTRL
Definition: kbdbios32.h:20
#define BIOS_KBD_BUFFER_SIZE
Definition: kbdbios32.h:16
int WINAPI ToAscii(_In_ UINT, _In_ UINT, _In_reads_opt_(256) CONST BYTE *, _Out_ LPWORD, _In_ UINT)
#define VK_SCROLL
Definition: winuser.h:2255
#define VK_NUMLOCK
Definition: winuser.h:2254
BYTE KeybdLedFlags
Definition: bios.h:101
VOID WINAPI BiosKeyboardService(LPWORD Stack)
Definition: kbdbios32.c:85
USHORT WINAPI getDI(VOID)
Definition: registers.c:434
#define VK_CAPITAL
Definition: winuser.h:2181
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
VOID WINAPI BiosKeyboardIrq(LPWORD Stack)
Definition: kbdbios32.c:199
#define BDA_KBDFLAG_CAPSLOCK
Definition: kbdbios32.h:34
VOID WINAPI setCX(USHORT)
Definition: registers.c:235
#define VK_CONTROL
Definition: winuser.h:2178
#define DPRINT1
Definition: precomp.h:8
#define VK_PAUSE
Definition: winuser.h:2180
USHORT WINAPI getDS(VOID)
Definition: registers.c:508
Definition: i386_sup.c:15
#define BIOS_KBD_INTERRUPT
Definition: kbdbios.h:14
USHORT WINAPI getBP(VOID)
Definition: registers.c:374
#define BDA_KBDFLAG_SCROLL_ON
Definition: kbdbios32.h:24
#define VK_LCONTROL
Definition: winuser.h:2259
static BOOLEAN BiosKbdBufferTop(LPWORD Data)
Definition: kbdbios32.c:54
#define RtlFillMemory(Dest, Length, Fill)
Definition: winternl.h:593
#define VK_SNAPSHOT
Definition: winuser.h:2206
#define BDA_KBDFLAG_SCROLL
Definition: kbdbios32.h:32
ULONG WINAPI getCF(VOID)
Definition: registers.c:566