[FREELDR] Formatting only.
[reactos.git] / boot / freeldr / freeldr / arch / i386 / pcvideo.c
1 /*
2 * FreeLoader
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include <freeldr.h>
20 #include <suppress.h>
21
22 #include <debug.h>
23 DBG_DEFAULT_CHANNEL(UI);
24
25 #define VIDEOPORT_PALETTE_READ 0x03C7
26 #define VIDEOPORT_PALETTE_WRITE 0x03C8
27 #define VIDEOPORT_PALETTE_DATA 0x03C9
28 #define VIDEOPORT_VERTICAL_RETRACE 0x03DA
29
30 #define VIDEOVGA_MEM_ADDRESS 0xA0000
31 #define VIDEOTEXT_MEM_ADDRESS 0xB8000
32 #define VIDEOTEXT_MEM_SIZE 0x8000
33
34 #define VIDEOCARD_CGA_OR_OTHER 0
35 #define VIDEOCARD_EGA 1
36 #define VIDEOCARD_VGA 2
37
38 #define VIDEOMODE_NORMAL_TEXT 0
39 #define VIDEOMODE_EXTENDED_TEXT 1
40 #define VIDEOMODE_80X28 0x501C
41 #define VIDEOMODE_80X30 0x501E
42 #define VIDEOMODE_80X34 0x5022
43 #define VIDEOMODE_80X43 0x502B
44 #define VIDEOMODE_80X60 0x503C
45 #define VIDEOMODE_132X25 0x8419
46 #define VIDEOMODE_132X43 0x842B
47 #define VIDEOMODE_132X50 0x8432
48 #define VIDEOMODE_132X60 0x843C
49
50 #define VERTRES_200_SCANLINES 0x00
51 #define VERTRES_350_SCANLINES 0x01
52 #define VERTRES_400_SCANLINES 0x02
53
54 #include <pshpack2.h>
55 typedef struct
56 {
57 USHORT ModeAttributes; /* mode attributes (see #00080) */
58 UCHAR WindowAttributesA; /* window attributes, window A (see #00081) */
59 UCHAR WindowsAttributesB; /* window attributes, window B (see #00081) */
60 USHORT WindowGranularity; /* window granularity in KB */
61 USHORT WindowSize; /* window size in KB */
62 USHORT WindowAStartSegment; /* start segment of window A (0000h if not supported) */
63 USHORT WindowBStartSegment; /* start segment of window B (0000h if not supported) */
64 ULONG WindowPositioningFunction; /* -> FAR window positioning function (equivalent to AX=4F05h) */
65 USHORT BytesPerScanLine; /* bytes per scan line */
66 /* ---remainder is optional for VESA modes in v1.0/1.1, needed for OEM modes--- */
67 USHORT WidthInPixels; /* width in pixels (graphics) or characters (text) */
68 USHORT HeightInPixels; /* height in pixels (graphics) or characters (text) */
69 UCHAR CharacterWidthInPixels; /* width of character cell in pixels */
70 UCHAR CharacterHeightInPixels; /* height of character cell in pixels */
71 UCHAR NumberOfMemoryPlanes; /* number of memory planes */
72 UCHAR BitsPerPixel; /* number of bits per pixel */
73 UCHAR NumberOfBanks; /* number of banks */
74 UCHAR MemoryModel; /* memory model type (see #00082) */
75 UCHAR BankSize; /* size of bank in KB */
76 UCHAR NumberOfImagePanes; /* number of image pages (less one) that will fit in video RAM */
77 UCHAR Reserved1; /* reserved (00h for VBE 1.0-2.0, 01h for VBE 3.0) */
78 /* ---VBE v1.2+ --- */
79 UCHAR RedMaskSize; /* red mask size */
80 UCHAR RedMaskPosition; /* red field position */
81 UCHAR GreenMaskSize; /* green mask size */
82 UCHAR GreenMaskPosition; /* green field size */
83 UCHAR BlueMaskSize; /* blue mask size */
84 UCHAR BlueMaskPosition; /* blue field size */
85 UCHAR ReservedMaskSize; /* reserved mask size */
86 UCHAR ReservedMaskPosition; /* reserved mask position */
87 UCHAR DirectColorModeInfo; /* direct color mode info */
88 /* bit 0:Color ramp is programmable */
89 /* bit 1:Bytes in reserved field may be used by application */
90 /* ---VBE v2.0+ --- */
91 ULONG LinearVideoBufferAddress; /* physical address of linear video buffer */
92 ULONG OffscreenMemoryPointer; /* pointer to start of offscreen memory */
93 USHORT OffscreenMemorySize; /* KB of offscreen memory */
94 /* ---VBE v3.0 --- */
95 USHORT LinearBytesPerScanLine; /* bytes per scan line in linear modes */
96 UCHAR BankedNumberOfImages; /* number of images (less one) for banked video modes */
97 UCHAR LinearNumberOfImages; /* number of images (less one) for linear video modes */
98 UCHAR LinearRedMaskSize; /* linear modes:Size of direct color red mask (in bits) */
99 UCHAR LinearRedMaskPosition; /* linear modes:Bit position of red mask LSB (e.g. shift count) */
100 UCHAR LinearGreenMaskSize; /* linear modes:Size of direct color green mask (in bits) */
101 UCHAR LinearGreenMaskPosition; /* linear modes:Bit position of green mask LSB (e.g. shift count) */
102 UCHAR LinearBlueMaskSize; /* linear modes:Size of direct color blue mask (in bits) */
103 UCHAR LinearBlueMaskPosition; /* linear modes:Bit position of blue mask LSB (e.g. shift count) */
104 UCHAR LinearReservedMaskSize; /* linear modes:Size of direct color reserved mask (in bits) */
105 UCHAR LinearReservedMaskPosition; /* linear modes:Bit position of reserved mask LSB */
106 ULONG MaximumPixelClock; /* maximum pixel clock for graphics video mode, in Hz */
107 UCHAR Reserved2[190]; /* 190 BYTEs reserved (0) */
108 } SVGA_MODE_INFORMATION, *PSVGA_MODE_INFORMATION;
109 #include <poppack.h>
110
111 static USHORT BiosVideoMode; /* Current video mode as known by BIOS */
112 static ULONG ScreenWidth = 80; /* Screen Width in characters */
113 static ULONG ScreenHeight = 25; /* Screen Height in characters */
114 static ULONG BytesPerScanLine = 160; /* Number of bytes per scanline (delta) */
115 static VIDEODISPLAYMODE DisplayMode = VideoTextMode; /* Current display mode */
116 static BOOLEAN VesaVideoMode = FALSE; /* Are we using a VESA mode? */
117 static SVGA_MODE_INFORMATION VesaVideoModeInformation; /* Only valid when in VESA mode */
118 static ULONG CurrentMemoryBank = 0; /* Currently selected VESA bank */
119
120 enum
121 {
122 INT1FhFont = 0x00,
123 INT43hFont = 0x01,
124 ROM_8x14CharacterFont = 0x02,
125 ROM_8x8DoubleDotFontLo = 0x03,
126 ROM_8x8DoubleDotFontHi = 0x04,
127 ROM_AlphaAlternate = 0x05,
128 ROM_8x16Font = 0x06,
129 ROM_Alternate9x16Font = 0x07,
130 UltraVision_8x20Font = 0x11,
131 UltraVision_8x10Font = 0x12,
132 };
133
134 static ULONG
135 PcVideoDetectVideoCard(VOID)
136 {
137 REGS Regs;
138
139 /* Int 10h AH=12h BL=10h
140 * VIDEO - ALTERNATE FUNCTION SELECT (PS,EGA,VGA,MCGA) - GET EGA INFO
141 *
142 * AH = 12h
143 * BL = 10h
144 * Return:
145 * BH = video state
146 * 00h color mode in effect (I/O port 3Dxh)
147 * 01h mono mode in effect (I/O port 3Bxh)
148 * BL = installed memory (00h = 64K, 01h = 128K, 02h = 192K, 03h = 256K)
149 * CH = feature connector bits
150 * CL = switch settings
151 * AH destroyed (at least by Tseng ET4000 BIOS v8.00n)
152 *
153 * Installation check;EGA
154 */
155 Regs.b.ah = 0x12;
156 Regs.b.bl = 0x10;
157 Int386(0x10, &Regs, &Regs);
158
159 /* If BL is still equal to 0x10 then there is no EGA/VGA present */
160 if (0x10 == Regs.b.bl)
161 {
162 return VIDEOCARD_CGA_OR_OTHER;
163 }
164
165 /* Int 10h AX=1A00h
166 * VIDEO - GET DISPLAY COMBINATION CODE (PS,VGA/MCGA)
167 *
168 * AX = 1A00h
169 * Return:
170 * AL = 1Ah if function was supported
171 * BL = active display code
172 * BH = alternate display code
173 *
174 * This function is commonly used to check for the presence of a VGA.
175 *
176 * Installation check;VGA
177 *
178 * Values for display combination code:
179 * 00h no display
180 * 01h monochrome adapter w/ monochrome display
181 * 02h CGA w/ color display
182 * 03h reserved
183 * 04h EGA w/ color display
184 * 05h EGA w/ monochrome display
185 * 06h PGA w/ color display
186 * 07h VGA w/ monochrome analog display
187 * 08h VGA w/ color analog display
188 * 09h reserved
189 * 0Ah MCGA w/ digital color display
190 * 0Bh MCGA w/ monochrome analog display
191 * 0Ch MCGA w/ color analog display
192 * FFh unknown display type
193 */
194 Regs.b.ah = 0x12;
195 Regs.b.bl = 0x10;
196 Int386(0x10, &Regs, &Regs);
197
198 if (0x1a == Regs.b.al)
199 {
200 return VIDEOCARD_VGA;
201 }
202 else
203 {
204 return VIDEOCARD_EGA;
205 }
206 }
207
208 static VOID PcVideoSetBiosMode(UCHAR VideoMode)
209 {
210 REGS Regs;
211
212 /* Int 10h AH=00h
213 * VIDEO - SET VIDEO MODE
214 *
215 * AH = 00h
216 * AL = desired video mode
217 * Return:
218 * AL = video mode flag (Phoenix, AMI BIOS)
219 * 20h mode > 7
220 * 30h modes 0-5 and 7
221 * 3Fh mode 6
222 * AL = CRT controller mode byte (Phoenix 386 BIOS v1.10)
223 */
224 Regs.b.ah = 0x00;
225 Regs.b.al = VideoMode;
226 Int386(0x10, &Regs, &Regs);
227 }
228
229 static VOID
230 PcVideoSetFont8x8(VOID)
231 {
232 REGS Regs;
233
234 /* Int 10h AX=1112h
235 * VIDEO - TEXT-MODE CHARGEN - LOAD ROM 8x8 DBL-DOT PATTERNS (PS,EGA,VGA)
236 *
237 * AX = 1112h
238 * BL = block to load
239 * Return:
240 * Nothing
241 */
242 Regs.w.ax = 0x1112;
243 Regs.b.bl = 0x00;
244 Int386(0x10, &Regs, &Regs);
245 }
246
247 static VOID
248 PcVideoSetFont8x14(VOID)
249 {
250 REGS Regs;
251
252 /* Int 10h AX=1111h
253 * VIDEO - TEXT-MODE CHARGEN - LOAD ROM MONOCHROME PATTERNS (PS,EGA,VGA)
254 *
255 * AX = 1111h
256 * BL = block to load
257 * Return:
258 * Nothing
259 */
260 Regs.w.ax = 0x1111;
261 Regs.b.bl = 0;
262 Int386(0x10, &Regs, &Regs);
263 }
264
265 static VOID
266 PcVideoSelectAlternatePrintScreen(VOID)
267 {
268 REGS Regs;
269
270 /* Int 10h AH=12h BL=20h
271 * VIDEO - ALTERNATE FUNCTION SELECT (PS,EGA,VGA,MCGA) - ALTERNATE PRTSC
272 *
273 * AH = 12h
274 * BL = 20h select alternate print screen routine
275 * Return:
276 * Nothing
277 *
278 * Installs a PrtSc routine from the video card's BIOS to replace the
279 * default PrtSc handler from the ROM BIOS, which usually does not
280 * understand screen heights other than 25 lines.
281 *
282 * Some adapters disable print-screen instead of enhancing it.
283 */
284 Regs.b.ah = 0x12;
285 Regs.b.bl = 0x20;
286 Int386(0x10, &Regs, &Regs);
287 }
288
289 static VOID
290 PcVideoDisableCursorEmulation(VOID)
291 {
292 REGS Regs;
293
294 /* Int 10h AH=12h BL=34h
295 * VIDEO - ALTERNATE FUNCTION SELECT (VGA) - CURSOR EMULATION
296 *
297 * AH = 12h
298 * BL = 34h
299 * AL = new state
300 * 00h enable alphanumeric cursor emulation
301 * 01h disable alphanumeric cursor emulation
302 * Return:
303 * AL = 12h if function supported
304 *
305 * Specify whether the BIOS should automatically remap cursor start/end
306 * according to the current character height in text modes.
307 */
308 Regs.b.ah = 0x12;
309 Regs.b.bl = 0x34;
310 Regs.b.al = 0x01;
311 Int386(0x10, &Regs, &Regs);
312 }
313
314 static VOID
315 PcVideoDefineCursor(UCHAR StartScanLine, UCHAR EndScanLine)
316 {
317 REGS Regs;
318
319 /* Int 10h AH=01h
320 * VIDEO - SET TEXT-MODE CURSOR SHAPE
321 *
322 * AH = 01h
323 * CH = cursor start and options
324 * CL = bottom scan line containing cursor (bits 0-4)
325 * Return:
326 * Nothing
327 *
328 * Specify the starting and ending scan lines to be occupied
329 * by the hardware cursor in text modes.
330 *
331 * AMI 386 BIOS and AST Premier 386 BIOS will lock up the
332 * system if AL is not equal to the current video mode.
333 *
334 * Bitfields for cursor start and options:
335 *
336 * Bit(s) Description
337 * 7 should be zero
338 * 6,5 cursor blink
339 * (00=normal, 01=invisible, 10=erratic, 11=slow).
340 * (00=normal, other=invisible on EGA/VGA)
341 * 4-0 topmost scan line containing cursor
342 */
343 Regs.b.ah = 0x01;
344 Regs.b.al = 0x03;
345 Regs.b.ch = StartScanLine;
346 Regs.b.cl = EndScanLine;
347 Int386(0x10, &Regs, &Regs);
348 }
349
350 static VOID
351 PcVideoSetVerticalResolution(UCHAR VerticalResolutionMode)
352 {
353 REGS Regs;
354
355 /* Int 10h AH=12h BL=30h
356 * VIDEO - ALTERNATE FUNCTION SELECT (VGA) - SELECT VERTICAL RESOLUTION
357 *
358 * AH = 12h
359 * BL = 30h
360 * AL = vertical resolution
361 * 00h 200 scan lines
362 * 01h 350 scan lines
363 * 02h 400 scan lines
364 * Return:
365 * AL = 12h if function supported
366 *
367 * Specify the number of scan lines used to display text modes.
368 *
369 * The specified resolution will take effect on the next mode set.
370 */
371 Regs.b.ah = 0x12;
372 Regs.b.bl = 0x30;
373 Regs.b.al = VerticalResolutionMode;
374 Int386(0x10, &Regs, &Regs);
375 }
376
377 static VOID
378 PcVideoSet480ScanLines(VOID)
379 {
380 INT_PTR CRTC;
381
382 /* Read CRTC port */
383 CRTC = READ_PORT_UCHAR((PUCHAR)0x03CC);
384
385 if (CRTC & 1)
386 {
387 CRTC = 0x3D4;
388 }
389 else
390 {
391 CRTC = 0x3B4;
392 }
393
394 /* Vertical sync end (also unlocks CR0-7) */
395 WRITE_PORT_UCHAR((PUCHAR)CRTC, 0x11);
396 WRITE_PORT_UCHAR((PUCHAR)CRTC+1, 0x0C);
397
398 /* Vertical total */
399 WRITE_PORT_UCHAR((PUCHAR)CRTC, 0x06);
400 WRITE_PORT_UCHAR((PUCHAR)CRTC+1, 0x0B);
401
402 /* (vertical) overflow */
403 WRITE_PORT_UCHAR((PUCHAR)CRTC, 0x07);
404 WRITE_PORT_UCHAR((PUCHAR)CRTC+1, 0x3E);
405
406 /* Vertical sync start */
407 WRITE_PORT_UCHAR((PUCHAR)CRTC, 0x10);
408 WRITE_PORT_UCHAR((PUCHAR)CRTC+1, 0xEA);
409
410 /* Vertical display end */
411 WRITE_PORT_UCHAR((PUCHAR)CRTC, 0x12);
412 WRITE_PORT_UCHAR((PUCHAR)CRTC+1, 0xDF);
413
414 /* Vertical blank start */
415 WRITE_PORT_UCHAR((PUCHAR)CRTC, 0x15);
416 WRITE_PORT_UCHAR((PUCHAR)CRTC+1, 0xE7);
417
418 /* Vertical blank end */
419 WRITE_PORT_UCHAR((PUCHAR)CRTC, 0x16);
420 WRITE_PORT_UCHAR((PUCHAR)CRTC+1, 0x04);
421
422 /* Misc output register (read) */
423 CRTC = READ_PORT_UCHAR((PUCHAR)0x03CC);
424
425 /* Preserve clock select bits and color bit */
426 CRTC = (CRTC & 0x0D);
427 /* Set correct sync polarity */
428 CRTC = (CRTC | 0xE2);
429
430 /* (write) */
431 WRITE_PORT_UCHAR((PUCHAR)0x03C2, (UCHAR)CRTC);
432 }
433
434 static VOID
435 PcVideoSetDisplayEnd(VOID)
436 {
437 INT_PTR CRTC;
438
439 /* Read CRTC port */
440 CRTC = READ_PORT_UCHAR((PUCHAR)0x03CC);
441
442 if (CRTC & 1)
443 {
444 CRTC = 0x3D4;
445 }
446 else
447 {
448 CRTC = 0x3B4;
449 }
450
451 /* Vertical display end */
452 WRITE_PORT_UCHAR((PUCHAR)CRTC, 0x12);
453 WRITE_PORT_UCHAR((PUCHAR)CRTC+1, 0xDF);
454 }
455
456 static BOOLEAN
457 PcVideoVesaGetSVGAModeInformation(USHORT Mode, PSVGA_MODE_INFORMATION ModeInformation)
458 {
459 REGS Regs;
460
461 RtlZeroMemory((PVOID)BIOSCALLBUFFER, 256);
462
463 /* VESA SuperVGA BIOS - GET SuperVGA MODE INFORMATION
464 * AX = 4F01h
465 * CX = SuperVGA video mode (see #04082 for bitfields)
466 * ES:DI -> 256-byte buffer for mode information (see #00079)
467 * Return:
468 * AL = 4Fh if function supported
469 * AH = status
470 * 00h successful
471 * ES:DI buffer filled
472 * 01h failed
473 *
474 * Desc: Determine the attributes of the specified video mode
475 *
476 * Note: While VBE 1.1 and higher will zero out all unused bytes
477 * of the buffer, v1.0 did not, so applications that want to be
478 * backward compatible should clear the buffer before calling
479 */
480 Regs.w.ax = 0x4F01;
481 Regs.w.cx = Mode;
482 Regs.w.es = BIOSCALLBUFSEGMENT;
483 Regs.w.di = BIOSCALLBUFOFFSET;
484 Int386(0x10, &Regs, &Regs);
485
486 if (Regs.w.ax != 0x004F)
487 {
488 return FALSE;
489 }
490
491 RtlCopyMemory(ModeInformation, (PVOID)BIOSCALLBUFFER, sizeof(SVGA_MODE_INFORMATION));
492
493 TRACE("\n");
494 TRACE("BiosVesaGetSVGAModeInformation() mode 0x%x\n", Mode);
495 TRACE("ModeAttributes = 0x%x\n", ModeInformation->ModeAttributes);
496 TRACE("WindowAttributesA = 0x%x\n", ModeInformation->WindowAttributesA);
497 TRACE("WindowAttributesB = 0x%x\n", ModeInformation->WindowsAttributesB);
498 TRACE("WindowGranularity = %dKB\n", ModeInformation->WindowGranularity);
499 TRACE("WindowSize = %dKB\n", ModeInformation->WindowSize);
500 TRACE("WindowAStartSegment = 0x%x\n", ModeInformation->WindowAStartSegment);
501 TRACE("WindowBStartSegment = 0x%x\n", ModeInformation->WindowBStartSegment);
502 TRACE("WindowPositioningFunction = 0x%x\n", ModeInformation->WindowPositioningFunction);
503 TRACE("BytesPerScanLine = %d\n", ModeInformation->BytesPerScanLine);
504 TRACE("WidthInPixels = %d\n", ModeInformation->WidthInPixels);
505 TRACE("HeightInPixels = %d\n", ModeInformation->HeightInPixels);
506 TRACE("CharacterWidthInPixels = %d\n", ModeInformation->CharacterWidthInPixels);
507 TRACE("CharacterHeightInPixels = %d\n", ModeInformation->CharacterHeightInPixels);
508 TRACE("NumberOfMemoryPlanes = %d\n", ModeInformation->NumberOfMemoryPlanes);
509 TRACE("BitsPerPixel = %d\n", ModeInformation->BitsPerPixel);
510 TRACE("NumberOfBanks = %d\n", ModeInformation->NumberOfBanks);
511 TRACE("MemoryModel = %d\n", ModeInformation->MemoryModel);
512 TRACE("BankSize = %d\n", ModeInformation->BankSize);
513 TRACE("NumberOfImagePlanes = %d\n", ModeInformation->NumberOfImagePanes);
514 TRACE("---VBE v1.2+ ---\n");
515 TRACE("RedMaskSize = %d\n", ModeInformation->RedMaskSize);
516 TRACE("RedMaskPosition = %d\n", ModeInformation->RedMaskPosition);
517 TRACE("GreenMaskSize = %d\n", ModeInformation->GreenMaskSize);
518 TRACE("GreenMaskPosition = %d\n", ModeInformation->GreenMaskPosition);
519 TRACE("BlueMaskSize = %d\n", ModeInformation->BlueMaskSize);
520 TRACE("BlueMaskPosition = %d\n", ModeInformation->BlueMaskPosition);
521 TRACE("ReservedMaskSize = %d\n", ModeInformation->ReservedMaskSize);
522 TRACE("ReservedMaskPosition = %d\n", ModeInformation->ReservedMaskPosition);
523 TRACE("\n");
524
525 return TRUE;
526 }
527
528 static BOOLEAN
529 PcVideoSetBiosVesaMode(USHORT Mode)
530 {
531 REGS Regs;
532
533 /* Int 10h AX=4F02h
534 * VESA SuperVGA BIOS - SET SuperVGA VIDEO MODE
535 *
536 * AX = 4F02h
537 * BX = new video mode
538 * ES:DI -> (VBE 3.0+) CRTC information block, bit mode bit 11 set
539 * Return:
540 * AL = 4Fh if function supported
541 * AH = status
542 * 00h successful
543 * 01h failed
544 *
545 * Values for VESA video mode:
546 * 00h-FFh OEM video modes (see #00010 at AH=00h)
547 * 100h 640x400x256
548 * 101h 640x480x256
549 * 102h 800x600x16
550 * 103h 800x600x256
551 * 104h 1024x768x16
552 * 105h 1024x768x256
553 * 106h 1280x1024x16
554 * 107h 1280x1024x256
555 * 108h 80x60 text
556 * 109h 132x25 text
557 * 10Ah 132x43 text
558 * 10Bh 132x50 text
559 * 10Ch 132x60 text
560 * ---VBE v1.2+ ---
561 * 10Dh 320x200x32K
562 * 10Eh 320x200x64K
563 * 10Fh 320x200x16M
564 * 110h 640x480x32K
565 * 111h 640x480x64K
566 * 112h 640x480x16M
567 * 113h 800x600x32K
568 * 114h 800x600x64K
569 * 115h 800x600x16M
570 * 116h 1024x768x32K
571 * 117h 1024x768x64K
572 * 118h 1024x768x16M
573 * 119h 1280x1024x32K (1:5:5:5)
574 * 11Ah 1280x1024x64K (5:6:5)
575 * 11Bh 1280x1024x16M
576 * ---VBE 2.0+ ---
577 * 120h 1600x1200x256
578 * 121h 1600x1200x32K
579 * 122h 1600x1200x64K
580 * 81FFh special full-memory access mode
581 *
582 * Notes: The special mode 81FFh preserves the contents of the video memory and gives
583 * access to all of the memory; VESA recommends that the special mode be a packed-pixel
584 * mode. For VBE 2.0+, it is required that the VBE implement the mode, but not place it
585 * in the list of available modes (mode information for this mode can be queried
586 * directly, however).. As of VBE 2.0, VESA will no longer define video mode numbers
587 */
588 Regs.w.ax = 0x4F02;
589 Regs.w.bx = Mode;
590 Int386(0x10, &Regs, &Regs);
591
592 if (0x004F != Regs.w.ax)
593 {
594 return FALSE;
595 }
596
597 return TRUE;
598 }
599
600 static BOOLEAN
601 PcVideoSetMode80x25(VOID)
602 {
603 PcVideoSetBiosMode(0x03);
604 ScreenWidth = 80;
605 ScreenHeight = 25;
606
607 return TRUE;
608 }
609
610 static BOOLEAN
611 PcVideoSetMode80x50_80x43(VOID)
612 {
613 if (VIDEOCARD_VGA == PcVideoDetectVideoCard())
614 {
615 PcVideoSetBiosMode(0x12);
616 PcVideoSetFont8x8();
617 PcVideoSelectAlternatePrintScreen();
618 PcVideoDisableCursorEmulation();
619 PcVideoDefineCursor(6, 7);
620 ScreenWidth = 80;
621 ScreenHeight = 50;
622 }
623 else if (VIDEOCARD_EGA == PcVideoDetectVideoCard())
624 {
625 PcVideoSetBiosMode(0x03);
626 PcVideoSetFont8x8();
627 PcVideoSelectAlternatePrintScreen();
628 PcVideoDisableCursorEmulation();
629 PcVideoDefineCursor(6, 7);
630 ScreenWidth = 80;
631 ScreenHeight = 43;
632 }
633 else /* VIDEOCARD_CGA_OR_OTHER */
634 {
635 return FALSE;
636 }
637
638 return TRUE;
639 }
640
641 static BOOLEAN
642 PcVideoSetMode80x28(VOID)
643 {
644 /* FIXME: Is this VGA-only? */
645 PcVideoSetMode80x25();
646 PcVideoSetFont8x14();
647 PcVideoDefineCursor(11, 12);
648 ScreenWidth = 80;
649 ScreenHeight = 28;
650
651 return TRUE;
652 }
653
654 static BOOLEAN
655 PcVideoSetMode80x30(VOID)
656 {
657 /* FIXME: Is this VGA-only? */
658 PcVideoSetMode80x25();
659 PcVideoSet480ScanLines();
660 ScreenWidth = 80;
661 ScreenHeight = 30;
662
663 return TRUE;
664 }
665
666 static BOOLEAN
667 PcVideoSetMode80x34(VOID)
668 {
669 /* FIXME: Is this VGA-only? */
670 PcVideoSetMode80x25();
671 PcVideoSet480ScanLines();
672 PcVideoSetFont8x14();
673 PcVideoDefineCursor(11, 12);
674 PcVideoSetDisplayEnd();
675 ScreenWidth = 80;
676 ScreenHeight = 34;
677
678 return TRUE;
679 }
680
681 static BOOLEAN
682 PcVideoSetMode80x43(VOID)
683 {
684 /* FIXME: Is this VGA-only? */
685 PcVideoSetVerticalResolution(VERTRES_350_SCANLINES);
686 PcVideoSetMode80x25();
687 PcVideoSetFont8x8();
688 PcVideoSelectAlternatePrintScreen();
689 PcVideoDisableCursorEmulation();
690 PcVideoDefineCursor(6, 7);
691 ScreenWidth = 80;
692 ScreenHeight = 43;
693
694 return TRUE;
695 }
696
697 static BOOLEAN
698 PcVideoSetMode80x60(VOID)
699 {
700 /* FIXME: Is this VGA-only? */
701 PcVideoSetMode80x25();
702 PcVideoSet480ScanLines();
703 PcVideoSetFont8x8();
704 PcVideoSelectAlternatePrintScreen();
705 PcVideoDisableCursorEmulation();
706 PcVideoDefineCursor(6, 7);
707 PcVideoSetDisplayEnd();
708 ScreenWidth = 80;
709 ScreenHeight = 60;
710
711 return TRUE;
712 }
713
714 static BOOLEAN
715 PcVideoSetMode(USHORT NewMode)
716 {
717 CurrentMemoryBank = 0;
718
719 /* Set the values for the default text modes
720 * If they are setting a graphics mode then
721 * these values will be changed.
722 */
723 BiosVideoMode = NewMode;
724 ScreenWidth = 80;
725 ScreenHeight = 25;
726 BytesPerScanLine = 160;
727 DisplayMode = VideoTextMode;
728 VesaVideoMode = FALSE;
729
730 switch (NewMode)
731 {
732 case VIDEOMODE_NORMAL_TEXT:
733 case 0x03: /* BIOS 80x25 text mode number */
734 return PcVideoSetMode80x25();
735 case VIDEOMODE_EXTENDED_TEXT:
736 return PcVideoSetMode80x50_80x43();
737 case VIDEOMODE_80X28:
738 return PcVideoSetMode80x28();
739 case VIDEOMODE_80X30:
740 return PcVideoSetMode80x30();
741 case VIDEOMODE_80X34:
742 return PcVideoSetMode80x34();
743 case VIDEOMODE_80X43:
744 return PcVideoSetMode80x43();
745 case VIDEOMODE_80X60:
746 return PcVideoSetMode80x60();
747 }
748
749 if (0x12 == NewMode)
750 {
751 /* 640x480x16 */
752 PcVideoSetBiosMode((UCHAR)NewMode);
753 WRITE_PORT_USHORT((USHORT*)0x03CE, 0x0F01); /* For some reason this is necessary? */
754 ScreenWidth = 640;
755 ScreenHeight = 480;
756 BytesPerScanLine = 80;
757 BiosVideoMode = NewMode;
758 DisplayMode = VideoGraphicsMode;
759
760 return TRUE;
761 }
762 else if (0x13 == NewMode)
763 {
764 /* 320x200x256 */
765 PcVideoSetBiosMode((UCHAR)NewMode);
766 ScreenWidth = 320;
767 ScreenHeight = 200;
768 BytesPerScanLine = 320;
769 BiosVideoMode = NewMode;
770 DisplayMode = VideoGraphicsMode;
771
772 return TRUE;
773 }
774 else if (0x0108 <= NewMode && NewMode <= 0x010C)
775 {
776 /* VESA Text Mode */
777 if (! PcVideoVesaGetSVGAModeInformation(NewMode, &VesaVideoModeInformation))
778 {
779 return FALSE;
780 }
781
782 if (! PcVideoSetBiosVesaMode(NewMode))
783 {
784 return FALSE;
785 }
786
787 ScreenWidth = VesaVideoModeInformation.WidthInPixels;
788 ScreenHeight = VesaVideoModeInformation.HeightInPixels;
789 BytesPerScanLine = VesaVideoModeInformation.BytesPerScanLine;
790 BiosVideoMode = NewMode;
791 DisplayMode = VideoTextMode;
792 VesaVideoMode = TRUE;
793
794 return TRUE;
795 }
796 else
797 {
798 /* VESA Graphics Mode */
799 if (! PcVideoVesaGetSVGAModeInformation(NewMode, &VesaVideoModeInformation))
800 {
801 return FALSE;
802 }
803
804 if (! PcVideoSetBiosVesaMode(NewMode))
805 {
806 return FALSE;
807 }
808
809 ScreenWidth = VesaVideoModeInformation.WidthInPixels;
810 ScreenHeight = VesaVideoModeInformation.HeightInPixels;
811 BytesPerScanLine = VesaVideoModeInformation.BytesPerScanLine;
812 BiosVideoMode = NewMode;
813 DisplayMode = VideoGraphicsMode;
814 VesaVideoMode = TRUE;
815
816 return TRUE;
817 }
818
819 return FALSE;
820 }
821
822 static VOID
823 PcVideoSetBlinkBit(BOOLEAN Enable)
824 {
825 REGS Regs;
826
827 /* Int 10h AX=1003h
828 * VIDEO - TOGGLE INTENSITY/BLINKING BIT (Jr, PS, TANDY 1000, EGA, VGA)
829 *
830 * AX = 1003h
831 * BL = new state
832 * 00h background intensity enabled
833 * 01h blink enabled
834 * BH = 00h to avoid problems on some adapters
835 * Return:
836 * Nothing
837 *
838 * Note: although there is no function to get
839 * the current status, bit 5 of 0040h:0065h
840 * indicates the state.
841 */
842 Regs.w.ax = 0x1003;
843 Regs.w.bx = Enable ? 0x0001 : 0x0000;
844 Int386(0x10, &Regs, &Regs);
845 }
846
847 static VOID
848 PcVideoSetMemoryBank(USHORT BankNumber)
849 {
850 REGS Regs;
851
852 if (CurrentMemoryBank != BankNumber)
853 {
854 /* Int 10h AX=4F05h
855 * VESA SuperVGA BIOS - CPU VIDEO MEMORY CONTROL
856 *
857 * AX = 4F05h
858 * BH = subfunction
859 * 00h select video memory window
860 * 01h get video memory window
861 * DX = window address in video memory (in granularity units)
862 * Return:
863 * DX = window address in video memory (in gran. units)
864 * BL = window number
865 * 00h window A
866 * 01h window B.
867 * Return:
868 * AL = 4Fh if function supported
869 * AH = status
870 * 00h successful
871 * 01h failed
872 */
873 Regs.w.ax = 0x4F05;
874 Regs.w.bx = 0x0000;
875 Regs.w.dx = BankNumber;
876 Int386(0x10, &Regs, &Regs);
877
878 if (0x004F == Regs.w.ax)
879 {
880 CurrentMemoryBank = BankNumber;
881 }
882 }
883 }
884
885 VIDEODISPLAYMODE
886 PcVideoSetDisplayMode(char *DisplayModeName, BOOLEAN Init)
887 {
888 USHORT VideoMode = VIDEOMODE_NORMAL_TEXT;
889
890 if (NULL == DisplayModeName || '\0' == *DisplayModeName)
891 {
892 PcVideoSetBlinkBit(! Init);
893 return DisplayMode;
894 }
895
896 if (VIDEOCARD_CGA_OR_OTHER == PcVideoDetectVideoCard())
897 {
898 TRACE("CGA or other display adapter detected.\n");
899 printf("CGA or other display adapter detected.\n");
900 printf("Using 80x25 text mode.\n");
901 VideoMode = VIDEOMODE_NORMAL_TEXT;
902 }
903 else if (VIDEOCARD_EGA == PcVideoDetectVideoCard())
904 {
905 TRACE("EGA display adapter detected.\n");
906 printf("EGA display adapter detected.\n");
907 printf("Using 80x25 text mode.\n");
908 VideoMode = VIDEOMODE_NORMAL_TEXT;
909 }
910 else /* if (VIDEOCARD_VGA == PcVideoDetectVideoCard()) */
911 {
912 TRACE("VGA display adapter detected.\n");
913
914 if (0 == _stricmp(DisplayModeName, "NORMAL_VGA"))
915 {
916 VideoMode = VIDEOMODE_NORMAL_TEXT;
917 }
918 else if (0 == _stricmp(DisplayModeName, "EXTENDED_VGA"))
919 {
920 VideoMode = VIDEOMODE_EXTENDED_TEXT;
921 }
922 else
923 {
924 VideoMode = (USHORT)strtoul(DisplayModeName, NULL, 0);
925 }
926 }
927
928 if (! PcVideoSetMode(VideoMode))
929 {
930 printf("Error: unable to set video display mode 0x%x\n", (int) VideoMode);
931 printf("Defaulting to 80x25 text mode.\n");
932 printf("Press any key to continue.\n");
933 PcConsGetCh();
934
935 PcVideoSetMode(VIDEOMODE_NORMAL_TEXT);
936 }
937
938 PcVideoSetBlinkBit(! Init);
939
940 return DisplayMode;
941 }
942
943 VOID
944 PcVideoGetDisplaySize(PULONG Width, PULONG Height, PULONG Depth)
945 {
946 *Width = ScreenWidth;
947 *Height = ScreenHeight;
948 if (VideoGraphicsMode == DisplayMode && VesaVideoMode)
949 {
950 if (16 == VesaVideoModeInformation.BitsPerPixel)
951 {
952 /* 16-bit color modes give green an extra bit (5:6:5)
953 * 15-bit color modes have just 5:5:5 for R:G:B */
954 *Depth = (6 == VesaVideoModeInformation.GreenMaskSize ? 16 : 15);
955 }
956 else
957 {
958 *Depth = VesaVideoModeInformation.BitsPerPixel;
959 }
960 }
961 else
962 {
963 *Depth = 0;
964 }
965 }
966
967 ULONG
968 PcVideoGetBufferSize(VOID)
969 {
970 return ScreenHeight * BytesPerScanLine;
971 }
972
973 VOID
974 PcVideoGetFontsFromFirmware(PULONG RomFontPointers)
975 {
976 REGS BiosRegs;
977
978 /* Get the address of the BIOS ROM fonts.
979 Int 10h, AX=1130h, BH = pointer specifier
980 returns: es:bp = address */
981 BiosRegs.d.eax = 0x1130;
982 BiosRegs.b.bh = ROM_8x14CharacterFont;
983 Int386(0x10, &BiosRegs, &BiosRegs);
984 RomFontPointers[0] = BiosRegs.w.es << 4 | BiosRegs.w.bp;
985
986 BiosRegs.b.bh = ROM_8x8DoubleDotFontLo;
987 Int386(0x10, &BiosRegs, &BiosRegs);
988 RomFontPointers[1] = BiosRegs.w.es << 16 | BiosRegs.w.bp;
989
990 BiosRegs.b.bh = ROM_8x8DoubleDotFontHi;
991 Int386(0x10, &BiosRegs, &BiosRegs);
992 RomFontPointers[2] = BiosRegs.w.es << 16 | BiosRegs.w.bp;
993
994 BiosRegs.b.bh = ROM_AlphaAlternate;
995 Int386(0x10, &BiosRegs, &BiosRegs);
996 RomFontPointers[3] = BiosRegs.w.es << 16 | BiosRegs.w.bp;
997
998 BiosRegs.b.bh = ROM_8x16Font;
999 Int386(0x10, &BiosRegs, &BiosRegs);
1000 RomFontPointers[4] = BiosRegs.w.es << 16 | BiosRegs.w.bp;
1001
1002 BiosRegs.b.bh = ROM_Alternate9x16Font;
1003 Int386(0x10, &BiosRegs, &BiosRegs);
1004 RomFontPointers[5] = BiosRegs.w.es << 16 | BiosRegs.w.bp;
1005 }
1006
1007 VOID
1008 PcVideoSetTextCursorPosition(UCHAR X, UCHAR Y)
1009 {
1010 REGS Regs;
1011
1012 /* Int 10h AH=02h
1013 * VIDEO - SET CURSOR POSITION
1014 *
1015 * AH = 02h
1016 * BH = page number
1017 * 0-3 in modes 2&3
1018 * 0-7 in modes 0&1
1019 * 0 in graphics modes
1020 * DH = row (00h is top)
1021 * DL = column (00h is left)
1022 * Return:
1023 * Nothing
1024 */
1025 Regs.b.ah = 0x02;
1026 Regs.b.bh = 0x00;
1027 Regs.b.dh = Y;
1028 Regs.b.dl = X;
1029 Int386(0x10, &Regs, &Regs);
1030 }
1031
1032 VOID
1033 PcVideoHideShowTextCursor(BOOLEAN Show)
1034 {
1035 if (Show)
1036 {
1037 PcVideoDefineCursor(0x0D, 0x0E);
1038 }
1039 else
1040 {
1041 PcVideoDefineCursor(0x20, 0x00);
1042 }
1043 }
1044
1045 VOID
1046 PcVideoCopyOffScreenBufferToVRAM(PVOID Buffer)
1047 {
1048 USHORT BanksToCopy;
1049 ULONG BytesInLastBank;
1050 USHORT CurrentBank;
1051 ULONG BankSize;
1052
1053 /* PcVideoWaitForVerticalRetrace(); */
1054
1055 /* Text mode (BIOS or VESA) */
1056 if (VideoTextMode == DisplayMode)
1057 {
1058 RtlCopyMemory((PVOID) VIDEOTEXT_MEM_ADDRESS, Buffer, PcVideoGetBufferSize());
1059 }
1060 /* VESA graphics mode */
1061 else if (VideoGraphicsMode == DisplayMode && VesaVideoMode)
1062 {
1063 BankSize = VesaVideoModeInformation.WindowGranularity << 10;
1064 BanksToCopy = (USHORT)((VesaVideoModeInformation.HeightInPixels * VesaVideoModeInformation.BytesPerScanLine) / BankSize);
1065 BytesInLastBank = (VesaVideoModeInformation.HeightInPixels * VesaVideoModeInformation.BytesPerScanLine) % BankSize;
1066
1067 /* Copy all the banks but the last one because
1068 * it is probably a partial bank */
1069 for (CurrentBank = 0; CurrentBank < BanksToCopy; CurrentBank++)
1070 {
1071 PcVideoSetMemoryBank(CurrentBank);
1072 RtlCopyMemory((PVOID) VIDEOVGA_MEM_ADDRESS, (char *) Buffer + CurrentBank * BankSize, BankSize);
1073 }
1074
1075 /* Copy the remaining bytes into the last bank */
1076 PcVideoSetMemoryBank(CurrentBank);
1077 RtlCopyMemory((PVOID)VIDEOVGA_MEM_ADDRESS, (char *) Buffer + CurrentBank * BankSize, BytesInLastBank);
1078 }
1079 /* BIOS graphics mode */
1080 else
1081 {
1082 UNIMPLEMENTED;
1083 }
1084 }
1085
1086 VOID
1087 PcVideoClearScreen(UCHAR Attr)
1088 {
1089 USHORT AttrChar;
1090 USHORT *BufPtr;
1091
1092 AttrChar = ((USHORT) Attr << 8) | ' ';
1093 for (BufPtr = (USHORT *) VIDEOTEXT_MEM_ADDRESS;
1094 BufPtr < (USHORT *) (VIDEOTEXT_MEM_ADDRESS + VIDEOTEXT_MEM_SIZE);
1095 BufPtr++)
1096 {
1097 _PRAGMA_WARNING_SUPPRESS(__WARNING_DEREF_NULL_PTR)
1098 *BufPtr = AttrChar;
1099 }
1100 }
1101
1102 VOID
1103 PcVideoPutChar(int Ch, UCHAR Attr, unsigned X, unsigned Y)
1104 {
1105 USHORT *BufPtr;
1106
1107 BufPtr = (USHORT *) (ULONG_PTR)(VIDEOTEXT_MEM_ADDRESS + Y * BytesPerScanLine + X * 2);
1108 *BufPtr = ((USHORT) Attr << 8) | (Ch & 0xff);
1109 }
1110
1111 BOOLEAN
1112 PcVideoIsPaletteFixed(VOID)
1113 {
1114 return FALSE;
1115 }
1116
1117 VOID
1118 PcVideoSetPaletteColor(UCHAR Color, UCHAR Red, UCHAR Green, UCHAR Blue)
1119 {
1120 WRITE_PORT_UCHAR((UCHAR*) VIDEOPORT_PALETTE_WRITE, Color);
1121 WRITE_PORT_UCHAR((UCHAR*) VIDEOPORT_PALETTE_DATA, Red);
1122 WRITE_PORT_UCHAR((UCHAR*) VIDEOPORT_PALETTE_DATA, Green);
1123 WRITE_PORT_UCHAR((UCHAR*) VIDEOPORT_PALETTE_DATA, Blue);
1124 }
1125
1126 VOID
1127 PcVideoGetPaletteColor(UCHAR Color, UCHAR* Red, UCHAR* Green, UCHAR* Blue)
1128 {
1129 WRITE_PORT_UCHAR((UCHAR*) VIDEOPORT_PALETTE_READ, Color);
1130 *Red = READ_PORT_UCHAR((UCHAR*) VIDEOPORT_PALETTE_DATA);
1131 *Green = READ_PORT_UCHAR((UCHAR*) VIDEOPORT_PALETTE_DATA);
1132 *Blue = READ_PORT_UCHAR((UCHAR*) VIDEOPORT_PALETTE_DATA);
1133 }
1134
1135 VOID
1136 PcVideoSync(VOID)
1137 {
1138 while ((READ_PORT_UCHAR((UCHAR*)VIDEOPORT_VERTICAL_RETRACE) & 0x08))
1139 {
1140 /*
1141 * Keep reading the port until bit 3 is clear
1142 * This waits for the current retrace to end and
1143 * we can catch the next one so we know we are
1144 * getting a full retrace.
1145 */
1146 }
1147
1148 while (!(READ_PORT_UCHAR((UCHAR*)VIDEOPORT_VERTICAL_RETRACE) & 0x08))
1149 {
1150 /*
1151 * Keep reading the port until bit 3 is set
1152 * Now that we know we aren't doing a vertical
1153 * retrace we need to wait for the next one.
1154 */
1155 }
1156 }
1157
1158 VOID
1159 PcVideoPrepareForReactOS(VOID)
1160 {
1161 // PcVideoSetMode80x50_80x43();
1162 PcVideoSetMode80x25();
1163 PcVideoHideShowTextCursor(FALSE);
1164 }
1165
1166 /* EOF */