We are no longer generating .dbg.c files.
[wine] / dlls / winedos / int10.c
1 /*
2  * BIOS interrupt 10h handler
3  *
4  * Copyright 1998 Ove Kåven
5  * Copyright 1998 Joseph Pranevich
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include "config.h"
23
24 #include <stdlib.h>
25
26 #include "vga.h"
27 #include "wine/debug.h"
28 #include "dosexe.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(int);
31
32 /*
33  * Display combination code for active display.
34  *
35  * Values (hex):
36  * 00 - no display
37  * 01 - monochrome adapter w/ monochrome display
38  * 02 - CGA w/ color display
39  * 03 - reserved
40  * 04 - EGA w/ color display
41  * 05 - EGA w/ monochrome display
42  * 06 - PGA w/ color display
43  * 07 - VGA w/ monochrome analog display
44  * 08 - VGA w/ color analog display
45  * 09 - reserved
46  * 0A - MCGA w/ digital color display
47  * 0B - MCGA w/ monochrome analog display
48  * 0C - MCGA w/ color analog display
49  * FF - unknown display type
50  */
51 #define INT10_DCC 0x08
52
53 #include "pshpack1.h"
54
55 /*
56  * Structure for DOS data that can be accessed directly from applications.
57  * This structure must be correctly packed.
58  */
59 typedef struct _INT10_HEAP {
60     BYTE  StaticModeSupport[7];     /* modes supported 1..7 */
61     BYTE  StaticScanlineSupport;    /* scan lines supported */
62     BYTE  StaticNumberCharBlocks;   /* total number of char blocks */
63     BYTE  StaticActiveCharBlocks;   /* max number of active char blocks */
64     WORD  StaticMiscFlags;          /* misc function support flags */
65     WORD  StaticReserved1;          /* reserved */
66     BYTE  StaticSavePointerFlags;   /* save pointer function flags */
67     BYTE  StaticReserved2;          /* reserved */
68
69     WORD  VesaCurrentMode;
70     WORD  VesaModeList[64];
71     char  VesaOEMName[32];
72     char  VesaProductName[32];
73     char  VesaProductRev[32];
74     char  VesaVendorName[32];
75
76     WORD  WineHeapSegment;
77 } INT10_HEAP;
78
79 /*
80  * Structure for VBE Mode Info Block. See the VBE 3.0 standard for details.
81  * This structure must be correctly packed.
82  */
83 struct _ModeInfoBlock {
84     WORD  ModeAttributes;       /* 0x00 */
85     BYTE  WinAAttributes;       /* 0x02 */
86     BYTE  WinBAttributes;       /* 0x03 */
87     WORD  WinGranularity;       /* 0x04 */
88     WORD  WinSize;              /* 0x06 */
89     WORD  WinASegment;          /* 0x08 */
90     WORD  WinBSegment;          /* 0x0A */
91     DWORD WinFuncPtr;           /* 0x0C */
92     WORD  BytesPerScanLine;     /* 0x10 */
93     /* mandatory for VBE 1.2+ */
94     WORD  XResolution;          /* 0x12 */
95     WORD  YResolution;          /* 0x14 */
96     BYTE  XCharSize;            /* 0x16 */
97     BYTE  YCharSize;            /* 0x17 */
98     BYTE  NumberOfPlanes;       /* 0x18 */
99     BYTE  BitsPerPixel;         /* 0x19 */
100     BYTE  NumberOfBanks;        /* 0x1A */
101     BYTE  MemoryModel;          /* 0x1B */
102     BYTE  BankSize;             /* 0x1C */
103     BYTE  NumberOfImagePages;   /* 0x1D */
104     BYTE  Reserved1;            /* 0x1E */
105     BYTE  RedMaskSize;          /* 0x1F */
106     BYTE  RedFieldPosition;     /* 0x20 */
107     BYTE  GreenMaskSize;        /* 0x21 */
108     BYTE  GreenFieldPosition;   /* 0x22 */
109     BYTE  BlueMaskSize;         /* 0x23 */
110     BYTE  BlueFieldPosition;    /* 0x24 */
111     BYTE  RsvdMaskSize;         /* 0x25 */
112     BYTE  RsvdFieldPosition;    /* 0x26 */
113     BYTE  DirectColorModeInfo;  /* 0x27 */
114     /* mandatory for VBE 2.0+ */
115     DWORD PhysBasePtr;          /* 0x28 */
116     DWORD Reserved2;            /* 0x2C */
117     WORD  Reserved3;            /* 0x30 */
118     /* mandatory for VBE 3.0+ */
119     WORD  LinBytesPerScanLine;  /* 0x32 */
120     BYTE  BnkNumberOfImagePages;/* 0x34 */
121     BYTE  LinNumberOfImagePages;/* 0x35 */
122     BYTE  LinRedMaskSize;       /* 0x36 */
123     BYTE  LinRedFieldPosition;  /* 0x37 */
124     BYTE  LinGreenMaskSize;     /* 0x38 */
125     BYTE  LinGreenFieldPosition;/* 0x39 */
126     BYTE  LinBlueMaskSize;      /* 0x3A */
127     BYTE  LinBlueFieldPosition; /* 0x3B */
128     BYTE  LinRsvdMaskSize;      /* 0x3C */
129     BYTE  LinRsvdFieldPosition; /* 0x3D */
130     DWORD MaxPixelClock;        /* 0x3E */
131     BYTE  Reserved4[190];       /* 0x42 */
132 };
133
134 #include "poppack.h"
135
136 /*
137  * Wine internal information about video modes.
138  * If depth is zero, the mode is considered to
139  * be a text mode.
140  */
141 typedef struct {
142     WORD Mode;
143     WORD Width;
144     WORD Height;
145     WORD Depth;
146 } INT10_MODE;
147
148
149 /*
150  * List of supported video modes.
151  */
152 static const INT10_MODE INT10_modelist[] =
153 {
154     {0x0000,   40,   25,  0},
155     {0x0001,   40,   25,  0},
156     {0x0002,   80,   25,  0},
157     {0x0003,   80,   25,  0},
158     {0x0007,   80,   25,  0},
159     {0x000d,  320,  200,  4},
160     {0x000e,  640,  200,  4},
161     {0x0010,  640,  350,  4},
162     {0x0012,  640,  480,  4},
163     {0x0013,  320,  200,  8},
164     {0x006a,  800,  600,  4},   /* VESA mode, same as 0x102 */
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},
173     {0x0108,   80,   60,  0},
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},
193     {0xffff,    0,    0,  0}
194 };
195
196 /* True if video mode is a vesa mode, false otherwise.
197  * More correct would be to use something like (x > 0xff || x == 0x6a)
198  * but as long as we have only the standard VGA and VESA modes this is ok too */
199 #define IS_VESA_MODE(x)         ((x) >= 0x6a)
200
201 /* Forward declarations. */
202 static INT10_HEAP *INT10_GetHeap(void);
203 static void INT10_SetCursorPos(BIOSDATA*, unsigned, unsigned, unsigned);
204
205
206 /**********************************************************************
207  *         INT10_FindMode
208  */
209 static const INT10_MODE *INT10_FindMode( WORD mode )
210 {
211     const INT10_MODE *ptr = INT10_modelist;
212     
213     /*
214      * Filter out flags.
215      */
216     mode &= 0x17f;
217
218     while (ptr->Mode != 0xffff)
219     {
220         if (ptr->Mode == mode)
221             return ptr;
222         ptr++;
223     }
224
225     return NULL;
226 }
227
228
229 /**********************************************************************
230  *         INT10_FillControllerInformation
231  *
232  * Fill 256-byte (VBE1.x) or 512-byte buffer (VBE2.0+) with
233  * capabilities of the video controller.
234  */
235 static void INT10_FillControllerInformation( BYTE *buffer )
236 {
237     INT10_HEAP *heap = INT10_GetHeap();
238
239     /* 00 - BYTE[4]: signature */
240     memmove( buffer, "VESA", 4 );
241
242     /* 04 - WORD: version number */
243     *(WORD*)(buffer + 4) = 0x0300; /* version 3.0 */
244     
245     /* 06 - DWORD: pointer to OEM name */
246     *(SEGPTR*)(buffer + 6) = MAKESEGPTR( heap->WineHeapSegment,
247                                          offsetof(INT10_HEAP,
248                                                   VesaOEMName) );
249
250     /*
251      * 10 - DWORD: capabilities flags 
252      * Bits:
253      *    0 - DAC can be switched into 8-bit mode
254      *    1 - non-VGA controller
255      *    2 - programmed DAC with blank bit
256      *    3 - controller supports hardware stereoscopic signalling
257      *    4 - =0 stereo signalling via external VESA stereo connector
258      *        =1 stereo signalling via VESA EVC connector
259      *    5 - controller supports hardware mouse cursor
260      *    6 - controller supports hardware clipping
261      *    7 - controller supports transparent BitBLT
262      * 8-31 - reserved (0)
263      */
264     *(DWORD*)(buffer + 10) = 0; /* FIXME */
265     
266     /* 14 - DWORD: pointer to list of supported VESA and OEM video modes */
267     *(SEGPTR*)(buffer + 14) = MAKESEGPTR( heap->WineHeapSegment,
268                                           offsetof(INT10_HEAP,
269                                                    VesaModeList) );
270
271     /* 18 - WORD: total amount of video memory in 64K blocks */
272     *(WORD*)(buffer + 18) = 16; /* FIXME */
273
274     /* 20 - WORD: OEM software version (BCD, high byte = major) */
275     *(WORD*)(buffer + 20) = 0x0100; /* version 1.0 */
276
277     /* 22 - DWORD: pointer to vendor name */
278     *(SEGPTR*)(buffer + 22) = MAKESEGPTR( heap->WineHeapSegment,
279                                           offsetof(INT10_HEAP,
280                                                    VesaVendorName) );
281
282     /* 26 - DWORD: pointer to product name */
283     *(SEGPTR*)(buffer + 26) = MAKESEGPTR( heap->WineHeapSegment,
284                                           offsetof(INT10_HEAP,
285                                                    VesaProductName) );
286
287     /* 30 - DWORD: pointer to product revision string */
288     *(SEGPTR*)(buffer + 30) = MAKESEGPTR( heap->WineHeapSegment,
289                                           offsetof(INT10_HEAP,
290                                                    VesaProductRev) );
291
292     /* 34 - WORD: VBE/AF version (if capabilities bit 3 set) */
293     *(WORD*)(buffer + 34) = 0;
294
295     /*
296      * 36 - DWORD: pointer to list of accelerated modes 
297      *             (if capabilities bit 3 set) 
298      */
299     *(SEGPTR*)(buffer + 36) = 0;
300
301     /* 40 - BYTE[216]: reserved for VBE implementation, set to zero */
302     memset( buffer + 40, 216, 0 );
303
304     /* 
305      * 256 - BYTE[256]: reserved for VBE3.0 implementation, 
306      *                  ignored in order to support older programs
307      */
308 }
309
310
311 /**********************************************************************
312  *         INT10_FillModeInformation
313  *
314  * Fill 256-byte buffer with extended information about display mode.
315  *
316  * Returns FALSE if mode is unknown and TRUE is mode is known
317  * even if it is not supported.
318  */
319 static BOOL INT10_FillModeInformation( struct _ModeInfoBlock *mib, WORD mode )
320 {
321     const INT10_MODE *ptr = INT10_FindMode( mode );
322     if (!ptr)
323         return FALSE;
324
325     /*
326      * 00 - WORD: mode attributes
327      * Bits:
328      *     0 - Mode supported by present hardware configuration.
329      *     1 - Optional information available. Must be =1 for VBE v1.2+.
330      *     2 - BIOS output supported.
331      *         Int10 functions 01, 02, 06, 07, 09, 0a and 0e are supported.
332      *     3 - Set if color, clear if monochrome.
333      *     4 - Set if graphics mode, clear if text mode.
334      *     5 - Mode is not VGA-compatible if set.
335      *         VGA-compatible modes support standard VGA I/O ports.
336      *     6 - Bank-switched (or windowed) mode is not supported if set.
337      *     7 - Linear framebuffer mode supported.
338      *     8 - Double scanning supported.
339      *     9 - Interlaced operation supported.
340      *    10 - Triple buffering supported.
341      *    11 - Stereoscopic display supported.
342      *    12 - Dual display start address supported.
343      * 13-15 - Reserved.
344      */
345     {
346         WORD attr = 0x000a; /* color mode, optional info */
347
348         /*
349          * FIXME: Attribute handling is incomplete.
350          */
351
352         /* Mode supported? FIXME: correct value */
353         attr |= 0x0001;
354
355         /* Graphical mode? */
356         if (ptr->Depth) 
357             attr |= 0x0010;
358
359         /* Not VGA-compatible? */
360         if (IS_VESA_MODE(mode))
361             attr |= 0x0020;
362
363         mib->ModeAttributes = attr;
364     }
365
366     /*
367      * 02 - BYTE[2]: window attributes, window A and window B
368      * Bits:
369      *   0 - Window exists.
370      *   1 - Window is readable.
371      *   2 - Window is writable.
372      * 3-7 - Reserved.
373      */
374     mib->WinAAttributes = 0x07; /* window A exists, readable and writable */
375     mib->WinBAttributes = 0x00; /* window B not supported */
376
377     /* 04 - WORD: window granularity in KB */
378     mib->WinGranularity = 64;
379
380     /* 06 - WORD: window size in KB */
381     mib->WinSize = 64;
382
383     /* 08 - WORD[2]: start segments, window A and window B */
384     mib->WinASegment = 0xa000; /* window A segment */
385     mib->WinBSegment = 0x0000; /* window B not supported */
386
387     /* 12 - DWORD: window positioning function */
388     mib->WinFuncPtr = 0; /* not supported */
389     
390     /* 16 - WORD: bytes per scan line */
391     /* FIXME: is this always correct? */
392     mib->BytesPerScanLine = ptr->Width * (ptr->Depth ? (ptr->Depth + 7) / 8 : 1);
393
394     /* 18 - WORD: width in pixels (graphics) or characters (text) */
395     mib->XResolution = ptr->Width;
396
397     /* 20 - WORD: height in pixels (graphics) or characters (text) */
398     mib->YResolution = ptr->Height;
399
400     /* 22 - BYTE: width of character cell in pixels */
401     mib->XCharSize = 0; /* FIXME */
402
403     /* 23 - BYTE: height of character cell in pixels */
404     mib->YCharSize = 0; /* FIXME */
405
406     /* 24 - BYTE: number of memory planes */
407     mib->NumberOfPlanes = 1; /* FIXME */
408
409     /* 25 - BYTE: number of bits per pixel */
410     mib->BitsPerPixel = ptr->Depth; /* FIXME: text modes? reserved bits? */
411
412     /* 26 - BYTE: number of banks */
413     mib->NumberOfBanks = 1; /* FIXME */
414
415     /*
416      * 27 - BYTE: memory model type
417      * Values (hex):
418      *    00 - Text mode
419      *    01 - CGA graphics
420      *    02 - Hercules graphics
421      *    03 - Planar
422      *    04 - Packed pixel
423      *    05 - Non-chain 4, 256 color
424      *    06 - Direct color
425      *    07 - YUV
426      * 08-0F - Reserved for VESA.
427      * 10-FF - OEM memory models.
428      */
429     if (!ptr->Depth)
430         mib->MemoryModel = 0; /* text mode */
431     else
432         mib->MemoryModel = 3; /* FIXME */
433
434     /* 28 - BYTE: size of bank in KB */
435     mib->BankSize = 0; /* FIXME */
436
437     /* 29 - BYTE: number of image pages (less one) in video RAM */
438     mib->NumberOfImagePages = 0; /* FIXME */
439
440     /* 30 - BYTE: reserved (0x00 for VBE 1.0-2.0, 0x01 for VBE 3.0) */
441     mib->Reserved1 = 0x01;
442
443     /* 
444      * 31,33,35 - BYTE: red/green/blue mask size 
445      * Size of red/green/blue color component in bits.
446      * 32,34,36 - BYTE: red/green/blue field position 
447      * Bit position of the least significant bit of red/green/blue color
448      * component.
449      * Both should be only used when memory model is direct color or YUV but
450      * "Imperium Romanum" uses this fields even when memory model is planar.
451      * So always fill this fields when we have a depth bigger then 8, otherwise
452      * set them to zero.
453      */
454     switch (ptr->Depth) {
455         case 24:
456             mib->RedMaskSize = 8;
457             mib->GreenMaskSize = 8;
458             mib->BlueMaskSize = 8;
459             mib->RsvdMaskSize = 0;
460             mib->RedFieldPosition = 16;
461             mib->GreenFieldPosition = 8;
462             mib->BlueFieldPosition = 0;
463             mib->RsvdFieldPosition = 0;
464             break;
465         case 16:
466             mib->RedMaskSize = 5;
467             mib->GreenMaskSize = 6;
468             mib->BlueMaskSize = 5;
469             mib->RsvdMaskSize = 0;
470             mib->RedFieldPosition = 11;
471             mib->GreenFieldPosition = 5;
472             mib->BlueFieldPosition = 0;
473             mib->RsvdFieldPosition = 0;
474             break;
475         case 15:
476             mib->RedMaskSize = 5;
477             mib->GreenMaskSize = 5;
478             mib->BlueMaskSize = 5;
479             mib->RsvdMaskSize = 1;
480             mib->RedFieldPosition = 10;
481             mib->GreenFieldPosition = 5;
482             mib->BlueFieldPosition = 0;
483             mib->RsvdFieldPosition = 15;
484             break;
485         default:
486             mib->RedMaskSize = 0;
487             mib->GreenMaskSize = 0;
488             mib->BlueMaskSize = 0;
489             mib->RsvdMaskSize = 0;
490             mib->RedFieldPosition = 0;
491             mib->GreenFieldPosition = 0;
492             mib->BlueFieldPosition = 0;
493             mib->RsvdFieldPosition = 0;
494             break;
495     }
496
497     /*
498      * 39 - BYTE: direct color mode info 
499      * Bits:
500      * 0 - Set if color ramp is programmable.
501      * 1 - Set if bytes in reserved field may be used by application.
502      */
503     mib->DirectColorModeInfo = 0; /* not supported */
504
505     /* 40 - DWORD: physical address of linear video buffer */
506     mib->PhysBasePtr = 0; /* not supported */
507
508     /* 44 - DWORD: reserved, always zero */
509     mib->Reserved2 = 0;
510
511     /* 48 - WORD: reserved, always zero */
512     mib->Reserved3 = 0;
513
514     /* 50 - WORD: bytes per scan line in linear modes */
515     mib->LinBytesPerScanLine = mib->BytesPerScanLine;
516
517     /* 52 - BYTE: number of images (less one) for banked video modes */
518     mib->BnkNumberOfImagePages = 0; /* FIXME */
519
520     /* 53 - BYTE: number of images (less one) for linear video modes */
521     mib->LinNumberOfImagePages = mib->BnkNumberOfImagePages;
522
523     /* 54 - BYTE: red mask size (linear modes) */
524     mib->LinRedMaskSize = mib->RedMaskSize;
525
526     /* 55 - BYTE: red field position (linear modes) */
527     mib->LinRedFieldPosition = mib->RedFieldPosition;
528
529     /* 56 - BYTE: green mask size (linear modes) */
530     mib->LinGreenMaskSize = mib->GreenMaskSize;
531
532     /* 57 - BYTE: green field size (linear modes) */
533     mib->LinGreenFieldPosition = mib->GreenFieldPosition;
534
535     /* 58 - BYTE: blue mask size (linear modes) */
536     mib->LinBlueMaskSize = mib->BlueMaskSize;
537
538     /* 59 - BYTE: blue field position (linear modes) */
539     mib->LinBlueFieldPosition = mib->BlueFieldPosition;
540
541     /* 60 - BYTE: reserved mask size (linear modes) */
542     mib->LinRsvdMaskSize = mib->RsvdMaskSize;
543
544     /* 61 - BYTE: reserved mask position (linear modes) */
545     mib->LinRsvdFieldPosition = mib->RsvdFieldPosition;
546
547     /* 62 - DWORD: maximum pixel clock for graphics video mode, in Hz */
548     mib->MaxPixelClock = 0; /* FIXME */
549
550     /* 66 - BYTE[190]: reserved, set to zero */
551     memset( &mib->Reserved4, 190, 0 );
552
553     return TRUE;
554 }
555
556
557 /**********************************************************************
558  *         INT10_FillStateInformation
559  *
560  * Fill 64-byte buffer with VGA state and functionality information.
561  */
562 static void INT10_FillStateInformation( BYTE *buffer, BIOSDATA *data )
563 {
564     INT10_HEAP *heap = INT10_GetHeap();
565
566     /* 00 - DWORD: address of static functionality table */
567     *(SEGPTR*)(buffer + 0) = MAKESEGPTR( heap->WineHeapSegment,
568                                          offsetof(INT10_HEAP, 
569                                                   StaticModeSupport) );
570
571     /* 04 - BYTE[30]: copy of BIOS data starting from 0x49 (VideoMode) */
572     memmove( buffer + 4, &data->VideoMode, 30 );
573
574     /* 34 - BYTE: number of rows - 1 */
575     buffer[34] = data->RowsOnScreenMinus1;
576
577     /* 35 - WORD: bytes/character */
578     *(WORD*)(buffer + 35) = data->BytesPerChar;
579
580     /* 37 - BYTE: display combination code of active display */
581     buffer[37] = INT10_DCC;
582
583     /* 38 - BYTE: DCC of alternate display */
584     buffer[38] = 0; /* no secondary display */
585
586     /* 39 - WORD: number of colors supported in current mode (0000h = mono) */
587     *(WORD*)(buffer + 39) = 16; /* FIXME */
588
589     /* 41 - BYTE: number of pages supported in current mode */
590     buffer[41] = 1; /* FIXME */
591
592     /*
593      * 42 - BYTE: number of scan lines active
594      * Values (hex):
595      * 00 = 200
596      * 01 = 350
597      * 02 = 400
598      * 03 = 480
599      */
600     buffer[42] = 3; /* FIXME */
601
602     /* 43 - BYTE: primary character block */
603     buffer[43] = 0; /* FIXME */
604
605     /* 44 - BYTE: secondary character block */
606     buffer[44] = 0; /* FIXME */
607
608     /*
609      * 45 - BYTE: miscellaneous flags
610      * Bits:
611      * 0 - all modes on all displays on
612      * 1 - gray summing on
613      * 2 - monochrome display attached
614      * 3 - default palette loading disabled
615      * 4 - cursor emulation enabled
616      * 5 - 0 = intensity; 1 = blinking
617      * 6 - flat-panel display is active
618      * 7 - unused (0)
619      */
620     /* FIXME: Correct value? */
621     buffer[45] =
622         (data->VGASettings & 0x0f) |
623         ((data->ModeOptions & 1) << 4); /* cursor emulation */
624
625     /*
626      * 46 - BYTE: non-VGA mode support 
627      * Bits:
628      *   0 - BIOS supports information return for adapter interface
629      *   1 - adapter interface driver required
630      *   2 - 16-bit VGA graphics present
631      *   3 - =1 MFI attributes enabled
632      *       =0 VGA attributes enabled
633      *   4 - 132-column mode supported
634      * 5-7 - reserved
635      */
636      buffer[46] = 0; /* FIXME: correct value? */
637
638      /* 47 - BYTE[2]: reserved, set to zero */
639      memset( buffer + 47, 2, 0 );
640
641      /*
642       * 49 - BYTE: video memory available
643       * Values (hex):
644       * 00 - 64K
645       * 01 - 128K
646       * 02 - 192K
647       * 03 - 256K
648       */
649      buffer[49] = (data->ModeOptions & 0x60) >> 5; /* FIXME */
650
651      /*
652       * 50 - BYTE: save pointer state flags
653       * Bits:
654       *   0 - 512 character set active
655       *   1 - dynamic save area present
656       *   2 - alpha font override active
657       *   3 - graphics font override active
658       *   4 - palette override active
659       *   5 - DCC override active
660       * 6-7 - unused (0)
661       */
662      buffer[50] = heap->StaticSavePointerFlags;
663
664      /*
665       * 51 - BYTE: display information and status 
666       * Bits:
667       *   0 - flat-panel display attached
668       *   1 - flat-panel display active
669       *   2 - color display
670       * 3-6 - reserved
671       *   7 - 640x480 flat-panel can be used simultaneously with CRT
672       */
673      buffer[51] = 4; /* FIXME: correct value? */
674
675      /* 52 - BYTE[12]: reserved, set to zero */
676      memset( buffer + 52, 12, 0 );
677 }
678
679
680 /**********************************************************************
681  *         INT10_GetHeap
682  */
683 INT10_HEAP *INT10_GetHeap( void )
684 {
685     static INT10_HEAP *heap_pointer = 0;
686
687     if (!heap_pointer)
688     {
689         WORD segment;
690         int  i;
691
692         heap_pointer = DOSVM_AllocDataUMB( sizeof(INT10_HEAP), 
693                                            &segment,
694                                            0 );
695
696         for (i = 0; i < 7; i++)
697             heap_pointer->StaticModeSupport[i] = 0xff; /* FIXME */
698
699         heap_pointer->StaticScanlineSupport = 7;  /* FIXME */
700         heap_pointer->StaticNumberCharBlocks = 0; /* FIXME */
701         heap_pointer->StaticActiveCharBlocks = 0; /* FIXME */
702         heap_pointer->StaticMiscFlags = 0x8ff;    /* FIXME */
703         heap_pointer->StaticReserved1 = 0;
704         heap_pointer->StaticSavePointerFlags = 0x3f; /* FIXME */
705         heap_pointer->StaticReserved2 = 0;
706
707         for (i=0; TRUE; i++)
708         {
709             heap_pointer->VesaModeList[i] = INT10_modelist[i].Mode;
710             if (INT10_modelist[i].Mode == 0xffff)
711                 break;
712         }
713
714         strcpy( heap_pointer->VesaOEMName, "WINE SVGA BOARD" );
715         strcpy( heap_pointer->VesaVendorName, "WINE" );
716         strcpy( heap_pointer->VesaProductName, "WINE SVGA" );
717         strcpy( heap_pointer->VesaProductRev, "2003" );
718         
719         heap_pointer->VesaCurrentMode = 0; /* Initialized later. */
720         heap_pointer->WineHeapSegment = segment;
721     }
722
723     return heap_pointer;
724 }
725
726
727 /**********************************************************************
728  *         INT10_SetVideoMode
729  *
730  * Change current video mode to any VGA or VESA mode.
731  * Returns TRUE if mode is supported.
732  *
733  * Mode bitfields:
734  * 0-6: .. Mode number (combined with bit 8).
735  *   7: =0 Clear screen.
736  *      =1 Preserve display memory on mode change (VGA modes).
737  *   8: =0 VGA mode.
738  *      =1 VESA mode.
739  *   9: .. Reserved, must be zero.
740  *  10: .. Reserved, must be zero.
741  *  11: =0 Use default refresh rate.
742  *      =1 Use user specified refresh rate.
743  *  12: .. Reserved, must be zero.
744  *  13: .. Reserved, must be zero.
745  *  14: =0 Use windowed frame buffer model.
746  *      =1 Use linear frame buffer model.
747  *  15: =0 Clear screen.
748  *      =1 Preserve display memory on mode change (VESA modes).
749  */
750 static BOOL INT10_SetVideoMode( BIOSDATA *data, WORD mode )
751 {
752     const INT10_MODE *ptr = INT10_FindMode( mode );
753     INT10_HEAP *heap = INT10_GetHeap();
754     BOOL clearScreen = TRUE;
755
756     if (!ptr)
757         return FALSE;
758
759     /*
760      * Linear framebuffer is not supported.
761      */
762     if (mode & 0x4000)
763         return FALSE;
764
765     /*
766      * Check for VGA and VESA preserve video memory flag.
767      */
768     if ((mode & 0x0080) || (mode & 0x8000))
769         clearScreen = FALSE;
770
771     /*
772      * Note that we do not mask out flags here on purpose.
773      */
774     heap->VesaCurrentMode = mode;
775     if (mode <= 0xff)
776         data->VideoMode = mode;
777     else
778         data->VideoMode = 0;
779
780     if (ptr->Depth == 0)
781     {
782         /* Text mode. */
783         TRACE( "Setting %s %dx%d text mode (screen %s)\n", 
784                IS_VESA_MODE(mode) ? "VESA" : "VGA", 
785                ptr->Width, ptr->Height, 
786                clearScreen ? "cleared" : "preserved" );
787
788         /*
789          * FIXME: We should check here if alpha mode could be set.
790          */
791         VGA_SetAlphaMode( ptr->Width, ptr->Height );
792
793         data->VideoColumns = ptr->Width;
794         data->RowsOnScreenMinus1 = ptr->Height - 1;
795
796         if (clearScreen)
797         {            
798             VGA_ClearText( 0, 0, ptr->Height-1, ptr->Width-1, 0x07 );
799             INT10_SetCursorPos( data, 0, 0, 0 );
800             VGA_SetCursorPos( 0, 0 );            
801         }
802     }
803     else
804     {
805         /* Graphics mode. */
806         TRACE( "Setting %s %dx%dx%d graphics mode (screen %s)\n", 
807                IS_VESA_MODE(mode) ? "VESA" : "VGA", 
808                ptr->Width, ptr->Height, ptr->Depth,
809                clearScreen ? "cleared" : "preserved" );
810
811         if (VGA_SetMode( ptr->Width, ptr->Height, ptr->Depth ))
812             return FALSE;
813     }
814
815     return TRUE;
816 }
817
818
819 /**********************************************************************
820  *         INT10_GetCursorPos
821  */
822 static void INT10_GetCursorPos(BIOSDATA*data,unsigned page,unsigned*X,unsigned*Y)
823 {
824     *X = data->VideoCursorPos[page*2];   /* column */
825     *Y = data->VideoCursorPos[page*2+1]; /* row */
826 }
827
828
829 /**********************************************************************
830  *         INT10_SetCursorPos
831  */
832 static void INT10_SetCursorPos(BIOSDATA*data,unsigned page,unsigned X,unsigned Y)
833 {
834     data->VideoCursorPos[page*2] = X;
835     data->VideoCursorPos[page*2+1] = Y;
836 }
837
838
839 /**********************************************************************
840  *         INT10_InitializeVideoMode
841  *
842  * The first time this function is called VGA emulation is set to the
843  * default text mode.
844  */
845 static void INT10_InitializeVideoMode( BIOSDATA *data )
846 {
847   static BOOL already_initialized = FALSE;
848   unsigned    width;
849   unsigned    height;
850
851   if(already_initialized)
852     return;
853   already_initialized = TRUE;
854
855   VGA_InitAlphaMode(&width, &height);
856
857   /*
858    * FIXME: Add more mappings between initial size and
859    *        text modes.
860    */
861   if (width >= 80 && height >= 25)
862       INT10_SetVideoMode( data, 0x03 );
863   else
864       INT10_SetVideoMode( data, 0x01 );
865 }
866
867
868 /**********************************************************************
869  *          INT10_HandleVESA
870  *
871  * Handler for VESA functions (int10 function 0x4f).
872  */
873 static void INT10_HandleVESA( CONTEXT86 *context )
874 {
875     BIOSDATA *data = DOSVM_BiosData();
876
877     switch(AL_reg(context)) {
878
879     case 0x00: /* RETURN CONTROLLER INFORMATION */
880         TRACE( "VESA RETURN CONTROLLER INFORMATION\n" );
881         {
882             BYTE *ptr = CTX_SEG_OFF_TO_LIN(context,
883                                            context->SegEs, 
884                                            context->Edi);
885             INT10_FillControllerInformation( ptr );
886             SET_AL( context, 0x4f );
887             SET_AH( context, 0x00 ); /* 0x00 = successful 0x01 = failed */
888         }
889         break;
890
891     case 0x01: /* RETURN MODE INFORMATION */
892         TRACE( "VESA RETURN MODE INFORMATION %04x\n", CX_reg(context) );
893         {
894             struct _ModeInfoBlock *ptr = CTX_SEG_OFF_TO_LIN(context,
895                                                             context->SegEs, 
896                                                             context->Edi);
897             SET_AL( context, 0x4f );
898             if (INT10_FillModeInformation( ptr, CX_reg(context) ))
899                 SET_AH( context, 0x00 ); /* status: success */
900             else
901                 SET_AH( context, 0x01 ); /* status: failed */
902         }
903         break;
904
905     case 0x02: /* SET SuperVGA VIDEO MODE */
906         TRACE( "Set VESA video mode %04x\n", BX_reg(context) );
907         SET_AL( context, 0x4f ); /* function supported */
908         if (INT10_SetVideoMode( data, BX_reg(context) ))
909             SET_AH( context, 0x00 ); /* success */
910         else
911             SET_AH( context, 0x01 ); /* failed */
912         break;
913
914     case 0x03: /* VESA SuperVGA BIOS - GET CURRENT VIDEO MODE */
915         SET_AL( context, 0x4f );
916         SET_AH( context, 0x00 );
917         SET_BX( context, INT10_GetHeap()->VesaCurrentMode );
918         break;
919
920     case 0x04: /* VESA SuperVGA BIOS - SAVE/RESTORE SuperVGA VIDEO STATE */
921         ERR("VESA SAVE/RESTORE Video State - Not Implemented\n");
922         /* AL_reg(context) = 0x4f; = supported so not set since not implemented */
923         /* maybe we should do this instead ? */
924         /* AH_reg(context = 0x01;  not implemented so just fail */
925         break;
926
927     case 0x05: /* VESA SuperVGA BIOS - CPU VIDEO MEMORY CONTROL */
928         /*
929          * This subfunction supports only Window A (BL_reg == 0) and
930          * is assumes that window granularity is 64k.
931          */
932         switch(BH_reg(context)) {
933         case 0x00: /* select video memory window */
934             SET_AL( context, 0x4f ); /* function supported */
935             if(BL_reg(context) == 0) {
936                 VGA_SetWindowStart(DX_reg(context) * 64 * 1024);
937                 SET_AH( context, 0x00 ); /* status: successful */
938             } else
939                 SET_AH( context, 0x01 ); /* status: failed */
940             break;
941         case 0x01: /* get video memory window */
942             SET_AL( context, 0x4f ); /* function supported */
943             if(BL_reg(context) == 0) {
944                 SET_DX( context, VGA_GetWindowStart() / 64 / 1024 );
945                 SET_AH( context, 0x00 ); /* status: successful */
946             } else
947                 SET_AH( context, 0x01 ); /* status: failed */
948             break;
949         default:
950             INT_BARF( context, 0x10 );
951         }
952         break;
953
954     case 0x06: /* VESA GET/SET LOGICAL SCAN LINE LENGTH */
955         ERR("VESA GET/SET LOGICAL SCAN LINE LENGTH - Not Implemented\n");
956         /* AL_reg(context) = 0x4f; = supported so not set since not implemented */
957         /* maybe we should do this instead ? */
958         /* AH_reg(context = 0x001; not implemented so just fail */
959         break;
960
961     case 0x07: /* GET/SET DISPLAY START */
962         ERR("VESA GET/SET DISPLAY START - Not Implemented\n");
963         /* AL_reg(context) = 0x4f; = supported so not set since not implemented */
964         /* maybe we should do this instead ? */
965         /* AH_reg(context = 0x001; not implemented so just fail */
966         break;
967
968     case 0x08: /* GET/SET DAC PALETTE CONTROL */
969         ERR("VESA GET/SET DAC PALETTE CONTROL- Not Implemented\n");
970         /* AL_reg(context) = 0x4f; = supported so not set since not implemented */
971         /* maybe we should do this instead ? */
972         /* AH_reg(context = 0x001; not implemented so just fail */
973         break;
974
975     case 0x09: /* SET PALETTE ENTRIES */
976         FIXME("VESA Set palette entries - not implemented\n");
977         break;
978
979     case 0x0a: /* GET PROTECTED-MODE CODE */
980         FIXME("VESA Get protected-mode code - not implemented\n");
981         break;
982
983     case 0x10: /* Display Power Management Extensions */
984         FIXME("VESA Display Power Management Extensions - not implemented\n");
985         break;
986
987     case 0xef:  /* get video mode for hercules-compatibles   */
988         /* There's no reason to really support this  */
989         /* is there?....................(A.C.)       */
990         TRACE("Just report the video not hercules compatible\n");
991         SET_DX( context, 0xffff );
992         break;
993
994     case 0xff: /* Turn VESA ON/OFF */
995         /* I don't know what to do */
996         break;
997
998     default:
999         FIXME("VESA Function (0x%x) - Not Supported\n", AH_reg(context));
1000         break;
1001     }
1002 }
1003
1004
1005 /**********************************************************************
1006  *          DOSVM_Int10Handler
1007  *
1008  * Handler for int 10h (video).
1009  *
1010  * NOTE:
1011  *    Most INT 10 functions for text-mode, CGA, EGA, and VGA cards
1012  *    are present in this list. (SVGA and XGA are not) That is not
1013  *    to say that all these functions should be supported, but if
1014  *    anyone is brain-damaged enough to want to emulate one of these
1015  *    beasts then this should get you started.
1016  *
1017  * NOTE:
1018  *    Several common graphical extensions used by Microsoft hook
1019  *    off of here. I have *not* added them to this list (yet). They
1020  *    include:
1021  *
1022  *    MSHERC.COM - More functionality for Hercules cards.
1023  *    EGA.SYS (also MOUSE.COM) - More for EGA cards.
1024  *
1025  *    Yes, MS also added this support into their mouse driver. Don't
1026  *    ask me, I don't work for them.
1027  *
1028  * Joseph Pranevich - 9/98
1029  *
1030  *  Jess Haas 2/99
1031  *      Added support for Vesa. It is not complete but is a start.
1032  *      NOTE: Im not sure if I did all this right or if any of it works.
1033  *      Currently I don't have a program that uses Vesa that actually gets far
1034  *      enough without crashing to do vesa stuff.
1035  *
1036  *      Added additional vga graphic support - 3/99
1037  */
1038 void WINAPI DOSVM_Int10Handler( CONTEXT86 *context )
1039 {
1040     BIOSDATA *data = DOSVM_BiosData();
1041
1042     INT10_InitializeVideoMode( data );
1043
1044     switch(AH_reg(context)) {
1045
1046     case 0x00: /* SET VIDEO MODE */
1047         TRACE( "Set VGA video mode %02x\n", AL_reg(context) );
1048         if (!INT10_SetVideoMode( data, AL_reg(context) ))
1049             FIXME( "Unsupported VGA video mode requested: %#x\n", 
1050                    AL_reg(context) );
1051         break;
1052
1053     case 0x01: /* SET CURSOR SHAPE */
1054         TRACE("Set Cursor Shape start %d end %d options %d\n",
1055               CH_reg(context) & 0x1f,
1056               CL_reg(context) & 0x1f,
1057               CH_reg(context) & 0xe0);
1058         data->VideoCursorType = CX_reg(context); /* direct copy */
1059         VGA_SetCursorShape(CH_reg(context), CL_reg(context));
1060         break;
1061
1062     case 0x02: /* SET CURSOR POSITION */
1063         /* BH = Page Number */ /* Not supported */
1064         /* DH = Row */ /* 0 is left */
1065         /* DL = Column */ /* 0 is top */
1066         INT10_SetCursorPos(data,BH_reg(context),DL_reg(context),DH_reg(context));
1067         if (BH_reg(context))
1068         {
1069            FIXME("Set Cursor Position: Cannot set to page %d\n",
1070               BH_reg(context));
1071         }
1072         else
1073         {
1074            VGA_SetCursorPos(DL_reg(context), DH_reg(context));
1075            TRACE("Set Cursor Position: %d/%d\n", DL_reg(context),
1076               DH_reg(context));
1077         }
1078         break;
1079
1080     case 0x03: /* GET CURSOR POSITION AND SIZE */
1081         {
1082           unsigned row, col;
1083
1084           TRACE("Get cursor position and size (page %d)\n", BH_reg(context));
1085           SET_CX( context, data->VideoCursorType );
1086           INT10_GetCursorPos(data,BH_reg(context),&col,&row);
1087           SET_DH( context, row );
1088           SET_DL( context, col );
1089           TRACE("Cursor Position: %d/%d\n", DL_reg(context), DH_reg(context));
1090         }
1091         break;
1092
1093     case 0x04: /* READ LIGHT PEN POSITION */
1094         FIXME("Read Light Pen Position - Not Supported\n");
1095         SET_AH( context, 0x00 ); /* Not down */
1096         break;
1097
1098     case 0x05: /* SELECT ACTIVE DISPLAY PAGE */
1099         FIXME("Select Active Display Page (%d) - Not Supported\n", AL_reg(context));
1100         data->VideoCurPage = AL_reg(context);
1101         break;
1102
1103     case 0x06: /* SCROLL UP WINDOW */
1104         /* AL = Lines to scroll */
1105         /* BH = Attribute */
1106         /* CH,CL = row, col upper-left */
1107         /* DH,DL = row, col lower-right */
1108         TRACE("Scroll Up Window %d\n", AL_reg(context));
1109
1110         if (AL_reg(context) == 0)
1111             VGA_ClearText( CH_reg(context), CL_reg(context),
1112                            DH_reg(context), DL_reg(context),
1113                            BH_reg(context) );
1114         else
1115             VGA_ScrollUpText( CH_reg(context), CL_reg(context),
1116                               DH_reg(context), DL_reg(context),
1117                               AL_reg(context), BH_reg(context) );
1118         break;
1119
1120     case 0x07: /* SCROLL DOWN WINDOW */
1121         /* AL = Lines to scroll */
1122         /* BH = Attribute */
1123         /* CH,CL = row, col upper-left */
1124         /* DH,DL = row, col lower-right */
1125         TRACE("Scroll Down Window %d\n", AL_reg(context));
1126
1127         if (AL_reg(context) == 0)
1128             VGA_ClearText( CH_reg(context), CL_reg(context),
1129                            DH_reg(context), DL_reg(context),
1130                            BH_reg(context) );
1131         else
1132             VGA_ScrollDownText( CH_reg(context), CL_reg(context),
1133                                 DH_reg(context), DL_reg(context),
1134                                 AL_reg(context), BH_reg(context) );
1135         break;
1136
1137     case 0x08: /* READ CHARACTER AND ATTRIBUTE AT CURSOR POSITION */
1138         {
1139             if (BH_reg(context)) /* Write to different page */
1140             {
1141                 FIXME("Read character and attribute at cursor position -"
1142                       " Can't read from non-0 page\n");
1143                 SET_AL( context, ' ' ); /* That page is blank */
1144                 SET_AH( context, 7 );
1145             }
1146             else
1147            {
1148                 BYTE ascii, attr;
1149                 TRACE("Read Character and Attribute at Cursor Position\n");
1150                 VGA_GetCharacterAtCursor(&ascii, &attr);
1151                 SET_AL( context, ascii );
1152                 SET_AH( context, attr );
1153             }
1154         }
1155         break;
1156
1157     case 0x09: /* WRITE CHARACTER AND ATTRIBUTE AT CURSOR POSITION */
1158     case 0x0a: /* WRITE CHARACTER ONLY AT CURSOR POSITION */
1159        /* AL = Character to display. */
1160        /* BH = Page Number */ /* We can't write to non-0 pages, yet. */
1161        /* BL = Attribute / Color */
1162        /* CX = Times to Write Char */
1163        /* Note here that the cursor is not advanced. */
1164        {
1165            unsigned row, col;
1166
1167            INT10_GetCursorPos(data,BH_reg(context),&col,&row);
1168            VGA_WriteChars(col, row,
1169                           AL_reg(context),
1170                           (AH_reg(context) == 0x09) ? BL_reg(context) : -1,
1171                           CX_reg(context));
1172            if (CX_reg(context) > 1)
1173               TRACE("Write Character%s at Cursor Position (Rep. %d): %c\n",
1174                     (AH_reg(context) == 0x09) ? " and Attribute" : "",
1175                  CX_reg(context), AL_reg(context));
1176            else
1177               TRACE("Write Character%s at Cursor Position: %c\n",
1178                     (AH_reg(context) == 0x09) ? " and Attribute" : "",
1179                 AL_reg(context));
1180        }
1181        break;
1182
1183     case 0x0b:
1184         switch BH_reg(context) {
1185         case 0x00: /* SET BACKGROUND/BORDER COLOR */
1186             /* In text modes, this sets only the border... */
1187             /* According to the interrupt list and one of my books. */
1188             /* Funny though that Beyond Zork seems to indicate that it
1189                also sets up the default background attributes for clears
1190                and scrolls... */
1191             /* Bear in mind here that we do not want to change,
1192                apparently, the foreground or attribute of the background
1193                with this call, so we should check first to see what the
1194                foreground already is... FIXME */
1195             FIXME("Set Background/Border Color: %d/%d\n",
1196                BH_reg(context), BL_reg(context));
1197             break;
1198         case 0x01: /* SET PALETTE */
1199             FIXME("Set Palette - Not Supported\n");
1200             break;
1201         default:
1202             FIXME("INT 10 AH = 0x0b BH = 0x%x - Unknown\n",
1203                BH_reg(context));
1204             break;
1205         }
1206         break;
1207
1208     case 0x0c: /* WRITE GRAPHICS PIXEL */
1209         /* Not in graphics mode, can ignore w/o error */
1210         FIXME("Write Graphics Pixel - Not Supported\n");
1211         break;
1212
1213     case 0x0d: /* READ GRAPHICS PIXEL */
1214         /* Not in graphics mode, can ignore w/o error */
1215         FIXME("Read Graphics Pixel - Not Supported\n");
1216         break;
1217
1218     case 0x0e: /* TELETYPE OUTPUT */
1219         TRACE("Teletype Output\n");
1220         DOSVM_PutChar(AL_reg(context));
1221         break;
1222
1223     case 0x0f: /* GET CURRENT VIDEO MODE */
1224         TRACE("Get current video mode: -> mode %d, columns %d\n", data->VideoMode, data->VideoColumns);
1225         /* Note: This should not be a constant value. */
1226         SET_AL( context, data->VideoMode );
1227         SET_AH( context, data->VideoColumns );
1228         SET_BH( context, 0 ); /* Display page 0 */
1229         break;
1230
1231     case 0x10:
1232         switch AL_reg(context) {
1233         case 0x00: /* SET SINGLE PALETTE REGISTER - A.C. */
1234             TRACE("Set Single Palette Register - Reg 0x0%x Value 0x0%x\n",
1235                 BL_reg(context),BH_reg(context));
1236                 /* BH is the value  BL is the register */
1237                 VGA_SetColor16((int)BL_reg(context),(int)BH_reg(context));
1238             break;
1239         case 0x01: /* SET BORDER (OVERSCAN) */
1240             /* Text terminals have no overscan */
1241             /* I'm setting it anyway. - A.C.   */
1242             TRACE("Set Border (Overscan) - Ignored but set.\n");
1243             VGA_SetColor16(16,(int)BH_reg(context));
1244             break;
1245         case 0x02: /* SET ALL PALETTE REGISTERS - A.C.*/
1246             TRACE("Set all palette registers\n");
1247                 /* ES:DX points to a 17 byte table of colors */
1248                 /* No return data listed */
1249                 /* I'll have to update my table and the default palette */
1250                VGA_Set16Palette(CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edx));
1251             break;
1252         case 0x03: /* TOGGLE INTENSITY/BLINKING BIT */
1253             FIXME("Toggle Intensity/Blinking Bit - Not Supported\n");
1254             break;
1255         case 0x07: /* GET INDIVIDUAL PALETTE REGISTER  - A.C.*/
1256             TRACE("Get Individual Palette Register 0x0%x\n",BL_reg(context));
1257                 /* BL is register to read [ 0-15 ] BH is return value */
1258                 SET_BH( context, VGA_GetColor16((int)BL_reg(context)) );
1259             break;
1260         case 0x08: /* READ OVERSCAN (BORDER COLOR) REGISTER  - A.C. */
1261             TRACE("Read Overscan (Border Color) Register \n");
1262                 SET_BH( context, VGA_GetColor16(16) );
1263             break;
1264         case 0x09: /* READ ALL PALETTE REGISTERS AND OVERSCAN REGISTER - A.C.*/
1265             TRACE("Read All Palette Registers and Overscan Register \n");
1266                 /* ES:DX points to a 17 byte table where the results */
1267                 /*  of this call should be stored.                   */
1268                VGA_Get16Palette(CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edx));
1269             break;
1270         case 0x10: /* SET INDIVIDUAL DAC REGISTER */
1271             {
1272                 PALETTEENTRY paldat;
1273
1274                 TRACE("Set Individual DAC register\n");
1275                 paldat.peRed   = DH_reg(context);
1276                 paldat.peGreen = CH_reg(context);
1277                 paldat.peBlue  = CL_reg(context);
1278                 paldat.peFlags = 0;
1279                 VGA_SetPalette(&paldat,BX_reg(context)&0xFF,1);
1280             }
1281             break;
1282         case 0x12: /* SET BLOCK OF DAC REGISTERS */
1283             {
1284                 int i;
1285                 PALETTEENTRY paldat;
1286                 BYTE *pt;
1287
1288                 TRACE("Set Block of DAC registers\n");
1289                 pt = (BYTE*)CTX_SEG_OFF_TO_LIN(context,context->SegEs,context->Edx);
1290                 for (i=0;i<CX_reg(context);i++)
1291                 {
1292                     paldat.peRed   = (*(pt+i*3+0)) << 2;
1293                     paldat.peGreen = (*(pt+i*3+1)) << 2;
1294                     paldat.peBlue  = (*(pt+i*3+2)) << 2;
1295                     paldat.peFlags = 0;
1296                     VGA_SetPalette(&paldat,(BX_reg(context)+i)&0xFF,1);
1297                 }
1298             }
1299             break;
1300         case 0x13: /* SELECT VIDEO DAC COLOR PAGE */
1301             FIXME("Select video DAC color page - Not Supported\n");
1302             break;
1303         case 0x15: /* READ INDIVIDUAL DAC REGISTER */
1304             FIXME("Read individual DAC register - Not Supported\n");
1305             break;
1306         case 0x17: /* READ BLOCK OF DAC REGISTERS */
1307             FIXME("Read block of DAC registers - Not Supported\n");
1308             break;
1309         case 0x18: /* SET PEL MASK */
1310             FIXME("Set PEL mask - Not Supported\n");
1311             break;
1312         case 0x19: /* READ PEL MASK */
1313             FIXME("Read PEL mask - Not Supported\n");
1314             break;
1315         case 0x1a: /* GET VIDEO DAC COLOR PAGE STATE */
1316             FIXME("Get video DAC color page state - Not Supported\n");
1317             break;
1318         case 0x1b: /* PERFORM GRAY-SCALE SUMMING */
1319             FIXME("Perform Gray-scale summing - Not Supported\n");
1320             break;
1321         default:
1322             FIXME("INT 10 AH = 0x10 AL = 0x%x - Unknown\n",
1323                AL_reg(context));
1324             break;
1325         }
1326         break;
1327
1328     case 0x11: /* TEXT MODE CHARGEN */
1329         /* Note that second subfunction is *almost* identical. */
1330         /* See INTERRUPT.A for details. */
1331         switch AL_reg(context) {
1332         case 0x00: /* LOAD USER SPECIFIED PATTERNS */
1333         case 0x10:
1334             FIXME("Load User Specified Patterns - Not Supported\n");
1335             break;
1336         case 0x01: /* LOAD ROM MONOCHROME PATTERNS */
1337         case 0x11:
1338             FIXME("Load ROM Monochrome Patterns - Not Supported\n");
1339             break;
1340         case 0x02: /* LOAD ROM 8x8 DOUBLE-DOT PATTERNS */
1341         case 0x12:
1342             FIXME(
1343                 "Load ROM 8x8 Double Dot Patterns - Not Supported\n");
1344             break;
1345         case 0x03: /* SET BLOCK SPECIFIER */
1346             FIXME("Set Block Specifier - Not Supported\n");
1347             break;
1348         case 0x04: /* LOAD ROM 8x16 CHARACTER SET */
1349         case 0x14:
1350             FIXME("Load ROM 8x16 Character Set - Not Supported\n");
1351             break;
1352         case 0x20: /* SET USER 8x16 GRAPHICS CHARS */
1353             FIXME("Set User 8x16 Graphics Chars - Not Supported\n");
1354             break;
1355         case 0x21: /* SET USER GRAPICS CHARACTERS */
1356             FIXME("Set User Graphics Characters - Not Supported\n");
1357             break;
1358         case 0x22: /* SET ROM 8x14 GRAPHICS CHARS */
1359             FIXME("Set ROM 8x14 Graphics Chars - Not Supported\n");
1360             break;
1361         case 0x23: /* SET ROM 8x8 DBL DOT CHARS */
1362             FIXME(
1363                 "Set ROM 8x8 Dbl Dot Chars (Graphics) - Not Supported\n");
1364             break;
1365         case 0x24: /* LOAD 8x16 GRAPHIC CHARS */
1366             FIXME("Load 8x16 Graphic Chars - Not Supported\n");
1367             break;
1368         case 0x30: /* GET FONT INFORMATION */
1369             FIXME("Get Font Information - Not Supported\n");
1370             break;
1371         default:
1372             FIXME("INT 10 AH = 0x11 AL = 0x%x - Unknown\n",
1373                AL_reg(context));
1374             break;
1375         }
1376         break;
1377
1378     case 0x12: /* ALTERNATE FUNCTION SELECT */
1379         switch BL_reg(context) {
1380         case 0x10: /* GET EGA INFO */
1381             TRACE("EGA info requested\n");
1382             SET_BH( context, 0x00 );   /* Color screen */
1383             SET_BL( context, data->ModeOptions >> 5 ); /* EGA memory size */
1384             SET_CX( context, data->FeatureBitsSwitches );
1385             break;
1386         case 0x20: /* ALTERNATE PRTSC */
1387             FIXME("Install Alternate Print Screen - Not Supported\n");
1388             break;
1389         case 0x30: /* SELECT VERTICAL RESOULTION */
1390             FIXME("Select vertical resolution - not supported\n");
1391             break;
1392         case 0x31: /* ENABLE/DISABLE DEFAULT PALETTE LOADING */
1393             FIXME("Default palette loading - not supported\n");
1394             data->VGASettings =
1395                 (data->VGASettings & 0xf7) |
1396                 ((AL_reg(context) == 1) << 3);
1397             break;
1398         case 0x32: /* ENABLE/DISABLE VIDEO ADDRERSSING */
1399             FIXME("Video Addressing - Not Supported\n");
1400             break;
1401         case 0x33: /* ENABLE/DISABLE GRAY SCALE SUMMING */
1402             FIXME("Gray Scale Summing - Not Supported\n");
1403             break;
1404         case 0x34: /* ENABLE/DISABLE CURSOR EMULATION */
1405             TRACE("Set cursor emulation to %d\n", AL_reg(context));
1406             data->ModeOptions =
1407                 (data->ModeOptions & 0xfe)|(AL_reg(context) == 1);
1408             break;
1409         case 0x36: /* VIDEO ADDRESS CONTROL */
1410             FIXME("Video Address Control - Not Supported\n");
1411             break;
1412         default:
1413             FIXME("INT 10 AH = 0x11 AL = 0x%x - Unknown\n",
1414                AL_reg(context));
1415             break;
1416         }
1417         break;
1418
1419     case 0x13: /* WRITE STRING */
1420         /* This one does not imply that string be at cursor. */
1421         FIXME("Write String - Not Supported\n");
1422         break;
1423
1424     case 0x1a:
1425         switch AL_reg(context) {
1426         case 0x00: /* GET DISPLAY COMBINATION CODE */
1427             TRACE("Get Display Combination Code\n");
1428             SET_AL( context, 0x1a );      /* Function supported */
1429             SET_BL( context, INT10_DCC ); /* Active display */
1430             SET_BH( context, 0x00 );      /* No alternate display */
1431             break;
1432         case 0x01: /* SET DISPLAY COMBINATION CODE */
1433             FIXME("Set Display Combination Code - Not Supported\n");
1434             break;
1435         default:
1436             FIXME("INT 10 AH = 0x1a AL = 0x%x - Unknown\n",
1437                AL_reg(context));
1438             break;
1439         }
1440     break;
1441
1442     case 0x1b: /* FUNCTIONALITY/STATE INFORMATION */
1443         TRACE("Get functionality/state information\n");
1444         if (BX_reg(context) == 0x0000)
1445         {
1446             BYTE *ptr = CTX_SEG_OFF_TO_LIN(context,
1447                                            context->SegEs, 
1448                                            context->Edi);
1449             SET_AL( context, 0x1b ); /* Function is supported */
1450             INT10_FillStateInformation( ptr, data );
1451         }
1452         break;
1453
1454     case 0x1c: /* SAVE/RESTORE VIDEO STATE */
1455         FIXME("Save/Restore Video State - Not Supported\n");
1456         break;
1457
1458         case 0xef:  /* get video mode for hercules-compatibles   */
1459                     /* There's no reason to really support this  */
1460                     /* is there?....................(A.C.)       */
1461                 TRACE("Just report the video not hercules compatible\n");
1462                 SET_DX( context, 0xffff );
1463                 break;
1464
1465     case 0x4f: /* VESA */
1466         INT10_HandleVESA(context);
1467         break;
1468
1469     case 0xfe: /* GET SHADOW BUFFER */
1470         TRACE( "GET SHADOW BUFFER %lx:%x - ignored\n",
1471                context->SegEs, DI_reg(context) );
1472         break;
1473
1474     default:
1475         FIXME("Unknown - 0x%x\n", AH_reg(context));
1476         INT_BARF( context, 0x10 );
1477     }
1478 }
1479
1480
1481 /**********************************************************************
1482  *         DOSVM_PutChar
1483  *
1484  * Write single character to VGA console at the current 
1485  * cursor position and updates the BIOS cursor position.
1486  */
1487 void WINAPI DOSVM_PutChar( BYTE ascii )
1488 {
1489   BIOSDATA *data = DOSVM_BiosData();
1490   unsigned  xpos, ypos;
1491
1492   TRACE("char: 0x%02x(%c)\n", ascii, ascii);
1493
1494   INT10_InitializeVideoMode( data );
1495
1496   VGA_PutChar( ascii );
1497   VGA_GetCursorPos( &xpos, &ypos );
1498   INT10_SetCursorPos( data, 0, xpos, ypos );
1499 }