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