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