@@ -106,12 +106,13 @@ typedef struct
106106 ULONG MaximumPixelClock ; /* Maximum pixel clock for graphics video mode, in Hz */
107107 UCHAR Reserved2 [190 ]; /* 190 BYTEs reserved (0) */
108108} SVGA_MODE_INFORMATION , * PSVGA_MODE_INFORMATION ;
109+ C_ASSERT (sizeof (SVGA_MODE_INFORMATION ) == 256 );
109110#include <poppack.h>
110111
111112UCHAR MachDefaultTextColor = COLOR_GRAY ;
112113
113114static ULONG VideoCard = VIDEOCARD_CGA_OR_OTHER ; /* Type of video card installed on the system */
114- static USHORT BiosVideoMode ; /* Current video mode as known by BIOS */
115+ static USHORT BiosVideoMode = VIDEOMODE_NORMAL_TEXT ; /* Current video mode as known by BIOS */
115116static ULONG ScreenWidth = 80 ; /* Screen Width in characters */
116117static ULONG ScreenHeight = 25 ; /* Screen Height in characters */
117118static ULONG BytesPerScanLine = 160 ; /* Number of bytes per scanline (delta) */
@@ -202,11 +203,13 @@ PcVideoDetectVideoCard(VOID)
202203}
203204
204205static BOOLEAN
205- PcVideoVesaGetSVGAModeInformation (USHORT Mode , PSVGA_MODE_INFORMATION ModeInformation )
206+ PcVideoVesaGetSVGAModeInformation (
207+ _In_ USHORT Mode ,
208+ _Out_ PSVGA_MODE_INFORMATION ModeInformation )
206209{
207210 REGS Regs ;
208211
209- RtlZeroMemory ((PVOID )BIOSCALLBUFFER , 256 );
212+ RtlZeroMemory ((PVOID )BIOSCALLBUFFER , sizeof ( * ModeInformation ) );
210213
211214 /* VESA SuperVGA BIOS - GET SuperVGA MODE INFORMATION
212215 * AX = 4F01h
@@ -234,43 +237,230 @@ PcVideoVesaGetSVGAModeInformation(USHORT Mode, PSVGA_MODE_INFORMATION ModeInform
234237 if (Regs .w .ax != 0x004F )
235238 return FALSE;
236239
237- RtlCopyMemory (ModeInformation , (PVOID )BIOSCALLBUFFER , sizeof (SVGA_MODE_INFORMATION ));
240+ RtlCopyMemory (ModeInformation , (PVOID )BIOSCALLBUFFER , sizeof (* ModeInformation ));
238241
239242 TRACE ("\n" );
240- TRACE ("BiosVesaGetSVGAModeInformation() mode 0x%x\n" , Mode );
241- TRACE ("ModeAttributes = 0x%x \n" , ModeInformation -> ModeAttributes );
242- TRACE ("WindowAttributesA = 0x%x \n" , ModeInformation -> WindowAttributesA );
243- TRACE ("WindowAttributesB = 0x%x \n" , ModeInformation -> WindowsAttributesB );
244- TRACE ("WindowGranularity = %dKB \n" , ModeInformation -> WindowGranularity );
245- TRACE ("WindowSize = %dKB \n" , ModeInformation -> WindowSize );
246- TRACE ("WindowAStartSegment = 0x%x \n" , ModeInformation -> WindowAStartSegment );
247- TRACE ("WindowBStartSegment = 0x%x \n" , ModeInformation -> WindowBStartSegment );
243+ TRACE ("BiosVesaGetSVGAModeInformation(Mode 0x%x) \n" , Mode );
244+ TRACE ("ModeAttributes = 0x%04x \n" , ModeInformation -> ModeAttributes );
245+ TRACE ("WindowAttributesA = 0x%02x \n" , ModeInformation -> WindowAttributesA );
246+ TRACE ("WindowAttributesB = 0x%02x \n" , ModeInformation -> WindowsAttributesB );
247+ TRACE ("WindowGranularity = %huKB \n" , ModeInformation -> WindowGranularity );
248+ TRACE ("WindowSize = %huKB \n" , ModeInformation -> WindowSize );
249+ TRACE ("WindowAStartSegment = 0x%04x \n" , ModeInformation -> WindowAStartSegment );
250+ TRACE ("WindowBStartSegment = 0x%04x \n" , ModeInformation -> WindowBStartSegment );
248251 TRACE ("WindowPositioningFunction = 0x%x\n" , ModeInformation -> WindowPositioningFunction );
249- TRACE ("BytesPerScanLine = %d\n" , ModeInformation -> BytesPerScanLine );
250- TRACE ("WidthInPixels = %d\n" , ModeInformation -> WidthInPixels );
251- TRACE ("HeightInPixels = %d\n" , ModeInformation -> HeightInPixels );
252- TRACE ("CharacterWidthInPixels = %d\n" , ModeInformation -> CharacterWidthInPixels );
253- TRACE ("CharacterHeightInPixels = %d\n" , ModeInformation -> CharacterHeightInPixels );
254- TRACE ("NumberOfMemoryPlanes = %d\n" , ModeInformation -> NumberOfMemoryPlanes );
255- TRACE ("BitsPerPixel = %d\n" , ModeInformation -> BitsPerPixel );
256- TRACE ("NumberOfBanks = %d\n" , ModeInformation -> NumberOfBanks );
257- TRACE ("MemoryModel = %d\n" , ModeInformation -> MemoryModel );
258- TRACE ("BankSize = %d\n" , ModeInformation -> BankSize );
259- TRACE ("NumberOfImagePlanes = %d\n" , ModeInformation -> NumberOfImagePanes );
252+ TRACE ("BytesPerScanLine = %hu\n" , ModeInformation -> BytesPerScanLine );
253+ TRACE ("WidthInPixels = %hu\n" , ModeInformation -> WidthInPixels );
254+ TRACE ("HeightInPixels = %hu\n" , ModeInformation -> HeightInPixels );
255+ TRACE ("CharacterWidthInPixels = %u\n" , ModeInformation -> CharacterWidthInPixels );
256+ TRACE ("CharacterHeightInPixels = %u\n" , ModeInformation -> CharacterHeightInPixels );
257+ TRACE ("NumberOfMemoryPlanes = %u\n" , ModeInformation -> NumberOfMemoryPlanes );
258+ TRACE ("BitsPerPixel = %u\n" , ModeInformation -> BitsPerPixel );
259+ TRACE ("NumberOfBanks = %u\n" , ModeInformation -> NumberOfBanks );
260+ TRACE ("MemoryModel = %u\n" , ModeInformation -> MemoryModel );
261+ TRACE ("BankSize = %u\n" , ModeInformation -> BankSize );
262+ TRACE ("NumberOfImagePanes = %u\n" , ModeInformation -> NumberOfImagePanes );
263+ TRACE ("Reserved1 = 0x%02x\n" , ModeInformation -> Reserved1 );
260264 TRACE ("---VBE v1.2+ ---\n" );
261- TRACE ("RedMaskSize = %d\n" , ModeInformation -> RedMaskSize );
262- TRACE ("RedMaskPosition = %d\n" , ModeInformation -> RedMaskPosition );
263- TRACE ("GreenMaskSize = %d\n" , ModeInformation -> GreenMaskSize );
264- TRACE ("GreenMaskPosition = %d\n" , ModeInformation -> GreenMaskPosition );
265- TRACE ("BlueMaskSize = %d\n" , ModeInformation -> BlueMaskSize );
266- TRACE ("BlueMaskPosition = %d\n" , ModeInformation -> BlueMaskPosition );
267- TRACE ("ReservedMaskSize = %d\n" , ModeInformation -> ReservedMaskSize );
268- TRACE ("ReservedMaskPosition = %d\n" , ModeInformation -> ReservedMaskPosition );
265+ TRACE ("RedMaskSize = %u\n" , ModeInformation -> RedMaskSize );
266+ TRACE ("RedMaskPosition = %u\n" , ModeInformation -> RedMaskPosition );
267+ TRACE ("GreenMaskSize = %u\n" , ModeInformation -> GreenMaskSize );
268+ TRACE ("GreenMaskPosition = %u\n" , ModeInformation -> GreenMaskPosition );
269+ TRACE ("BlueMaskSize = %u\n" , ModeInformation -> BlueMaskSize );
270+ TRACE ("BlueMaskPosition = %u\n" , ModeInformation -> BlueMaskPosition );
271+ TRACE ("ReservedMaskSize = %u\n" , ModeInformation -> ReservedMaskSize );
272+ TRACE ("ReservedMaskPosition = %u\n" , ModeInformation -> ReservedMaskPosition );
273+ TRACE ("DirectColorModeInfo = 0x%02x\n" , ModeInformation -> DirectColorModeInfo );
274+ TRACE ("---VBE v2.0+ ---\n" );
275+ TRACE ("LinearVideoBufferAddress = 0x%x\n" , ModeInformation -> LinearVideoBufferAddress );
276+ TRACE ("OffscreenMemoryPointer = 0x%x\n" , ModeInformation -> OffscreenMemoryPointer );
277+ TRACE ("OffscreenMemorySize = %huKB\n" , ModeInformation -> OffscreenMemorySize );
278+ TRACE ("---VBE v3.0 ---\n" );
279+ TRACE ("LinearBytesPerScanLine = %hu\n" , ModeInformation -> LinearBytesPerScanLine );
280+ TRACE ("BankedNumberOfImages = %u\n" , ModeInformation -> BankedNumberOfImages );
281+ TRACE ("LinearNumberOfImages = %u\n" , ModeInformation -> LinearNumberOfImages );
282+ TRACE ("LinearRedMaskSize = %u\n" , ModeInformation -> LinearRedMaskSize );
283+ TRACE ("LinearRedMaskPosition = %u\n" , ModeInformation -> LinearRedMaskPosition );
284+ TRACE ("LinearGreenMaskSize = %u\n" , ModeInformation -> LinearGreenMaskSize );
285+ TRACE ("LinearGreenMaskPosition = %u\n" , ModeInformation -> LinearGreenMaskPosition );
286+ TRACE ("LinearBlueMaskSize = %u\n" , ModeInformation -> LinearBlueMaskSize );
287+ TRACE ("LinearBlueMaskPosition = %u\n" , ModeInformation -> LinearBlueMaskPosition );
288+ TRACE ("LinearReservedMaskSize = %u\n" , ModeInformation -> LinearReservedMaskSize );
289+ TRACE ("LinearReservedMaskPosition = %u\n" , ModeInformation -> LinearReservedMaskPosition );
290+ TRACE ("MaximumPixelClock = %luHz\n" , ModeInformation -> MaximumPixelClock );
269291 TRACE ("\n" );
270292
271293 return TRUE;
272294}
273295
296+ static BOOLEAN
297+ PcVideoVesaGetCurrentSVGAMode (
298+ _Out_ PUSHORT Mode )
299+ {
300+ REGS Regs ;
301+
302+ /*
303+ * VESA SuperVGA BIOS - GET CURRENT VIDEO MODE
304+ *
305+ * AX = 4F03h
306+ * Return:
307+ * AL = 4Fh if function supported
308+ * AH = status
309+ * 00h successful
310+ * BX = video mode (see #00083,#00084)
311+ *
312+ * bit 13:
313+ * VBE/AF v1.0P accelerated video mode
314+ *
315+ * bit 14:
316+ * Linear frame buffer enabled (VBE v2.0+)
317+ *
318+ * bit 15:
319+ * Don't clear video memory
320+ * 01h failed
321+ */
322+ Regs .w .ax = 0x4F03 ;
323+ Int386 (0x10 , & Regs , & Regs );
324+
325+ if (Regs .w .ax != 0x004F )
326+ return FALSE;
327+
328+ * Mode = Regs .w .bx ;
329+ return TRUE;
330+ }
331+
332+ static BOOLEAN
333+ PcVideoGetBiosMode (
334+ _Out_ PUSHORT Mode )
335+ {
336+ REGS Regs ;
337+
338+ /* Int 10h AH=0Fh
339+ * VIDEO - GET CURRENT VIDEO MODE
340+ *
341+ * AH = 0Fh
342+ * Return:
343+ * AH = number of character columns
344+ * AL = display mode (see #00010 at AH=00h)
345+ * BH = active page (see AH=05h)
346+ *
347+ * Notes: If mode was set with bit 7 set ("no blanking"), the returned
348+ * mode will also have bit 7 set. EGA, VGA, and UltraVision return either
349+ * AL=03h (color) or AL=07h (monochrome) in all extended-row text modes.
350+ * HP 200LX returns AL=07h (monochrome) if mode was set to AL=21h and
351+ * always 80 resp. 40 columns in all text modes regardless of current
352+ * zoom setting (see AH=D0h). When using a Hercules Graphics Card,
353+ * additional checks are necessary:
354+ *
355+ * mode 05h:
356+ * If WORD 0040h:0063h is 03B4h, may be in graphics page 1
357+ * (as set by DOSSHELL and other Microsoft software)
358+ *
359+ * mode 06h:
360+ * If WORD 0040h:0063h is 03B4h, may be in graphics page 0
361+ * (as set by DOSSHELL and other Microsoft software)
362+ *
363+ * mode 07h:
364+ * If BYTE 0040h:0065h bit 1 is set, Hercules card is in
365+ * graphics mode, with bit 7 indicating the page (mode set by
366+ * Hercules driver for Borland Turbo C).
367+ * The Tandy 2000 BIOS is only documented as returning AL, not AH or BH
368+ */
369+ Regs .b .ah = 0x0F ;
370+ Int386 (0x10 , & Regs , & Regs );
371+
372+ if (Regs .b .ah == 0 )
373+ return FALSE;
374+
375+ * Mode = Regs .b .al ;
376+ return TRUE;
377+ }
378+
379+ static VOID
380+ PcVideoGetDisplayMode (VOID )
381+ {
382+ USHORT Mode = 0 ;
383+
384+ /* Is the current mode VESA? */
385+ if (PcVideoVesaGetCurrentSVGAMode (& Mode ) &&
386+ PcVideoVesaGetSVGAModeInformation (Mode , & VesaVideoModeInformation ))
387+ {
388+ TRACE ("VESA mode detected\n" );
389+ ScreenWidth = VesaVideoModeInformation .WidthInPixels ;
390+ ScreenHeight = VesaVideoModeInformation .HeightInPixels ;
391+ BytesPerScanLine = VesaVideoModeInformation .BytesPerScanLine ;
392+ BiosVideoMode = Mode ;
393+ DisplayMode = (0x0108 <= Mode && Mode <= 0x010C ) ? VideoTextMode : VideoGraphicsMode ;
394+ VesaVideoMode = TRUE;
395+ }
396+ /* If not, it should be a regular BIOS mode */
397+ else if (PcVideoGetBiosMode (& Mode ))
398+ {
399+ /*
400+ * The BIOS data area 0x400 holds information about the current video mode.
401+ * Infos at: https://web.archive.org/web/20240119203029/http://www.bioscentral.com/misc/bda.htm
402+ * https://stanislavs.org/helppc/bios_data_area.html
403+ */
404+
405+ UCHAR BiosMode = (* (PUCHAR )0x449 ) & 0x7F ; /* Current video mode */
406+ ASSERT (BiosMode == Mode );
407+ BiosVideoMode = Mode ;
408+ TRACE ("BIOS mode detected\n" );
409+
410+ ScreenWidth = * (PUSHORT )0x44A ; /* Number of screen columns */
411+ ScreenHeight = 1 + * (PUCHAR )0x484 ; /* 1 + "Rows on the screen (less 1, EGA+)" */
412+
413+ /*
414+ * Select bits 7 and 4 of "Video display data area (MCGA and VGA)"
415+ * |7|6|5|4|3|2|1|0|
416+ * | `------ see table below
417+ * `--------- alphanumeric scan lines (see table below)
418+ *
419+ * then convert to a number and map it to the scanline number:
420+ * Bit7 Bit4 Scan Lines
421+ * 0 0 350 line mode
422+ * 0 1 400 line mode
423+ * 1 0 200 line mode
424+ * 1 1 reserved
425+ */
426+ BytesPerScanLine = (* (PUCHAR )0x489 ) & 0x90 ;
427+ BytesPerScanLine = ((BytesPerScanLine & 0x80 ) >> 6 ) | ((BytesPerScanLine & 0x10 ) >> 4 );
428+ switch (BytesPerScanLine )
429+ {
430+ case VERTRES_200_SCANLINES :
431+ BytesPerScanLine = 200 ; break ;
432+ case VERTRES_350_SCANLINES :
433+ BytesPerScanLine = 350 ; break ;
434+ case VERTRES_400_SCANLINES :
435+ BytesPerScanLine = 400 ; break ;
436+ default :
437+ BytesPerScanLine = 160 ; break ;
438+ }
439+
440+ DisplayMode = VideoTextMode ;
441+ VesaVideoMode = FALSE;
442+ }
443+ else
444+ {
445+ /* Set the values for the default text mode.
446+ * If a graphics mode is set, these values will be changed. */
447+ TRACE ("Fallback mode detected\n" );
448+ BiosVideoMode = VIDEOMODE_NORMAL_TEXT ;
449+ ScreenWidth = 80 ;
450+ ScreenHeight = 25 ;
451+ BytesPerScanLine = 160 ;
452+ DisplayMode = VideoTextMode ;
453+ VesaVideoMode = FALSE;
454+ }
455+
456+ TRACE ("This is a %s video mode\n" , VesaVideoMode ? "VESA" : "BIOS" );
457+ TRACE ("BiosVideoMode = 0x%x\n" , BiosVideoMode );
458+ TRACE ("DisplayMode = %sMode\n" , DisplayMode == VideoTextMode ? "Text" : "Graphics" );
459+ TRACE ("ScreenWidth = %lu\n" , ScreenWidth );
460+ TRACE ("ScreenHeight = %lu\n" , ScreenHeight );
461+ TRACE ("BytesPerScanLine = %lu\n" , BytesPerScanLine );
462+ }
463+
274464static BOOLEAN
275465PcVideoSetBiosVesaMode (USHORT Mode )
276466{
@@ -849,6 +1039,14 @@ PcVideoInit(VOID)
8491039{
8501040 /* Detect the installed video card */
8511041 VideoCard = PcVideoDetectVideoCard ();
1042+
1043+ /* Retrieve the initial display mode parameters */
1044+ PcVideoGetDisplayMode ();
1045+
1046+ // FIXME: We don't support graphics modes yet!
1047+ // Revert to 80x25 text mode.
1048+ if (DisplayMode != VideoTextMode )
1049+ PcVideoSetMode (VIDEOMODE_NORMAL_TEXT );
8521050}
8531051
8541052VIDEODISPLAYMODE
0 commit comments