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