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