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