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