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