2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
22 #include "registers.h"
24 /* PRIVATE VARIABLES **********************************************************/
27 static BYTE BiosKeyboardMap
[256];
28 static HANDLE BiosConsoleInput
= INVALID_HANDLE_VALUE
;
29 static HANDLE BiosConsoleOutput
= INVALID_HANDLE_VALUE
;
30 static CONSOLE_SCREEN_BUFFER_INFO BiosSavedBufferInfo
;
33 * VGA Register Configurations for BIOS Video Modes
34 * The configurations come from DosBox.
36 static BYTE VideoMode_40x25_text
[] =
38 /* Miscellaneous Register */
41 /* Sequencer Registers */
42 0x00, 0x08, 0x03, 0x00, 0x07,
45 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x0F, 0xFF,
48 0x2D, 0x27, 0x28, 0x90, 0x2B, 0xA0, 0xBF, 0x1F, 0x00, 0x4F, 0x0D, 0x0E,
49 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x14, 0x1F, 0x96, 0xB9, 0xA3,
53 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
54 0x3C, 0x3D, 0x3E, 0x3F, 0x0C, 0x00, 0x0F, 0x08, 0x00
57 static BYTE VideoMode_80x25_text
[] =
59 /* Miscellaneous Register */
62 /* Sequencer Registers */
63 0x00, 0x00, 0x03, 0x00, 0x07,
66 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x0F, 0xFF,
69 0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F, 0x00, 0x4F, 0x0D, 0x0E,
70 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3,
74 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
75 0x3C, 0x3D, 0x3E, 0x3F, 0x0C, 0x00, 0x0F, 0x08, 0x00
78 static BYTE VideoMode_320x200_4color
[] =
80 /* Miscellaneous Register */
83 /* Sequencer Registers */
84 0x00, 0x09, 0x00, 0x00, 0x02,
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0F, 0x0F, 0xFF,
90 0x2D, 0x27, 0x28, 0x90, 0x2B, 0x80, 0xBF, 0x1F, 0x00, 0xC1, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x14, 0x00, 0x96, 0xB9, 0xA2,
95 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13,
96 0x14, 0x15, 0x16, 0x17, 0x01, 0x00, 0x0F, 0x00, 0x00
99 static BYTE VideoMode_640x200_2color
[] =
101 /* Miscellaneous Register */
104 /* Sequencer Registers */
105 0x00, 0x09, 0x0F, 0x00, 0x02,
108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0xFF,
111 0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0xC1, 0x00, 0x00,
112 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x28, 0x00, 0x96, 0xB9, 0xC2,
116 0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
117 0x17, 0x17, 0x17, 0x17, 0x01, 0x00, 0x01, 0x00, 0x00
120 static BYTE VideoMode_320x200_16color
[] =
122 /* Miscellaneous Register */
125 /* Sequencer Registers */
126 0x00, 0x09, 0x0F, 0x00, 0x02,
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF,
132 0x2D, 0x27, 0x28, 0x90, 0x2B, 0x80, 0xBF, 0x1F, 0x00, 0xC0, 0x00, 0x00,
133 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x14, 0x00, 0x96, 0xB9, 0xE3,
137 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
138 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00
141 static BYTE VideoMode_640x200_16color
[] =
143 /* Miscellaneous Register */
146 /* Sequencer Registers */
147 0x00, 0x01, 0x0F, 0x00, 0x02,
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF,
153 0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0xC0, 0x00, 0x00,
154 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x28, 0x00, 0x96, 0xB9, 0xE3,
158 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
159 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00
162 static BYTE VideoMode_640x350_16color
[] =
164 /* Miscellaneous Register */
167 /* Sequencer Registers */
168 0x00, 0x01, 0x0F, 0x00, 0x02,
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF,
174 0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0x40, 0x00, 0x00,
175 0x00, 0x00, 0x00, 0x00, 0x83, 0x85, 0x5D, 0x28, 0x0F, 0x63, 0xBA, 0xE3,
179 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
180 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00
183 static BYTE VideoMode_640x480_2color
[] =
185 /* Miscellaneous Register */
188 /* Sequencer Registers */
189 0x00, 0x01, 0x0F, 0x00, 0x02,
192 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF,
195 0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x0B, 0x3E, 0x00, 0x40, 0x00, 0x00,
196 0x00, 0x00, 0x00, 0x00, 0xEA, 0x8C, 0xDF, 0x28, 0x00, 0xE7, 0x04, 0xC3,
200 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
201 0x3F, 0x3F, 0x3F, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00
204 static BYTE VideoMode_640x480_16color
[] =
206 /* Miscellaneous Register */
209 /* Sequencer Registers */
210 0x00, 0x01, 0x0F, 0x00, 0x02,
213 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF,
216 0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x0B, 0x3E, 0x00, 0x40, 0x00, 0x00,
217 0x00, 0x00, 0x00, 0x00, 0xEA, 0x8C, 0xDF, 0x28, 0x00, 0xE7, 0x04, 0xE3,
221 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
222 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00
225 static BYTE VideoMode_320x200_256color
[] =
227 /* Miscellaneous Register */
230 /* Sequencer Registers */
231 0x00, 0x01, 0x0F, 0x00, 0x0E,
234 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF,
237 0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0x41, 0x00, 0x00,
238 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3,
242 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
243 0x0C, 0x0D, 0x0E, 0x0F, 0x41, 0x00, 0x0F, 0x00, 0x00
246 static LPBYTE VideoModes
[] =
248 VideoMode_40x25_text
, /* Mode 00h */
249 VideoMode_40x25_text
, /* Mode 01h */
250 VideoMode_80x25_text
, /* Mode 02h */
251 VideoMode_80x25_text
, /* Mode 03h */
252 VideoMode_320x200_4color
, /* Mode 04h */
253 VideoMode_320x200_4color
, /* Mode 05h */
254 VideoMode_640x200_2color
, /* Mode 06h */
261 VideoMode_320x200_16color
, /* Mode 0Dh */
262 VideoMode_640x200_16color
, /* Mode 0Eh */
264 VideoMode_640x350_16color
, /* Mode 10h */
265 VideoMode_640x480_2color
, /* Mode 11h */
266 VideoMode_640x480_16color
, /* Mode 12h */
267 VideoMode_320x200_256color
, /* Mode 13h */
270 static CONST COLORREF EgaPalette
[VGA_MAX_COLORS
/ 4] =
272 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
273 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0xAA, 0x00), RGB(0xAA, 0xAA, 0xAA),
274 RGB(0x00, 0x00, 0x55), RGB(0x00, 0x00, 0xFF), RGB(0x00, 0xAA, 0x55), RGB(0x00, 0xAA, 0xFF),
275 RGB(0xAA, 0x00, 0x55), RGB(0xAA, 0x00, 0xFF), RGB(0xAA, 0xAA, 0x55), RGB(0xAA, 0xAA, 0xFF),
276 RGB(0x00, 0x55, 0x00), RGB(0x00, 0x55, 0xAA), RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0xAA),
277 RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0x55, 0xAA), RGB(0xAA, 0xFF, 0x00), RGB(0xAA, 0xFF, 0xAA),
278 RGB(0x00, 0x55, 0x55), RGB(0x00, 0x55, 0xFF), RGB(0x00, 0xFF, 0x55), RGB(0x00, 0xFF, 0xFF),
279 RGB(0xAA, 0x55, 0x55), RGB(0xAA, 0x55, 0xFF), RGB(0xAA, 0xFF, 0x55), RGB(0xAA, 0xFF, 0xFF),
280 RGB(0x55, 0x00, 0x00), RGB(0x55, 0x00, 0xAA), RGB(0x55, 0xAA, 0x00), RGB(0x55, 0xAA, 0xAA),
281 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x00, 0xAA), RGB(0xFF, 0xAA, 0x00), RGB(0xFF, 0xAA, 0xAA),
282 RGB(0x55, 0x00, 0x55), RGB(0x55, 0x00, 0xFF), RGB(0x55, 0xAA, 0x55), RGB(0x55, 0xAA, 0xFF),
283 RGB(0xFF, 0x00, 0x55), RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0xAA, 0x55), RGB(0xFF, 0xAA, 0xFF),
284 RGB(0x55, 0x55, 0x00), RGB(0x55, 0x55, 0xAA), RGB(0x55, 0xFF, 0x00), RGB(0x55, 0xFF, 0xAA),
285 RGB(0xFF, 0x55, 0x00), RGB(0xFF, 0x55, 0xAA), RGB(0xFF, 0xFF, 0x00), RGB(0xFF, 0xFF, 0xAA),
286 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
287 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF)
290 /* PRIVATE FUNCTIONS **********************************************************/
292 static BOOLEAN
BiosKbdBufferPush(WORD Data
)
294 /* Get the location of the element after the tail */
295 WORD NextElement
= Bda
->KeybdBufferTail
+ sizeof(WORD
);
297 /* Wrap it around if it's at or beyond the end */
298 if (NextElement
>= Bda
->KeybdBufferEnd
) NextElement
= Bda
->KeybdBufferStart
;
300 /* If it's full, fail */
301 if (NextElement
== Bda
->KeybdBufferHead
) return FALSE
;
303 /* Put the value in the queue */
304 *((LPWORD
)((ULONG_PTR
)Bda
+ Bda
->KeybdBufferTail
)) = Data
;
305 Bda
->KeybdBufferTail
+= sizeof(WORD
);
307 /* Check if we are at, or have passed, the end of the buffer */
308 if (Bda
->KeybdBufferTail
>= Bda
->KeybdBufferEnd
)
310 /* Return it to the beginning */
311 Bda
->KeybdBufferTail
= Bda
->KeybdBufferStart
;
318 static BOOLEAN
BiosKbdBufferTop(LPWORD Data
)
320 /* If it's empty, fail */
321 if (Bda
->KeybdBufferHead
== Bda
->KeybdBufferTail
) return FALSE
;
323 /* Otherwise, get the value and return success */
324 *Data
= *((LPWORD
)((ULONG_PTR
)Bda
+ Bda
->KeybdBufferHead
));
329 static BOOLEAN
BiosKbdBufferPop(VOID
)
331 /* If it's empty, fail */
332 if (Bda
->KeybdBufferHead
== Bda
->KeybdBufferTail
) return FALSE
;
334 /* Remove the value from the queue */
335 Bda
->KeybdBufferHead
+= sizeof(WORD
);
337 /* Check if we are at, or have passed, the end of the buffer */
338 if (Bda
->KeybdBufferHead
>= Bda
->KeybdBufferEnd
)
340 /* Return it to the beginning */
341 Bda
->KeybdBufferHead
= Bda
->KeybdBufferStart
;
348 static VOID
BiosReadWindow(LPWORD Buffer
, SMALL_RECT Rectangle
, BYTE Page
)
353 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Page
* Bda
->VideoPageSize
);
355 for (i
= Rectangle
.Top
; i
<= Rectangle
.Bottom
; i
++)
357 for (j
= Rectangle
.Left
; j
<= Rectangle
.Right
; j
++)
359 /* Read from video memory */
360 VgaReadMemory(VideoAddress
+ (i
* Bda
->ScreenColumns
+ j
) * sizeof(WORD
),
364 /* Write the data to the buffer in row order */
365 Buffer
[Counter
++] = Character
;
370 static VOID
BiosWriteWindow(LPWORD Buffer
, SMALL_RECT Rectangle
, BYTE Page
)
375 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Page
* Bda
->VideoPageSize
);
377 for (i
= Rectangle
.Top
; i
<= Rectangle
.Bottom
; i
++)
379 for (j
= Rectangle
.Left
; j
<= Rectangle
.Right
; j
++)
381 Character
= Buffer
[Counter
++];
383 /* Write to video memory */
384 VgaWriteMemory(VideoAddress
+ (i
* Bda
->ScreenColumns
+ j
) * sizeof(WORD
),
391 /* PUBLIC FUNCTIONS ***********************************************************/
393 BYTE
BiosGetVideoMode(VOID
)
395 return Bda
->VideoMode
;
398 BOOLEAN
BiosSetVideoMode(BYTE ModeNumber
)
402 LPBYTE Values
= VideoModes
[ModeNumber
];
404 DPRINT1("Switching to mode %Xh; Values = 0x%p\n", ModeNumber
, Values
);
406 if (Values
== NULL
) return FALSE
;
408 /* Write the misc register */
409 VgaWritePort(VGA_MISC_WRITE
, *(Values
++));
411 /* Write the sequencer registers */
412 for (i
= 0; i
< VGA_SEQ_MAX_REG
; i
++)
414 VgaWritePort(VGA_SEQ_INDEX
, i
);
415 VgaWritePort(VGA_SEQ_DATA
, *(Values
++));
418 /* Write the GC registers */
419 for (i
= 0; i
< VGA_GC_MAX_REG
; i
++)
421 VgaWritePort(VGA_GC_INDEX
, i
);
422 VgaWritePort(VGA_GC_DATA
, *(Values
++));
425 /* Write the CRTC registers */
426 for (i
= 0; i
< VGA_CRTC_MAX_REG
; i
++)
428 VgaWritePort(VGA_CRTC_INDEX
, i
);
429 VgaWritePort(VGA_CRTC_DATA
, *(Values
++));
432 /* Write the AC registers */
433 for (i
= 0; i
< VGA_AC_MAX_REG
; i
++)
435 VgaWritePort(VGA_AC_INDEX
, i
);
436 VgaWritePort(VGA_AC_WRITE
, *(Values
++));
439 if ((ModeNumber
== 0x0D) || (ModeNumber
== 0x0E) || (ModeNumber
== 0x10))
442 for (i
= 0; i
< VGA_MAX_COLORS
/ 4; i
++)
444 VgaWritePort(VGA_DAC_WRITE_INDEX
, i
);
445 VgaWritePort(VGA_DAC_DATA
, VGA_COLOR_TO_DAC(GetRValue(EgaPalette
[i
])));
446 VgaWritePort(VGA_DAC_DATA
, VGA_COLOR_TO_DAC(GetGValue(EgaPalette
[i
])));
447 VgaWritePort(VGA_DAC_DATA
, VGA_COLOR_TO_DAC(GetBValue(EgaPalette
[i
])));
452 /* Reset the palette */
456 /* Update the values in the BDA */
457 Bda
->VideoMode
= ModeNumber
;
459 Bda
->VideoPageSize
= BIOS_PAGE_SIZE
;
460 Bda
->VideoPageOffset
= 0;
462 /* Get the character height */
463 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_MAX_SCAN_LINE_REG
);
464 Bda
->CharacterHeight
= 1 + (VgaReadPort(VGA_CRTC_DATA
) & 0x1F);
466 Resolution
= VgaGetDisplayResolution();
467 Bda
->ScreenColumns
= Resolution
.X
;
468 Bda
->ScreenRows
= Resolution
.Y
- 1;
473 BOOLEAN
BiosSetVideoPage(BYTE PageNumber
)
475 /* Check if the page exists */
476 if (PageNumber
>= BIOS_MAX_PAGES
) return FALSE
;
478 /* Check if this is the same page */
479 if (PageNumber
== Bda
->VideoPage
) return TRUE
;
481 /* Set the values in the BDA */
482 Bda
->VideoPage
= PageNumber
;
483 Bda
->VideoPageSize
= BIOS_PAGE_SIZE
;
484 Bda
->VideoPageOffset
= PageNumber
* BIOS_PAGE_SIZE
;
486 /* Set the start address in the CRTC */
487 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_CURSOR_LOC_LOW_REG
);
488 VgaWritePort(VGA_CRTC_DATA
, LOBYTE(Bda
->VideoPageOffset
));
489 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_CURSOR_LOC_HIGH_REG
);
490 VgaWritePort(VGA_CRTC_DATA
, HIBYTE(Bda
->VideoPageOffset
));
495 BOOLEAN
BiosInitialize(VOID
)
497 /* Initialize the BDA */
498 Bda
= (PBIOS_DATA_AREA
)SEG_OFF_TO_PTR(BDA_SEGMENT
, 0);
499 Bda
->EquipmentList
= BIOS_EQUIPMENT_LIST
;
501 * Conventional memory size is 640 kB,
502 * see: http://webpages.charter.net/danrollins/techhelp/0184.HTM
503 * and see Ralf Brown: http://www.ctyme.com/intr/rb-0598.htm
504 * for more information.
506 Bda
->MemorySize
= 0x0280;
507 Bda
->KeybdBufferStart
= FIELD_OFFSET(BIOS_DATA_AREA
, KeybdBuffer
);
508 Bda
->KeybdBufferEnd
= Bda
->KeybdBufferStart
+ BIOS_KBD_BUFFER_SIZE
* sizeof(WORD
);
510 /* Initialize the 32-bit Interrupt system */
511 InitializeInt32(BIOS_SEGMENT
);
513 /* Register the BIOS 32-bit Interrupts */
514 RegisterInt32(BIOS_VIDEO_INTERRUPT
, BiosVideoService
);
515 RegisterInt32(BIOS_EQUIPMENT_INTERRUPT
, BiosEquipmentService
);
516 RegisterInt32(BIOS_MEMORY_SIZE
, BiosGetMemorySize
);
517 RegisterInt32(BIOS_MISC_INTERRUPT
, BiosMiscService
);
518 RegisterInt32(BIOS_KBD_INTERRUPT
, BiosKeyboardService
);
519 RegisterInt32(BIOS_TIME_INTERRUPT
, BiosTimeService
);
520 RegisterInt32(BIOS_SYS_TIMER_INTERRUPT
, BiosSystemTimerInterrupt
);
522 /* Some interrupts are in fact addresses to tables */
523 ((PDWORD
)BaseAddress
)[0x1D] = (DWORD
)NULL
;
524 ((PDWORD
)BaseAddress
)[0x1E] = (DWORD
)NULL
;
525 ((PDWORD
)BaseAddress
)[0x1F] = (DWORD
)NULL
;
527 ((PDWORD
)BaseAddress
)[0x41] = (DWORD
)NULL
;
528 ((PDWORD
)BaseAddress
)[0x43] = (DWORD
)NULL
;
529 ((PDWORD
)BaseAddress
)[0x44] = (DWORD
)NULL
;
530 ((PDWORD
)BaseAddress
)[0x46] = (DWORD
)NULL
;
531 ((PDWORD
)BaseAddress
)[0x48] = (DWORD
)NULL
;
532 ((PDWORD
)BaseAddress
)[0x49] = (DWORD
)NULL
;
534 /* Get the input handle to the real console, and check for success */
535 BiosConsoleInput
= CreateFileW(L
"CONIN$",
536 GENERIC_READ
| GENERIC_WRITE
,
537 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
542 if (BiosConsoleInput
== INVALID_HANDLE_VALUE
)
547 /* Get the output handle to the real console, and check for success */
548 BiosConsoleOutput
= CreateFileW(L
"CONOUT$",
549 GENERIC_READ
| GENERIC_WRITE
,
550 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
555 if (BiosConsoleOutput
== INVALID_HANDLE_VALUE
)
557 CloseHandle(BiosConsoleInput
);
561 /* Save the console screen buffer information */
562 if (!GetConsoleScreenBufferInfo(BiosConsoleOutput
, &BiosSavedBufferInfo
))
564 CloseHandle(BiosConsoleOutput
);
565 CloseHandle(BiosConsoleInput
);
570 if (!VgaInitialize(BiosConsoleOutput
))
572 CloseHandle(BiosConsoleOutput
);
573 CloseHandle(BiosConsoleInput
);
577 /* Update the cursor position */
578 BiosSetCursorPosition(BiosSavedBufferInfo
.dwCursorPosition
.Y
,
579 BiosSavedBufferInfo
.dwCursorPosition
.X
,
582 /* Set the console input mode */
583 SetConsoleMode(BiosConsoleInput
, ENABLE_MOUSE_INPUT
| ENABLE_PROCESSED_INPUT
);
586 PS2Initialize(BiosConsoleInput
);
588 /* Initialize the PIC */
589 PicWriteCommand(PIC_MASTER_CMD
, PIC_ICW1
| PIC_ICW1_ICW4
);
590 PicWriteCommand(PIC_SLAVE_CMD
, PIC_ICW1
| PIC_ICW1_ICW4
);
592 /* Set the interrupt offsets */
593 PicWriteData(PIC_MASTER_DATA
, BIOS_PIC_MASTER_INT
);
594 PicWriteData(PIC_SLAVE_DATA
, BIOS_PIC_SLAVE_INT
);
596 /* Tell the master PIC there is a slave at IRQ 2 */
597 PicWriteData(PIC_MASTER_DATA
, 1 << 2);
598 PicWriteData(PIC_SLAVE_DATA
, 2);
600 /* Make sure the PIC is in 8086 mode */
601 PicWriteData(PIC_MASTER_DATA
, PIC_ICW4_8086
);
602 PicWriteData(PIC_SLAVE_DATA
, PIC_ICW4_8086
);
604 /* Clear the masks for both PICs */
605 PicWriteData(PIC_MASTER_DATA
, 0x00);
606 PicWriteData(PIC_SLAVE_DATA
, 0x00);
608 PitWriteCommand(0x34);
609 PitWriteData(0, 0x00);
610 PitWriteData(0, 0x00);
615 VOID
BiosCleanup(VOID
)
619 /* Restore the old screen buffer */
620 SetConsoleActiveScreenBuffer(BiosConsoleOutput
);
622 /* Restore the screen buffer size */
623 SetConsoleScreenBufferSize(BiosConsoleOutput
, BiosSavedBufferInfo
.dwSize
);
625 /* Close the console handles */
626 if (BiosConsoleOutput
!= INVALID_HANDLE_VALUE
) CloseHandle(BiosConsoleOutput
);
627 if (BiosConsoleInput
!= INVALID_HANDLE_VALUE
) CloseHandle(BiosConsoleInput
);
630 WORD
BiosPeekCharacter(VOID
)
632 WORD CharacterData
= 0;
634 /* Get the key from the queue, but don't remove it */
635 if (BiosKbdBufferTop(&CharacterData
)) return CharacterData
;
639 WORD
BiosGetCharacter(VOID
)
641 WORD CharacterData
= 0;
643 /* Check if there is a key available */
644 if (Bda
->KeybdBufferHead
!= Bda
->KeybdBufferTail
)
646 /* Get the key from the queue, and remove it */
647 BiosKbdBufferTop(&CharacterData
);
652 /* Set the handler CF to repeat the BOP */
653 EmulatorSetFlag(EMULATOR_FLAG_CF
);
656 return CharacterData
;
659 VOID
BiosGetCursorPosition(PBYTE Row
, PBYTE Column
, BYTE Page
)
661 /* Make sure the selected video page is valid */
662 if (Page
>= BIOS_MAX_PAGES
) return;
664 /* Get the cursor location */
665 *Row
= HIBYTE(Bda
->CursorPosition
[Page
]);
666 *Column
= LOBYTE(Bda
->CursorPosition
[Page
]);
669 VOID
BiosSetCursorPosition(BYTE Row
, BYTE Column
, BYTE Page
)
671 /* Make sure the selected video page is valid */
672 if (Page
>= BIOS_MAX_PAGES
) return;
674 /* Update the position in the BDA */
675 Bda
->CursorPosition
[Page
] = MAKEWORD(Column
, Row
);
677 /* Check if this is the current video page */
678 if (Page
== Bda
->VideoPage
)
680 WORD Offset
= Row
* Bda
->ScreenColumns
+ Column
;
682 /* Modify the CRTC registers */
683 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_CURSOR_LOC_LOW_REG
);
684 VgaWritePort(VGA_CRTC_DATA
, LOBYTE(Offset
));
685 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_CURSOR_LOC_HIGH_REG
);
686 VgaWritePort(VGA_CRTC_DATA
, HIBYTE(Offset
));
690 BOOLEAN
BiosScrollWindow(INT Direction
,
692 SMALL_RECT Rectangle
,
698 WORD WindowWidth
= Rectangle
.Right
- Rectangle
.Left
+ 1;
699 WORD WindowHeight
= Rectangle
.Bottom
- Rectangle
.Top
+ 1;
700 DWORD WindowSize
= WindowWidth
* WindowHeight
;
702 /* Allocate a buffer for the window */
703 WindowData
= (LPWORD
)HeapAlloc(GetProcessHeap(),
705 WindowSize
* sizeof(WORD
));
706 if (WindowData
== NULL
) return FALSE
;
708 /* Read the window data */
709 BiosReadWindow(WindowData
, Rectangle
, Page
);
712 || (((Direction
== SCROLL_DIRECTION_UP
)
713 || (Direction
== SCROLL_DIRECTION_DOWN
))
714 && (Amount
>= WindowHeight
))
715 || (((Direction
== SCROLL_DIRECTION_LEFT
)
716 || (Direction
== SCROLL_DIRECTION_RIGHT
))
717 && (Amount
>= WindowWidth
)))
719 /* Fill the window */
720 for (i
= 0; i
< WindowSize
; i
++)
722 WindowData
[i
] = MAKEWORD(' ', FillAttribute
);
730 case SCROLL_DIRECTION_UP
:
732 RtlMoveMemory(WindowData
,
733 &WindowData
[WindowWidth
* Amount
],
734 (WindowSize
- WindowWidth
* Amount
) * sizeof(WORD
));
736 for (i
= 0; i
< Amount
* WindowWidth
; i
++)
738 WindowData
[WindowSize
- i
- 1] = MAKEWORD(' ', FillAttribute
);
744 case SCROLL_DIRECTION_DOWN
:
746 RtlMoveMemory(&WindowData
[WindowWidth
* Amount
],
748 (WindowSize
- WindowWidth
* Amount
) * sizeof(WORD
));
750 for (i
= 0; i
< Amount
* WindowWidth
; i
++)
752 WindowData
[i
] = MAKEWORD(' ', FillAttribute
);
760 // TODO: NOT IMPLEMENTED!
766 /* Write back the window data */
767 BiosWriteWindow(WindowData
, Rectangle
, Page
);
769 /* Free the window buffer */
770 HeapFree(GetProcessHeap(), 0, WindowData
);
775 VOID
BiosPrintCharacter(CHAR Character
, BYTE Attribute
, BYTE Page
)
777 WORD CharData
= MAKEWORD(Character
, Attribute
);
780 /* Make sure the page exists */
781 if (Page
>= BIOS_MAX_PAGES
) return;
783 /* Get the cursor location */
784 BiosGetCursorPosition(&Row
, &Column
, Page
);
786 if (Character
== '\a')
788 /* Bell control character */
789 // NOTE: We may use what the terminal emulator offers to us...
793 else if (Character
== '\b')
795 /* Backspace control character */
802 Column
= Bda
->ScreenColumns
- 1;
806 /* Erase the existing character */
807 CharData
= MAKEWORD(' ', Attribute
);
808 EmulatorWriteMemory(&EmulatorContext
,
809 TO_LINEAR(TEXT_VIDEO_SEG
,
810 Page
* Bda
->VideoPageSize
+
811 (Row
* Bda
->ScreenColumns
+ Column
) * sizeof(WORD
)),
815 else if (Character
== '\t')
817 /* Horizontal Tabulation control character */
821 BiosPrintCharacter(' ', Attribute
, Page
);
822 BiosGetCursorPosition(&Row
, &Column
, Page
);
823 } while (Column
% 8);
825 else if (Character
== '\n')
827 /* Line Feed control character */
830 else if (Character
== '\r')
832 /* Carriage Return control character */
837 /* Default character */
839 /* Write the character */
840 EmulatorWriteMemory(&EmulatorContext
,
841 TO_LINEAR(TEXT_VIDEO_SEG
,
842 Page
* Bda
->VideoPageSize
+
843 (Row
* Bda
->ScreenColumns
+ Column
) * sizeof(WORD
)),
847 /* Advance the cursor */
851 /* Check if it passed the end of the row */
852 if (Column
>= Bda
->ScreenColumns
)
854 /* Return to the first column and go to the next line */
859 /* Scroll the screen up if needed */
860 if (Row
> Bda
->ScreenRows
)
862 /* The screen must be scrolled up */
863 SMALL_RECT Rectangle
= { 0, 0, Bda
->ScreenColumns
- 1, Bda
->ScreenRows
};
865 BiosScrollWindow(SCROLL_DIRECTION_UP
,
874 /* Set the cursor position */
875 BiosSetCursorPosition(Row
, Column
, Page
);
878 VOID WINAPI
BiosVideoService(LPWORD Stack
)
885 BiosSetVideoMode(getAL());
890 /* Set Text-Mode Cursor Shape */
894 Bda
->CursorStartLine
= getCH();
895 Bda
->CursorEndLine
= getCL();
897 /* Modify the CRTC registers */
898 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_CURSOR_START_REG
);
899 VgaWritePort(VGA_CRTC_DATA
, Bda
->CursorStartLine
);
900 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_CURSOR_END_REG
);
901 VgaWritePort(VGA_CRTC_DATA
, Bda
->CursorEndLine
);
906 /* Set Cursor Position */
909 BiosSetCursorPosition(getDH(), getDL(), getBH());
913 /* Get Cursor Position */
916 /* Make sure the selected video page exists */
917 if (getBH() >= BIOS_MAX_PAGES
) break;
919 /* Return the result */
921 setCX(MAKEWORD(Bda
->CursorEndLine
, Bda
->CursorStartLine
));
922 setDX(Bda
->CursorPosition
[getBH()]);
926 /* Query Light Pen */
930 * On modern BIOSes, this function returns 0
931 * so that we can ignore the other registers.
937 /* Select Active Display Page */
940 BiosSetVideoPage(getAL());
944 /* Scroll Window Up/Down */
948 SMALL_RECT Rectangle
= { getCL(), getCH(), getDL(), getDH() };
950 /* Call the internal function */
951 BiosScrollWindow((getAH() == 0x06) ? SCROLL_DIRECTION_UP
952 : SCROLL_DIRECTION_DOWN
,
961 /* Read/Write Character From Cursor Position */
966 WORD CharacterData
= MAKEWORD(getAL(), getBL());
970 /* Check if the page exists */
971 if (Page
>= BIOS_MAX_PAGES
) break;
973 /* Find the offset of the character */
974 Offset
= Page
* Bda
->VideoPageSize
+
975 (HIBYTE(Bda
->CursorPosition
[Page
]) * Bda
->ScreenColumns
+
976 LOBYTE(Bda
->CursorPosition
[Page
])) * 2;
980 /* Read from the video memory */
981 VgaReadMemory(TO_LINEAR(TEXT_VIDEO_SEG
, Offset
),
982 (LPVOID
)&CharacterData
,
985 /* Return the character in AX */
986 setAX(CharacterData
);
990 /* Write to video memory */
991 VgaWriteMemory(TO_LINEAR(TEXT_VIDEO_SEG
, Offset
),
992 (LPVOID
)&CharacterData
,
993 (getBH() == 0x09) ? sizeof(WORD
) : sizeof(BYTE
));
999 /* Teletype Output */
1002 BiosPrintCharacter(getAL(), getBL(), getBH());
1006 /* Get Current Video Mode */
1009 setAX(MAKEWORD(Bda
->VideoMode
, Bda
->ScreenColumns
));
1010 setBX(MAKEWORD(getBL(), Bda
->VideoPage
));
1014 /* Palette Control */
1019 /* Set Single Palette Register */
1022 /* Reset the flip-flop */
1023 VgaReadPort(VGA_STAT_COLOR
);
1025 /* Write the index */
1026 VgaWritePort(VGA_AC_INDEX
, getBL());
1028 /* Write the data */
1029 VgaWritePort(VGA_AC_WRITE
, getBH());
1034 /* Set Overscan Color */
1037 /* Reset the flip-flop */
1038 VgaReadPort(VGA_STAT_COLOR
);
1040 /* Write the index */
1041 VgaWritePort(VGA_AC_INDEX
, VGA_AC_OVERSCAN_REG
);
1043 /* Write the data */
1044 VgaWritePort(VGA_AC_WRITE
, getBH());
1049 /* Set All Palette Registers */
1053 LPBYTE Buffer
= SEG_OFF_TO_PTR(getES(), getDX());
1055 /* Set the palette registers */
1056 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
1058 /* Reset the flip-flop */
1059 VgaReadPort(VGA_STAT_COLOR
);
1061 /* Write the index */
1062 VgaWritePort(VGA_AC_INDEX
, i
);
1064 /* Write the data */
1065 VgaWritePort(VGA_AC_WRITE
, Buffer
[i
]);
1068 /* Set the overscan register */
1069 VgaWritePort(VGA_AC_INDEX
, VGA_AC_OVERSCAN_REG
);
1070 VgaWritePort(VGA_AC_WRITE
, Buffer
[VGA_AC_PAL_F_REG
+ 1]);
1075 /* Get Single Palette Register */
1078 /* Reset the flip-flop */
1079 VgaReadPort(VGA_STAT_COLOR
);
1081 /* Write the index */
1082 VgaWritePort(VGA_AC_INDEX
, getBL());
1085 setBH(VgaReadPort(VGA_AC_READ
));
1090 /* Get Overscan Color */
1093 /* Reset the flip-flop */
1094 VgaReadPort(VGA_STAT_COLOR
);
1096 /* Write the index */
1097 VgaWritePort(VGA_AC_INDEX
, VGA_AC_OVERSCAN_REG
);
1100 setBH(VgaReadPort(VGA_AC_READ
));
1105 /* Get All Palette Registers */
1109 LPBYTE Buffer
= SEG_OFF_TO_PTR(getES(), getDX());
1111 /* Get the palette registers */
1112 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
1114 /* Reset the flip-flop */
1115 VgaReadPort(VGA_STAT_COLOR
);
1117 /* Write the index */
1118 VgaWritePort(VGA_AC_INDEX
, i
);
1121 Buffer
[i
] = VgaReadPort(VGA_AC_READ
);
1124 /* Get the overscan register */
1125 VgaWritePort(VGA_AC_INDEX
, VGA_AC_OVERSCAN_REG
);
1126 Buffer
[VGA_AC_PAL_F_REG
+ 1] = VgaReadPort(VGA_AC_READ
);
1131 /* Set Individual DAC Register */
1134 /* Write the index */
1135 // Certainly in BL and not in BX as said by Ralf Brown...
1136 VgaWritePort(VGA_DAC_WRITE_INDEX
, getBL());
1138 /* Write the data in this order: Red, Green, Blue */
1139 VgaWritePort(VGA_DAC_DATA
, getDH());
1140 VgaWritePort(VGA_DAC_DATA
, getCH());
1141 VgaWritePort(VGA_DAC_DATA
, getCL());
1146 /* Set Block of DAC Registers */
1150 LPBYTE Buffer
= SEG_OFF_TO_PTR(getES(), getDX());
1152 /* Write the index */
1153 // Certainly in BL and not in BX as said by Ralf Brown...
1154 VgaWritePort(VGA_DAC_WRITE_INDEX
, getBL());
1156 for (i
= 0; i
< getCX(); i
++)
1158 /* Write the data in this order: Red, Green, Blue */
1159 VgaWritePort(VGA_DAC_DATA
, *Buffer
++);
1160 VgaWritePort(VGA_DAC_DATA
, *Buffer
++);
1161 VgaWritePort(VGA_DAC_DATA
, *Buffer
++);
1167 /* Get Individual DAC Register */
1170 /* Write the index */
1171 VgaWritePort(VGA_DAC_READ_INDEX
, getBL());
1173 /* Read the data in this order: Red, Green, Blue */
1174 setDH(VgaReadPort(VGA_DAC_DATA
));
1175 setCH(VgaReadPort(VGA_DAC_DATA
));
1176 setCL(VgaReadPort(VGA_DAC_DATA
));
1181 /* Get Block of DAC Registers */
1185 LPBYTE Buffer
= SEG_OFF_TO_PTR(getES(), getDX());
1187 /* Write the index */
1188 // Certainly in BL and not in BX as said by Ralf Brown...
1189 VgaWritePort(VGA_DAC_READ_INDEX
, getBL());
1191 for (i
= 0; i
< getCX(); i
++)
1193 /* Write the data in this order: Red, Green, Blue */
1194 *Buffer
++ = VgaReadPort(VGA_DAC_DATA
);
1195 *Buffer
++ = VgaReadPort(VGA_DAC_DATA
);
1196 *Buffer
++ = VgaReadPort(VGA_DAC_DATA
);
1204 DPRINT1("BIOS Palette Control Sub-command AL = 0x%02X NOT IMPLEMENTED\n",
1216 SMALL_RECT Rectangle
= { getCL(), getCH(), getDL(), getDH() };
1218 /* Call the internal function */
1219 BiosScrollWindow(getBL(),
1228 /* Display combination code */
1233 case 0x00: /* Get Display combiantion code */
1234 setAX(MAKEWORD(0x1A, 0x1A));
1235 setBX(MAKEWORD(0x08, 0x00)); /* VGA w/ color analog display */
1237 case 0x01: /* Set Display combination code */
1238 DPRINT1("Set Display combination code - Unsupported\n");
1248 DPRINT1("BIOS Function INT 10h, AH = 0x%02X NOT IMPLEMENTED\n",
1254 VOID WINAPI
BiosEquipmentService(LPWORD Stack
)
1256 /* Return the equipment list */
1257 setAX(Bda
->EquipmentList
);
1260 VOID WINAPI
BiosGetMemorySize(LPWORD Stack
)
1262 /* Return the conventional memory size in kB, typically 640 kB */
1263 setAX(Bda
->MemorySize
);
1266 VOID WINAPI
BiosMiscService(LPWORD Stack
)
1270 /* Copy Extended Memory */
1273 DWORD Count
= (DWORD
)getCX() * 2;
1274 PFAST486_GDT_ENTRY Gdt
= (PFAST486_GDT_ENTRY
)SEG_OFF_TO_PTR(getES(), getSI());
1275 DWORD SourceBase
= Gdt
[2].Base
+ (Gdt
[2].BaseMid
<< 16) + (Gdt
[2].BaseHigh
<< 24);
1276 DWORD SourceLimit
= Gdt
[2].Limit
+ (Gdt
[2].LimitHigh
<< 16);
1277 DWORD DestBase
= Gdt
[3].Base
+ (Gdt
[3].BaseMid
<< 16) + (Gdt
[3].BaseHigh
<< 24);
1278 DWORD DestLimit
= Gdt
[3].Limit
+ (Gdt
[3].LimitHigh
<< 16);
1280 /* Check for flags */
1281 if (Gdt
[2].Granularity
) SourceLimit
= (SourceLimit
<< 12) | 0xFFF;
1282 if (Gdt
[3].Granularity
) DestLimit
= (DestLimit
<< 12) | 0xFFF;
1284 if ((Count
> SourceLimit
) || (Count
> DestLimit
))
1287 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1293 RtlMoveMemory((PVOID
)((ULONG_PTR
)BaseAddress
+ DestBase
),
1294 (PVOID
)((ULONG_PTR
)BaseAddress
+ SourceBase
),
1297 setAX(ERROR_SUCCESS
);
1298 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1302 /* Get Extended Memory Size */
1305 /* Return the number of KB of RAM after 1 MB */
1306 setAX((MAX_ADDRESS
- 0x100000) / 1024);
1309 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1316 DPRINT1("BIOS Function INT 15h, AH = 0x%02X NOT IMPLEMENTED\n",
1322 VOID WINAPI
BiosKeyboardService(LPWORD Stack
)
1326 /* Wait for keystroke and read */
1328 /* Wait for extended keystroke and read */
1329 case 0x10: // FIXME: Temporarily do the same as INT 16h, 00h
1331 /* Read the character (and wait if necessary) */
1332 setAX(BiosGetCharacter());
1336 /* Get keystroke status */
1338 /* Get extended keystroke status */
1339 case 0x11: // FIXME: Temporarily do the same as INT 16h, 01h
1341 WORD Data
= BiosPeekCharacter();
1345 /* There is a character, clear ZF and return it */
1346 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_ZF
;
1351 /* No character, set ZF */
1352 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_ZF
;
1358 /* Get shift status */
1361 /* Return the lower byte of the keyboard shift status word */
1362 setAL(LOBYTE(Bda
->KeybdShiftFlags
));
1369 DPRINT1("BIOS Function INT 16h, AH = 0x04 is RESERVED\n");
1373 /* Push keystroke */
1376 /* Return 0 if success, 1 if failure */
1377 setAL(BiosKbdBufferPush(getCX()) == FALSE
);
1381 /* Get extended shift status */
1385 * Be careful! The returned word is similar to Bda->KeybdShiftFlags
1386 * but the high byte is organized differently:
1387 * the bytes 2 and 3 of the high byte are not the same...
1389 WORD KeybdShiftFlags
= (Bda
->KeybdShiftFlags
& 0xF3FF);
1391 /* Return the extended keyboard shift status word */
1392 setAX(KeybdShiftFlags
);
1398 DPRINT1("BIOS Function INT 16h, AH = 0x%02X NOT IMPLEMENTED\n",
1404 VOID WINAPI
BiosTimeService(LPWORD Stack
)
1410 /* Set AL to 1 if midnight had passed, 0 otherwise */
1411 setAL(Bda
->MidnightPassed
? 0x01 : 0x00);
1413 /* Return the tick count in CX:DX */
1414 setCX(HIWORD(Bda
->TickCounter
));
1415 setDX(LOWORD(Bda
->TickCounter
));
1417 /* Reset the midnight flag */
1418 Bda
->MidnightPassed
= FALSE
;
1425 /* Set the tick count to CX:DX */
1426 Bda
->TickCounter
= MAKELONG(getDX(), getCX());
1428 /* Reset the midnight flag */
1429 Bda
->MidnightPassed
= FALSE
;
1436 DPRINT1("BIOS Function INT 1Ah, AH = 0x%02X NOT IMPLEMENTED\n",
1442 VOID WINAPI
BiosSystemTimerInterrupt(LPWORD Stack
)
1444 /* Increase the system tick count */
1448 VOID
BiosHandleIrq(BYTE IrqNumber
, LPWORD Stack
)
1455 /* Perform the system timer interrupt */
1456 EmulatorInterrupt(BIOS_SYS_TIMER_INTERRUPT
);
1463 BYTE ScanCode
, VirtualKey
;
1466 /* Get the scan code and virtual key code */
1467 ScanCode
= PS2ReadPort(PS2_DATA_PORT
);
1468 VirtualKey
= MapVirtualKey(ScanCode
& 0x7F, MAPVK_VSC_TO_VK
);
1470 /* Check if this is a key press or release */
1471 if (!(ScanCode
& (1 << 7)))
1474 if (VirtualKey
== VK_NUMLOCK
||
1475 VirtualKey
== VK_CAPITAL
||
1476 VirtualKey
== VK_SCROLL
||
1477 VirtualKey
== VK_INSERT
)
1479 /* For toggle keys, toggle the lowest bit in the keyboard map */
1480 BiosKeyboardMap
[VirtualKey
] ^= ~(1 << 0);
1483 /* Set the highest bit */
1484 BiosKeyboardMap
[VirtualKey
] |= (1 << 7);
1486 /* Find out which character this is */
1488 if (ToAscii(VirtualKey
, ScanCode
, BiosKeyboardMap
, &Character
, 0) == 0)
1494 /* Push it onto the BIOS keyboard queue */
1495 BiosKbdBufferPush(MAKEWORD(Character
, ScanCode
));
1499 /* Key release, unset the highest bit */
1500 BiosKeyboardMap
[VirtualKey
] &= ~(1 << 7);
1503 /* Clear the keyboard flags */
1504 Bda
->KeybdShiftFlags
= 0;
1506 /* Set the appropriate flags based on the state */
1507 if (BiosKeyboardMap
[VK_RSHIFT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_RSHIFT
;
1508 if (BiosKeyboardMap
[VK_LSHIFT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_LSHIFT
;
1509 if (BiosKeyboardMap
[VK_CONTROL
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_CTRL
;
1510 if (BiosKeyboardMap
[VK_MENU
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_ALT
;
1511 if (BiosKeyboardMap
[VK_SCROLL
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_SCROLL_ON
;
1512 if (BiosKeyboardMap
[VK_NUMLOCK
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_NUMLOCK_ON
;
1513 if (BiosKeyboardMap
[VK_CAPITAL
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_CAPSLOCK_ON
;
1514 if (BiosKeyboardMap
[VK_INSERT
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_INSERT_ON
;
1515 if (BiosKeyboardMap
[VK_RMENU
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_RALT
;
1516 if (BiosKeyboardMap
[VK_LMENU
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_LALT
;
1517 if (BiosKeyboardMap
[VK_SNAPSHOT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_SYSRQ
;
1518 if (BiosKeyboardMap
[VK_PAUSE
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_PAUSE
;
1519 if (BiosKeyboardMap
[VK_SCROLL
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_SCROLL
;
1520 if (BiosKeyboardMap
[VK_NUMLOCK
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_NUMLOCK
;
1521 if (BiosKeyboardMap
[VK_CAPITAL
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_CAPSLOCK
;
1522 if (BiosKeyboardMap
[VK_INSERT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_INSERT
;
1528 /* Send End-of-Interrupt to the PIC */
1529 if (IrqNumber
>= 8) PicWriteCommand(PIC_SLAVE_CMD
, PIC_OCW2_EOI
);
1530 PicWriteCommand(PIC_MASTER_CMD
, PIC_OCW2_EOI
);