;---------------------------------------------------------------
;                          INFO.ASM
;     Utility to determine and report system parameters
;
;                                      by Jeff Duntemann
;                                      MASM/TASM
;                                      Last update 12/26/89
;---------------------------------------------------------------

INCLUDE MYLIB.MAC               ; Load in macro library

;----------------------------|
;    BEGIN STACK SEGMENT     |
;----------------------------|
MYSTACK    SEGMENT STACK        ; STACK word ensures loading of SS by DOS

           DB      64 DUP ('STACK!!!') ; This reserves 512 bytes for the stack

MYSTACK    ENDS
;----------------------------|
;     END STACK SEGMENT      |
;----------------------------|

;----------------------------|
;     BEGIN DATA SEGMENT     |
;----------------------------|
MyData     SEGMENT

;---------------------------------------------------------------
; DISPLAY INFORMATION VARIABLES
;
; The following block of variables all relate to the video
; system and are initialized by the VidCheck procedure:
;---------------------------------------------------------------
DispType   DB      0       ; Code for display adapter type
VidOrigin  DW      0       ; Offset for FAR pointer to refresh buffer
VidSegment DW      0B000H  ; Segment of installed display buffer
VisibleX   DB      80      ; Number of columns on screen
VisibleY   DB      25      ; Number of lines on screen
VidBufSize DW      4000    ; Default to 25 X 80 X 2 (char & attribute)
FontSize   DB      8       ; Either 8, 14, or 16; default to 8
BordName   DW      ?       ; NEAR pointer to name string of installed board
; 18H = 24D; 4FH = 79D; Combined 0-based X,Y of 80 x 25 screen LR corner:
LRXY       DW      184FH

;---------------------------------------------------------------
; DISPLAY ADAPTER INFORMATION LOOKUP TABLE
;
; This is the lookup table containing information on all legal
; display adapters.  The first field in each element is a 26-
; character string containing a brief description of the
; adapter.  The next field is the segment of the video refresh
; buffer.  The last three fields are the number of screen lines
; an adapter displays when the 8-pixel, 14-pixel, and 16-pixel
; fonts are loaded, respectively.  Note that not all adapters
; support all fonts, but a screen line count is given for all
; three fonts for all adapter types.  Illegal combinations will
; not be accessed.
;---------------------------------------------------------------
VidInfoTbl DB      'No adapter identified      '    ; Code 0
           DW      0B000H
           DB      25,25,25
           DB      'Monochrome Display Adapter '    ; Code 1
           DW      0B000H
           DB      25,25,25
           DB      'Color Graphics Adapter     '    ; Code 2
           DW      0B800H
           DB      25,25,25
           DB      'Code 3: Undefined          '    ; Code 3
           DW      0B000H
           DB      25,25,25
           DB      'EGA with color monitor     '    ; Code 4
           DW      0B800H
           DB      43,25,25
           DB      'EGA with mono monitor      '    ; Code 5
           DW      0B000H
           DB      43,25,25
           DB      'Code 6: Undefined          '    ; Code 6
           DW      0B000H
           DB      25,25,25
           DB      'VGA with mono monitor      '    ; Code 7
           DW      0B000H
           DB      50,27,25
           DB      'VGA with color monitor     '    ; Code 8
           DW      0B800H
           DB      50,27,25
           DB      'Code 9: Undefined          '    ; Code 9
           DW      0B000H
           DB      25,25,25
           DB      'MCGA with digital color    '    ; Code 0AH
           DW      0B800H
           DB      25,25,25
           DB      'MCGA with monochrome       '    ; Code 0BH
           DW      0B000H
           DB      25,25,25
           DB      'MCGA with analog color     '    ; Code 0CH
           DW      0B800H
           DB      25,25,25

Digits     DB      '0123456789ABCDEF' ; Lookup table for numeric/string conv.

;---------------------------------------------------------------
; These two variables are screen-clear "atoms" useable by the
; Clear macro.  The high byte is the display attribute, while
; the low byte is the character with which Clear fills the
; video refresh buffer to clear the screen.
;---------------------------------------------------------------
HToneAtom  DW      07B0H          ; Clears screen to halftone pattern
ClearAtom  DW      0720H          ; Clears screen to blanks

;---------------------------------------------------------------
; This is where all predefined string variables are stored.
;---------------------------------------------------------------
CRLF       DB      0DH,0AH        ; Newline string
IDString   DB      '>>>INFO V1.0'
LIDString  EQU     $-IDString
AuthorStr  DB      '   by Jeff Duntemann'
LAuthorStr EQU     $-AuthorStr
VidIDStr   DB      '   The installed video board is: '
LVidIDStr  EQU     $-VidIDStr
OrgIDStr   DB      '   The segment of the video refresh buffer is: '
LOrgIDStr  EQU     $-OrgIDStr
FontSzStr  DB      '   The size of the current text font is: '
LFontSzStr EQU     $-FontSzStr
ScrnLnStr  DB      '   The number of lines currently on the screen is: '
LScrnLnStr EQU     $-ScrnLnStr
BufSizStr  DB      '   The size of the refresh buffer in bytes is: '
LBufSizStr EQU     $-BufSizStr
DigitStr   DB      '       '
LDigitStr  EQU     $-DigitStr

MyData     ENDS
;----------------------------|
;      END DATA SEGMENT      |
;----------------------------|

;----------------------------|
;     BEGIN CODE SEGMENT     |
;----------------------------|
MyProg     SEGMENT

           ASSUME CS:MyProg,DS:MyData
Main       PROC

Start:     ; This is where program execution begins:
           mov  AX,MyData     ; Set up our own data segment address in DS
           mov  DS,AX         ; Can't load segment reg. directly from memory

           call VidCheck      ; Initialize all video information variables

           Clear VidOrigin,ClearAtom,VidBufSize  ; Clear the screen

           ; Here we display the name of the program and its author:
           Writeln IDString,LIDString      ; Display the program name
           Writeln AuthorStr,LAuthorStr    ; display the author name
           Newline

           ; Here we display the name of the installed video board:
           Write VidIDStr,LVidIDStr        ; Display the intro string
           mov BX,1         ; Select DOS file handle 1: Standard Output
           mov CX,27        ; The name strings are 27 bytes long
           mov DX,BordName  ; The string address is stored in BordName
           mov AH,40H       ; Service 40H: Write string to file
           int 21H          ; Call DOS to display to Standard Output
           Newline

           ; Here we display the segment address of the refresh buffer:
           Write OrgIDStr,LOrgIDStr     ; Display the intro string
           mov  AX,VidSegment ; AX gets the value to convert to a string
           lea  SI,DigitStr   ; String equivalent is written to DigitStr
           call Word2Str      ; Do the actual string conversion
           PokeChar DigitStr,'H',4   ; Append 'H' on the end of the string
           Writeln DigitStr,5 ;  and display the string equivalent

           ; Here we display the size of the current text font:
           Write FontSzStr,LFontSzStr   ; Display the intro string
           mov  AL,FontSize   ; AL gets the value to convert to a string
           lea  SI,DigitStr   ; String equivalent is written to DigitStr
           call Byte2Str      ; Do the actual string conversion
           PokeChar DigitStr,'H',2   ; Append 'H' on the end of the string
           Writeln DigitStr,3 ;  and display the string equivalent

           ; Here we display the number of lines on the screen:
           Write ScrnLnStr,LScrnLnStr
           mov  AL,VisibleY   ; AL gets the value to convert to a string
           lea  SI,DigitStr   ; String equivalent is written to DigitStr
           call Byte2Str      ; Do the actual string conversion
           PokeChar DigitStr,'H',2   ; Append 'H' on the end of the string
           Writeln DigitStr,3 ;  and display the string equivalent

           ;Finally, we display the size of the video refresh buffer:
           Write BufSizStr,LBufSizStr     ; Display the intro string
           mov  AX,VidBufSize ; AX gets the value to convert to a string
           lea  SI,DigitStr   ; String equivalent is written to DigitStr
           call Word2Str      ; Do the actual string conversion
           PokeChar DigitStr,'H',4   ; Append 'H' on the end of the string
           Writeln DigitStr,5 ;  and display the string equivalent
           Newline

           mov  AH,4CH        ; Terminate process DOS service
           mov  AL,0          ; Pass this value back to ERRORLEVEL
           int  21H           ; Control returns to DOS

Main       ENDP


;---------------------------------------------------------------
;   Byte2Str  --  Converts a byte passed in AL to a string at
;                 DS:SI
;   Last update 3/8/89
;
;   1 entry point:
;
;   Byte2Str:
;      Caller must pass:
;      AL : Byte to be converted
;      DS : Segment of destination string
;      SI : Offset of destination string
;
;      This routine converts 8-bit values to 2-digit hexadecimal
;      string representations at DS:SI.
;---------------------------------------------------------------

Byte2Str   PROC
           mov DI,AX                ; Duplicate byte in DI
           and DI,000FH             ; Mask out high 12 bits of DI
           mov BX,OFFSET Digits     ; Load offset of Digits into DI
           mov AH,BYTE PTR [BX+DI]  ; Load digit from table into AH
           mov [SI+1],AH            ;   and store digit into string
           xor AH,AH                ; Zero out AH
           mov DI,AX                ; And move byte into DI
           shr DI,1                 ; Shift high nybble of byte to
           shr DI,1                 ;   low nybble
           shr DI,1
           shr DI,1
           mov AH,BYTE PTR [BX+DI]  ; Load digit from table into AH
           mov [SI],AH              ;   and store digit into string
           ret                      ; We're done--go home!
Byte2Str   ENDP


;---------------------------------------------------------------
;   Word2Str  --  Converts a word passed in AX to a string at
;                 DS:SI
;   Last update 3/8/89
;
;   1 entry point:
;
;   Word2Str:
;      Caller must pass:
;      AX : Word to be converted
;      DS : Segment of destination string
;      SI : Offset of destination string
;---------------------------------------------------------------

Word2Str   PROC
           mov  CX,AX       ; Save a copy of convertee in CX
           xchg AH,AL       ; Swap high and low AX bytes to do high first
           call Byte2Str    ; Convert AL to string at DS:SI
           add  SI,2        ; Bump SI to point to second 2 characters
           mov  AX,CX       ; Reload convertee into AX
           call Byte2Str    ; Convert AL to string at DS:SI
           ret              ; And we're done!
Word2Str   ENDP


;---------------------------------------------------------------
;   VidCheck  --  Identifies display board & display parameters
;   Last update 3/16/89
;
;   1 entry point:
;
;   VidCheck:
;      Caller need pass no parameters.
;      VidCheck identifies the installed display board by
;      calling DispID.  It then calculates numerous display
;      information values, which it then stores in the block
;      of display information variables in the data segment.
;---------------------------------------------------------------

VidCheck   PROC
           ; First task is to figure out which board is on the bus:
           call DispID        ; Ask BIOS for adapter code; returns in AL
           mov  DispType,AL   ; Store display adapter code in DispType

           ; Next we determine the font size currently in force:
           cmp  AL,0AH        ; See if board is an MCGA
           jl   TryOld        ; If less than code 0AH, it's not an MCGA
           mov  FontSize,16   ; MCGA supports *only* 16 pixel text font
           jmp  GetName       ; Jump ahead to look up adapter name string
TryOld:    cmp  DispType,1    ; Is the display adapter code 1, for MDA?
           jne  TryCGA        ; If not, go test for CGA code 2
           mov  FontSize,14   ; MDA uses *only* 14-pixel text font
           jmp  GetName       ; Jump ahead to look up adapter name string
TryCGA:    cmp  DispType,2    ; Is the display adapter code 2, for CGA?
           jne  TryVGA        ; If not, go test for EGA/VGA font size
           mov  FontSize,8    ; CGA uses *only* 8-pixel text font
           jmp  GetName       ; Jump ahead to look up adapter name string
TryVGA:    mov  AH,11H        ; Select VIDEO Get Font Information subservice
           mov  AL,30H        ;   requires AH = 11H and AL = 30H
           mov  BH,0          ; 0 = Get info about current font
           int  10H           ; Call VIDEO
           mov  FontSize,CL   ; Font size in pixels is returned in CL

           ; Next we get the name string for the board from the info table:
GetName:   mov  AL,DispType   ; Load display adapter code into AL
           xor  AH,AH         ; Zero AH so we don't copy trash into DI
           mov  DI,AX         ; Copy AX (with code in AL) into DI
           mov  CL,5          ; We must shift the code 5 bits to mult. by 32
           shl  DI,CL         ; Multiply code by 32 to act as table index
           lea  BX,VidInfoTbl ; Load address of origin table into BX
           mov  BordName,BX   ; Save pointer to video info. table in BordName
           add  Bordname,DI   ; Add offset into table to right element

           ; Next we get the refresh buffer segment from the table:
           mov  AX,[BX+DI+27] ; Index into table past name string to segment
           mov  VidSegment,AX ; Store segment from table to VidSegment variable

           ; Here we calculate the number of lines on-screen from font size:
           xor  AH,AH         ; Make sure AH has no trash in it
           mov  AL,FontSize   ; Load the font size in pixels into AL
           cmp  AL,8          ; Is it the 8-pixel font?
           jne  Try14         ; If not, try the 14-pixel font
           mov  AL,1          ; The 8-pixel font is table offset 1
           jmp  ReadLns       ; Jump ahead to read screen lines from table
Try14:     cmp  AL,14         ; Is it the 14-pixel font?
           jne  Do16          ; If not, it has to be the 16-pixel font
           mov  AL,2          ; The 14-pixel font is table offset 2
           jmp  ReadLns       ; Jump ahead to read screen lines from table
Do16:      mov  AL,3          ; The 16-pixel font is table offset 3
ReadLns:   add  DI,AX         ; Add font size offset to table element offset
           mov  AL,[BX+DI+28] ; Load the screen lines value from the table
           mov  VisibleY,AL   ;  and store it in the VisibleY variable
           mov  AH,VisibleX   ; Load the screen columns value to AH
           xchg AH,AL         ; Exchange AH & AL for 0-basing
           dec  AL            ; Subtract one from column count for 0-basing
           dec  AH            ; Subtract one from line count for zero-basing
           mov  LRXY,AX       ; And store 0-based X,Y word into LRXY variable

           ; Finally, we calculate the size of the refresh buffer in bytes:
           mov  AL,VisibleY   ; We multiply screen lines time screen columns
           mul  VisibleX      ;  times 2 (for attributes) to get buffer size
           shl  AX,1          ; Multiply lines * columns by 2
           mov  VidBufSize,AX ; Store refresh buffer size in VidBufSize

           ret                ; Return to caller
VidCheck   ENDP


;---------------------------------------------------------------
;   DispID  --  Identifies the installed display adapter
;   Last update 3/8/89
;
;   1 entry point:
;
;   DispID:
;      Caller passes no parameters
;      Routine returns a code value in AX.
;      The codes are these:
;      0 : Adapter is unknown; recommend aborting
;      1 : MDA (Monochrome Display Adapter)
;      2 : CGA (Color Graphics Adapter)
;
;---------------------------------------------------------------

DispID     PROC
           mov  AH,1AH      ; Select PS/2 Identify Adapter Service
           xor  AL,AL       ; Select Get Combination Code Subservice (AL=0)
           int  10H         ; Call VIDEO
           cmp  AL,1AH      ; If AL comes back with 1AH, we have a PS/2
           jne  TryEGA      ; If not, jump down to test for the EGA
           mov  AL,BL       ; Put Combination Code into AL
           ret              ;   and go home!
TryEGA:    mov  AH,12H      ; Select EGA Alternate Function
           mov  BX,10H      ; Select Get Configuration Information subservice
           int  10H         ; Call VIDEO
           cmp  BX,10H      ; If BX comes back unchanged, EGA is *not* there
           je   OldBords    ; Go see whether it's an MDA or CGA
           cmp  BH,0        ; If BH = 0, it's an EGA/color combo
           je   EGAColor    ;   otherwise it's EGA/mono
           mov  AL,5        ; Store code 5 for EGA mono
           ret              ;   and go home!
EGAColor:  mov  AL,4        ; Store code 4 for EGA color
           ret              ;   and go home!
OldBords:  int  11H         ; Call Equipment Configuration interrupt
           and  AL,30H      ; Mask out all but bits 4 & 5
           cmp  AL,30H      ; If bits 4 & 5 are both =1, it's an MDA
           jne  CGA         ;   otherwise it's a CGA
           mov  AL,1        ; Store code 1 for MDA
           ret              ;   and go home!
CGA:       mov  AL,2        ; Store code 2 for CGA
           ret              ;   and go home!
DispID     ENDP


MyProg     ENDS

;----------------------------|
;      END CODE SEGMENT      |
;----------------------------|

           END Start    ; The procedure named Start becomes the main program
