2 * BIOS interrupt 10h handler
4 * Copyright 1998 Ove Kåven
5 * Copyright 1998 Joseph Pranevich
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(int);
34 * Display combination code for active display.
38 * 01 - monochrome adapter w/ monochrome display
39 * 02 - CGA w/ color display
41 * 04 - EGA w/ color display
42 * 05 - EGA w/ monochrome display
43 * 06 - PGA w/ color display
44 * 07 - VGA w/ monochrome analog display
45 * 08 - VGA w/ color analog display
47 * 0A - MCGA w/ digital color display
48 * 0B - MCGA w/ monochrome analog display
49 * 0C - MCGA w/ color analog display
50 * FF - unknown display type
52 #define INT10_DCC 0x08
57 * Structure for DOS data that can be accessed directly from applications.
58 * This structure must be correctly packed.
60 typedef struct _INT10_HEAP {
61 BYTE StaticModeSupport[7]; /* modes supported 1..7 */
62 BYTE StaticScanlineSupport; /* scan lines supported */
63 BYTE StaticNumberCharBlocks; /* total number of char blocks */
64 BYTE StaticActiveCharBlocks; /* max number of active char blocks */
65 WORD StaticMiscFlags; /* misc function support flags */
66 WORD StaticReserved1; /* reserved */
67 BYTE StaticSavePointerFlags; /* save pointer function flags */
68 BYTE StaticReserved2; /* reserved */
71 WORD VesaModeList[64];
73 char VesaProductName[32];
74 char VesaProductRev[32];
75 char VesaVendorName[32];
81 * Structure for VBE Mode Info Block. See the VBE 3.0 standard for details.
82 * This structure must be correctly packed.
84 struct _ModeInfoBlock {
85 WORD ModeAttributes; /* 0x00 */
86 BYTE WinAAttributes; /* 0x02 */
87 BYTE WinBAttributes; /* 0x03 */
88 WORD WinGranularity; /* 0x04 */
89 WORD WinSize; /* 0x06 */
90 WORD WinASegment; /* 0x08 */
91 WORD WinBSegment; /* 0x0A */
92 DWORD WinFuncPtr; /* 0x0C */
93 WORD BytesPerScanLine; /* 0x10 */
94 /* mandatory for VBE 1.2+ */
95 WORD XResolution; /* 0x12 */
96 WORD YResolution; /* 0x14 */
97 BYTE XCharSize; /* 0x16 */
98 BYTE YCharSize; /* 0x17 */
99 BYTE NumberOfPlanes; /* 0x18 */
100 BYTE BitsPerPixel; /* 0x19 */
101 BYTE NumberOfBanks; /* 0x1A */
102 BYTE MemoryModel; /* 0x1B */
103 BYTE BankSize; /* 0x1C */
104 BYTE NumberOfImagePages; /* 0x1D */
105 BYTE Reserved1; /* 0x1E */
106 BYTE RedMaskSize; /* 0x1F */
107 BYTE RedFieldPosition; /* 0x20 */
108 BYTE GreenMaskSize; /* 0x21 */
109 BYTE GreenFieldPosition; /* 0x22 */
110 BYTE BlueMaskSize; /* 0x23 */
111 BYTE BlueFieldPosition; /* 0x24 */
112 BYTE RsvdMaskSize; /* 0x25 */
113 BYTE RsvdFieldPosition; /* 0x26 */
114 BYTE DirectColorModeInfo; /* 0x27 */
115 /* mandatory for VBE 2.0+ */
116 DWORD PhysBasePtr; /* 0x28 */
117 DWORD Reserved2; /* 0x2C */
118 WORD Reserved3; /* 0x30 */
119 /* mandatory for VBE 3.0+ */
120 WORD LinBytesPerScanLine; /* 0x32 */
121 BYTE BnkNumberOfImagePages;/* 0x34 */
122 BYTE LinNumberOfImagePages;/* 0x35 */
123 BYTE LinRedMaskSize; /* 0x36 */
124 BYTE LinRedFieldPosition; /* 0x37 */
125 BYTE LinGreenMaskSize; /* 0x38 */
126 BYTE LinGreenFieldPosition;/* 0x39 */
127 BYTE LinBlueMaskSize; /* 0x3A */
128 BYTE LinBlueFieldPosition; /* 0x3B */
129 BYTE LinRsvdMaskSize; /* 0x3C */
130 BYTE LinRsvdFieldPosition; /* 0x3D */
131 DWORD MaxPixelClock; /* 0x3E */
132 BYTE Reserved4[190]; /* 0x42 */
138 * Wine internal information about video modes.
139 * If depth is zero, the mode is considered to
151 * List of supported video modes.
153 static const INT10_MODE INT10_modelist[] =
160 {0x000d, 320, 200, 4},
161 {0x000e, 640, 200, 4},
162 {0x0010, 640, 350, 4},
163 {0x0012, 640, 480, 4},
164 {0x0013, 320, 200, 8},
165 {0x0100, 640, 400, 8},
166 {0x0101, 640, 480, 8},
167 {0x0102, 800, 600, 4},
168 {0x0103, 800, 600, 8},
169 {0x0104, 1024, 768, 4},
170 {0x0105, 1024, 768, 8},
171 {0x0106, 1280, 1024, 4},
172 {0x0107, 1280, 1024, 8},
174 {0x0109, 132, 25, 0},
175 {0x010a, 132, 43, 0},
176 {0x010b, 132, 50, 0},
177 {0x010c, 132, 60, 0},
178 {0x010d, 320, 200, 15},
179 {0x010e, 320, 200, 16},
180 {0x010f, 320, 200, 24},
181 {0x0110, 640, 480, 15},
182 {0x0111, 640, 480, 16},
183 {0x0112, 640, 480, 24},
184 {0x0113, 800, 600, 15},
185 {0x0114, 800, 600, 16},
186 {0x0115, 800, 600, 24},
187 {0x0116, 1024, 768, 15},
188 {0x0117, 1024, 768, 16},
189 {0x0118, 1024, 768, 24},
190 {0x0119, 1280, 1024, 15},
191 {0x011a, 1280, 1024, 16},
192 {0x011b, 1280, 1024, 24},
196 /* Forward declarations. */
197 static INT10_HEAP *INT10_GetHeap(void);
198 static void INT10_SetCursorPos(BIOSDATA*, unsigned, unsigned, unsigned);
201 /**********************************************************************
204 static const INT10_MODE *INT10_FindMode( WORD mode )
206 const INT10_MODE *ptr = INT10_modelist;
213 while (ptr->Mode != 0xffff)
215 if (ptr->Mode == mode)
224 /**********************************************************************
225 * INT10_FillControllerInformation
227 * Fill 256-byte (VBE1.x) or 512-byte buffer (VBE2.0+) with
228 * capabilities of the video controller.
230 static void INT10_FillControllerInformation( BYTE *buffer )
232 INT10_HEAP *heap = INT10_GetHeap();
234 /* 00 - BYTE[4]: signature */
235 memmove( buffer, "VESA", 4 );
237 /* 04 - WORD: version number */
238 *(WORD*)(buffer + 4) = 0x0300; /* version 3.0 */
240 /* 06 - DWORD: pointer to OEM name */
241 *(SEGPTR*)(buffer + 6) = MAKESEGPTR( heap->WineHeapSegment,
246 * 10 - DWORD: capabilities flags
248 * 0 - DAC can be switched into 8-bit mode
249 * 1 - non-VGA controller
250 * 2 - programmed DAC with blank bit
251 * 3 - controller supports hardware stereoscopic signalling
252 * 4 - =0 stereo signalling via external VESA stereo connector
253 * =1 stereo signalling via VESA EVC connector
254 * 5 - controller supports hardware mouse cursor
255 * 6 - controller supports hardware clipping
256 * 7 - controller supports transparent BitBLT
257 * 8-31 - reserved (0)
259 *(DWORD*)(buffer + 10) = 0; /* FIXME */
261 /* 14 - DWORD: pointer to list of supported VESA and OEM video modes */
262 *(SEGPTR*)(buffer + 14) = MAKESEGPTR( heap->WineHeapSegment,
266 /* 18 - WORD: total amount of video memory in 64K blocks */
267 *(WORD*)(buffer + 18) = 16; /* FIXME */
269 /* 20 - WORD: OEM software version (BCD, high byte = major) */
270 *(WORD*)(buffer + 20) = 0x0100; /* version 1.0 */
272 /* 22 - DWORD: pointer to vendor name */
273 *(SEGPTR*)(buffer + 22) = MAKESEGPTR( heap->WineHeapSegment,
277 /* 26 - DWORD: pointer to product name */
278 *(SEGPTR*)(buffer + 26) = MAKESEGPTR( heap->WineHeapSegment,
282 /* 30 - DWORD: pointer to product revision string */
283 *(SEGPTR*)(buffer + 30) = MAKESEGPTR( heap->WineHeapSegment,
287 /* 34 - WORD: VBE/AF version (if capabilities bit 3 set) */
288 *(WORD*)(buffer + 34) = 0;
291 * 36 - DWORD: pointer to list of accelerated modes
292 * (if capabilities bit 3 set)
294 *(SEGPTR*)(buffer + 36) = 0;
296 /* 40 - BYTE[216]: reserved for VBE implementation, set to zero */
297 memset( buffer + 40, 216, 0 );
300 * 256 - BYTE[256]: reserved for VBE3.0 implementation,
301 * ignored in order to support older programs
306 /**********************************************************************
307 * INT10_FillModeInformation
309 * Fill 256-byte buffer with extended information about display mode.
311 * Returns FALSE if mode is unknown and TRUE is mode is known
312 * even if it is not supported.
314 static BOOL INT10_FillModeInformation( struct _ModeInfoBlock *mib, WORD mode )
316 const INT10_MODE *ptr = INT10_FindMode( mode );
321 * 00 - WORD: mode attributes
323 * 0 - Mode supported by present hardware configuration.
324 * 1 - Optional information available. Must be =1 for VBE v1.2+.
325 * 2 - BIOS output supported.
326 * Int10 functions 01, 02, 06, 07, 09, 0a and 0e are supported.
327 * 3 - Set if color, clear if monochrome.
328 * 4 - Set if graphics mode, clear if text mode.
329 * 5 - Mode is not VGA-compatible if set.
330 * VGA-compatible modes support standard VGA I/O ports.
331 * 6 - Bank-switched (or windowed) mode is not supported if set.
332 * 7 - Linear framebuffer mode supported.
333 * 8 - Double scanning supported.
334 * 9 - Interlaced operation supported.
335 * 10 - Triple buffering supported.
336 * 11 - Stereoscopic display supported.
337 * 12 - Dual display start address supported.
341 WORD attr = 0x000a; /* color mode, optional info */
344 * FIXME: Attribute handling is incomplete.
347 /* Mode supported? FIXME: correct value */
350 /* Graphical mode? */
354 /* Not VGA-compatible? */
358 mib->ModeAttributes = attr;
362 * 02 - BYTE[2]: window attributes, window A and window B
365 * 1 - Window is readable.
366 * 2 - Window is writable.
369 mib->WinAAttributes = 0x07; /* window A exists, readable and writable */
370 mib->WinBAttributes = 0x00; /* window B not supported */
372 /* 04 - WORD: window granularity in KB */
373 mib->WinGranularity = 64;
375 /* 06 - WORD: window size in KB */
378 /* 08 - WORD[2]: start segments, window A and window B */
379 mib->WinASegment = 0xa000; /* window A segment */
380 mib->WinBSegment = 0x0000; /* window B not supported */
382 /* 12 - DWORD: window positioning function */
383 mib->WinFuncPtr = 0; /* not supported */
385 /* 16 - WORD: bytes per scan line */
386 /* FIXME: is this always correct? */
387 mib->BytesPerScanLine = ptr->Width * (ptr->Depth ? (ptr->Depth + 7) / 8 : 1);
389 /* 18 - WORD: width in pixels (graphics) or characters (text) */
390 mib->XResolution = ptr->Width;
392 /* 20 - WORD: height in pixels (graphics) or characters (text) */
393 mib->YResolution = ptr->Height;
395 /* 22 - BYTE: width of character cell in pixels */
396 mib->XCharSize = 0; /* FIXME */
398 /* 23 - BYTE: height of character cell in pixels */
399 mib->YCharSize = 0; /* FIXME */
401 /* 24 - BYTE: number of memory planes */
402 mib->NumberOfPlanes = 1; /* FIXME */
404 /* 25 - BYTE: number of bits per pixel */
405 mib->BitsPerPixel = ptr->Depth; /* FIXME: text modes? reserved bits? */
407 /* 26 - BYTE: number of banks */
408 mib->NumberOfBanks = 1; /* FIXME */
411 * 27 - BYTE: memory model type
415 * 02 - Hercules graphics
418 * 05 - Non-chain 4, 256 color
421 * 08-0F - Reserved for VESA.
422 * 10-FF - OEM memory models.
425 mib->MemoryModel = 0; /* text mode */
427 mib->MemoryModel = 3; /* FIXME */
429 /* 28 - BYTE: size of bank in KB */
430 mib->BankSize = 0; /* FIXME */
432 /* 29 - BYTE: number of image pages (less one) in video RAM */
433 mib->NumberOfImagePages = 0; /* FIXME */
435 /* 30 - BYTE: reserved (0x00 for VBE 1.0-2.0, 0x01 for VBE 3.0) */
436 mib->Reserved1 = 0x01;
439 * 31,33,35 - BYTE: red/green/blue mask size
440 * Size of red/green/blue color component in bits.
441 * 32,34,36 - BYTE: red/green/blue field position
442 * Bit position of the least significant bit of red/green/blue color
444 * Both should be only used when memory model is direct color or YUV but
445 * "Imperium Romanum" uses this fields even when memory model is planar.
446 * So always fill this fields when we have a depth bigger then 8, otherwise
449 switch (ptr->Depth) {
451 mib->RedMaskSize = 8;
452 mib->GreenMaskSize = 8;
453 mib->BlueMaskSize = 8;
454 mib->RsvdMaskSize = 0;
455 mib->RedFieldPosition = 16;
456 mib->GreenFieldPosition = 8;
457 mib->BlueFieldPosition = 0;
458 mib->RsvdFieldPosition = 0;
461 mib->RedMaskSize = 5;
462 mib->GreenMaskSize = 6;
463 mib->BlueMaskSize = 5;
464 mib->RsvdMaskSize = 0;
465 mib->RedFieldPosition = 11;
466 mib->GreenFieldPosition = 5;
467 mib->BlueFieldPosition = 0;
468 mib->RsvdFieldPosition = 0;
471 mib->RedMaskSize = 5;
472 mib->GreenMaskSize = 5;
473 mib->BlueMaskSize = 5;
474 mib->RsvdMaskSize = 1;
475 mib->RedFieldPosition = 10;
476 mib->GreenFieldPosition = 5;
477 mib->BlueFieldPosition = 0;
478 mib->RsvdFieldPosition = 15;
481 mib->RedMaskSize = 0;
482 mib->GreenMaskSize = 0;
483 mib->BlueMaskSize = 0;
484 mib->RsvdMaskSize = 0;
485 mib->RedFieldPosition = 0;
486 mib->GreenFieldPosition = 0;
487 mib->BlueFieldPosition = 0;
488 mib->RsvdFieldPosition = 0;
493 * 39 - BYTE: direct color mode info
495 * 0 - Set if color ramp is programmable.
496 * 1 - Set if bytes in reserved field may be used by application.
498 mib->DirectColorModeInfo = 0; /* not supported */
500 /* 40 - DWORD: physical address of linear video buffer */
501 mib->PhysBasePtr = 0; /* not supported */
503 /* 44 - DWORD: reserved, always zero */
506 /* 48 - WORD: reserved, always zero */
509 /* 50 - WORD: bytes per scan line in linear modes */
510 mib->LinBytesPerScanLine = mib->BytesPerScanLine;
512 /* 52 - BYTE: number of images (less one) for banked video modes */
513 mib->BnkNumberOfImagePages = 0; /* FIXME */
515 /* 53 - BYTE: number of images (less one) for linear video modes */
516 mib->LinNumberOfImagePages = mib->BnkNumberOfImagePages;
518 /* 54 - BYTE: red mask size (linear modes) */
519 mib->LinRedMaskSize = mib->RedMaskSize;
521 /* 55 - BYTE: red field position (linear modes) */
522 mib->LinRedFieldPosition = mib->RedFieldPosition;
524 /* 56 - BYTE: green mask size (linear modes) */
525 mib->LinGreenMaskSize = mib->GreenMaskSize;
527 /* 57 - BYTE: green field size (linear modes) */
528 mib->LinGreenFieldPosition = mib->GreenFieldPosition;
530 /* 58 - BYTE: blue mask size (linear modes) */
531 mib->LinBlueMaskSize = mib->BlueMaskSize;
533 /* 59 - BYTE: blue field position (linear modes) */
534 mib->LinBlueFieldPosition = mib->BlueFieldPosition;
536 /* 60 - BYTE: reserved mask size (linear modes) */
537 mib->LinRsvdMaskSize = mib->RsvdMaskSize;
539 /* 61 - BYTE: reserved mask position (linear modes) */
540 mib->LinRsvdFieldPosition = mib->RsvdFieldPosition;
542 /* 62 - DWORD: maximum pixel clock for graphics video mode, in Hz */
543 mib->MaxPixelClock = 0; /* FIXME */
545 /* 66 - BYTE[190]: reserved, set to zero */
546 memset( &mib->Reserved4, 190, 0 );
552 /**********************************************************************
553 * INT10_FillStateInformation
555 * Fill 64-byte buffer with VGA state and functionality information.
557 static void INT10_FillStateInformation( BYTE *buffer, BIOSDATA *data )
559 INT10_HEAP *heap = INT10_GetHeap();
561 /* 00 - DWORD: address of static functionality table */
562 *(SEGPTR*)(buffer + 0) = MAKESEGPTR( heap->WineHeapSegment,
564 StaticModeSupport) );
566 /* 04 - BYTE[30]: copy of BIOS data starting from 0x49 (VideoMode) */
567 memmove( buffer + 4, &data->VideoMode, 30 );
569 /* 34 - BYTE: number of rows - 1 */
570 buffer[34] = data->RowsOnScreenMinus1;
572 /* 35 - WORD: bytes/character */
573 *(WORD*)(buffer + 35) = data->BytesPerChar;
575 /* 37 - BYTE: display combination code of active display */
576 buffer[37] = INT10_DCC;
578 /* 38 - BYTE: DCC of alternate display */
579 buffer[38] = 0; /* no secondary display */
581 /* 39 - WORD: number of colors supported in current mode (0000h = mono) */
582 *(WORD*)(buffer + 39) = 16; /* FIXME */
584 /* 41 - BYTE: number of pages supported in current mode */
585 buffer[41] = 1; /* FIXME */
588 * 42 - BYTE: number of scan lines active
595 buffer[42] = 3; /* FIXME */
597 /* 43 - BYTE: primary character block */
598 buffer[43] = 0; /* FIXME */
600 /* 44 - BYTE: secondary character block */
601 buffer[44] = 0; /* FIXME */
604 * 45 - BYTE: miscellaneous flags
606 * 0 - all modes on all displays on
607 * 1 - gray summing on
608 * 2 - monochrome display attached
609 * 3 - default palette loading disabled
610 * 4 - cursor emulation enabled
611 * 5 - 0 = intensity; 1 = blinking
612 * 6 - flat-panel display is active
615 /* FIXME: Correct value? */
617 (data->VGASettings & 0x0f) |
618 ((data->ModeOptions & 1) << 4); /* cursor emulation */
621 * 46 - BYTE: non-VGA mode support
623 * 0 - BIOS supports information return for adapter interface
624 * 1 - adapter interface driver required
625 * 2 - 16-bit VGA graphics present
626 * 3 - =1 MFI attributes enabled
627 * =0 VGA attributes enabled
628 * 4 - 132-column mode supported
631 buffer[46] = 0; /* FIXME: correct value? */
633 /* 47 - BYTE[2]: reserved, set to zero */
634 memset( buffer + 47, 2, 0 );
637 * 49 - BYTE: video memory available
644 buffer[49] = (data->ModeOptions & 0x60) >> 5; /* FIXME */
647 * 50 - BYTE: save pointer state flags
649 * 0 - 512 character set active
650 * 1 - dynamic save area present
651 * 2 - alpha font override active
652 * 3 - graphics font override active
653 * 4 - palette override active
654 * 5 - DCC override active
657 buffer[50] = heap->StaticSavePointerFlags;
660 * 51 - BYTE: display information and status
662 * 0 - flat-panel display attached
663 * 1 - flat-panel display active
666 * 7 - 640x480 flat-panel can be used simultaneously with CRT
668 buffer[51] = 4; /* FIXME: correct value? */
670 /* 52 - BYTE[12]: reserved, set to zero */
671 memset( buffer + 52, 12, 0 );
675 /**********************************************************************
678 INT10_HEAP *INT10_GetHeap( void )
680 static INT10_HEAP *heap_pointer = 0;
687 heap_pointer = DOSVM_AllocDataUMB( sizeof(INT10_HEAP),
691 for (i = 0; i < 7; i++)
692 heap_pointer->StaticModeSupport[i] = 0xff; /* FIXME */
694 heap_pointer->StaticScanlineSupport = 7; /* FIXME */
695 heap_pointer->StaticNumberCharBlocks = 0; /* FIXME */
696 heap_pointer->StaticActiveCharBlocks = 0; /* FIXME */
697 heap_pointer->StaticMiscFlags = 0x8ff; /* FIXME */
698 heap_pointer->StaticReserved1 = 0;
699 heap_pointer->StaticSavePointerFlags = 0x3f; /* FIXME */
700 heap_pointer->StaticReserved2 = 0;
704 heap_pointer->VesaModeList[i] = INT10_modelist[i].Mode;
705 if (INT10_modelist[i].Mode == 0xffff)
709 strcpy( heap_pointer->VesaOEMName, "WINE SVGA BOARD" );
710 strcpy( heap_pointer->VesaVendorName, "WINE" );
711 strcpy( heap_pointer->VesaProductName, "WINE SVGA" );
712 strcpy( heap_pointer->VesaProductRev, "2003" );
714 heap_pointer->VesaCurrentMode = 0; /* Initialized later. */
715 heap_pointer->WineHeapSegment = segment;
722 /**********************************************************************
725 * Change current video mode to any VGA or VESA mode.
726 * Returns TRUE if mode is supported.
729 * 0-6: .. Mode number (combined with bit 8).
730 * 7: =0 Clear screen.
731 * =1 Preserve display memory on mode change (VGA modes).
734 * 9: .. Reserved, must be zero.
735 * 10: .. Reserved, must be zero.
736 * 11: =0 Use default refresh rate.
737 * =1 Use user specified refresh rate.
738 * 12: .. Reserved, must be zero.
739 * 13: .. Reserved, must be zero.
740 * 14: =0 Use windowed frame buffer model.
741 * =1 Use linear frame buffer model.
742 * 15: =0 Clear screen.
743 * =1 Preserve display memory on mode change (VESA modes).
745 static BOOL INT10_SetVideoMode( BIOSDATA *data, WORD mode )
747 const INT10_MODE *ptr = INT10_FindMode( mode );
748 INT10_HEAP *heap = INT10_GetHeap();
749 BOOL clearScreen = TRUE;
755 * Linear framebuffer is not supported.
761 * Check for VGA and VESA preserve video memory flag.
763 if ((mode & 0x0080) || (mode & 0x8000))
767 * Note that we do not mask out flags here on purpose.
769 heap->VesaCurrentMode = mode;
771 data->VideoMode = mode;
778 TRACE( "Setting %s %dx%d text mode (screen %s)\n",
779 mode <= 0xff ? "VGA" : "VESA",
780 ptr->Width, ptr->Height,
781 clearScreen ? "cleared" : "preserved" );
784 * FIXME: We should check here if alpha mode could be set.
786 VGA_SetAlphaMode( ptr->Width, ptr->Height );
788 data->VideoColumns = ptr->Width;
789 data->RowsOnScreenMinus1 = ptr->Height - 1;
793 VGA_ClearText( 0, 0, ptr->Height-1, ptr->Width-1, 0x07 );
794 INT10_SetCursorPos( data, 0, 0, 0 );
795 VGA_SetCursorPos( 0, 0 );
801 TRACE( "Setting %s %dx%dx%d graphics mode (screen %s)\n",
802 mode <= 0xff ? "VGA" : "VESA",
803 ptr->Width, ptr->Height, ptr->Depth,
804 clearScreen ? "cleared" : "preserved" );
806 if (VGA_SetMode( ptr->Width, ptr->Height, ptr->Depth ))
814 /**********************************************************************
817 static void INT10_GetCursorPos(BIOSDATA*data,unsigned page,unsigned*X,unsigned*Y)
819 *X = data->VideoCursorPos[page*2]; /* column */
820 *Y = data->VideoCursorPos[page*2+1]; /* row */
824 /**********************************************************************
827 static void INT10_SetCursorPos(BIOSDATA*data,unsigned page,unsigned X,unsigned Y)
829 data->VideoCursorPos[page*2] = X;
830 data->VideoCursorPos[page*2+1] = Y;
834 /**********************************************************************
835 * INT10_InitializeVideoMode
837 * The first time this function is called VGA emulation is set to the
840 static void INT10_InitializeVideoMode( BIOSDATA *data )
842 static BOOL already_initialized = FALSE;
846 if(already_initialized)
848 already_initialized = TRUE;
850 VGA_InitAlphaMode(&width, &height);
853 * FIXME: Add more mappings between initial size and
856 if (width >= 80 && height >= 25)
857 INT10_SetVideoMode( data, 0x03 );
859 INT10_SetVideoMode( data, 0x01 );
863 /**********************************************************************
866 * Handler for VESA functions (int10 function 0x4f).
868 static void INT10_HandleVESA( CONTEXT86 *context )
870 BIOSDATA *data = DOSVM_BiosData();
872 switch(AL_reg(context)) {
874 case 0x00: /* RETURN CONTROLLER INFORMATION */
875 TRACE( "VESA RETURN CONTROLLER INFORMATION\n" );
877 BYTE *ptr = CTX_SEG_OFF_TO_LIN(context,
880 INT10_FillControllerInformation( ptr );
881 SET_AL( context, 0x4f );
882 SET_AH( context, 0x00 ); /* 0x00 = successful 0x01 = failed */
886 case 0x01: /* RETURN MODE INFORMATION */
887 TRACE( "VESA RETURN MODE INFORMATION %04x\n", CX_reg(context) );
889 struct _ModeInfoBlock *ptr = CTX_SEG_OFF_TO_LIN(context,
892 SET_AL( context, 0x4f );
893 if (INT10_FillModeInformation( ptr, CX_reg(context) ))
894 SET_AH( context, 0x00 ); /* status: success */
896 SET_AH( context, 0x01 ); /* status: failed */
900 case 0x02: /* SET SuperVGA VIDEO MODE */
901 TRACE( "Set VESA video mode %04x\n", BX_reg(context) );
902 SET_AL( context, 0x4f ); /* function supported */
903 if (INT10_SetVideoMode( data, BX_reg(context) ))
904 SET_AH( context, 0x00 ); /* success */
906 SET_AH( context, 0x01 ); /* failed */
909 case 0x03: /* VESA SuperVGA BIOS - GET CURRENT VIDEO MODE */
910 SET_AL( context, 0x4f );
911 SET_AH( context, 0x00 );
912 SET_BX( context, INT10_GetHeap()->VesaCurrentMode );
915 case 0x04: /* VESA SuperVGA BIOS - SAVE/RESTORE SuperVGA VIDEO STATE */
916 ERR("VESA SAVE/RESTORE Video State - Not Implemented\n");
917 /* AL_reg(context) = 0x4f; = supported so not set since not implemented */
918 /* maybe we should do this instead ? */
919 /* AH_reg(context = 0x01; not implemented so just fail */
922 case 0x05: /* VESA SuperVGA BIOS - CPU VIDEO MEMORY CONTROL */
924 * This subfunction supports only Window A (BL_reg == 0) and
925 * is assumes that window granularity is 64k.
927 switch(BH_reg(context)) {
928 case 0x00: /* select video memory window */
929 SET_AL( context, 0x4f ); /* function supported */
930 if(BL_reg(context) == 0) {
931 VGA_SetWindowStart(DX_reg(context) * 64 * 1024);
932 SET_AH( context, 0x00 ); /* status: successful */
934 SET_AH( context, 0x01 ); /* status: failed */
936 case 0x01: /* get video memory window */
937 SET_AL( context, 0x4f ); /* function supported */
938 if(BL_reg(context) == 0) {
939 SET_DX( context, VGA_GetWindowStart() / 64 / 1024 );
940 SET_AH( context, 0x00 ); /* status: successful */
942 SET_AH( context, 0x01 ); /* status: failed */
945 INT_BARF( context, 0x10 );
949 case 0x06: /* VESA GET/SET LOGICAL SCAN LINE LENGTH */
950 ERR("VESA GET/SET LOGICAL SCAN LINE LENGTH - Not Implemented\n");
951 /* AL_reg(context) = 0x4f; = supported so not set since not implemented */
952 /* maybe we should do this instead ? */
953 /* AH_reg(context = 0x001; not implemented so just fail */
956 case 0x07: /* GET/SET DISPLAY START */
957 ERR("VESA GET/SET DISPLAY START - Not Implemented\n");
958 /* AL_reg(context) = 0x4f; = supported so not set since not implemented */
959 /* maybe we should do this instead ? */
960 /* AH_reg(context = 0x001; not implemented so just fail */
963 case 0x08: /* GET/SET DAC PALETTE CONTROL */
964 ERR("VESA GET/SET DAC PALETTE CONTROL- Not Implemented\n");
965 /* AL_reg(context) = 0x4f; = supported so not set since not implemented */
966 /* maybe we should do this instead ? */
967 /* AH_reg(context = 0x001; not implemented so just fail */
970 case 0x09: /* SET PALETTE ENTRIES */
971 FIXME("VESA Set palette entries - not implemented\n");
974 case 0x0a: /* GET PROTECTED-MODE CODE */
975 FIXME("VESA Get protected-mode code - not implemented\n");
978 case 0x10: /* Display Power Management Extensions */
979 FIXME("VESA Display Power Management Extensions - not implemented\n");
982 case 0xef: /* get video mode for hercules-compatibles */
983 /* There's no reason to really support this */
984 /* is there?....................(A.C.) */
985 TRACE("Just report the video not hercules compatible\n");
986 SET_DX( context, 0xffff );
989 case 0xff: /* Turn VESA ON/OFF */
990 /* i dont know what to do */
994 FIXME("VESA Function (0x%x) - Not Supported\n", AH_reg(context));
1000 /**********************************************************************
1001 * DOSVM_Int10Handler
1003 * Handler for int 10h (video).
1006 * Most INT 10 functions for text-mode, CGA, EGA, and VGA cards
1007 * are present in this list. (SVGA and XGA are not) That is not
1008 * to say that all these functions should be supported, but if
1009 * anyone is brain-damaged enough to want to emulate one of these
1010 * beasts then this should get you started.
1013 * Several common graphical extensions used by Microsoft hook
1014 * off of here. I have *not* added them to this list (yet). They
1017 * MSHERC.COM - More functionality for Hercules cards.
1018 * EGA.SYS (also MOUSE.COM) - More for EGA cards.
1020 * Yes, MS also added this support into their mouse driver. Don't
1021 * ask me, I don't work for them.
1023 * Joseph Pranevich - 9/98
1026 * Added support for Vesa. It is not complete but is a start.
1027 * NOTE: Im not sure if i did all this right or if eny of it works.
1028 * Currently i dont have a program that uses Vesa that actually gets far
1029 * enough without crashing to do vesa stuff.
1031 * Added additional vga graphic support - 3/99
1033 void WINAPI DOSVM_Int10Handler( CONTEXT86 *context )
1035 BIOSDATA *data = DOSVM_BiosData();
1037 INT10_InitializeVideoMode( data );
1039 switch(AH_reg(context)) {
1041 case 0x00: /* SET VIDEO MODE */
1042 TRACE( "Set VGA video mode %02x\n", AL_reg(context) );
1043 if (!INT10_SetVideoMode( data, AL_reg(context) ))
1044 FIXME( "Unsupported VGA video mode requested: %d\n",
1048 case 0x01: /* SET CURSOR SHAPE */
1049 TRACE("Set Cursor Shape start %d end %d options %d\n",
1050 CH_reg(context) & 0x1f,
1051 CL_reg(context) & 0x1f,
1052 CH_reg(context) & 0xe0);
1053 data->VideoCursorType = CX_reg(context); /* direct copy */
1054 VGA_SetCursorShape(CH_reg(context), CL_reg(context));
1057 case 0x02: /* SET CURSOR POSITION */
1058 /* BH = Page Number */ /* Not supported */
1059 /* DH = Row */ /* 0 is left */
1060 /* DL = Column */ /* 0 is top */
1061 INT10_SetCursorPos(data,BH_reg(context),DL_reg(context),DH_reg(context));
1062 if (BH_reg(context))
1064 FIXME("Set Cursor Position: Cannot set to page %d\n",
1069 VGA_SetCursorPos(DL_reg(context), DH_reg(context));
1070 TRACE("Set Cursor Position: %d/%d\n", DL_reg(context),
1075 case 0x03: /* GET CURSOR POSITION AND SIZE */
1079 TRACE("Get cursor position and size (page %d)\n", BH_reg(context));
1080 SET_CX( context, data->VideoCursorType );
1081 INT10_GetCursorPos(data,BH_reg(context),&col,&row);
1082 SET_DH( context, row );
1083 SET_DL( context, col );
1084 TRACE("Cursor Position: %d/%d\n", DL_reg(context), DH_reg(context));
1088 case 0x04: /* READ LIGHT PEN POSITION */
1089 FIXME("Read Light Pen Position - Not Supported\n");
1090 SET_AH( context, 0x00 ); /* Not down */
1093 case 0x05: /* SELECT ACTIVE DISPLAY PAGE */
1094 FIXME("Select Active Display Page (%d) - Not Supported\n", AL_reg(context));
1095 data->VideoCurPage = AL_reg(context);
1098 case 0x06: /* SCROLL UP WINDOW */
1099 /* AL = Lines to scroll */
1100 /* BH = Attribute */
1101 /* CH,CL = row, col upper-left */
1102 /* DH,DL = row, col lower-right */
1103 TRACE("Scroll Up Window %d\n", AL_reg(context));
1105 if (AL_reg(context) == 0)
1106 VGA_ClearText( CH_reg(context), CL_reg(context),
1107 DH_reg(context), DL_reg(context),
1110 VGA_ScrollUpText( CH_reg(context), CL_reg(context),
1111 DH_reg(context), DL_reg(context),
1112 AL_reg(context), BH_reg(context) );
1115 case 0x07: /* SCROLL DOWN WINDOW */
1116 /* AL = Lines to scroll */
1117 /* BH = Attribute */
1118 /* CH,CL = row, col upper-left */
1119 /* DH,DL = row, col lower-right */
1120 TRACE("Scroll Down Window %d\n", AL_reg(context));
1122 if (AL_reg(context) == 0)
1123 VGA_ClearText( CH_reg(context), CL_reg(context),
1124 DH_reg(context), DL_reg(context),
1127 VGA_ScrollDownText( CH_reg(context), CL_reg(context),
1128 DH_reg(context), DL_reg(context),
1129 AL_reg(context), BH_reg(context) );
1132 case 0x08: /* READ CHARACTER AND ATTRIBUTE AT CURSOR POSITION */
1134 if (BH_reg(context)) /* Write to different page */
1136 FIXME("Read character and attribute at cursor position -"
1137 " Can't read from non-0 page\n");
1138 SET_AL( context, ' ' ); /* That page is blank */
1139 SET_AH( context, 7 );
1144 TRACE("Read Character and Attribute at Cursor Position\n");
1145 VGA_GetCharacterAtCursor(&ascii, &attr);
1146 SET_AL( context, ascii );
1147 SET_AH( context, attr );
1152 case 0x09: /* WRITE CHARACTER AND ATTRIBUTE AT CURSOR POSITION */
1153 case 0x0a: /* WRITE CHARACTER ONLY AT CURSOR POSITION */
1154 /* AL = Character to display. */
1155 /* BH = Page Number */ /* We can't write to non-0 pages, yet. */
1156 /* BL = Attribute / Color */
1157 /* CX = Times to Write Char */
1158 /* Note here that the cursor is not advanced. */
1162 INT10_GetCursorPos(data,BH_reg(context),&col,&row);
1163 VGA_WriteChars(col, row,
1165 (AH_reg(context) == 0x09) ? BL_reg(context) : -1,
1167 if (CX_reg(context) > 1)
1168 TRACE("Write Character%s at Cursor Position (Rep. %d): %c\n",
1169 (AH_reg(context) == 0x09) ? " and Attribute" : "",
1170 CX_reg(context), AL_reg(context));
1172 TRACE("Write Character%s at Cursor Position: %c\n",
1173 (AH_reg(context) == 0x09) ? " and Attribute" : "",
1179 switch BH_reg(context) {
1180 case 0x00: /* SET BACKGROUND/BORDER COLOR */
1181 /* In text modes, this sets only the border... */
1182 /* According to the interrupt list and one of my books. */
1183 /* Funny though that Beyond Zork seems to indicate that it
1184 also sets up the default background attributes for clears
1186 /* Bear in mind here that we do not want to change,
1187 apparently, the foreground or attribute of the background
1188 with this call, so we should check first to see what the
1189 foreground already is... FIXME */
1190 FIXME("Set Background/Border Color: %d/%d\n",
1191 BH_reg(context), BL_reg(context));
1193 case 0x01: /* SET PALETTE */
1194 FIXME("Set Palette - Not Supported\n");
1197 FIXME("INT 10 AH = 0x0b BH = 0x%x - Unknown\n",
1203 case 0x0c: /* WRITE GRAPHICS PIXEL */
1204 /* Not in graphics mode, can ignore w/o error */
1205 FIXME("Write Graphics Pixel - Not Supported\n");
1208 case 0x0d: /* READ GRAPHICS PIXEL */
1209 /* Not in graphics mode, can ignore w/o error */
1210 FIXME("Read Graphics Pixel - Not Supported\n");
1213 case 0x0e: /* TELETYPE OUTPUT */
1214 TRACE("Teletype Output\n");
1215 DOSVM_PutChar(AL_reg(context));
1218 case 0x0f: /* GET CURRENT VIDEO MODE */
1219 TRACE("Get current video mode: -> mode %d, columns %d\n", data->VideoMode, data->VideoColumns);
1220 /* Note: This should not be a constant value. */
1221 SET_AL( context, data->VideoMode );
1222 SET_AH( context, data->VideoColumns );
1223 SET_BH( context, 0 ); /* Display page 0 */
1227 switch AL_reg(context) {
1228 case 0x00: /* SET SINGLE PALETTE REGISTER - A.C. */
1229 TRACE("Set Single Palette Register - Reg 0x0%x Value 0x0%x\n",
1230 BL_reg(context),BH_reg(context));
1231 /* BH is the value BL is the register */
1232 VGA_SetColor16((int)BL_reg(context),(int)BH_reg(context));
1234 case 0x01: /* SET BORDER (OVERSCAN) */
1235 /* Text terminals have no overscan */
1236 /* I'm setting it anyway. - A.C. */
1237 TRACE("Set Border (Overscan) - Ignored but set.\n");
1238 VGA_SetColor16(16,(int)BH_reg(context));
1240 case 0x02: /* SET ALL PALETTE REGISTERS - A.C.*/
1241 TRACE("Set all palette registers\n");
1242 /* ES:DX points to a 17 byte table of colors */
1243 /* No return data listed */
1244 /* I'll have to update my table and the default palette */
1245 VGA_Set16Palette(CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edx));
1247 case 0x03: /* TOGGLE INTENSITY/BLINKING BIT */
1248 FIXME("Toggle Intensity/Blinking Bit - Not Supported\n");
1250 case 0x07: /* GET INDIVIDUAL PALETTE REGISTER - A.C.*/
1251 TRACE("Get Individual Palette Register 0x0%x\n",BL_reg(context));
1252 /* BL is register to read [ 0-15 ] BH is return value */
1253 SET_BH( context, VGA_GetColor16((int)BL_reg(context)) );
1255 case 0x08: /* READ OVERSCAN (BORDER COLOR) REGISTER - A.C. */
1256 TRACE("Read Overscan (Border Color) Register \n");
1257 SET_BH( context, VGA_GetColor16(16) );
1259 case 0x09: /* READ ALL PALETTE REGISTERS AND OVERSCAN REGISTER - A.C.*/
1260 TRACE("Read All Palette Registers and Overscan Register \n");
1261 /* ES:DX points to a 17 byte table where the results */
1262 /* of this call should be stored. */
1263 VGA_Get16Palette(CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edx));
1265 case 0x10: /* SET INDIVIDUAL DAC REGISTER */
1267 PALETTEENTRY paldat;
1269 TRACE("Set Individual DAC register\n");
1270 paldat.peRed = DH_reg(context);
1271 paldat.peGreen = CH_reg(context);
1272 paldat.peBlue = CL_reg(context);
1274 VGA_SetPalette(&paldat,BX_reg(context)&0xFF,1);
1277 case 0x12: /* SET BLOCK OF DAC REGISTERS */
1280 PALETTEENTRY paldat;
1283 TRACE("Set Block of DAC registers\n");
1284 pt = (BYTE*)CTX_SEG_OFF_TO_LIN(context,context->SegEs,context->Edx);
1285 for (i=0;i<CX_reg(context);i++)
1287 paldat.peRed = (*(pt+i*3+0)) << 2;
1288 paldat.peGreen = (*(pt+i*3+1)) << 2;
1289 paldat.peBlue = (*(pt+i*3+2)) << 2;
1291 VGA_SetPalette(&paldat,(BX_reg(context)+i)&0xFF,1);
1295 case 0x13: /* SELECT VIDEO DAC COLOR PAGE */
1296 FIXME("Select video DAC color page - Not Supported\n");
1298 case 0x15: /* READ INDIVIDUAL DAC REGISTER */
1299 FIXME("Read individual DAC register - Not Supported\n");
1301 case 0x17: /* READ BLOCK OF DAC REGISTERS */
1302 FIXME("Read block of DAC registers - Not Supported\n");
1304 case 0x18: /* SET PEL MASK */
1305 FIXME("Set PEL mask - Not Supported\n");
1307 case 0x19: /* READ PEL MASK */
1308 FIXME("Read PEL mask - Not Supported\n");
1310 case 0x1a: /* GET VIDEO DAC COLOR PAGE STATE */
1311 FIXME("Get video DAC color page state - Not Supported\n");
1313 case 0x1b: /* PERFORM GRAY-SCALE SUMMING */
1314 FIXME("Perform Gray-scale summing - Not Supported\n");
1317 FIXME("INT 10 AH = 0x10 AL = 0x%x - Unknown\n",
1323 case 0x11: /* TEXT MODE CHARGEN */
1324 /* Note that second subfunction is *almost* identical. */
1325 /* See INTERRUPT.A for details. */
1326 switch AL_reg(context) {
1327 case 0x00: /* LOAD USER SPECIFIED PATTERNS */
1329 FIXME("Load User Specified Patterns - Not Supported\n");
1331 case 0x01: /* LOAD ROM MONOCHROME PATTERNS */
1333 FIXME("Load ROM Monochrome Patterns - Not Supported\n");
1335 case 0x02: /* LOAD ROM 8x8 DOUBLE-DOT PATTERNS */
1338 "Load ROM 8x8 Double Dot Patterns - Not Supported\n");
1340 case 0x03: /* SET BLOCK SPECIFIER */
1341 FIXME("Set Block Specifier - Not Supported\n");
1343 case 0x04: /* LOAD ROM 8x16 CHARACTER SET */
1345 FIXME("Load ROM 8x16 Character Set - Not Supported\n");
1347 case 0x20: /* SET USER 8x16 GRAPHICS CHARS */
1348 FIXME("Set User 8x16 Graphics Chars - Not Supported\n");
1350 case 0x21: /* SET USER GRAPICS CHARACTERS */
1351 FIXME("Set User Graphics Characters - Not Supported\n");
1353 case 0x22: /* SET ROM 8x14 GRAPHICS CHARS */
1354 FIXME("Set ROM 8x14 Graphics Chars - Not Supported\n");
1356 case 0x23: /* SET ROM 8x8 DBL DOT CHARS */
1358 "Set ROM 8x8 Dbl Dot Chars (Graphics) - Not Supported\n");
1360 case 0x24: /* LOAD 8x16 GRAPHIC CHARS */
1361 FIXME("Load 8x16 Graphic Chars - Not Supported\n");
1363 case 0x30: /* GET FONT INFORMATION */
1364 FIXME("Get Font Information - Not Supported\n");
1367 FIXME("INT 10 AH = 0x11 AL = 0x%x - Unknown\n",
1373 case 0x12: /* ALTERNATE FUNCTION SELECT */
1374 switch BL_reg(context) {
1375 case 0x10: /* GET EGA INFO */
1376 TRACE("EGA info requested\n");
1377 SET_BH( context, 0x00 ); /* Color screen */
1378 SET_BL( context, data->ModeOptions >> 5 ); /* EGA memory size */
1379 SET_CX( context, data->FeatureBitsSwitches );
1381 case 0x20: /* ALTERNATE PRTSC */
1382 FIXME("Install Alternate Print Screen - Not Supported\n");
1384 case 0x30: /* SELECT VERTICAL RESOULTION */
1385 FIXME("Select vertical resolution - not supported\n");
1387 case 0x31: /* ENABLE/DISABLE DEFAULT PALETTE LOADING */
1388 FIXME("Default palette loading - not supported\n");
1390 (data->VGASettings & 0xf7) |
1391 ((AL_reg(context) == 1) << 3);
1393 case 0x32: /* ENABLE/DISABLE VIDEO ADDRERSSING */
1394 FIXME("Video Addressing - Not Supported\n");
1396 case 0x33: /* ENABLE/DISABLE GRAY SCALE SUMMING */
1397 FIXME("Gray Scale Summing - Not Supported\n");
1399 case 0x34: /* ENABLE/DISABLE CURSOR EMULATION */
1400 TRACE("Set cursor emulation to %d\n", AL_reg(context));
1402 (data->ModeOptions & 0xfe)|(AL_reg(context) == 1);
1404 case 0x36: /* VIDEO ADDRESS CONTROL */
1405 FIXME("Video Address Control - Not Supported\n");
1408 FIXME("INT 10 AH = 0x11 AL = 0x%x - Unknown\n",
1414 case 0x13: /* WRITE STRING */
1415 /* This one does not imply that string be at cursor. */
1416 FIXME("Write String - Not Supported\n");
1420 switch AL_reg(context) {
1421 case 0x00: /* GET DISPLAY COMBINATION CODE */
1422 TRACE("Get Display Combination Code\n");
1423 SET_AL( context, 0x1a ); /* Function supported */
1424 SET_BL( context, INT10_DCC ); /* Active display */
1425 SET_BH( context, 0x00 ); /* No alternate display */
1427 case 0x01: /* SET DISPLAY COMBINATION CODE */
1428 FIXME("Set Display Combination Code - Not Supported\n");
1431 FIXME("INT 10 AH = 0x1a AL = 0x%x - Unknown\n",
1437 case 0x1b: /* FUNCTIONALITY/STATE INFORMATION */
1438 TRACE("Get functionality/state information\n");
1439 if (BX_reg(context) == 0x0000)
1441 BYTE *ptr = CTX_SEG_OFF_TO_LIN(context,
1444 SET_AL( context, 0x1b ); /* Function is supported */
1445 INT10_FillStateInformation( ptr, data );
1449 case 0x1c: /* SAVE/RESTORE VIDEO STATE */
1450 FIXME("Save/Restore Video State - Not Supported\n");
1453 case 0xef: /* get video mode for hercules-compatibles */
1454 /* There's no reason to really support this */
1455 /* is there?....................(A.C.) */
1456 TRACE("Just report the video not hercules compatible\n");
1457 SET_DX( context, 0xffff );
1460 case 0x4f: /* VESA */
1461 INT10_HandleVESA(context);
1464 case 0xfe: /* GET SHADOW BUFFER */
1465 TRACE( "GET SHADOW BUFFER %lx:%x - ignored\n",
1466 context->SegEs, DI_reg(context) );
1470 FIXME("Unknown - 0x%x\n", AH_reg(context));
1471 INT_BARF( context, 0x10 );
1476 /**********************************************************************
1479 * Write single character to VGA console at the current
1480 * cursor position and updates the BIOS cursor position.
1482 void WINAPI DOSVM_PutChar( BYTE ascii )
1484 BIOSDATA *data = DOSVM_BiosData();
1485 unsigned xpos, ypos;
1487 TRACE("char: 0x%02x(%c)\n", ascii, ascii);
1489 INT10_InitializeVideoMode( data );
1491 VGA_PutChar( ascii );
1492 VGA_GetCursorPos( &xpos, &ypos );
1493 INT10_SetCursorPos( data, 0, xpos, ypos );