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 /* MACROS *********************************************************************/
27 // These macros are defined for ease-of-use of some VGA I/O ports
28 // whose addresses depend whether we are in Monochrome or Colour mode.
30 #define VGA_INSTAT1_READ Bda->CrtBasePort + 6 // VGA_INSTAT1_READ_MONO or VGA_INSTAT1_READ_COLOR
31 #define VGA_CRTC_INDEX Bda->CrtBasePort // VGA_CRTC_INDEX_MONO or VGA_CRTC_INDEX_COLOR
32 #define VGA_CRTC_DATA Bda->CrtBasePort + 1 // VGA_CRTC_DATA_MONO or VGA_CRTC_DATA_COLOR
34 /* PRIVATE VARIABLES **********************************************************/
37 static BYTE BiosKeyboardMap
[256];
38 static HANDLE BiosConsoleInput
= INVALID_HANDLE_VALUE
;
39 static HANDLE BiosConsoleOutput
= INVALID_HANDLE_VALUE
;
40 static CONSOLE_SCREEN_BUFFER_INFO BiosSavedBufferInfo
;
43 * VGA Register Configurations for BIOS Video Modes
44 * The configurations come from DosBox.
46 static VGA_REGISTERS VideoMode_40x25_text
=
48 /* Miscellaneous Register */
51 /* Sequencer Registers */
52 {0x00, 0x08, 0x03, 0x00, 0x07},
55 {0x2D, 0x27, 0x28, 0x90, 0x2B, 0xA0, 0xBF, 0x1F, 0x00, 0x4F, 0x0D, 0x0E,
56 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x14, 0x1F, 0x96, 0xB9, 0xA3,
60 {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x0F, 0xFF},
63 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
64 0x3C, 0x3D, 0x3E, 0x3F, 0x0C, 0x00, 0x0F, 0x08, 0x00}
67 static VGA_REGISTERS VideoMode_80x25_text
=
69 /* Miscellaneous Register */
72 /* Sequencer Registers */
73 {0x00, 0x00, 0x03, 0x00, 0x07},
76 {0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F, 0x00, 0x4F, 0x0D, 0x0E,
77 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3,
81 {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x0F, 0xFF},
84 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
85 0x3C, 0x3D, 0x3E, 0x3F, 0x0C, 0x00, 0x0F, 0x08, 0x00}
88 static VGA_REGISTERS VideoMode_320x200_4color
=
90 /* Miscellaneous Register */
93 /* Sequencer Registers */
94 {0x00, 0x09, 0x00, 0x00, 0x02},
97 {0x2D, 0x27, 0x28, 0x90, 0x2B, 0x80, 0xBF, 0x1F, 0x00, 0xC1, 0x00, 0x00,
98 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x14, 0x00, 0x96, 0xB9, 0xA2,
102 {0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0F, 0x0F, 0xFF},
105 {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13,
106 0x14, 0x15, 0x16, 0x17, 0x01, 0x00, 0x0F, 0x00, 0x00}
109 static VGA_REGISTERS VideoMode_640x200_2color
=
111 /* Miscellaneous Register */
114 /* Sequencer Registers */
115 {0x00, 0x09, 0x0F, 0x00, 0x02},
118 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0xC1, 0x00, 0x00,
119 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x28, 0x00, 0x96, 0xB9, 0xC2,
123 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0xFF},
126 {0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
127 0x17, 0x17, 0x17, 0x17, 0x01, 0x00, 0x01, 0x00, 0x00}
130 static VGA_REGISTERS VideoMode_320x200_16color
=
132 /* Miscellaneous Register */
135 /* Sequencer Registers */
136 {0x00, 0x09, 0x0F, 0x00, 0x02},
139 {0x2D, 0x27, 0x28, 0x90, 0x2B, 0x80, 0xBF, 0x1F, 0x00, 0xC0, 0x00, 0x00,
140 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x14, 0x00, 0x96, 0xB9, 0xE3,
144 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
147 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
148 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00}
151 static VGA_REGISTERS VideoMode_640x200_16color
=
153 /* Miscellaneous Register */
156 /* Sequencer Registers */
157 {0x00, 0x01, 0x0F, 0x00, 0x02},
160 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0xC0, 0x00, 0x00,
161 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x28, 0x00, 0x96, 0xB9, 0xE3,
165 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
168 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
169 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00}
172 static VGA_REGISTERS VideoMode_640x350_16color
=
174 /* Miscellaneous Register */
177 /* Sequencer Registers */
178 {0x00, 0x01, 0x0F, 0x00, 0x02},
181 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0x40, 0x00, 0x00,
182 0x00, 0x00, 0x00, 0x00, 0x83, 0x85, 0x5D, 0x28, 0x0F, 0x63, 0xBA, 0xE3,
186 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
189 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
190 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00}
193 static VGA_REGISTERS VideoMode_640x480_2color
=
195 /* Miscellaneous Register */
198 /* Sequencer Registers */
199 {0x00, 0x01, 0x0F, 0x00, 0x02},
202 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x0B, 0x3E, 0x00, 0x40, 0x00, 0x00,
203 0x00, 0x00, 0x00, 0x00, 0xEA, 0x8C, 0xDF, 0x28, 0x00, 0xE7, 0x04, 0xC3,
207 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
210 {0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
211 0x3F, 0x3F, 0x3F, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00}
214 static VGA_REGISTERS VideoMode_640x480_16color
=
216 /* Miscellaneous Register */
219 /* Sequencer Registers */
220 {0x00, 0x01, 0x0F, 0x00, 0x02},
223 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x0B, 0x3E, 0x00, 0x40, 0x00, 0x00,
224 0x00, 0x00, 0x00, 0x00, 0xEA, 0x8C, 0xDF, 0x28, 0x00, 0xE7, 0x04, 0xE3,
228 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
231 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
232 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00}
235 static VGA_REGISTERS VideoMode_320x200_256color
=
237 /* Miscellaneous Register */
240 /* Sequencer Registers */
241 {0x00, 0x01, 0x0F, 0x00, 0x0E},
244 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0x41, 0x00, 0x00,
245 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3,
249 {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF},
252 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
253 0x0C, 0x0D, 0x0E, 0x0F, 0x41, 0x00, 0x0F, 0x00, 0x00}
256 /* See http://wiki.osdev.org/Drawing_In_Protected_Mode#Locating_Video_Memory */
257 static PVGA_REGISTERS VideoModes
[] =
259 &VideoMode_40x25_text
, /* Mode 00h */ // 16 color (mono)
260 &VideoMode_40x25_text
, /* Mode 01h */ // 16 color
261 &VideoMode_80x25_text
, /* Mode 02h */ // 16 color (mono)
262 &VideoMode_80x25_text
, /* Mode 03h */ // 16 color
263 &VideoMode_320x200_4color
, /* Mode 04h */
264 &VideoMode_320x200_4color
, /* Mode 05h */ // same (m)
265 &VideoMode_640x200_2color
, /* Mode 06h */ // 640*200 2 color
266 NULL
, /* Mode 07h */ // MDA monochrome text 80*25
267 NULL
, /* Mode 08h */ // PCjr
268 NULL
, /* Mode 09h */ // PCjr
269 NULL
, /* Mode 0Ah */ // PCjr
270 NULL
, /* Mode 0Bh */ // Reserved
271 NULL
, /* Mode 0Ch */ // Reserved
272 &VideoMode_320x200_16color
, /* Mode 0Dh */ // EGA 320*200 16 color
273 &VideoMode_640x200_16color
, /* Mode 0Eh */ // EGA 640*200 16 color
274 NULL
, /* Mode 0Fh */ // EGA 640*350 mono
275 &VideoMode_640x350_16color
, /* Mode 10h */ // EGA 640*350 16 color
276 &VideoMode_640x480_2color
, /* Mode 11h */ // VGA 640*480 mono
277 &VideoMode_640x480_16color
, /* Mode 12h */
278 &VideoMode_320x200_256color
, /* Mode 13h */
281 /* PRIVATE FUNCTIONS **********************************************************/
283 static BOOLEAN
BiosKbdBufferPush(WORD Data
)
285 /* Get the location of the element after the tail */
286 WORD NextElement
= Bda
->KeybdBufferTail
+ sizeof(WORD
);
288 /* Wrap it around if it's at or beyond the end */
289 if (NextElement
>= Bda
->KeybdBufferEnd
) NextElement
= Bda
->KeybdBufferStart
;
291 /* If it's full, fail */
292 if (NextElement
== Bda
->KeybdBufferHead
) return FALSE
;
294 /* Put the value in the queue */
295 *((LPWORD
)((ULONG_PTR
)Bda
+ Bda
->KeybdBufferTail
)) = Data
;
296 Bda
->KeybdBufferTail
+= sizeof(WORD
);
298 /* Check if we are at, or have passed, the end of the buffer */
299 if (Bda
->KeybdBufferTail
>= Bda
->KeybdBufferEnd
)
301 /* Return it to the beginning */
302 Bda
->KeybdBufferTail
= Bda
->KeybdBufferStart
;
309 static BOOLEAN
BiosKbdBufferTop(LPWORD Data
)
311 /* If it's empty, fail */
312 if (Bda
->KeybdBufferHead
== Bda
->KeybdBufferTail
) return FALSE
;
314 /* Otherwise, get the value and return success */
315 *Data
= *((LPWORD
)((ULONG_PTR
)Bda
+ Bda
->KeybdBufferHead
));
320 static BOOLEAN
BiosKbdBufferPop(VOID
)
322 /* If it's empty, fail */
323 if (Bda
->KeybdBufferHead
== Bda
->KeybdBufferTail
) return FALSE
;
325 /* Remove the value from the queue */
326 Bda
->KeybdBufferHead
+= sizeof(WORD
);
328 /* Check if we are at, or have passed, the end of the buffer */
329 if (Bda
->KeybdBufferHead
>= Bda
->KeybdBufferEnd
)
331 /* Return it to the beginning */
332 Bda
->KeybdBufferHead
= Bda
->KeybdBufferStart
;
339 static VOID
BiosReadWindow(LPWORD Buffer
, SMALL_RECT Rectangle
, BYTE Page
)
344 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Page
* Bda
->VideoPageSize
);
346 for (i
= Rectangle
.Top
; i
<= Rectangle
.Bottom
; i
++)
348 for (j
= Rectangle
.Left
; j
<= Rectangle
.Right
; j
++)
350 /* Read from video memory */
351 VgaReadMemory(VideoAddress
+ (i
* Bda
->ScreenColumns
+ j
) * sizeof(WORD
),
355 /* Write the data to the buffer in row order */
356 Buffer
[Counter
++] = Character
;
361 static VOID
BiosWriteWindow(LPWORD Buffer
, SMALL_RECT Rectangle
, BYTE Page
)
366 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Page
* Bda
->VideoPageSize
);
368 for (i
= Rectangle
.Top
; i
<= Rectangle
.Bottom
; i
++)
370 for (j
= Rectangle
.Left
; j
<= Rectangle
.Right
; j
++)
372 Character
= Buffer
[Counter
++];
374 /* Write to video memory */
375 VgaWriteMemory(VideoAddress
+ (i
* Bda
->ScreenColumns
+ j
) * sizeof(WORD
),
382 static BOOLEAN
VgaSetRegisters(PVGA_REGISTERS Registers
)
386 if (Registers
== NULL
) return FALSE
;
388 /* Clear interrupts */
392 * Set the CRT base address according to the selected mode,
393 * monochrome or color. The following macros:
394 * VGA_INSTAT1_READ, VGA_CRTC_INDEX and VGA_CRTC_DATA are then
395 * used to access the correct VGA I/O ports.
397 Bda
->CrtBasePort
= (Registers
->Misc
& 0x01) ? VGA_CRTC_INDEX_COLOR
398 : VGA_CRTC_INDEX_MONO
;
400 /* Write the misc register */
401 VgaWritePort(VGA_MISC_WRITE
, Registers
->Misc
);
403 /* Synchronous reset on */
404 VgaWritePort(VGA_SEQ_INDEX
, VGA_SEQ_RESET_REG
);
405 VgaWritePort(VGA_SEQ_DATA
, VGA_SEQ_RESET_AR
);
407 /* Write the sequencer registers */
408 for (i
= 1; i
< VGA_SEQ_MAX_REG
; i
++)
410 VgaWritePort(VGA_SEQ_INDEX
, i
);
411 VgaWritePort(VGA_SEQ_DATA
, Registers
->Sequencer
[i
]);
414 /* Synchronous reset off */
415 VgaWritePort(VGA_SEQ_INDEX
, VGA_SEQ_RESET_REG
);
416 VgaWritePort(VGA_SEQ_DATA
, VGA_SEQ_RESET_SR
| VGA_SEQ_RESET_AR
);
418 /* Unlock CRTC registers 0-7 */
419 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_END_HORZ_BLANKING_REG
);
420 VgaWritePort(VGA_CRTC_DATA
, VgaReadPort(VGA_CRTC_DATA
) | 0x80);
421 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_VERT_RETRACE_END_REG
);
422 VgaWritePort(VGA_CRTC_DATA
, VgaReadPort(VGA_CRTC_DATA
) & ~0x80);
423 // Make sure they remain unlocked
424 Registers
->CRT
[VGA_CRTC_END_HORZ_BLANKING_REG
] |= 0x80;
425 Registers
->CRT
[VGA_CRTC_VERT_RETRACE_END_REG
] &= ~0x80;
427 /* Write the CRTC registers */
428 for (i
= 0; i
< VGA_CRTC_MAX_REG
; i
++)
430 VgaWritePort(VGA_CRTC_INDEX
, i
);
431 VgaWritePort(VGA_CRTC_DATA
, Registers
->CRT
[i
]);
434 /* Write the GC registers */
435 for (i
= 0; i
< VGA_GC_MAX_REG
; i
++)
437 VgaWritePort(VGA_GC_INDEX
, i
);
438 VgaWritePort(VGA_GC_DATA
, Registers
->Graphics
[i
]);
441 /* Write the AC registers */
442 for (i
= 0; i
< VGA_AC_MAX_REG
; i
++)
444 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
445 VgaWritePort(VGA_AC_INDEX
, i
);
446 VgaWritePort(VGA_AC_WRITE
, Registers
->Attribute
[i
]);
449 /* Set the PEL mask */
450 VgaWritePort(VGA_DAC_MASK
, 0xFF);
452 /* Enable screen and disable palette access */
453 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
454 VgaWritePort(VGA_AC_INDEX
, 0x20);
462 /* PUBLIC FUNCTIONS ***********************************************************/
464 BYTE
BiosGetVideoMode(VOID
)
466 return Bda
->VideoMode
;
469 BOOLEAN
BiosSetVideoMode(BYTE ModeNumber
)
473 PVGA_REGISTERS VgaMode
= VideoModes
[ModeNumber
];
475 DPRINT1("Switching to mode %Xh; VgaMode = 0x%p\n", ModeNumber
, VgaMode
);
477 if (!VgaSetRegisters(VgaMode
)) return FALSE
;
479 // /* Disable screen and enable palette access */
480 // VgaReadPort(VGA_INSTAT1_READ); // Put the AC register into index state
481 // VgaWritePort(VGA_AC_INDEX, 0x00);
483 if ((ModeNumber
== 0x0D) || (ModeNumber
== 0x0E) || (ModeNumber
== 0x10))
486 extern CONST COLORREF EgaPalette
[VGA_MAX_COLORS
/ 4];
487 for (i
= 0; i
< sizeof(EgaPalette
)/sizeof(EgaPalette
[0]); i
++)
489 VgaWritePort(VGA_DAC_WRITE_INDEX
, i
);
490 VgaWritePort(VGA_DAC_DATA
, VGA_COLOR_TO_DAC(GetRValue(EgaPalette
[i
])));
491 VgaWritePort(VGA_DAC_DATA
, VGA_COLOR_TO_DAC(GetGValue(EgaPalette
[i
])));
492 VgaWritePort(VGA_DAC_DATA
, VGA_COLOR_TO_DAC(GetBValue(EgaPalette
[i
])));
497 /* Reset the palette */
501 // /* Enable screen and disable palette access */
502 // VgaReadPort(VGA_INSTAT1_READ); // Put the AC register into index state
503 // VgaWritePort(VGA_AC_INDEX, 0x20);
505 // Bda->CrtModeControl;
506 // Bda->CrtColorPaletteMask;
508 /* Update the values in the BDA */
509 Bda
->VideoMode
= ModeNumber
;
511 Bda
->VideoPageSize
= BIOS_PAGE_SIZE
;
512 Bda
->VideoPageOffset
= 0;
514 /* Get the character height */
515 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_MAX_SCAN_LINE_REG
);
516 Bda
->CharacterHeight
= 1 + (VgaReadPort(VGA_CRTC_DATA
) & 0x1F);
518 Resolution
= VgaGetDisplayResolution();
519 Bda
->ScreenColumns
= Resolution
.X
;
520 Bda
->ScreenRows
= Resolution
.Y
- 1;
525 BOOLEAN
BiosSetVideoPage(BYTE PageNumber
)
527 /* Check if the page exists */
528 if (PageNumber
>= BIOS_MAX_PAGES
) return FALSE
;
530 /* Check if this is the same page */
531 if (PageNumber
== Bda
->VideoPage
) return TRUE
;
533 /* Set the values in the BDA */
534 Bda
->VideoPage
= PageNumber
;
535 Bda
->VideoPageSize
= BIOS_PAGE_SIZE
;
536 Bda
->VideoPageOffset
= PageNumber
* BIOS_PAGE_SIZE
;
538 /* Set the start address in the CRTC */
539 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_CURSOR_LOC_LOW_REG
);
540 VgaWritePort(VGA_CRTC_DATA
, LOBYTE(Bda
->VideoPageOffset
));
541 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_CURSOR_LOC_HIGH_REG
);
542 VgaWritePort(VGA_CRTC_DATA
, HIBYTE(Bda
->VideoPageOffset
));
547 BOOLEAN
BiosInitialize(VOID
)
549 /* Initialize the BDA */
550 Bda
= (PBIOS_DATA_AREA
)SEG_OFF_TO_PTR(BDA_SEGMENT
, 0);
551 Bda
->EquipmentList
= BIOS_EQUIPMENT_LIST
;
553 * Conventional memory size is 640 kB,
554 * see: http://webpages.charter.net/danrollins/techhelp/0184.HTM
555 * and see Ralf Brown: http://www.ctyme.com/intr/rb-0598.htm
556 * for more information.
558 Bda
->MemorySize
= 0x0280;
559 Bda
->KeybdBufferStart
= FIELD_OFFSET(BIOS_DATA_AREA
, KeybdBuffer
);
560 Bda
->KeybdBufferEnd
= Bda
->KeybdBufferStart
+ BIOS_KBD_BUFFER_SIZE
* sizeof(WORD
);
561 Bda
->KeybdBufferHead
= Bda
->KeybdBufferTail
= 0;
563 /* Initialize the 32-bit Interrupt system */
564 InitializeInt32(BIOS_SEGMENT
);
566 /* Register the BIOS 32-bit Interrupts */
567 RegisterInt32(BIOS_VIDEO_INTERRUPT
, BiosVideoService
);
568 RegisterInt32(BIOS_EQUIPMENT_INTERRUPT
, BiosEquipmentService
);
569 RegisterInt32(BIOS_MEMORY_SIZE
, BiosGetMemorySize
);
570 RegisterInt32(BIOS_MISC_INTERRUPT
, BiosMiscService
);
571 RegisterInt32(BIOS_KBD_INTERRUPT
, BiosKeyboardService
);
572 RegisterInt32(BIOS_TIME_INTERRUPT
, BiosTimeService
);
573 RegisterInt32(BIOS_SYS_TIMER_INTERRUPT
, BiosSystemTimerInterrupt
);
575 /* Some interrupts are in fact addresses to tables */
576 ((PDWORD
)BaseAddress
)[0x1D] = (DWORD
)NULL
;
577 ((PDWORD
)BaseAddress
)[0x1E] = (DWORD
)NULL
;
578 ((PDWORD
)BaseAddress
)[0x1F] = (DWORD
)NULL
;
580 ((PDWORD
)BaseAddress
)[0x41] = (DWORD
)NULL
;
581 ((PDWORD
)BaseAddress
)[0x43] = (DWORD
)NULL
;
582 ((PDWORD
)BaseAddress
)[0x44] = (DWORD
)NULL
;
583 ((PDWORD
)BaseAddress
)[0x46] = (DWORD
)NULL
;
584 ((PDWORD
)BaseAddress
)[0x48] = (DWORD
)NULL
;
585 ((PDWORD
)BaseAddress
)[0x49] = (DWORD
)NULL
;
587 /* Get the input handle to the real console, and check for success */
588 BiosConsoleInput
= CreateFileW(L
"CONIN$",
589 GENERIC_READ
| GENERIC_WRITE
,
590 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
595 if (BiosConsoleInput
== INVALID_HANDLE_VALUE
)
600 /* Get the output handle to the real console, and check for success */
601 BiosConsoleOutput
= CreateFileW(L
"CONOUT$",
602 GENERIC_READ
| GENERIC_WRITE
,
603 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
608 if (BiosConsoleOutput
== INVALID_HANDLE_VALUE
)
610 CloseHandle(BiosConsoleInput
);
614 /* Save the console screen buffer information */
615 if (!GetConsoleScreenBufferInfo(BiosConsoleOutput
, &BiosSavedBufferInfo
))
617 CloseHandle(BiosConsoleOutput
);
618 CloseHandle(BiosConsoleInput
);
623 if (!VgaInitialize(BiosConsoleOutput
))
625 CloseHandle(BiosConsoleOutput
);
626 CloseHandle(BiosConsoleInput
);
630 /* Update the cursor position */
631 BiosSetCursorPosition(BiosSavedBufferInfo
.dwCursorPosition
.Y
,
632 BiosSavedBufferInfo
.dwCursorPosition
.X
,
635 /* Set the console input mode */
636 SetConsoleMode(BiosConsoleInput
, ENABLE_MOUSE_INPUT
| ENABLE_PROCESSED_INPUT
);
639 PS2Initialize(BiosConsoleInput
);
641 /* Initialize the PIC */
642 PicWriteCommand(PIC_MASTER_CMD
, PIC_ICW1
| PIC_ICW1_ICW4
);
643 PicWriteCommand(PIC_SLAVE_CMD
, PIC_ICW1
| PIC_ICW1_ICW4
);
645 /* Set the interrupt offsets */
646 PicWriteData(PIC_MASTER_DATA
, BIOS_PIC_MASTER_INT
);
647 PicWriteData(PIC_SLAVE_DATA
, BIOS_PIC_SLAVE_INT
);
649 /* Tell the master PIC there is a slave at IRQ 2 */
650 PicWriteData(PIC_MASTER_DATA
, 1 << 2);
651 PicWriteData(PIC_SLAVE_DATA
, 2);
653 /* Make sure the PIC is in 8086 mode */
654 PicWriteData(PIC_MASTER_DATA
, PIC_ICW4_8086
);
655 PicWriteData(PIC_SLAVE_DATA
, PIC_ICW4_8086
);
657 /* Clear the masks for both PICs */
658 PicWriteData(PIC_MASTER_DATA
, 0x00);
659 PicWriteData(PIC_SLAVE_DATA
, 0x00);
661 PitWriteCommand(0x34);
662 PitWriteData(0, 0x00);
663 PitWriteData(0, 0x00);
668 VOID
BiosCleanup(VOID
)
672 /* Restore the old screen buffer */
673 SetConsoleActiveScreenBuffer(BiosConsoleOutput
);
675 /* Restore the screen buffer size */
676 SetConsoleScreenBufferSize(BiosConsoleOutput
, BiosSavedBufferInfo
.dwSize
);
678 /* Close the console handles */
679 if (BiosConsoleOutput
!= INVALID_HANDLE_VALUE
) CloseHandle(BiosConsoleOutput
);
680 if (BiosConsoleInput
!= INVALID_HANDLE_VALUE
) CloseHandle(BiosConsoleInput
);
683 WORD
BiosPeekCharacter(VOID
)
685 WORD CharacterData
= 0;
687 /* Get the key from the queue, but don't remove it */
688 if (BiosKbdBufferTop(&CharacterData
)) return CharacterData
;
692 WORD
BiosGetCharacter(VOID
)
694 WORD CharacterData
= 0;
696 /* Check if there is a key available */
697 if (BiosKbdBufferTop(&CharacterData
))
699 /* A key was available, remove it from the queue */
704 /* No key available. Set the handler CF to repeat the BOP */
705 EmulatorSetFlag(EMULATOR_FLAG_CF
);
706 // CharacterData = 0xFFFF;
709 return CharacterData
;
712 VOID
BiosGetCursorPosition(PBYTE Row
, PBYTE Column
, BYTE Page
)
714 /* Make sure the selected video page is valid */
715 if (Page
>= BIOS_MAX_PAGES
) return;
717 /* Get the cursor location */
718 *Row
= HIBYTE(Bda
->CursorPosition
[Page
]);
719 *Column
= LOBYTE(Bda
->CursorPosition
[Page
]);
722 VOID
BiosSetCursorPosition(BYTE Row
, BYTE Column
, BYTE Page
)
724 /* Make sure the selected video page is valid */
725 if (Page
>= BIOS_MAX_PAGES
) return;
727 /* Update the position in the BDA */
728 Bda
->CursorPosition
[Page
] = MAKEWORD(Column
, Row
);
730 /* Check if this is the current video page */
731 if (Page
== Bda
->VideoPage
)
733 WORD Offset
= Row
* Bda
->ScreenColumns
+ Column
;
735 /* Modify the CRTC registers */
736 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_CURSOR_LOC_LOW_REG
);
737 VgaWritePort(VGA_CRTC_DATA
, LOBYTE(Offset
));
738 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_CURSOR_LOC_HIGH_REG
);
739 VgaWritePort(VGA_CRTC_DATA
, HIBYTE(Offset
));
743 BOOLEAN
BiosScrollWindow(INT Direction
,
745 SMALL_RECT Rectangle
,
751 WORD WindowWidth
= Rectangle
.Right
- Rectangle
.Left
+ 1;
752 WORD WindowHeight
= Rectangle
.Bottom
- Rectangle
.Top
+ 1;
753 DWORD WindowSize
= WindowWidth
* WindowHeight
;
755 /* Allocate a buffer for the window */
756 WindowData
= (LPWORD
)HeapAlloc(GetProcessHeap(),
758 WindowSize
* sizeof(WORD
));
759 if (WindowData
== NULL
) return FALSE
;
761 /* Read the window data */
762 BiosReadWindow(WindowData
, Rectangle
, Page
);
765 || (((Direction
== SCROLL_DIRECTION_UP
)
766 || (Direction
== SCROLL_DIRECTION_DOWN
))
767 && (Amount
>= WindowHeight
))
768 || (((Direction
== SCROLL_DIRECTION_LEFT
)
769 || (Direction
== SCROLL_DIRECTION_RIGHT
))
770 && (Amount
>= WindowWidth
)))
772 /* Fill the window */
773 for (i
= 0; i
< WindowSize
; i
++)
775 WindowData
[i
] = MAKEWORD(' ', FillAttribute
);
783 case SCROLL_DIRECTION_UP
:
785 RtlMoveMemory(WindowData
,
786 &WindowData
[WindowWidth
* Amount
],
787 (WindowSize
- WindowWidth
* Amount
) * sizeof(WORD
));
789 for (i
= 0; i
< Amount
* WindowWidth
; i
++)
791 WindowData
[WindowSize
- i
- 1] = MAKEWORD(' ', FillAttribute
);
797 case SCROLL_DIRECTION_DOWN
:
799 RtlMoveMemory(&WindowData
[WindowWidth
* Amount
],
801 (WindowSize
- WindowWidth
* Amount
) * sizeof(WORD
));
803 for (i
= 0; i
< Amount
* WindowWidth
; i
++)
805 WindowData
[i
] = MAKEWORD(' ', FillAttribute
);
813 // TODO: NOT IMPLEMENTED!
819 /* Write back the window data */
820 BiosWriteWindow(WindowData
, Rectangle
, Page
);
822 /* Free the window buffer */
823 HeapFree(GetProcessHeap(), 0, WindowData
);
828 VOID
BiosPrintCharacter(CHAR Character
, BYTE Attribute
, BYTE Page
)
830 WORD CharData
= MAKEWORD(Character
, Attribute
);
833 /* Make sure the page exists */
834 if (Page
>= BIOS_MAX_PAGES
) return;
836 /* Get the cursor location */
837 BiosGetCursorPosition(&Row
, &Column
, Page
);
839 if (Character
== '\a')
841 /* Bell control character */
842 // NOTE: We may use what the terminal emulator offers to us...
846 else if (Character
== '\b')
848 /* Backspace control character */
855 Column
= Bda
->ScreenColumns
- 1;
859 /* Erase the existing character */
860 CharData
= MAKEWORD(' ', Attribute
);
861 EmulatorWriteMemory(&EmulatorContext
,
862 TO_LINEAR(TEXT_VIDEO_SEG
,
863 Page
* Bda
->VideoPageSize
+
864 (Row
* Bda
->ScreenColumns
+ Column
) * sizeof(WORD
)),
868 else if (Character
== '\t')
870 /* Horizontal Tabulation control character */
874 BiosPrintCharacter(' ', Attribute
, Page
);
875 BiosGetCursorPosition(&Row
, &Column
, Page
);
876 } while (Column
% 8);
878 else if (Character
== '\n')
880 /* Line Feed control character */
883 else if (Character
== '\r')
885 /* Carriage Return control character */
890 /* Default character */
892 /* Write the character */
893 EmulatorWriteMemory(&EmulatorContext
,
894 TO_LINEAR(TEXT_VIDEO_SEG
,
895 Page
* Bda
->VideoPageSize
+
896 (Row
* Bda
->ScreenColumns
+ Column
) * sizeof(WORD
)),
900 /* Advance the cursor */
904 /* Check if it passed the end of the row */
905 if (Column
>= Bda
->ScreenColumns
)
907 /* Return to the first column and go to the next line */
912 /* Scroll the screen up if needed */
913 if (Row
> Bda
->ScreenRows
)
915 /* The screen must be scrolled up */
916 SMALL_RECT Rectangle
= { 0, 0, Bda
->ScreenColumns
- 1, Bda
->ScreenRows
};
918 BiosScrollWindow(SCROLL_DIRECTION_UP
,
927 /* Set the cursor position */
928 BiosSetCursorPosition(Row
, Column
, Page
);
931 VOID WINAPI
BiosVideoService(LPWORD Stack
)
938 BiosSetVideoMode(getAL());
943 /* Set Text-Mode Cursor Shape */
947 Bda
->CursorStartLine
= getCH();
948 Bda
->CursorEndLine
= getCL();
950 /* Modify the CRTC registers */
951 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_CURSOR_START_REG
);
952 VgaWritePort(VGA_CRTC_DATA
, Bda
->CursorStartLine
);
953 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_CURSOR_END_REG
);
954 VgaWritePort(VGA_CRTC_DATA
, Bda
->CursorEndLine
);
959 /* Set Cursor Position */
962 BiosSetCursorPosition(getDH(), getDL(), getBH());
966 /* Get Cursor Position */
969 /* Make sure the selected video page exists */
970 if (getBH() >= BIOS_MAX_PAGES
) break;
972 /* Return the result */
974 setCX(MAKEWORD(Bda
->CursorEndLine
, Bda
->CursorStartLine
));
975 setDX(Bda
->CursorPosition
[getBH()]);
979 /* Query Light Pen */
983 * On modern BIOSes, this function returns 0
984 * so that we can ignore the other registers.
990 /* Select Active Display Page */
993 BiosSetVideoPage(getAL());
997 /* Scroll Window Up/Down */
1001 SMALL_RECT Rectangle
= { getCL(), getCH(), getDL(), getDH() };
1003 /* Call the internal function */
1004 BiosScrollWindow((getAH() == 0x06) ? SCROLL_DIRECTION_UP
1005 : SCROLL_DIRECTION_DOWN
,
1014 /* Read/Write Character From Cursor Position */
1019 WORD CharacterData
= MAKEWORD(getAL(), getBL());
1020 BYTE Page
= getBH();
1023 /* Check if the page exists */
1024 if (Page
>= BIOS_MAX_PAGES
) break;
1026 /* Find the offset of the character */
1027 Offset
= Page
* Bda
->VideoPageSize
+
1028 (HIBYTE(Bda
->CursorPosition
[Page
]) * Bda
->ScreenColumns
+
1029 LOBYTE(Bda
->CursorPosition
[Page
])) * 2;
1031 if (getAH() == 0x08)
1033 /* Read from the video memory */
1034 VgaReadMemory(TO_LINEAR(TEXT_VIDEO_SEG
, Offset
),
1035 (LPVOID
)&CharacterData
,
1038 /* Return the character in AX */
1039 setAX(CharacterData
);
1043 /* Write to video memory */
1044 VgaWriteMemory(TO_LINEAR(TEXT_VIDEO_SEG
, Offset
),
1045 (LPVOID
)&CharacterData
,
1046 (getBH() == 0x09) ? sizeof(WORD
) : sizeof(BYTE
));
1052 /* Teletype Output */
1055 BiosPrintCharacter(getAL(), getBL(), getBH());
1059 /* Get Current Video Mode */
1062 setAX(MAKEWORD(Bda
->VideoMode
, Bda
->ScreenColumns
));
1063 setBX(MAKEWORD(getBL(), Bda
->VideoPage
));
1067 /* Palette Control */
1072 /* Set Single Palette Register */
1075 /* Write the index */
1076 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1077 VgaWritePort(VGA_AC_INDEX
, getBL());
1079 /* Write the data */
1080 VgaWritePort(VGA_AC_WRITE
, getBH());
1085 /* Set Overscan Color */
1088 /* Write the index */
1089 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1090 VgaWritePort(VGA_AC_INDEX
, VGA_AC_OVERSCAN_REG
);
1092 /* Write the data */
1093 VgaWritePort(VGA_AC_WRITE
, getBH());
1098 /* Set All Palette Registers */
1102 LPBYTE Buffer
= SEG_OFF_TO_PTR(getES(), getDX());
1104 /* Set the palette registers */
1105 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
1107 /* Write the index */
1108 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1109 VgaWritePort(VGA_AC_INDEX
, i
);
1111 /* Write the data */
1112 VgaWritePort(VGA_AC_WRITE
, Buffer
[i
]);
1115 /* Set the overscan register */
1116 VgaWritePort(VGA_AC_INDEX
, VGA_AC_OVERSCAN_REG
);
1117 VgaWritePort(VGA_AC_WRITE
, Buffer
[VGA_AC_PAL_F_REG
+ 1]);
1122 /* Get Single Palette Register */
1125 /* Write the index */
1126 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1127 VgaWritePort(VGA_AC_INDEX
, getBL());
1130 setBH(VgaReadPort(VGA_AC_READ
));
1135 /* Get Overscan Color */
1138 /* Write the index */
1139 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1140 VgaWritePort(VGA_AC_INDEX
, VGA_AC_OVERSCAN_REG
);
1143 setBH(VgaReadPort(VGA_AC_READ
));
1148 /* Get All Palette Registers */
1152 LPBYTE Buffer
= SEG_OFF_TO_PTR(getES(), getDX());
1154 /* Get the palette registers */
1155 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
1157 /* Write the index */
1158 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1159 VgaWritePort(VGA_AC_INDEX
, i
);
1162 Buffer
[i
] = VgaReadPort(VGA_AC_READ
);
1165 /* Get the overscan register */
1166 VgaWritePort(VGA_AC_INDEX
, VGA_AC_OVERSCAN_REG
);
1167 Buffer
[VGA_AC_PAL_F_REG
+ 1] = VgaReadPort(VGA_AC_READ
);
1172 /* Set Individual DAC Register */
1175 /* Write the index */
1176 // Certainly in BL and not in BX as said by Ralf Brown...
1177 VgaWritePort(VGA_DAC_WRITE_INDEX
, getBL());
1179 /* Write the data in this order: Red, Green, Blue */
1180 VgaWritePort(VGA_DAC_DATA
, getDH());
1181 VgaWritePort(VGA_DAC_DATA
, getCH());
1182 VgaWritePort(VGA_DAC_DATA
, getCL());
1187 /* Set Block of DAC Registers */
1191 LPBYTE Buffer
= SEG_OFF_TO_PTR(getES(), getDX());
1193 /* Write the index */
1194 // Certainly in BL and not in BX as said by Ralf Brown...
1195 VgaWritePort(VGA_DAC_WRITE_INDEX
, getBL());
1197 for (i
= 0; i
< getCX(); i
++)
1199 /* Write the data in this order: Red, Green, Blue */
1200 VgaWritePort(VGA_DAC_DATA
, *Buffer
++);
1201 VgaWritePort(VGA_DAC_DATA
, *Buffer
++);
1202 VgaWritePort(VGA_DAC_DATA
, *Buffer
++);
1208 /* Get Individual DAC Register */
1211 /* Write the index */
1212 VgaWritePort(VGA_DAC_READ_INDEX
, getBL());
1214 /* Read the data in this order: Red, Green, Blue */
1215 setDH(VgaReadPort(VGA_DAC_DATA
));
1216 setCH(VgaReadPort(VGA_DAC_DATA
));
1217 setCL(VgaReadPort(VGA_DAC_DATA
));
1222 /* Get Block of DAC Registers */
1226 LPBYTE Buffer
= SEG_OFF_TO_PTR(getES(), getDX());
1228 /* Write the index */
1229 // Certainly in BL and not in BX as said by Ralf Brown...
1230 VgaWritePort(VGA_DAC_READ_INDEX
, getBL());
1232 for (i
= 0; i
< getCX(); i
++)
1234 /* Write the data in this order: Red, Green, Blue */
1235 *Buffer
++ = VgaReadPort(VGA_DAC_DATA
);
1236 *Buffer
++ = VgaReadPort(VGA_DAC_DATA
);
1237 *Buffer
++ = VgaReadPort(VGA_DAC_DATA
);
1245 DPRINT1("BIOS Palette Control Sub-command AL = 0x%02X NOT IMPLEMENTED\n",
1257 SMALL_RECT Rectangle
= { getCL(), getCH(), getDL(), getDH() };
1259 /* Call the internal function */
1260 BiosScrollWindow(getBL(),
1269 /* Display combination code */
1274 case 0x00: /* Get Display combiantion code */
1275 setAX(MAKEWORD(0x1A, 0x1A));
1276 setBX(MAKEWORD(0x08, 0x00)); /* VGA w/ color analog display */
1278 case 0x01: /* Set Display combination code */
1279 DPRINT1("Set Display combination code - Unsupported\n");
1289 DPRINT1("BIOS Function INT 10h, AH = 0x%02X NOT IMPLEMENTED\n",
1295 VOID WINAPI
BiosEquipmentService(LPWORD Stack
)
1297 /* Return the equipment list */
1298 setAX(Bda
->EquipmentList
);
1301 VOID WINAPI
BiosGetMemorySize(LPWORD Stack
)
1303 /* Return the conventional memory size in kB, typically 640 kB */
1304 setAX(Bda
->MemorySize
);
1307 VOID WINAPI
BiosMiscService(LPWORD Stack
)
1311 /* Copy Extended Memory */
1314 DWORD Count
= (DWORD
)getCX() * 2;
1315 PFAST486_GDT_ENTRY Gdt
= (PFAST486_GDT_ENTRY
)SEG_OFF_TO_PTR(getES(), getSI());
1316 DWORD SourceBase
= Gdt
[2].Base
+ (Gdt
[2].BaseMid
<< 16) + (Gdt
[2].BaseHigh
<< 24);
1317 DWORD SourceLimit
= Gdt
[2].Limit
+ (Gdt
[2].LimitHigh
<< 16);
1318 DWORD DestBase
= Gdt
[3].Base
+ (Gdt
[3].BaseMid
<< 16) + (Gdt
[3].BaseHigh
<< 24);
1319 DWORD DestLimit
= Gdt
[3].Limit
+ (Gdt
[3].LimitHigh
<< 16);
1321 /* Check for flags */
1322 if (Gdt
[2].Granularity
) SourceLimit
= (SourceLimit
<< 12) | 0xFFF;
1323 if (Gdt
[3].Granularity
) DestLimit
= (DestLimit
<< 12) | 0xFFF;
1325 if ((Count
> SourceLimit
) || (Count
> DestLimit
))
1328 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1334 RtlMoveMemory((PVOID
)((ULONG_PTR
)BaseAddress
+ DestBase
),
1335 (PVOID
)((ULONG_PTR
)BaseAddress
+ SourceBase
),
1338 setAX(ERROR_SUCCESS
);
1339 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1343 /* Get Extended Memory Size */
1346 /* Return the number of KB of RAM after 1 MB */
1347 setAX((MAX_ADDRESS
- 0x100000) / 1024);
1350 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1357 DPRINT1("BIOS Function INT 15h, AH = 0x%02X NOT IMPLEMENTED\n",
1363 VOID WINAPI
BiosKeyboardService(LPWORD Stack
)
1367 /* Wait for keystroke and read */
1369 /* Wait for extended keystroke and read */
1370 case 0x10: // FIXME: Temporarily do the same as INT 16h, 00h
1372 /* Read the character (and wait if necessary) */
1373 setAX(BiosGetCharacter());
1377 /* Get keystroke status */
1379 /* Get extended keystroke status */
1380 case 0x11: // FIXME: Temporarily do the same as INT 16h, 01h
1382 WORD Data
= BiosPeekCharacter();
1386 /* There is a character, clear ZF and return it */
1387 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_ZF
;
1392 /* No character, set ZF */
1393 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_ZF
;
1399 /* Get shift status */
1402 /* Return the lower byte of the keyboard shift status word */
1403 setAL(LOBYTE(Bda
->KeybdShiftFlags
));
1410 DPRINT1("BIOS Function INT 16h, AH = 0x04 is RESERVED\n");
1414 /* Push keystroke */
1417 /* Return 0 if success, 1 if failure */
1418 setAL(BiosKbdBufferPush(getCX()) == FALSE
);
1422 /* Get extended shift status */
1426 * Be careful! The returned word is similar to Bda->KeybdShiftFlags
1427 * but the high byte is organized differently:
1428 * the bytes 2 and 3 of the high byte are not the same...
1430 WORD KeybdShiftFlags
= (Bda
->KeybdShiftFlags
& 0xF3FF);
1432 /* Return the extended keyboard shift status word */
1433 setAX(KeybdShiftFlags
);
1439 DPRINT1("BIOS Function INT 16h, AH = 0x%02X NOT IMPLEMENTED\n",
1445 VOID WINAPI
BiosTimeService(LPWORD Stack
)
1451 /* Set AL to 1 if midnight had passed, 0 otherwise */
1452 setAL(Bda
->MidnightPassed
? 0x01 : 0x00);
1454 /* Return the tick count in CX:DX */
1455 setCX(HIWORD(Bda
->TickCounter
));
1456 setDX(LOWORD(Bda
->TickCounter
));
1458 /* Reset the midnight flag */
1459 Bda
->MidnightPassed
= FALSE
;
1466 /* Set the tick count to CX:DX */
1467 Bda
->TickCounter
= MAKELONG(getDX(), getCX());
1469 /* Reset the midnight flag */
1470 Bda
->MidnightPassed
= FALSE
;
1477 DPRINT1("BIOS Function INT 1Ah, AH = 0x%02X NOT IMPLEMENTED\n",
1483 VOID WINAPI
BiosSystemTimerInterrupt(LPWORD Stack
)
1485 /* Increase the system tick count */
1489 VOID
BiosHandleIrq(BYTE IrqNumber
, LPWORD Stack
)
1496 /* Perform the system timer interrupt */
1497 EmulatorInterrupt(BIOS_SYS_TIMER_INTERRUPT
);
1504 BYTE ScanCode
, VirtualKey
;
1507 /* Get the scan code and virtual key code */
1508 ScanCode
= PS2ReadPort(PS2_DATA_PORT
);
1509 VirtualKey
= MapVirtualKey(ScanCode
& 0x7F, MAPVK_VSC_TO_VK
);
1511 /* Check if this is a key press or release */
1512 if (!(ScanCode
& (1 << 7)))
1515 if (VirtualKey
== VK_NUMLOCK
||
1516 VirtualKey
== VK_CAPITAL
||
1517 VirtualKey
== VK_SCROLL
||
1518 VirtualKey
== VK_INSERT
)
1520 /* For toggle keys, toggle the lowest bit in the keyboard map */
1521 BiosKeyboardMap
[VirtualKey
] ^= ~(1 << 0);
1524 /* Set the highest bit */
1525 BiosKeyboardMap
[VirtualKey
] |= (1 << 7);
1527 /* Find out which character this is */
1529 if (ToAscii(VirtualKey
, ScanCode
, BiosKeyboardMap
, &Character
, 0) == 0)
1535 /* Push it onto the BIOS keyboard queue */
1536 BiosKbdBufferPush(MAKEWORD(Character
, ScanCode
));
1540 /* Key release, unset the highest bit */
1541 BiosKeyboardMap
[VirtualKey
] &= ~(1 << 7);
1544 /* Clear the keyboard flags */
1545 Bda
->KeybdShiftFlags
= 0;
1547 /* Set the appropriate flags based on the state */
1548 if (BiosKeyboardMap
[VK_RSHIFT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_RSHIFT
;
1549 if (BiosKeyboardMap
[VK_LSHIFT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_LSHIFT
;
1550 if (BiosKeyboardMap
[VK_CONTROL
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_CTRL
;
1551 if (BiosKeyboardMap
[VK_MENU
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_ALT
;
1552 if (BiosKeyboardMap
[VK_SCROLL
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_SCROLL_ON
;
1553 if (BiosKeyboardMap
[VK_NUMLOCK
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_NUMLOCK_ON
;
1554 if (BiosKeyboardMap
[VK_CAPITAL
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_CAPSLOCK_ON
;
1555 if (BiosKeyboardMap
[VK_INSERT
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_INSERT_ON
;
1556 if (BiosKeyboardMap
[VK_RMENU
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_RALT
;
1557 if (BiosKeyboardMap
[VK_LMENU
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_LALT
;
1558 if (BiosKeyboardMap
[VK_SNAPSHOT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_SYSRQ
;
1559 if (BiosKeyboardMap
[VK_PAUSE
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_PAUSE
;
1560 if (BiosKeyboardMap
[VK_SCROLL
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_SCROLL
;
1561 if (BiosKeyboardMap
[VK_NUMLOCK
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_NUMLOCK
;
1562 if (BiosKeyboardMap
[VK_CAPITAL
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_CAPSLOCK
;
1563 if (BiosKeyboardMap
[VK_INSERT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_INSERT
;
1569 /* Send End-of-Interrupt to the PIC */
1570 if (IrqNumber
>= 8) PicWriteCommand(PIC_SLAVE_CMD
, PIC_OCW2_EOI
);
1571 PicWriteCommand(PIC_MASTER_CMD
, PIC_OCW2_EOI
);