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