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