xref: /reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.c (revision f7d612f3)
1 /*
2  * COPYRIGHT:       GPLv2+ - See COPYING in the top level directory
3  * PROJECT:         ReactOS Virtual DOS Machine
4  * FILE:            subsystems/mvdm/ntvdm/bios/bios32/vbe.c
5  * PURPOSE:         VDM VESA BIOS Extensions (for the Cirrus CL-GD5434 emulated card)
6  * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include "ntvdm.h"
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 #include "emulator.h"
17 #include "cpu/cpu.h"
18 #include "bios32p.h"
19 #include "hardware/video/svga.h"
20 
21 #include "vbe.h"
22 
23 #include "io.h"
24 
25 /* PRIVATE VARIABLES **********************************************************/
26 
27 static const VBE_MODE_INFO VbeMode_640x480x256_Info =
28 {
29     /* Attributes */
30     VBE_MODE_SUPPORTED
31     | VBE_MODE_OPTIONAL_INFO
32     // | VBE_MODE_BIOS_SUPPORT
33     | VBE_MODE_COLOR
34     | VBE_MODE_GRAPHICS,
35 
36     /* Window A attributes */
37     VBE_WINDOW_EXISTS | VBE_WINDOW_READABLE | VBE_WINDOW_WRITABLE,
38     /* Window B attributes */
39     0,
40 
41     16,                   /* Window granularity, in KB */
42     64,                   /* Window size, in KB */
43     0xA000,               /* Window A segment, or zero if not supported */
44     0x0000,               /* Window B segment, or zero if not supported */
45     0x00000000,           /* Window position function pointer */
46     640,                  /* Bytes per scanline */
47     640,                  /* Width */
48     480,                  /* Height */
49     8,                    /* Character cell width */
50     16,                   /* Character cell height */
51     1,                    /* Number of memory planes */
52     8,                    /* Bits per pixel */
53     1,                    /* Number of banks */
54     VBE_MODEL_PACKED,     /* Memory model */
55     0,                    /* Bank size */
56     11,                   /* Number of image pages */
57     0,                    /* Reserved field */
58     0,                    /* Red mask size */
59     0,                    /* Red field position */
60     0,                    /* Green mask size */
61     0,                    /* Green field position */
62     0,                    /* Blue mask size */
63     0,                    /* Blue field position */
64     0,                    /* Reserved mask size */
65     0,                    /* Reserved field position */
66     0,                    /* Direct color info */
67 };
68 
69 static SVGA_REGISTERS VbeMode_640x480x256_Registers =
70 {
71     /* Miscellaneous Register */
72     0x63,
73 
74     /* Hidden Register */
75     0x00,
76 
77     /* Sequencer Registers */
78     {
79         0x03, 0x21, 0x0F, 0x00, 0x0E, 0x00, 0x12, 0x11, 0x00, 0x00, 0x18, 0x58,
80         0x58, 0x58, 0x58, 0x98, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x20,
81         0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x2D
82     },
83 
84     /* CRTC Registers */
85     {
86         0x5F, 0x4F, 0x4F, 0x80, 0x52, 0x1E, 0x0B, 0x3E, 0x00, 0x40, 0x00, 0x00,
87         0x00, 0x00, 0x00, 0x00, 0xEA, 0x2C, 0xDF, 0x50, 0x40, 0xDF, 0x0B, 0xC3,
88         0xFF, 0x00, 0x00, 0x22, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF,
89         0x80, 0x00, 0x20, 0xB8
90     },
91 
92     /* GC Registers */
93     {
94         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF, 0x00, 0x00, 0x20,
95         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96         0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98         0x00, 0x00, 0x00, 0x00
99     },
100 
101     /* AC Registers */
102     {
103         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
104         0x0C, 0x0D, 0x0E, 0x0F, 0x41, 0x00, 0x0F, 0x00, 0x00
105     }
106 };
107 
108 static const VBE_MODE_INFO VbeMode_800x600x256_Info =
109 {
110     /* Attributes */
111     VBE_MODE_SUPPORTED
112     | VBE_MODE_OPTIONAL_INFO
113     // | VBE_MODE_BIOS_SUPPORT
114     | VBE_MODE_COLOR
115     | VBE_MODE_GRAPHICS,
116 
117     /* Window A attributes */
118     VBE_WINDOW_EXISTS | VBE_WINDOW_READABLE | VBE_WINDOW_WRITABLE,
119     /* Window B attributes */
120     0,
121 
122     16,                   /* Window granularity, in KB */
123     64,                   /* Window size, in KB */
124     0xA000,               /* Window A segment, or zero if not supported */
125     0x0000,               /* Window B segment, or zero if not supported */
126     0x00000000,           /* Window position function pointer */
127     800,                  /* Bytes per scanline */
128     800,                  /* Width */
129     600,                  /* Height */
130     8,                    /* Character cell width */
131     16,                   /* Character cell height */
132     1,                    /* Number of memory planes */
133     8,                    /* Bits per pixel */
134     1,                    /* Number of banks */
135     VBE_MODEL_PACKED,     /* Memory model */
136     0,                    /* Bank size */
137     7,                    /* Number of image pages */
138     0,                    /* Reserved field */
139     0,                    /* Red mask size */
140     0,                    /* Red field position */
141     0,                    /* Green mask size */
142     0,                    /* Green field position */
143     0,                    /* Blue mask size */
144     0,                    /* Blue field position */
145     0,                    /* Reserved mask size */
146     0,                    /* Reserved field position */
147     0,                    /* Direct color info */
148 };
149 
150 static SVGA_REGISTERS VbeMode_800x600x256_Registers =
151 {
152     /* Miscellaneous Register */
153     0x63,
154 
155     /* Hidden Register */
156     0x00,
157 
158     /* Sequencer Registers */
159     {
160         0x03, 0x21, 0x0F, 0x00, 0x0E, 0x00, 0x12, 0x11, 0x00, 0x00, 0x18, 0x23,
161         0x23, 0x23, 0x23, 0x98, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x20,
162         0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x14, 0x2D
163     },
164 
165     /* CRTC Registers */
166     {
167         0x7D, 0x63, 0x63, 0x80, 0x6B, 0x1A, 0x98, 0xF0, 0x00, 0x60, 0x00, 0x00,
168         0x00, 0x00, 0x00, 0x00, 0x7D, 0x23, 0x57, 0x64, 0x40, 0x57, 0x98, 0xC3,
169         0xFF, 0x00, 0x00, 0x22, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF,
170         0x80, 0x00, 0x20, 0xB8
171     },
172 
173     /* GC Registers */
174     {
175         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF, 0x00, 0x00, 0x20,
176         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177         0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179         0x00, 0x00, 0x00, 0x00
180     },
181 
182     /* AC Registers */
183     {
184         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
185         0x0C, 0x0D, 0x0E, 0x0F, 0x41, 0x00, 0x0F, 0x00, 0x00
186     }
187 };
188 
189 static const VBE_MODE Modes[VBE_MODE_COUNT] =
190 {
191     { 0x14, 0xFFFF, NULL                     , NULL /* TODO */                },
192     { 0x54, 0x10A , NULL /* TODO */          , NULL /* TODO */                },
193     { 0x55, 0x109 , NULL /* TODO */          , NULL /* TODO */                },
194     { 0x58, 0x102 , NULL /* TODO */          , NULL /* TODO */                },
195     { 0x5C, 0x103 , &VbeMode_800x600x256_Info, &VbeMode_800x600x256_Registers },
196     { 0x5D, 0x104 , NULL /* TODO */          , NULL /* TODO */                },
197     { 0x5E, 0x100 , NULL /* TODO */          , NULL /* TODO */                },
198     { 0x5F, 0x101 , &VbeMode_640x480x256_Info, &VbeMode_640x480x256_Registers },
199     { 0x60, 0x105 , NULL /* TODO */          , NULL /* TODO */                },
200     { 0x64, 0x111 , NULL /* TODO */          , NULL /* TODO */                },
201     { 0x65, 0x114 , NULL /* TODO */          , NULL /* TODO */                },
202     { 0x66, 0x110 , NULL /* TODO */          , NULL /* TODO */                },
203     { 0x67, 0x113 , NULL /* TODO */          , NULL /* TODO */                },
204     { 0x68, 0x116 , NULL /* TODO */          , NULL /* TODO */                },
205     { 0x69, 0x119 , NULL /* TODO */          , NULL /* TODO */                },
206     { 0x6C, 0x106 , NULL /* TODO */          , NULL /* TODO */                },
207     { 0x6D, 0x107 , NULL /* TODO */          , NULL /* TODO */                },
208     { 0x71, 0x112 , NULL /* TODO */          , NULL /* TODO */                },
209     { 0x72, 0xFFFF, NULL                     , NULL /* TODO */                },
210     { 0x73, 0xFFFF, NULL                     , NULL /* TODO */                },
211     { 0x74, 0x117 , NULL /* TODO */          , NULL /* TODO */                },
212     { 0x75, 0x11A , NULL /* TODO */          , NULL /* TODO */                },
213     { 0x76, 0xFFFF, NULL                     , NULL /* TODO */                },
214     { 0x78, 0x115 , NULL /* TODO */          , NULL /* TODO */                },
215     { 0x79, 0x118 , NULL /* TODO */          , NULL /* TODO */                },
216 };
217 
218 /* PRIVATE FUNCTIONS **********************************************************/
219 
VbeGetModeByNumber(WORD Number)220 PCVBE_MODE VbeGetModeByNumber(WORD Number)
221 {
222     INT i;
223 
224     Number &= 0x1FF;
225 
226     /* Find the mode */
227     for (i = 0; i < VBE_MODE_COUNT; i++)
228     {
229         if ((!(Number & 0x100) && (Number == Modes[i].Number))
230             || ((Number & 0x100) && (Number== Modes[i].VesaNumber)))
231         {
232             return &Modes[i];
233         }
234     }
235 
236     return NULL;
237 }
238 
239 /* This function is based on VgaSetRegisters in vidbios.c */
VbeSetExtendedRegisters(PSVGA_REGISTERS Registers)240 static VOID VbeSetExtendedRegisters(PSVGA_REGISTERS Registers)
241 {
242     UINT i;
243 
244     /* Disable interrupts */
245     BOOLEAN Interrupts = getIF();
246     setIF(0);
247 
248     /*
249      * Set the CRT base address according to the selected mode,
250      * monochrome or color. The following macros:
251      * VGA_INSTAT1_READ, VGA_CRTC_INDEX and VGA_CRTC_DATA are then
252      * used to access the correct VGA I/O ports.
253      */
254     Bda->CrtBasePort = (Registers->Misc & 0x01) ? VGA_CRTC_INDEX_COLOR
255                                                 : VGA_CRTC_INDEX_MONO;
256     /* Bit 1 indicates whether display is color (0) or monochrome (1) */
257     Bda->VGAOptions     = (Bda->VGAOptions     & 0xFD) | (!(Registers->Misc & 0x01) << 1);
258     Bda->CrtModeControl = (Bda->CrtModeControl & 0xFB) | (!(Registers->Misc & 0x01) << 1);
259 
260     /* Update blink bit in BDA */
261     if (Registers->Attribute[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_BLINK)
262         Bda->CrtModeControl |= (1 << 5);
263     else
264         Bda->CrtModeControl &= ~(1 << 5);
265 
266     /* Turn the video off */
267     IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_CLOCK_REG);
268     IOWriteB(VGA_SEQ_DATA , IOReadB(VGA_SEQ_DATA) | VGA_SEQ_CLOCK_SD);
269 
270     /* Write the misc register */
271     IOWriteB(VGA_MISC_WRITE, Registers->Misc);
272 
273     /* Synchronous reset on */
274     IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_RESET_REG);
275     IOWriteB(VGA_SEQ_DATA , VGA_SEQ_RESET_AR );
276 
277     /* Write the sequencer registers */
278     for (i = 1; i < SVGA_SEQ_MAX_REG; i++)
279     {
280         if (i != VGA_SEQ_MAX_REG && i != SVGA_SEQ_UNLOCK_REG)
281         {
282             IOWriteB(VGA_SEQ_INDEX, i);
283             IOWriteB(VGA_SEQ_DATA , Registers->Sequencer[i]);
284         }
285     }
286 
287     /* Synchronous reset off */
288     IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_RESET_REG);
289     IOWriteB(VGA_SEQ_DATA , VGA_SEQ_RESET_SR | VGA_SEQ_RESET_AR);
290 
291     /* Unlock CRTC registers 0-7 */
292     IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_END_HORZ_BLANKING_REG);
293     IOWriteB(VGA_CRTC_DATA , IOReadB(VGA_CRTC_DATA) | 0x80);
294     IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_END_VERT_RETRACE_REG);
295     IOWriteB(VGA_CRTC_DATA , IOReadB(VGA_CRTC_DATA) & ~0x80);
296     // Make sure they remain unlocked
297     Registers->CRT[VGA_CRTC_END_HORZ_BLANKING_REG] |= 0x80;
298     Registers->CRT[VGA_CRTC_END_VERT_RETRACE_REG] &= ~0x80;
299 
300     /* Write the CRTC registers */
301     for (i = 0; i < SVGA_CRTC_MAX_REG; i++)
302     {
303         if ((i < SVGA_CRTC_UNUSED0_REG || i > SVGA_CRTC_UNUSED6_REG) && i != SVGA_CRTC_UNUSED7_REG)
304         {
305             IOWriteB(VGA_CRTC_INDEX, i);
306             IOWriteB(VGA_CRTC_DATA , Registers->CRT[i]);
307         }
308     }
309 
310     /* Write the GC registers */
311     for (i = 0; i < SVGA_GC_MAX_REG; i++)
312     {
313         if (i != SVGA_GC_UNUSED0_REG && i != SVGA_GC_UNUSED11_REG
314             && (i < SVGA_GC_UNUSED1_REG || i > SVGA_GC_UNUSED10_REG))
315         {
316             IOWriteB(VGA_GC_INDEX, i);
317             IOWriteB(VGA_GC_DATA , Registers->Graphics[i]);
318         }
319     }
320 
321     /* Write the AC registers */
322     for (i = 0; i < VGA_AC_MAX_REG; i++)
323     {
324         /* Write the index */
325         IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
326         IOWriteB(VGA_AC_INDEX, i);
327 
328         /* Write the data */
329         IOWriteB(VGA_AC_WRITE, Registers->Attribute[i]);
330     }
331 
332     /* Perform 4 dummy reads from the DAC mask to access the hidden register */
333     for (i = 0; i < 4; i++) IOReadB(VGA_DAC_MASK);
334 
335     /* Set the hidden register */
336     IOWriteB(VGA_DAC_MASK, Registers->Hidden);
337 
338     /* Set the PEL mask */
339     IOWriteB(VGA_DAC_MASK, 0xFF);
340 
341     /* Enable screen and disable palette access */
342     IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
343     IOWriteB(VGA_AC_INDEX, 0x20);
344 
345     /* Turn the video on */
346     IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_CLOCK_REG);
347     IOWriteB(VGA_SEQ_DATA , IOReadB(VGA_SEQ_DATA) & ~VGA_SEQ_CLOCK_SD);
348 
349     /* Restore interrupts */
350     setIF(Interrupts);
351 }
352 
353 
354 /* PUBLIC FUNCTIONS ***********************************************************/
355 
VbeSetExtendedVideoMode(BYTE ModeNumber)356 BOOLEAN WINAPI VbeSetExtendedVideoMode(BYTE ModeNumber)
357 {
358     PCVBE_MODE Mode = VbeGetModeByNumber(ModeNumber);
359     if (Mode == NULL) return FALSE;
360 
361     /* At this point, Mode->Registers shouldn't be NULL unless the mode is unimplemented */
362     if (Mode->Registers == NULL)
363     {
364         DPRINT1("Extended video mode %02X still UNIMPLEMENTED.\n", ModeNumber);
365         return FALSE;
366     }
367 
368     /* Set the registers */
369     VbeSetExtendedRegisters(Mode->Registers);
370 
371     /* Update the current video mode in the BDA */
372     Bda->VideoMode = ModeNumber;
373 
374     /* Clear the screen */
375     VgaClearMemory();
376 
377     return TRUE;
378 }
379 
VbeResetExtendedRegisters(VOID)380 VOID WINAPI VbeResetExtendedRegisters(VOID)
381 {
382     BYTE i;
383 
384     /* Disable interrupts */
385     BOOLEAN Interrupts = getIF();
386     setIF(0);
387 
388     /* Turn the video off */
389     IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_CLOCK_REG);
390     IOWriteB(VGA_SEQ_DATA , IOReadB(VGA_SEQ_DATA) | VGA_SEQ_CLOCK_SD);
391 
392     /* Synchronous reset on */
393     IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_RESET_REG);
394     IOWriteB(VGA_SEQ_DATA , VGA_SEQ_RESET_AR );
395 
396     /* Clear the extended sequencer registers, except for the VCLKs and MCLK */
397     for (i = SVGA_SEQ_EXT_MODE_REG; i < SVGA_SEQ_VCLK0_DENOMINATOR_REG; i++)
398     {
399         if (i != VGA_SEQ_MAX_REG && i != SVGA_SEQ_UNLOCK_REG
400             && (i < SVGA_SEQ_VCLK0_NUMERATOR_REG || i > SVGA_SEQ_VCLK3_NUMERATOR_REG))
401         {
402             IOWriteB(VGA_SEQ_INDEX, i);
403             IOWriteB(VGA_SEQ_DATA, 0x00);
404         }
405     }
406 
407     /* Reset the VCLKs */
408     IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_VCLK0_NUMERATOR_REG);
409     IOWriteB(VGA_SEQ_DATA, 0x66);
410     IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_VCLK0_DENOMINATOR_REG);
411     IOWriteB(VGA_SEQ_DATA, 0x3B);
412 
413     IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_VCLK1_NUMERATOR_REG);
414     IOWriteB(VGA_SEQ_DATA, 0x5B);
415     IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_VCLK1_DENOMINATOR_REG);
416     IOWriteB(VGA_SEQ_DATA, 0x2F);
417 
418     IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_VCLK2_NUMERATOR_REG);
419     IOWriteB(VGA_SEQ_DATA, 0x45);
420     IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_VCLK2_DENOMINATOR_REG);
421     IOWriteB(VGA_SEQ_DATA, 0x30);
422 
423     IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_VCLK3_NUMERATOR_REG);
424     IOWriteB(VGA_SEQ_DATA, 0x7E);
425     IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_VCLK3_DENOMINATOR_REG);
426     IOWriteB(VGA_SEQ_DATA, 0x33);
427 
428     /* Reset the MCLK */
429     IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_MCLK_REG);
430     IOWriteB(VGA_SEQ_DATA, 0x1C);
431 
432     /* Synchronous reset off */
433     IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_RESET_REG);
434     IOWriteB(VGA_SEQ_DATA , VGA_SEQ_RESET_SR | VGA_SEQ_RESET_AR);
435 
436     /* Reset the extended CRTC registers */
437     for (i = SVGA_CRTC_INTERLACE_END_REG; i < SVGA_CRTC_MAX_REG; i++)
438     {
439         if ((i < SVGA_CRTC_UNUSED0_REG || i > SVGA_CRTC_UNUSED6_REG) && i != SVGA_CRTC_UNUSED7_REG)
440         {
441             IOWriteB(VGA_CRTC_INDEX, i);
442             IOWriteB(VGA_CRTC_DATA, 0x00);
443         }
444     }
445 
446     /* Reset the extended GC registers */
447     for (i = SVGA_GC_OFFSET_0_REG; i < SVGA_GC_MAX_REG; i++)
448     {
449         if (i != SVGA_GC_UNUSED0_REG && i != SVGA_GC_UNUSED11_REG
450             && (i < SVGA_GC_UNUSED1_REG || i > SVGA_GC_UNUSED10_REG))
451         {
452             IOWriteB(VGA_GC_INDEX, i);
453             IOWriteB(VGA_GC_DATA, 0x00);
454         }
455     }
456 
457     /*
458      * And finally, reset the hidden register. This requires 4 dummy reads from
459      * the DAC mask register.
460      */
461     for (i = 0; i < 4; i++) IOReadB(VGA_DAC_MASK);
462     IOWriteB(VGA_DAC_MASK, 0x00);
463 
464     /* Turn the video on */
465     IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_CLOCK_REG);
466     IOWriteB(VGA_SEQ_DATA , IOReadB(VGA_SEQ_DATA) & ~VGA_SEQ_CLOCK_SD);
467 
468     /* Restore interrupts */
469     setIF(Interrupts);
470 }
471 
VbeService(LPWORD Stack)472 VOID WINAPI VbeService(LPWORD Stack)
473 {
474     INT i;
475 
476     switch (getAL())
477     {
478         /* Get VBE Information */
479         case 0x00:
480         {
481             VBE_INFORMATION Info;
482             PWORD Data = (PWORD)&Info;
483 
484             /* Function recognized */
485             setAL(0x4F);
486 
487             ZeroMemory(&Info, sizeof(VBE_INFORMATION));
488             Info.Signature = 'ASEV';
489             Info.Version = 0x0102;
490             Info.OemName = OEM_NAME_PTR;
491             Info.Capabilities = 0;
492             Info.ModeList = MAKELONG(LOWORD(getDI()
493                                      + FIELD_OFFSET(VBE_INFORMATION, ModeListBuffer)),
494                                      getES());
495             Info.VideoMemory = HIWORD(SVGA_BANK_SIZE * VGA_NUM_BANKS);
496 
497             /* Fill the mode list */
498             for (i = 0; i < VBE_MODE_COUNT; i++)
499             {
500                 /* Some modes don't have VESA numbers */
501                 if (Modes[i].VesaNumber != 0xFFFF)
502                 {
503                     Info.ModeListBuffer[i] = Modes[i].VesaNumber;
504                 }
505             }
506 
507             Info.ModeListBuffer[VBE_MODE_COUNT] = 0xFFFF;
508 
509             /* Copy the data to the caller */
510             for (i = 0; i < sizeof(VBE_INFORMATION) / sizeof(WORD); i++)
511             {
512                 *(PWORD)SEG_OFF_TO_PTR(getES(), LOWORD(getDI() + i * 2)) = Data[i];
513             }
514 
515             setAH(0);
516             break;
517         }
518 
519         /* Get VBE Mode Information */
520         case 0x01:
521         {
522             PCVBE_MODE Mode = VbeGetModeByNumber(getCX());
523             PWORD Data = NULL;
524 
525             /* Function recognized */
526             setAL(0x4F);
527 
528             if (Mode == NULL)
529             {
530                 /* Mode not found */
531                 setAH(1);
532                 break;
533             }
534 
535             Data = (PWORD)Mode->Info;
536             if (Data == NULL)
537             {
538                 DPRINT1("WARNING: The mode information for mode %02X (%03X) is missing!\n",
539                         Mode->Number,
540                         Mode->VesaNumber);
541 
542                 setAH(1);
543                 break;
544             }
545 
546             /* Clear the buffer */
547             for (i = 0; i < 128; i++)
548             {
549                 *(PWORD)SEG_OFF_TO_PTR(getES(), LOWORD(getDI() + i * 2)) = 0;
550             }
551 
552             /* Copy the data to the caller */
553             for (i = 0; i < sizeof(VBE_MODE_INFO) / sizeof(WORD); i++)
554             {
555                 *(PWORD)SEG_OFF_TO_PTR(getES(), LOWORD(getDI() + i * 2)) = Data[i];
556             }
557 
558             setAH(0);
559             break;
560         }
561 
562         /* Set VBE Mode */
563         case 0x02:
564         {
565             WORD VesaNumber = getBX();
566             setAL(0x4F);
567 
568             if (VesaNumber <= BIOS_MAX_VIDEO_MODE)
569             {
570                 /* Call the VGA BIOS */
571                 setAH(0x00);
572                 setAL(VesaNumber);
573                 Int32Call(&BiosContext, BIOS_VIDEO_INTERRUPT);
574 
575                 setAH(Bda->VideoMode != VesaNumber);
576             }
577             else
578             {
579                 /* This is an extended video mode */
580                 PCVBE_MODE Mode = VbeGetModeByNumber(VesaNumber);
581 
582                 if (Mode) setAH(!VbeSetExtendedVideoMode(Mode->Number));
583                 else setAH(1);
584             }
585 
586             break;
587         }
588 
589         /* Get Current VBE Mode */
590         case 0x03:
591         {
592             PCVBE_MODE Mode = VbeGetModeByNumber(Bda->VideoMode);
593 
594             setAL(0x4F);
595 
596             if (Mode)
597             {
598                 setBX(Mode->VesaNumber != 0xFFFF
599                       ? Mode->VesaNumber : Mode->Number);
600                 setAH(0);
601             }
602             else
603             {
604                 setAH(1);
605             }
606 
607             break;
608         }
609 
610         /* CPU Video Memory Control */
611         case 0x05:
612         {
613             BYTE Window = getBL();
614             BYTE OldGcIndex = IOReadB(VGA_GC_INDEX);
615 
616             switch (getBH())
617             {
618                 /* Select Memory Window */
619                 case 0:
620                 {
621                     setAL(0x4F);
622 
623                     if (getDH() != 0)
624                     {
625                         /* Offset too high */
626                         setAH(1);
627                         break;
628                     }
629 
630                     IOWriteB(VGA_GC_INDEX, (Window == 0) ? SVGA_GC_OFFSET_0_REG : SVGA_GC_OFFSET_1_REG);
631                     IOWriteB(VGA_GC_DATA, getDL());
632 
633                     setAH(0);
634                     break;
635                 }
636 
637                 /* Return Memory Window */
638                 case 1:
639                 {
640                     IOWriteB(VGA_GC_INDEX, (Window == 0) ? SVGA_GC_OFFSET_0_REG : SVGA_GC_OFFSET_1_REG);
641                     setDX(IOReadB(VGA_GC_DATA));
642 
643                     setAX(0x004F);
644                     break;
645                 }
646 
647                 default:
648                 {
649                     DPRINT1("VESA INT 0x10, AL = 0x05, Unknown subfunction: 0x%02X\n", getBH());
650                 }
651             }
652 
653             IOWriteB(VGA_GC_INDEX, OldGcIndex);
654             break;
655         }
656 
657         /* Get/Set Display Start */
658         case 0x07:
659         {
660             DWORD StartAddress;
661             BYTE Value;
662             PCVBE_MODE Mode = VbeGetModeByNumber(Bda->VideoMode);
663             BYTE OldCrtcIndex = IOReadB(VGA_CRTC_INDEX_COLOR);
664 
665             if (getBL() & 0x80)
666             {
667                 /* Wait for a vertical retrace */
668                 if (!(IOReadB(VGA_INSTAT1_READ_COLOR) & VGA_STAT_VRETRACE))
669                 {
670                     setCF(1);
671                     break;
672                 }
673 
674                 setCF(0);
675             }
676 
677             switch (getBL() & 0x7F)
678             {
679                 /* Set Display Start */
680                 case 0x00:
681                 {
682                     setAL(0x4F);
683 
684                     if (Mode == NULL || Mode->Info == NULL)
685                     {
686                         /* This is not a VBE mode */
687                         // TODO: Support anyway, perhaps? It can be done.
688                         setAH(0x01);
689                         break;
690                     }
691 
692                     StartAddress = getCX() + getDX() * Mode->Info->BytesPerScanline;
693 
694                     IOWriteB(VGA_CRTC_INDEX_COLOR, SVGA_CRTC_OVERLAY_REG);
695                     Value = IOReadB(VGA_CRTC_DATA_COLOR);
696                     Value &= ~SVGA_CRTC_EXT_ADDR_BIT19;
697                     Value |= (StartAddress >> 12) & SVGA_CRTC_EXT_ADDR_BIT19;
698                     IOWriteB(VGA_CRTC_DATA_COLOR, Value);
699 
700                     IOWriteB(VGA_CRTC_INDEX_COLOR, SVGA_CRTC_EXT_DISPLAY_REG);
701                     Value = IOReadB(VGA_CRTC_DATA_COLOR);
702                     Value &= ~(SVGA_CRTC_EXT_ADDR_BIT16 | SVGA_CRTC_EXT_ADDR_BITS1718);
703                     Value |= (StartAddress >> 16) & SVGA_CRTC_EXT_ADDR_BIT16;
704                     Value |= (StartAddress >> 15) & SVGA_CRTC_EXT_ADDR_BITS1718;
705                     IOWriteB(VGA_CRTC_DATA_COLOR, Value);
706 
707                     IOWriteB(VGA_CRTC_INDEX_COLOR, VGA_CRTC_START_ADDR_HIGH_REG);
708                     IOWriteB(VGA_CRTC_DATA_COLOR, (StartAddress >> 8) & 0xFF);
709                     IOWriteB(VGA_CRTC_INDEX_COLOR, VGA_CRTC_START_ADDR_LOW_REG);
710                     IOWriteB(VGA_CRTC_DATA_COLOR, StartAddress & 0xFF);
711 
712                     setAH(0);
713                     break;
714                 }
715 
716                 /* Get Display Start */
717                 case 0x01:
718                 {
719                     setAL(0x4F);
720                     StartAddress = 0;
721 
722                     if (Mode == NULL || Mode->Info == NULL)
723                     {
724                         /* This is not a VBE mode */
725                         // TODO: Support anyway, perhaps? It can be done.
726                         setAH(0x01);
727                         break;
728                     }
729 
730                     IOWriteB(VGA_CRTC_INDEX_COLOR, SVGA_CRTC_OVERLAY_REG);
731                     StartAddress = (IOReadB(VGA_CRTC_DATA_COLOR) & SVGA_CRTC_EXT_ADDR_BIT19) << 12;
732 
733                     IOWriteB(VGA_CRTC_INDEX_COLOR, SVGA_CRTC_EXT_DISPLAY_REG);
734                     Value = IOReadB(VGA_CRTC_DATA_COLOR);
735                     StartAddress |= (Value & SVGA_CRTC_EXT_ADDR_BIT16) << 16;
736                     StartAddress |= (Value & SVGA_CRTC_EXT_ADDR_BITS1718) << 15;
737 
738                     IOWriteB(VGA_CRTC_INDEX_COLOR, VGA_CRTC_START_ADDR_HIGH_REG);
739                     StartAddress |= IOReadB(VGA_CRTC_DATA_COLOR) << 8;
740                     IOWriteB(VGA_CRTC_INDEX_COLOR, VGA_CRTC_START_ADDR_LOW_REG);
741                     StartAddress |= IOReadB(VGA_CRTC_DATA_COLOR);
742 
743                     setCX(StartAddress % Mode->Info->BytesPerScanline);
744                     setDX(StartAddress / Mode->Info->BytesPerScanline);
745 
746                     setAH(0);
747                     break;
748                 }
749             }
750 
751             IOWriteB(VGA_CRTC_INDEX_COLOR, OldCrtcIndex);
752             break;
753         }
754 
755         default:
756         {
757             DPRINT1("VESA BIOS Extensions function %02Xh NOT IMPLEMENTED!\n", getAL());
758             break;
759         }
760     }
761 }
762 
VbeInitialize(VOID)763 BOOLEAN VbeInitialize(VOID)
764 {
765     BOOLEAN Success;
766     BYTE SeqIndex = IOReadB(VGA_SEQ_INDEX);
767 
768     /* Store the OEM name */
769     strcpy(FAR_POINTER(OEM_NAME_PTR), OEM_NAME);
770 
771     /* Unlock SVGA extensions on the card */
772     IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_UNLOCK_REG);
773     IOWriteB(VGA_SEQ_DATA, SVGA_SEQ_UNLOCKED);
774 
775     /* Check if it worked */
776     Success = IOReadB(VGA_SEQ_DATA) == SVGA_SEQ_UNLOCKED;
777 
778     IOWriteB(VGA_SEQ_INDEX, SeqIndex);
779     return Success;
780 }
781