;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
;/*****************************************************************************
;*
;* SOURCE FILE NAME = svgaid.asm
;*
;* DESCRIPTIVE NAME = Identify a super VGA adapter in the system, if one exsts.
;*
;*
;* VERSION      V2.0
;*
;* DATE
;*
;* DESCRIPTION  Identify a super VGA adapter in the system, if one exists.
;*
;*              extern void _IdentifySVGA (void);
;*
;*              Call from 'C' as:
;*
;*                      IdentifySVGA();
;*
;* FUNCTIONS
;*              UpperCaseSearch
;*              FindStringExpansion
;*              FindStringSomewhere
;*              FindStringPlanar
;*              FindString
;*              LookStringExpansion
;*              LookStringSomewhere
;*              LookStringPlanar
;*              LookString
;*              TextDelay
;*              OutpwDelay
;*              OutpDelay
;*              OutpData
;*              InpDelay
;*              InpwDelay
;*              InpData
;*              OutpInp
;*              OutpChk
;*              OutpIdxInpData
;*              SaveOutpChk
;*              OutpIdxXchgData
;*              OutpIdxChkXchgData
;*              OutpwChk
;*              SaveOutpwChk
;*              SaveXORChk
;*              SaveXORConst
;*              GetPortBase
;*              GetCrtcBase
;*              GetCrtcBaseSave1
;*              GetSave1
;*              GetSave2
;*              GetCrtcBaseSave2
;*              RestoreSave2
;*              RestoreSave1
;*              ATCOutpIdx
;*              IsNoCrtCWrap
;*              IsNOTISAAliased
;*              ATIWaitIdle
;*              ATIOutpChk
;*              ATIDestXOutpChk
;*              ATIAccelerator
;*              IsATI
;*              IsSpeedWay
;*              IsTrident
;*              IsTseng
;*              Video7EnableExt
;*              Video7DisableExt
;*              IsVideo7
;*              IsChips
;*              IsWeitek
;*              IsWeitekP9x00
;*              IsWesternDig
;*              WhichATI
;*              WhichTrident
;*              TsengSetATCMisc
;*              TsengLock
;*              TsengEnableExt
;*              TsengDisableExt
;*              WhichTseng
;*              WhichVideo7
;*              WhichWeitek
;*              WhichWeitekP9x00
;*              WhichWesternDig
;*              _IdentifySVGA
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;* EXTERNAL FUNCTIONS
;*
;****************************************************************************

        PAGE    58,132
        TITLE   SVGA Idenfication Routines - (svgaid.asm)

INCL_16         EQU     1                                      ;/*          */

ifdef SVGAUTIL
        .286
;!! Should this be imported somehow?                           ;/*          */
DOSIODELAYCNT   EQU     10
else ;/* SVGAUTIL */
        .386p
        include devhlp.inc              ;Define DevHlp functions
endif ;/* SVGAUTIL */


.xlist
        include struc.inc                                      ;/*          */
        include iodelay.inc                                    ;/*          */
        UNDEFINE_SVGA   EQU     1       ; exclude various unwanted defs
        include svgadefs.inc            ;          
.list

;!! How do we insure no one interrupts us while we do this?     /*          */
;* There is some chance of incorrect results here,              /*          */
;* due to an interrupting process which changes the contents of /*          */
;* of some VGA index register(s) between our setting them,      /*          */
;* and our reading or setting the associated data register.     /*          */
;* A screen saver program would be an example such process.     /*          */

;/*
;**     Stuff which should be private
;*/

;           all important indicies and values are saved on the stack
; STACK FRAME for identify routines
;Index/Value pairs must be in consecutive bytes for load by word.
;Reorder for easy loading                                       /*          */
SaveValue1      EQU   <BYTE PTR [bp-1]>         ; BYTE
SaveIndex1      EQU   <BYTE PTR [bp-2]>         ; BYTE
SaveReg1        EQU   <WORD PTR [bp-4]>         ; WORD
SaveValue2      EQU   <BYTE PTR [bp-5]>         ; BYTE
SaveIndex2      EQU   <BYTE PTR [bp-6]>         ; BYTE
SaveReg2        EQU   <WORD PTR [bp-8]>         ; WORD
SaveValue3      EQU   <BYTE PTR [bp-9]>         ; BYTE
SaveIndex3      EQU   <BYTE PTR [bp-10]>        ; BYTE
SaveReg3        EQU   <WORD PTR [bp-12]>        ; WORD
SaveValue4      EQU   <BYTE PTR [bp-13]>        ; BYTE
SaveIndex4      EQU   <BYTE PTR [bp-14]>        ; BYTE
SaveReg4        EQU   <BYTE PTR [bp-16]>        ; WORD
STACKBLOCK      EQU   16

DGROUP  GROUP   BioData

        EXTRN   _sSVGA:DWORD            ;                       /*          */
        EXTRN   _XGAInstance:WORD       ;                       /*          */
ifndef SVGAUTIL
        EXTRN  PCI_DeviceTbl:DWORD     ;@senja array of upto 8 (hw=Vendow ID, lw=Device ID)
        EXTRN  PCI_Num:WORD            ;@senja number of PCI devices found
endif

ifdef SVGAUTIL
BioData SEGMENT WORD PUBLIC 'DATA'
else
BioData SEGMENT WORD PUBLIC 'DATA' USE16
endif ;/* SVGAUTIL */

        ASSUME  DS:DGROUP


ifdef SVGAUTIL
else
        EXTRN DevHelp: DWORD
endif ;/* SVGAUTIL */

PUBLIC  SvgaOEMInfo
PUBLIC  SvgaBaseAddr
PUBLIC  DATA_END

SvgaOEMInfo     OEMINFO <SIZE OEMINFO,,>  ;@senja
SvgaBaseAddr    DD      0

;
; The following label defines the end of the Screen resident data.
;
DATA_END LABEL  BYTE

ATISig          DB      ' 761295520'    ; 
DiamondViperSig DB      'VIPER'         ;                       /*          */
WDSig           DB      'VGA='          ; 
WeitekSig       DB      'WEITEK'        ;                       /*          */
;                                                               /*          */
;       SEQ06 == Everybody's favorite lock register!            /*          */
;                                                               /*          */
;       But since WD and Video7 made the restore value          /*          */
;       not DIRECTLY readable, we cannot just read it           /*          */
;       while poking around looking for something else and      /*          */
;       restore what we read, expecting to preserve things!     /*          */
;                                                               /*          */
;       In fact, we CANNOT restore SEQ06 until after we know    /*          */
;       which adapter it is!                                    /*          */
;                                                               /*          */
;       But we CAN read enough without knowing which adapter    /*          */
;       to restore SEQ06 once we know which adapter!            /*          */
;                                                               /*          */
;       WD's SEQ06 restore value can be determined from         /*          */
;       how many bits the sequencer index preserves             /*          */
;       when you write to it: 6 unlocked, 3 locked.             /*          */
;                                                               /*          */
;       Video's SEQ06 restore value can be determined from      /*          */
;       the bit zero of what you read from SEQ06.               /*          */
;                                                               /*          */
;       Cirrus uses SEQ06 as a lock,                            /*          */
;       but at least you can read it! (Thank you!)              /*          */
;                                                               /*          */
SEQ06           DB      ?               ;What we will restore!  /*          */
SEQ06WD         DB      ?               ;Unless we are WD!      /*          */

BioData ends



ifdef SVGAUTIL
BiosSeg SEGMENT WORD Public 'CODE'
else
BiosSeg SEGMENT WORD Public 'CODE' USE16
endif ;/* SVGAUTIL */

BIOSSeg ends




;;endif ;endif svgautil

; set opcodes back to normal

ifdef SVGAUTIL
        .286
else ;/* SVGAUTIL */
        .386p
endif ;/* SVGAUTIL */


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; end jwk18



ifdef SVGAUTIL
BiosSeg SEGMENT WORD Public 'CODE'
else
BiosSeg SEGMENT WORD Public 'CODE' USE16
endif ;/* SVGAUTIL */

        ASSUME  CS:BiosSeg

;/****************************************************************************
;*
;* FUNCTION NAME = SVGAPhysToVirt
;*
;* DESCRIPTION   = Convert physical address to virtual.
;*
;* INPUT     =  AX = address high
;*              BX = address low
;*              CX = length
;* OUTPUT    =  DS:SI = selector/offset pair.
;*
;* RETURN-NORMAL = NC if no errors.
;* RETURN-ERROR  = CR if errors.
;*
;****************************************************************************/

SVGAPhysToVirt  PROC    Near
                PUBLIC  SVGAPhysToVirt

ifdef SVGAUTIL
        mov     si, ax
        ror     si, 4
        and     si, 0f000h              ;Clears carry too!
        mov     ds, si
        mov     si, bx
else
        push    dx                      ;                       /*          */
        mov     dh, 0                   ; 
        mov     dl, DevHlp_PhysToVirt
        call    DevHelp                 ;Leave result in DS:SI
        pop     dx                      ;                       /*          */
endif ;/* SVGAUTIL */

        ret

SVGAPhysToVirt  ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = SVGAUnPhysToVirt
;*
;* DESCRIPTION   = Unconvert physical address to virtual.
;*
;* INPUT     =  AX = address high
;*              BX = address low
;*              CX = length
;* OUTPUT    =  NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;****************************************************************************/

SVGAUnPhysToVirt PROC   Near
                PUBLIC  SVGAUnPhysToVirt

ifdef SVGAUTIL
        clc                             ;Return NC.
else
        push    dx                      ;                       /*          */
        mov     dl, DevHlp_UnPhysToVirt ;Let DevHlp know we're done
        pushf                           ;Save results flags     /*          */
        call    DevHelp                 ; using virtual addresses.
        popf                            ;Restore results flags  /*          */
        pop     dx                      ;                       /*          */
endif ;/* SVGAUTIL */

        ret

SVGAUnPhysToVirt ENDP

;*                                                             ;/*          */
;/****************************************************************************
;*
;* FUNCTION NAME = SVGAPhysToUVirt
;*
;* DESCRIPTION   = Convert physical address to virtual.
;*
;* INPUT     =  AX = address high
;*              BX = address low
;*              CX = length
;* OUTPUT    =  ES:BX = selector/offset pair.
;*
;* RETURN-NORMAL = NC if no errors.
;* RETURN-ERROR  = CR if errors.
;*
;****************************************************************************/

SVGAPhysToUVirt PROC    Near
                PUBLIC  SVGAPhysToUVirt

ifdef SVGAUTIL
;*
;*!!This is a non-working "safe"? dummy routine which points to ROM.
;*!!What we really need is an extension to the DOS XMS specification
;*!!or a ROM BIOS routine which handles 32-bit (not 24-bit) addresses,
;*!!which would provide a handle to physical memory         which do not
;*!!have RAM in them.
;*
        mov     si, 0f000h              ;Point to ROM in case no carry check!
        mov     es, si
        mov     si, bx
        stc                             ;Always an error for now!
else
        push    dx                      ;                       /*          */
        mov     dh, 004h                ;Read/Write Segment&I/O Privilege
        mov     dl, DevHlp_PhysToUVirt
        call    DevHelp
        pop     dx                      ;                       /*          */
endif ;/* SVGAUTIL */

        ret

SVGAPhysToUVirt ENDP

;*                                                             ;/*          */
;/****************************************************************************
;*
;* FUNCTION NAME = SVGAUnPhysToUVirt
;*
;* DESCRIPTION   = Unconvert physical address to virtual.
;*
;* INPUT     =  ES = selector to virtual address.
;* OUTPUT    =  NONE
;*
;* RETURN-NORMAL = NC if no errors.
;* RETURN-ERROR  = CR if errors.
;*
;****************************************************************************/

SVGAUnPhysToUVirt PROC   Near
                PUBLIC  SVGAUnPhysToUVirt

ifdef SVGAUTIL
        clc                             ;Return NC.
else
        push    ax                      ;                       /*          */
        mov     ax, es                  ;DevHelp Selector reg   /*          */
        push    dx                      ;                       /*          */
        mov     dh, 002h                ;UnMap
        mov     dl, DevHlp_PhysToUVirt
        pushf                           ;Save results flags     /*          */
        call    DevHelp
        popf                            ;Restore results flags  /*          */
        pop     dx                      ;                       /*          */
        pop     ax                      ;                       /*          */
endif ;/* SVGAUTIL */

        ret

SVGAUnPhysToUVirt ENDP


;***    UpperCaseSearch
;          
;       Entry:  DS : SI Starting address of the string
;               CX = length of string
;               ES : DI ROM address to compare with
;
;       Capitalize the string at the location.
;       Restores all entry registers
;
;* RETURN-NORMAL = ZR if found.
;* RETURN-ERROR  = NZ if not found.
;
UpperCaseSearch PROC    Near
                PUBLIC  UpperCaseSearch

        push    cx                      ;                       /*          */
        jcxz    ExitUpperCase           ;Exit w/CX zero=success!/*          */
        push    ax                      ;                       /*          */
        push    si                      ;                       /*          */
        push    di                      ;                       /*          */
UpperCaseLoop:                          ;                       /*          */
        mov     al, byte ptr ds:[si]
        cmp     al, 'a'
        jl      short @F
        cmp     al, 'z'
        jg      short @F
        sub     al, 20h
@@:
        cmp     es:[di], al
        jne     StringNotFound          ;Exit with CX non zero=failure!
        inc     si
        inc     di
        loop    UpperCaseLoop           ;Loop or w/CX=success!  /*          */
StringNotFound:                         ;                       /*          */
        pop     di                      ;                       /*          */
        pop     si                      ;                       /*          */
        pop     ax                      ;                       /*          */
ExitUpperCase:
        and     cx, cx                  ;Success=no chars left  /*          */
        pop     cx                      ;                       /*          */
        ret

UpperCaseSearch ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = FindStringExpansion
;*
;* DESCRIPTION   =
;*      Look for string at C000:xxxx ROM BIOS location to identify a SVGA card.
;*                 Capitalize the string searched as to make it case insensitive.
;*
;* INPUT     =  BX = ROM address (low)
;*              CX = length of string
;*              DS:DI -> string to compare (in DGROUP)
;*
;* OUTPUT    =  AX = 0000ch
;*
;* RETURN-NORMAL = ZR if found.
;* RETURN-ERROR  = NZ if not found.
;*
;****************************************************************************/

FindStringExpansion PROC    Near
                PUBLIC  FindStringExpansion

        mov     ax, 0000ch              ;                       /*          */
;       Now fall thru to (call and return):

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = FindStringSomewhere
;*
;* DESCRIPTION   =
;*      Look for string at ROM BIOS location to identify a SVGA card.
;*                 Capitalize the string searched as to make it case insensitive.
;*
;* INPUT     =  AX = ROM address (high)
;*              BX = ROM address (low)
;*              CX = length of string
;*              DS:DI -> string to compare (in DGROUP)
;*
;* OUTPUT    =  NONE
;*
;* RETURN-NORMAL = ZR if found.
;* RETURN-ERROR  = NZ if not found.
;*
;****************************************************************************/

FindStringSomewhere PROC    Near
                PUBLIC  FindStringSomewhere

        push    es
        push    ds
        push    ds                      ;Move match string selector to ES.
        pop     es
        call    SVGAPhysToVirt          ;Get virtual address into DS:SI.

        ASSUME  DS:NOTHING, ES:DGROUP

        cld
;       xor     ax, ax                  ;                       /*          */
        call    UpperCaseSearch
        pop     ds                      ;Restore DEVHLP ptr selector!
        pop     es

        ASSUME  DS:DGROUP, ES:NOTHING

        call    SVGAUnPhysToVirt        ;Unmap AX:BX.
        ret

FindStringSomewhere     ENDP

FindStringExpansion     ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = FindStringPlanar
;*
;* DESCRIPTION   =
;*      Look for string at E000:xxxx ROM BIOS location to identify a SVGA card.
;*                 Capitalize the string searched as to make it case insensitive.
;*
;* INPUT     =  BX = ROM address (low)
;*              CX = length of string
;*              DS:DI -> string to compare (in DGROUP)
;*
;* OUTPUT    =  AX = 0000eh
;*
;* RETURN-NORMAL = ZR if found.
;* RETURN-ERROR  = NZ if not found.
;*
;****************************************************************************/

FindStringPlanar PROC    Near
                PUBLIC  FindStringPlanar

        mov     ax, 0000eh              ;                       /*          */
        call    FindStringSomewhere
        ret

FindStringPlanar     ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = FindString
;*
;* DESCRIPTION   =
;*      Look for string at ROM BIOS location to identify a SVGA card.
;*                 Capitalize the string searched as to make it case insensitive.
;*
;* INPUT     =  BX = ROM address (low)
;*              CX = length of string
;*              DS:DI -> string to compare (in DGROUP)
;*
;* OUTPUT    =  AX = ROM address (high)
;*
;* RETURN-NORMAL = ZR if found.
;* RETURN-ERROR  = NZ if not found.
;*
;****************************************************************************/

FindString      PROC    Near
                PUBLIC  FindString

        call    FindStringExpansion
        .if     < nz >                  ;If not found on expansion card:
            call    FindStringPlanar    ;Try planar ROM instead.
        .endif
        ret

FindString      ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = LookStringExpansion
;*
;* DESCRIPTION   =
;*      Look for string at C000:0-200 ROM BIOS location to identify a SVGA card.
;*                 Capitalize the string searched as to make it case insensitive.
;*
;* INPUT     =  CX = length of string
;*              DS:DI -> string to compare (in DGROUP)
;*
;* OUTPUT    =  AX = 0000ch
;*
;* RETURN-NORMAL = ZR if found.
;* RETURN-ERROR  = NZ if not found.
;*
;****************************************************************************/

LookStringExpansion PROC    Near
                PUBLIC  LookStringExpansion

        mov     ax, 0000ch              ;                       /*          */
;       Now fall thru to (call and return):

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = LookStringSomewhere
;*
;* DESCRIPTION   =
;*      Look for string at ROM BIOS offsets 0-200 to identify a SVGA card.
;*                 Capitalize the string searched as to make it case insensitive.
;*
;* INPUT     =  AX = ROM address (high)
;*              CX = length of string
;*              DS:DI -> string to compare (in DGROUP)
;*
;* OUTPUT    =  NONE
;*
;* RETURN-NORMAL = ZR if found.
;* RETURN-ERROR  = NZ if not found.
;*
;****************************************************************************/

LookStringSomewhere PROC    Near
                PUBLIC  LookStringSomewhere

        push    bx
        push    es
        push    ds
        push    cx                      ;Save string length.
        push    ds                      ;Move match string selector to ES.
        pop     es
        xor     bx, bx                  ;Low offset zero.
        add     cx, 00200h              ;Limit search to first 200 bytes.
        call    SVGAPhysToVirt          ;Get virtual address into DS:SI.
        pop     cx                      ;Restore string length

        ASSUME  DS:NOTHING, ES:DGROUP

        cld
;       xor     ax, ax                  ;                       /*          */
        .repeat
            call    UpperCaseSearch
        .until  <e> OR                  ;Until string found (z).
            inc     si                  ;Check next location in ROM.
        .until  <si a 00200h>           ;Until no more locations to check (nz).
        pop     ds                      ;Restore DEVHLP ptr selector!
        pop     es

        ASSUME  DS:DGROUP, ES:NOTHING

        call    SVGAUnPhysToVirt        ;Unmap AX:BX.
        pop     bx
        ret

LookStringSomewhere     ENDP

LookStringExpansion     ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = LookStringPlanar
;*
;* DESCRIPTION   =
;*      Look for string at E000:0-200 ROM BIOS location to identify a SVGA card.
;*                 Capitalize the string searched as to make it case insensitive.
;*
;* INPUT     =  CX = length of string
;*              DS:DI -> string to compare (in DGROUP)
;*
;* OUTPUT    =  AX = 0000eh
;*
;* RETURN-NORMAL = ZR if found.
;* RETURN-ERROR  = NZ if not found.
;*
;****************************************************************************/

LookStringPlanar PROC    Near
                PUBLIC  LookStringPlanar

        mov     ax, 0000eh              ;                       /*          */
        call    LookStringSomewhere
        ret

LookStringPlanar     ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = LookString
;*
;* DESCRIPTION   =
;*      Look for string at ROM BIOS offsets 0-200 to identify a SVGA card.
;*                 Capitalize the string searched as to make it case insensitive.
;*
;* INPUT     =  CX = length of string
;*              DS:DI -> string to compare (in DGROUP)
;*
;* OUTPUT    =  AX = ROM address (high)
;*
;* RETURN-NORMAL = ZR if found.
;* RETURN-ERROR  = NZ if not found.
;*
;****************************************************************************/

LookString      PROC    Near
                PUBLIC  LookString

        call    LookStringExpansion
        .if     < nz >                  ;If not found on expansion card:
            call    LookStringPlanar    ;Try planar ROM instead.
        .endif
        ret

LookString      ENDP

;*
;*      All input and output instructions were deliberately put into
;*      separate subroutines to insure that a TextDelay preceeded each.
;*      Even though the chip being LOOKED FOR often does not need such
;*      delays, the chip being TESTED may need them!
;*
;*      We need to be able to minimize changes made to the chip being TESTED
;*      and restore it to its original state when we are done,
;*      so that we minimize the potential for annoying or damaging
;*      "special effects" on OTHER manufacturer's chips.
;*

;/****************************************************************************
;*
;* FUNCTION NAME = TextDelay
;*
;* DESCRIPTION   = Instead of using the macro to save code space
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*                 WARNING - trashes si
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*      OutpwDelay
;*      OutpDelay
;*      InpDelay
;*      InpwDelay
;*
;****************************************************************************/

TextDelay       PROC    Near            ; 
                PUBLIC  TextDelay       ; 

        push       si                   ;                       ;JWK07
        pushf                           ;Save flag register.    /*          */
        DevIODelay si                   ; 
        popf                            ;Restore flags.         /*          */
        pop        si                   ;                       ;JWK07
        ret                             ; 

TextDelay       ENDP                    ; 

;/****************************************************************************
;*
;* FUNCTION NAME = _TextDelay
;*
;* DESCRIPTION   = Instead of using the macro to save code space
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*      InputDelay
;*      OutputDelay
;*
;****************************************************************************/

_TextDelay      PROC    Far             ;                       /*          */
                PUBLIC  _TextDelay      ; 

        call    TextDelay               ; 
        ret

_TextDelay      ENDP                    ; 

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = OutpwDelay
;*
;* DESCRIPTION   = Output to word port preceeded by I/O delay.
;*
;* INPUT         = DX = Output port.
;*                 AX = Value to output.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

OutpwDelay      PROC    Near
                PUBLIC  OutpwDelay

        call    TextDelay               ;IMMEDIATELY before to minimize delay!
        out     dx, ax                  ;Output to port.
        ret

OutpwDelay       ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = OutpDelay
;*
;* DESCRIPTION   = Output to byte port preceeded by I/O delay.
;*
;* INPUT         = DX = Output port.
;*                 AL = Value to output.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

OutpDelay       PROC    Near
                PUBLIC  OutpDelay

        call    TextDelay               ;IMMEDIATELY before to minimize delay!
        out     dx, al                  ;Output to port.
        ret

OutpDelay        ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = OutpData
;*
;* DESCRIPTION   = Output to byte port preceeded by I/O delay.
;*
;* INPUT         = DX = Output index port.
;*                 AL = Data value to output.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

OutpData        PROC    Near
                PUBLIC  OutpData

        inc     dx                      ;Point to data register.
        call    OutpDelay               ; 
        dec     dx                      ;Point back to index register.
        ret

OutpData        ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = InpDelay
;*
;* DESCRIPTION   = Input from byte port preceeded by I/O delay.
;*
;* INPUT         = DX = Input port.
;* OUTPUT        = AL = Input value.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

InpDelay        PROC    Near
                PUBLIC  InpDelay

        call    TextDelay               ;IMMEDIATELY before to minimize delay!
        in      al, dx                  ;Input from port.
        ret

InpDelay        ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = InpwDelay
;*
;* DESCRIPTION   = Input from word port preceeded by I/O delay.
;*
;* INPUT         = DX = Input port.
;* OUTPUT        = AX = Input value.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

InpwDelay       PROC    Near
                PUBLIC  InpwDelay

        call    TextDelay               ;IMMEDIATELY before to minimize delay!
        in      ax, dx                  ;Input from port.
        ret

InpwDelay       ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = InpData
;*
;* DESCRIPTION   = Input from byte port preceeded by I/O delay.
;*
;* INPUT         = DX = Output index port.
;* OUTPUT        = AL = Data value input.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*      OutpIdxInpData
;*      IsTrident
;*      IsWeitek
;*      IsWeitekP9x00
;*      WhichWesternDig
;*
;****************************************************************************/

InpData         PROC    Near
                PUBLIC  InpData

        inc     dx                      ;Point to data register.
        call    InpDelay                ; 
        dec     dx                      ;Point back to index register.
        ret

InpData         ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = OutpInp
;*
;* DESCRIPTION   = Output to byte port and re-read it.
;*
;* INPUT         = DX = Input port.
;*                 AL = New value.
;* OUTPUT        = AL = Modified new value.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*      OutpChk
;*      SaveXORConst
;*      IsNotISAAliased
;*      IsCirrus
;*
;****************************************************************************/

OutpInp         PROC    Near
                PUBLIC  OutpInp

        call    OutpDelay               ;Write byte out.
        call    InpDelay                ;Read modified byte back.
        ret

OutpInp         ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = OutpChk
;*
;* DESCRIPTION   = Test for read/write register.
;*
;* INPUT         = DX = port address.
;*                 AL = new value.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ZR (reads match writes).
;* RETURN-ERROR  = NZ (reads do not match writes).
;*
;* CALLED BY
;*      SaveOutpChk
;*      OutpIdxXchgData
;*      OutpIdxChkXchgData
;*      OutpwChk
;*      SaveXORChk
;*      ATCOutpIdx
;*      IsTseng
;*      LastAttempt
;*
;****************************************************************************/

OutpChk         PROC    Near
                PUBLIC  OutpChk

        push    ax
        mov     ah, al                  ;Save value written.
        call    OutpInp                 ;Write new & read modified value.
        cmp     al, ah                  ;Was read same as write?
        pop     ax
        ret

OutpChk         ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = OutpIdxInpData
;*
;* DESCRIPTION   = Read indexed register.
;*
;* INPUT         = DX = port address.
;*                 AL = index.
;* OUTPUT        = AL = value read.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*      OutpIdxXchgData
;*      IsNoCrtcWrap
;*      IsS3
;*      TsengSetATCMisc
;*      IsVideo7
;*      WDRegPairString
;*      IsWeitek
;*      IsWeitekP9x00
;*      LastAttempt
;*      WhichATI
;*      WhichCirrus
;*      WhichS3
;*      WhichTrident
;*      WhichTseng
;*      WhichVideo7
;*      WhichWeitek
;*      WhichWesternDig
;*
;****************************************************************************/

OutpIdxInpData  PROC    Near
                PUBLIC  OutpIdxInpData

        call    OutpDelay               ;Write the new index value.
        call    InpData                 ;Read the data value.
        ret

OutpIdxInpData  ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = SaveOutpChk
;*
;* DESCRIPTION   = Test for read/write register.
;*
;* INPUT         = DX = port address.
;*                 AL = new value.
;* OUTPUT        = NONE
;*                 original value restored.
;*
;* RETURN-NORMAL = ZR (reads match writes).
;* RETURN-ERROR  = NZ (reads do not match writes).
;*
;* CALLED BY
;*      OutpIdxChkXchgData
;*      OutpwChk
;*      SaveOutpwChk
;*      LastAttempt
;*
;****************************************************************************/

SaveOutpChk     PROC    Near
                PUBLIC  SaveOutpChk

        push    ax
        mov     ah, al                  ;Save new value.
        call    InpDelay                ;Read the original value.
        xchg    ah, al                  ;Save original value, use new.
        call    OutpChk                 ;Write new value and compare.
        mov     al, ah                  ;Get back old value.
        call    OutpDelay               ;Restore old value if possible.
        .if     < z >                   ;If new value was the same,
            call    InpDelay            ;Read back the value.
            cmp     al, ah              ;Was read same as write?
        .endif
        pop     ax
        ret

SaveOutpChk     ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = OutpIdxXchgData
;*
;* DESCRIPTION   = Read and save indexed register, write with new value.
;*
;* INPUT         = DX = port address.
;*                 AL = index.
;*                 AH = new value to write.
;* OUTPUT        = AL = value read.
;*                 This value can be/must be "restored" to register addressed
;*                 with the INPUT index.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*      IsCirrus
;*      IsTrident
;*      WhichS3
;*
;****************************************************************************/

OutpIdxXchgData PROC    Near
                PUBLIC  OutpIdxXchgData

        call    OutpIdxInpData          ;Read the original value.
        xchg    al, ah                  ;Exchange old & new values.
        call    OutpData                ;Test for read/writable reg
        xchg    al, ah                  ;Exchange old & new values.
        ret

OutpIdxXchgData ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = OutpIdxChkXchgData
;*
;* DESCRIPTION   = Read and save indexed register, write with new value.
;*
;* INPUT         = DX = port address.
;*                 AL = index.
;*                 AH = new value to write.
;* OUTPUT        = AL = value read.
;*                 This value can be/must be "restored" to register addressed
;*                 with the INPUT index, even when error (NZ) returned!
;*
;* RETURN-NORMAL = ZR (reads match writes).
;* RETURN-ERROR  = NZ (reads do not match writes).
;*
;* CALLED BY
;*      GetCrtcBaseSave2
;*      IsCirrus
;*      Video7EnableExt
;*      IsVideo7
;*      WDEnableExt
;*      WhichCirrus
;*
;****************************************************************************/

OutpIdxChkXchgData PROC    Near
                PUBLIC  OutpIdxChkXchgData

        call    SaveOutpChk             ;Test for read/writeable index reg.
        pushf                           ;Save flags.
        call    OutpIdxInpData          ;Read the original value.
        popf                            ;Restore flags.
        .if     < z >                   ;If read/write index:
            xchg    al, ah              ;Exchange old & new values.
            push    dx
            inc     dx                  ;Point to the data register.
            call    OutpChk             ;Test for read/writable reg
            pop     dx
            xchg    al, ah              ;Exchange old & new values.
        .endif
        ret

OutpIdxChkXchgData ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = OutpwChk
;*
;* DESCRIPTION   = Test for read/write indexed/word register.
;*
;* INPUT         = DX = port address.
;*                 AX = index (AL) and new value (AH).
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ZR (reads match writes).
;* RETURN-ERROR  = NZ (reads do not match writes).
;*
;* CALLED BY
;*      WhichCirrus
;*
;****************************************************************************/

OutpwChk        PROC    Near
                PUBLIC  OutpwChk

        call    SaveOutpChk             ;Check index set.
        .if     < z >                   ;If no error setting index:
            push    dx
            call    OutpDelay           ;Write the new index value.
            inc     dx                  ;Point to the data register.
            xchg    al, ah              ;Get new value.
            call    OutpChk
            xchg    al, ah
            pop     dx
        .endif
        ret

OutpwChk          ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = SaveOutpwChk
;*
;* DESCRIPTION   = Test indexed register for read/write register.
;*
;* INPUT         = DX = port address.
;*                 AL = index register number.
;*                 AH = new value.
;* OUTPUT        = original value restored.
;*
;* RETURN-NORMAL = ZR (reads match writes).
;* RETURN-ERROR  = NZ (reads do not match writes).
;*
;* CALLED BY
;*
;****************************************************************************/

SaveOutpwChk    PROC    Near
                PUBLIC  SaveOutpwChk

        call    SaveOutpChk             ;Check index set.
        .if     < z >                   ;If no error and can set index:
            push    dx
            call    OutpDelay           ;Write the new index value.
            inc     dx                  ;Point to the data register.
            xchg    al, ah              ;Get new value.
            call    SaveOutpChk
            xchg    al, ah
            pop     dx
        .endif
        ret

SaveOutpwChk          ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = SaveXORChk
;*
;* DESCRIPTION   = Test for read write register.
;*
;* INPUT         = DX = port address.
;*                 AL = value to XOR with.
;* OUTPUT        = original value restored.
;*
;* RETURN-NORMAL = ZR (reads match writes).
;* RETURN-ERROR  = NZ (reads do not match writes).
;*
;* CALLED BY
;*
;****************************************************************************/

SaveXORChk      PROC    Near
                PUBLIC  SaveXORChk

        push    ax
        mov     ah, al                  ;Save bits to modify.
        call    InpDelay                ;Read the original value.
        xchg    ah, al                  ;Save original value, restore mask.
        xor     al, ah                  ;XOR in changable bits.
        call    OutpChk                 ;Write new value and compare.
        mov     al, ah                  ;Get back old value.
        call    OutpDelay               ;Restore old value if possible.
        .if     < z >                   ;If new value was the same,
            call    InpDelay            ;Read back the value.
            cmp     al, ah              ;Was read same as write?
        .endif
        pop     ax
        ret

SaveXORChk      ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = SaveXORConst
;*
;* DESCRIPTION   = Test for unwritable (constant) bits in register.
;*
;* INPUT         = DX = port address.
;*                 AL = value to XOR with.
;* OUTPUT        = original value restored.
;*
;* RETURN-NORMAL = ZR (no bits changed).
;* RETURN-ERROR  = NZ (some bits changed).
;*
;* CALLED BY
;*
;****************************************************************************/

SaveXORConst    PROC    Near
                PUBLIC  SaveXORConst

        push    ax
        mov     ah, al                  ;Save bits to modify.
        call    InpDelay                ;Get original value.
        xchg    ah, al                  ;Save original value, restore mask.
        xor     al, ah                  ;XOR in presumed constant bits.
        call    OutpInp                 ;Write new & read modified values.
        xor     al, ah                  ;Did bits stay same? Return success!
        mov     al, ah                  ;Get original value.
        call    OutpDelay               ;Restore original value.
        pop     ax
        ret

SaveXORConst     ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = GetPortBase
;*
;* DESCRIPTION   = Return port base address in DX (3b0 or 3d0)
;*                 depending on mono/colour mode.
;*
;* INPUT         = NONE
;* OUTPUT        = DX = 3x0 (3b0 or 3d0) port base address.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*      GetCrtcBase
;*      ATCOutpIdx
;*      TsengLock
;*      TsengEnableExt
;*
;****************************************************************************/

GetPortBase     PROC    Near
                PUBLIC  GetPortBase

        push    ax                      ;                       /*          */
        mov     dx, 03cch               ;Misc Output Read addr
        call    InpDelay                ;Input from port.
        mov     dl, 0b0h                ; assume mono           /*          */
        and     al, 001h                ;                       /*          */
        shl     al, 5                   ;                       /*          */
        add     dl, al                  ;Bump up to color maybe /*          */
        pop     ax                      ;                       /*          */
        ret                             ;                       /*          */

GetPortBase     ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = GetCrtcBase
;*
;* DESCRIPTION   = Return port base address in DX (3b0 or 3d0)
;*                 depending on mono/colour mode.
;*
;* INPUT         = NONE
;* OUTPUT        = DX = 3x4 port base address.
;*                 CX = 3x0 base address.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*      GetCrtcBaseSave1
;*      WhichCirrus
;*      WhichTrident
;*      WhichTseng
;*
;****************************************************************************/

GetCrtcBase     PROC    Near
                PUBLIC  GetCrtcBase

        call    GetPortBase             ;Depends on mono/color  /*          */
        mov     cx, dx                  ; 
        add     dl, 0004h               ;Crtc index address.
        ret

GetCrtcBase     ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = GetCrtcBaseSave1
;*
;* DESCRIPTION   = Return port base address in DX (3b0 or 3d0)
;*                 depending on mono/colour mode.
;*
;* INPUT         = AX = index register to save and new value.
;*                 BP = stack frame pointer.
;* OUTPUT        = DX = 3x4 port base address.
;*                 CX = 3x0 base address.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

GetCrtcBaseSave1 PROC    Near
                PUBLIC  GetCrtcBaseSave1

        call    GetCrtcBase             ;(3d4)                  /*          */
;*      OUTPUT   = DX = 003x4 (CRTC index address)
;       Now fall thru to (call and return):

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = GetSave1
;*
;* DESCRIPTION   = Input from byte port preceeded by I/O delay.
;*                 Save into SaveReg1/SaveIndex1 pair.
;*
;* INPUT         = DX = Input port.
;*                 BP = Stack frame pointer.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*      GetCrtcBaseSave1
;*      IsCirrus
;*      IsTrident
;*      IsWeitek
;*      IsWeitekP9x00
;*      WhichCirrus
;*      WhichTseng
;*      WhichWeitek
;*
;****************************************************************************/

GetSave1        PROC    Near
                PUBLIC  GetSave1

        mov     [SaveReg1], dx
        push    ax
        call    InpDelay                ;Read the original value.
        mov     [SaveIndex1], al        ;Save it.
        pop     ax
        ret

GetSave1        ENDP

GetCrtcBaseSave1 ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = GetSave2
;*
;* DESCRIPTION   = Input from byte port preceeded by I/O delay.
;*                 Save into SaveReg2/SaveIndex2 pair.
;*
;* INPUT         = DX = Input port.
;*                 BP = Stack frame pointer.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*      TsengEnableExt
;*      Video7EnableExt
;*      LastAttempt
;*
;****************************************************************************/

GetSave2        PROC    Near
                PUBLIC  GetSave2

        mov     [SaveReg2], dx
        push    ax
        call    InpDelay                ;Read the original value.
        mov     [SaveIndex2], al        ;Save it.
        pop     ax
        ret

GetSave2        ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = GetCrtcBaseSave2
;*
;* DESCRIPTION   = Return port base address in DX (3b0 or 3d0)
;*                 depending on mono/colour mode.
;*
;* INPUT         = AX = index register to save and new value.
;*                 BP = stack frame pointer.
;* OUTPUT        = DX = 3x4 port base address.
;*                 CX = 3x0 base address.
;*
;* RETURN-NORMAL = ZR (reads match writes).
;* RETURN-ERROR  = NZ (reads do not match writes).
;*
;* CALLED BY
;*
;****************************************************************************/

GetCrtcBaseSave2 PROC    Near
                PUBLIC  GetCrtcBaseSave2

        call    GetCrtcBaseSave1        ;(3d4)                  /*          */
;*      OUTPUT   = DX = 003x4 (CRTC index address)
        mov     [SaveReg2], dx          ;Save register address.
        mov     [SaveIndex2], al        ;Save index register.
        push    ax                      ;Save index register and value.
        call    OutpIdxChkXchgData      ;Read original value, write new.
        mov     [SaveValue2], al        ;Save original value for restore.
        pop     ax                      ;Restore index register and value.
        ret

GetCrtcBaseSave2 ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = RestoreSave2
;*
;* DESCRIPTION   = Restore indexed register and index value.
;*
;* INPUT         = BP = Stack frame pointer.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*      IsCirrus
;*      WDDisableExt
;*      WhichCirrus
;*      WhichS3
;*
;****************************************************************************/

RestoreSave2    PROC    Near
                PUBLIC  RestoreSave2

        mov     dx, [SaveReg2]
        push    ax
        mov     ax, word ptr [SaveIndex2]   ;Get the original value.
        call    OutpwDelay              ;Write the original value.
        pop     ax
;       Now fall thru to (call and return):

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = RestoreSave1
;*
;* DESCRIPTION   = Restore original index register value.
;*
;* INPUT         = BP = Stack frame pointer.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*      RestoreSave2
;*      IsTrident
;*      IsTseng
;*      IsVideo7
;*      IsWeitek
;*      IsWeitekP9x00
;*      LastAttempt
;*      WhichTseng
;*      WhichWeitek
;*
;****************************************************************************/

RestoreSave1    PROC    Near
                PUBLIC  RestoreSave1

        mov     dx, [SaveReg1]
        push    ax
        mov     al, [SaveIndex1]        ;Get the original value.
        call    OutpDelay               ;Write the original value.
        pop     ax
        ret

RestoreSave1     ENDP

RestoreSave2     ENDP

;*                                                                /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = ATCOutpIdx
;*
;* DESCRIPTION   = Reset ATC Flip flop and set ATC index.
;*
;* INPUT         = AL = New index value to set.
;* OUTPUT        = DX = 3c0 = ATC Index address
;*                 CX = 3x0 base address
;* CLOBBERS      = AH
;*
;* RETURN-NORMAL = ZR (reads match writes).
;* RETURN-ERROR  = NZ (reads do not match writes).
;*
;* CALLED BY
;*      IsTseng
;*
;****************************************************************************/

ATCOutpIdx      PROC    Near
                PUBLIC  ATCOutpIdx

        call    GetPortBase             ;Get port base address
        add     dx, 00ah
        push    ax                      ;Save new index to set.
        call    InpDelay                ;Dummy read to set to index write.
        pop     ax                      ;Restore new index to set.
        mov     dl, 0c0h                ;ATC address (3c0)
        call    OutpChk                 ;Write new ATC index value.
        ret

ATCOutpIdx      ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = IsNoCrtcWrap
;*
;* DESCRIPTION   = Check for CTRC Wrap at 020h
;*
;* INPUT         = BP = Stack frame pointer.
;*                 DX = 3x4 port base address.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ZR (if no wrap).
;* RETURN-ERROR  = NZ (if wrap).
;*
;* CALLED BY
;*      WDEnableExt
;*      IsS3
;*      IsTseng
;*
;****************************************************************************/

IsNoCrtcWrap    PROC    Near
                PUBLIC  IsNoCrtcWrap

        mov     al, 00fh + 020h         ;Use safe reg: cur addr low
        call    OutpIdxInpData          ;Get current value
        mov     ah, al                  ; 
        mov     al, 00fh                ;Point to cur addr low reg
        call    OutpIdxInpData          ; 
        .if     <al e ah>               ;If regs are same:
            not     al                  ;Get ones complement.
            call    OutpData            ; 
            mov     al, 00fh + 020h     ;Point past wrapping
            call    OutpIdxInpData      ; 
            not     al                  ;Get ones complement.
            cmp     al, ah              ;See if regs are still the same.
            mov     al, 00fh            ;Point to row offset reg
            call    OutpwDelay          ;Restore cur addr low.
        .endif
        lahf                            ;Get flags into AH.
        and     ah, 040h                ;Complement zero flag!
        ret

IsNoCrtcWrap    ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = IsNotISAAliased
;*
;* DESCRIPTION   = Test for register NOT ISA aliased.
;*
;* INPUT         = DX = port address.
;*                 AL = SAFE new mask to XOR test.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ZR (reads do not match writes).  Is NOT Aliased!
;* RETURN-ERROR  = NZ (reads match writes).  Is Aliased!
;*
;* CALLED BY
;*      IsSpeedWay
;*
;****************************************************************************/

IsNotISAAliased PROC    Near
                PUBLIC  IsNotISAAliased

        push    ax                      ;Save original & test values.
        push    bx
        push    cx
        mov     bl, al                  ;Save test mask to XOR.
        mov     cx, dx                  ;Save original port.
        call    InpDelay                ;Get value at original port.
        mov     bh, al                  ;Save value at original port.
;
;               003ffh mask should be similarly effective.      /*          */
;
        and     dx, 00fffh              ;Get alias port address.
        call    InpDelay                ;Get value at alias port.
        xchg    dx, cx                  ;Get back original port.
        .if     <al e bh>               ;Can only be alias if same now first!
            mov     al, bh              ;Restore original value.
            xor     al, bl              ;XOR with test mask to force changes.
            call    OutpInp             ;Write new & read modified values.
            mov     ah, al              ;Save modified test value.
            xchg    dx, cx              ;Get back alias port.
            call    InpDelay            ;Read back the value.
            cmp     al, ah              ;Was alias read same as write?
            xchg    dx, cx              ;Get back original port.
            mov     al, bh              ;Get original value.
            call    OutpDelay           ;Restore original value.
        .endif
        lahf                            ;Get flags.
        and     ah, 040h                ;Complement ZR, now NOT aliased!
        pop     cx
        pop     bx
        pop     ax
        ret

IsNotISAAliased    ENDP

;*****************************************************************************
;
;
;
;*****************************************************************************

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = ATIWaitIdle
;*
;* DESCRIPTION   = Wait for ATI accelerator to be idle.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ZR (now idle)
;* RETURN-ERROR  = NZ (timeout)
;*
;* CALLED BY
;*
;****************************************************************************/

ATIWaitIdle     PROC    near                                    ;          
                PUBLIC  ATIWaitIdle

        xor     cx, cx                  ;Initialize timeout.
        push    dx
        mov     dx, 09aeeh              ;EXT_FIFO_STATUS reg.
        .repeat
            call    InpwDelay           ;Read EXT_FIFO_STATUS reg.
            test    ax, 00001h          ;16 free FIFOs?
        .loop   < nz >                  ;Wait until timeout or YES.
        .if     < z >                   ;If no failure:
            xor     cx, cx              ;Initialize timeout.
            mov     dx, 09ae8h          ;GP_STAT reg.
            .repeat
                call    InpwDelay       ;Read GP_STAT reg.
                test    ax, 00200h      ;GP_BUSY?
            .loop   < nz >              ;Wait until timeout or NO.
        .endif
        pop dx
        ret

ATIWaitIdle ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = ATIOutpChk
;*
;* DESCRIPTION   = Test ATI chip for register writable.
;*
;* INPUT         = AX - value to write.
;*                 DX - register address to write to and read from.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ZR (now idle and same)
;* RETURN-ERROR  = NZ (timeout or different)
;*
;* CALLED BY
;*
;****************************************************************************/

ATIOutpChk      PROC    near                                     ;          
                PUBLIC  ATIOutpChk

        mov     bx, ax                      ;Save original value to write.
        call    OutpwDelay                  ;Write register value.
        call    ATIWaitIdle
        .if     < z >                       ;If idle and OK so far:
            call    InpwDelay               ;Read the register again.
            cmp     ax, bx                  ;Compare with original written value.
        .endif                              ;Else failure.
        ret

ATIOutpChk      ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = ATIDestXOutpChk
;*
;* DESCRIPTION   = Test ATI chip for DESTX_DIASTP set effecting READ_SRC_X.
;*
;* INPUT         = AX - value to write.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ZR (now idle and same)
;* RETURN-ERROR  = NZ (timeout or different)
;*
;* CALLED BY
;*
;****************************************************************************/

ATIDestXOutpChk PROC    Near
                PUBLIC  ATIDestXOutpChk

        mov     bx, ax              ;Save original value to write.
        mov     dx, 08ee8h          ;Get DESTX_DIASTP reg address.
        call    OutpwDelay          ;Write the new value.
        call    ATIWaitIdle
        .if     < z >               ;If idle and OK so far:
            mov     dx,0daeeh       ;Get READ_SRC_X reg address.
            call    InpwDelay       ;Read the value.
            cmp     ax,bx           ;Compare with original written value.
        .endif                      ;Else failure.
        ret

ATIDestXOutpChk ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = ATI8514
;*
;* DESCRIPTION   = Test ATI chip for 8514 Accelerator.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ZR (has 8514 Accelerator)
;* RETURN-ERROR  = NZ (timeout or other failure)
;*
;* CALLED BY
;*
;****************************************************************************/

ATI8514         PROC    near            ;                       /*          */
                PUBLIC  ATI8514         ;                       /*          */

;*
;*  Test for 8514 first.
;*
        mov     dx, 042e8h              ;SUBSYS_CNTL reg.
        mov     ax, 0900fh
        call    OutpwDelay              ;Write the new value.
        mov     ax, 0400fh
        call    OutpwDelay              ;Write the new value.
        mov     dx, 002ebh              ;DAC_R_INDEX reg.
        mov     al, 0a4h
        call    OutpDelay               ;Write the new value.
        xor     cx, cx
        .repeat                         ;Wait fixed amount of time.
        .loop
        mov     dx, 002ech              ;DAC_W_INDEX reg
        call    InpDelay                ;Input from port.
        .if     <al e 0a5h>             ;Always one more!       /*          */
            mov     dx, 092e8h          ;ERR_TERM reg address.
            call    InpwDelay           ;Read the value.
            push    ax                  ;Save original value.
            not     ax                  ;Change all the bits.   /*          */
            call    ATIOutpChk          ;See if they all change./*          */
            pop     ax                  ;                       /*          */
            call    OutpwDelay          ;Restore original value./*          */
        .endif                          ;Else success! 8514!
;*
;*  Test for ATI Accelerator:
;*
        .if     < z >                   ;If some type of 8514:
            mov     dx, 052eeh          ;ROM_ADDR_1 reg address.
            call    InpwDelay           ;Read the value.
            push    ax                  ; 
            not     ax                  ;Change all the bits.   /*          */
            call    ATIOutpChk          ;See if they all change.
            pop     ax                  ; 
            call    OutpwDelay          ;Restore original value.
        .endif                          ;Else failure.
        ret                             ; 

ATI8514         ENDP                    ;                       /*          */

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = ATIMach64
;*
;* DESCRIPTION   = Test ATI chip for Mach64 Accelerator.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ZR (has Mach64 Accelerator)
;* RETURN-ERROR  = NZ (timeout or other failure)
;*
;* CALLED BY
;*
;****************************************************************************/

ATIMach64       PROC    near            ;                       /*          */
                PUBLIC  ATIMach64

        mov     dx, 01eeeh              ;CRTC_GEN_CTRL addr.
        call    InpwDelay               ;Read the current value.
        push    ax                      ;Save current value.
        and     ah, not 001h            ;Disable VGA passthru.
        call    OutpwDelay              ;Write the new value.
        mov     dx, 066eeh              ;GEN_TEST_CTRL reg.
        call    InpwDelay               ;Read the current value.
        push    ax                      ;Save gen_test_ctrl.
        and     al, not 070h            ;Turn off test mode.
        call    OutpwDelay              ;Write the new value.
        mov     dx, 066ech              ;GEN_TEST_CTRL reg.
        call    InpwDelay               ;Read the current value.
        push    ax                      ;Save gen_test_ctrl.
        and     ah, not 001h            ;Reset GUI engine.
        call    OutpwDelay              ;Write the new value.
        pop     ax                      ;Restore gen_test_ctrl.
        call    OutpwDelay              ;Restore original value.
        mov     dx, 01ceh               ;ATI Extended regs index/*          */
        mov     ah, 0a0h                ;ATI20 index value      /*          */
        mov     al, ah                  ;                       /*          */
        call    OutpIdxInpData          ;Get current DAC RS[3:2]/*          */
        push    ax                      ;Save ATI20 data        /*          */
        and     al, not 060h            ;Clear DAC RS[3:2]      /*          */
        xchg    ah, al                  ;Restore index,save data/*          */
        call    OutpwDelay              ;                       /*          */
        mov     dx, 05eefh              ;DAC_R_INDEX reg.
        mov     al, 0a4h                ; 
        call    OutpDelay               ;Write the new value.
        xor     cx, cx                  ; 
        .repeat                         ;Wait fixed amount of time.
        .loop                           ; 
        mov     dx, 05eech              ;DAC_W_INDEX reg
        call    InpDelay                ;Input from port.
        .if     <al e 0a5h>             ;Always one more!
            mov     dx, 042ech          ;SCRATCH_REG0 reg addr.
            call    InpwDelay           ;Read the value.
            push    ax                  ; 
            not     ax                  ;Change all the bits.
            call    OutpwChk            ;See if it changes.
            pop     ax                  ; 
            call    OutpwDelay          ;Restore original value.
        .endif                          ;Else failure.
        mov     dx, 01ceh               ;ATI Extended regs index/*          */
        pop     ax                      ;Restore ATI20 data     /*          */
        call    OutpwDelay              ;Restore original value./*          */
        pop     ax                      ;Restore gen_test_ctrl.
        mov     dx, 066eeh              ;GEN_TEST_CTRL reg.
        call    OutpwDelay              ;Restore original value.
        pop     ax                      ;Restore Crtc ctrl.
        mov     dx, 01eeeh              ;CRTC_GEN_CTRL addr.
        call    OutpwDelay              ;Restore original value.
        ret

ATIMach64       ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = IsATI
;*
;* DESCRIPTION   = Look for an ATI Wonder.
;*
;*                 Check for product signature string at C000:30
;*                 which should read '761295520'
;*
;*                 Assume DS -> DGROUP on entry
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

IsATI           PROC    Near
                PUBLIC  IsATI

        push    di
        mov     bx, 00030h              ;Search target offset.
        mov     cx, 10                  ;Search string length.
        mov     di, OFFSET DGROUP :ATISig ;Search string value.
;@V3.0JLO01  call    FindString              ;See if string is there in ROM.
        call    LookString              ;See if string is there in ROM.
        pop     di
        ret

IsATI           ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = IsCirrus
;*
;* DESCRIPTION   = Graphics Cursor X position register (3c5, index 10,30,50...F0)
;*                 uses both index and data for position value. Bits 7-5 of
;*                 the index are bits 0-2 of the cursor position.  Data value
;*                 represents bits 3-10 of the cursor position.
;*                 If 3c4 loaded with a value and then read without
;*                 writing data to 3c5, it returns 3 bits of the
;*                 previously set cursor position.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ZR if found.
;* RETURN-ERROR  = NZ if not found.
;*
;* CALLED BY
;*
;****************************************************************************/
;          

IsCirrus        PROC    Near
                PUBLIC  IsCirrus

        enter   STACKBLOCK, 0           ;          
        mov     dx, 03c4h               ;SEQ index address (3c4)/*          */
        call    GetSave1                ;Read original index & save it.
        mov     ax, 01206h              ; sr6 register index and unlock.
;       Current SEQ06 value now saved globally!                 /*          */
;       But at least TRY to restore it as soon as possible!     /*          */
        mov     [SaveReg2], dx          ;                       /*          */
        mov     [SaveIndex2], al        ;                       /*          */
;                                                               /*          */
;       Cannot call OutpIdxChkXchgData here                     /*          */
;       since GD5401 has no SEQ SR6!                            /*          */
;                                                               /*          */
        call    OutpIdxXchgData         ;Try setting SEQ SR6.   /*          */
        mov     [SaveValue2], al        ;Save old value.        /*          */
        mov     al, 010h                ;SEQ SR10 index.
        call    OutpInp                 ;Write new & read modified values.
;                                       ;Read value is first 3 bits, shifted by 5
        cmp     al, 010h                ;Test for read/writable /*          */
        jb      IsCirrusExit            ;Exit if not.           /*          */
        test    al, 00fh                ;Test for read/writable /*          */
        jnz     IsCirrusExit            ;Exit if not.           /*          */
        mov     [SaveIndex3], al        ;Read/writable index?   /*          */
;       mov     ah, 000h                ;Any data at all!       /*          */
        call    OutpIdxChkXchgData      ;Test for read/writable /*          */
                                        ;Read value is bits 3-10 of the current position
        mov     [SaveValue3], al        ;                       /*          */
        .if     < z >                   ;If read/write:         /*          */
            mov     ax, 02850h          ;Set cursor to position 322. This value chosen in
            mov     bl, al              ;Save index.            /*          */
;                                                               /*          */
;           Cannot call OutpIdxChkXchgData here                 /*          */
;           since index register has extra "data" bits.         /*          */
;                                                               /*          */
            call    OutpIdxXchgData     ;No index check!        /*          */
            mov     bh, al              ;Save data.             /*          */
            mov     al, 070h            ; write the index only
            call    OutpInp             ;Write new & read modified values.
;                                       ;Read value should be 50h
            cmp     al, bl              ; if 0 it is Cirrus, else not
            mov     ax, bx              ;Restore index & data   /*          */
            call    OutpwDelay          ;Restore the old value. /*          */
        .endif                          ;Else not read/write    /*          */
        mov     ax, word ptr [SaveIndex3]
        call    OutpwDelay              ;Restore the old value.
IsCirrusExit:
        call    RestoreSave2            ;Restore original values/*          */
        leave                           ;          
        ret

IsCirrus     ENDP

;/*****************************************************************            ;          
;*
;* FUNCTION NAME = IsS3                                     
;*
;* DESCRIPTION   =
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ZR if found.
;* RETURN-ERROR  = NZ if not found.
;*
;* CALLED BY
;*
;****************************************************************************/

IsS3            PROC    Near            ;                       /*          */
                PUBLIC  IsS3

        enter   STACKBLOCK, 0           ;                       /*          */
;*                                                              /*          */
;*      Weitek VGA used to pass the following test!
;*      so it was clearly not specific enough!
;*
        mov     ax, 04838h              ;Unlock extensions.
        call    GetCrtcBaseSave2        ;(3d4)                  /*          */
;*      OUTPUT   = DX = 003x4 (CRTC index address)
;*                                                              /*          */
;*      Cannot check return since                               /*          */
;*      not all the S3 bits are writable!                       /*          */
;*                                                              /*          */
;*      .if     <z> AND                 ;Exit if not R/W!       /*          */
;*                                                              /*          */
            mov     al, 0cch            ;                       /*          */
            inc     dx                  ;Point to data register /*          */
            call    SaveXORChk          ;                       /*          */
        .if     <z> AND                 ;Exit if not R/W!
            dec     dx                  ;Point back to index reg/*          */
;*                                                              /*          */
;*          We must eliminate this possibility
;*          to reject the Weitek VGA!
;*
            call    IsNoCrtcWrap        ;(3d4)                  /*          */
        .if     <z> AND                 ;Exit if wraps!         /*          */
;*
            mov     al, 030h            ;Chip-ID/Rev index      /*          */
            call    OutpDelay           ;                       /*          */
            inc     dx                  ;Point to data register /*          */
            mov     al, 0ffh            ;                       /*          */
            call    SaveXORConst        ;Must be read only!     /*          */
        .if     <z> AND                 ;Exit if R/W!           /*          */
            dec     dx                  ;Point back to index reg/*          */
            mov     al, 030h            ; 
            call    OutpIdxInpData      ;Read indexed reg       /*          */
            and     al, 0f0h            ;mask out lower nibble  /*          */
        .if     <al be 0d0h>            ;Vision964              /*@V3.0YEE01*/
;           cmp     al, 0a0h            ;801/805 family
;           je      S3Exit
;           cmp     al, 080h            ;80 is 911/924          /*          */
;           je      S3Exit
;           cmp     al, 090h            ;928 family
;           je      S3Exit
;           cmp     al, 0b0h            ;928 PCI                /*          */
            cmp     al, al              ;Always success here!   /*          */
        .endif                                                  /*@V2.1MNH13*/
S3Exit:                                 ;                       /*          */
        call    RestoreSave2            ;Restore original values
        leave                           ;                       /*          */
        ret

IsS3            ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = IsSpeedWay
;*
;* DESCRIPTION   = Look for IBM 'SVGA'
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

IsSpeedWay      PROC    Near
                PUBLIC  IsSpeedWay

        mov     dx, 02170h              ;Start from 8th instance OpMode Reg.
        .repeat
            call    InpDelay            ;Read the OpMode setting.
            test    al, 0eah            ;Any of these bits on?
            .if     < z > AND           ;Valid value?
                mov     al, 0ffh        ;Test all of the bits.
                call    IsNotISAAliased
            .if     < z > AND           ;If not aliased
;
;               This should be INSIDE the loop & not AFTER!     /*          */
;               If both XGA and Speedway
;               (a real but maybe dumb possibility),
;               then keep looking until we find the speedway address!
;
                mov     al, 0eah
                call    SaveXORConst
            .if     < z > AND           ;If no changes:
                mov     al, 00fh
                or      dl, 008h        ;VRAM Index
                call    SaveXORChk
            .if     < z > AND           ;If reads match writes:
                mov     al, 0f4h
                or      dl, 009h        ;Setup Memory Access    /*          */
                call    SaveXORConst
            .if     < z >               ;Exit with success!
                and dx, not 0000fh
                mov [_XGAInstance], dx  ;Remember XGA instance  /*          */
                cmp     al, al          ;Return success
                jmp short @F
            .endif
SWayNextPort:
            sub     dx, 00010h          ;Next configuration
        .until  <dx b 02100h>           ;Still more ports to check
@@:
        ret

IsSpeedWay      ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = _GetXGAInstance
;*
;* DESCRIPTION   = Get XGAInstance value
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

_GetXGAInstance PROC    Far             ;                       /*          */
                PUBLIC  _GetXGAInstance ;                       /*          */

        call    IsSpeedWay
        ret

_GetXGAInstance ENDP                    ;                       /*          */

;/****************************************************************************
;*
;* FUNCTION NAME = IsTrident
;*
;* DESCRIPTION   = Look for Trident chip set
;*                 check for presence of inverting bit field in
;*                 Mode Control register 1
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

IsTrident       PROC    Near
                PUBLIC  IsTrident

        enter   STACKBLOCK, 0           ;          
        mov     dx, 03c4h               ;SEQ index address (3c4)/*          */
        call    GetSave1                ;Read value & save it.  /*          */
        call    OutpChk
        mov     ax, 0000eh              ;Write all zeroes       /*          */
;                                                               /*          */
;       Need to check for index wrap so we do not clobber       /*          */
;       TSeng Tsequencer 0x0e&0x07==0x06! (Tsix!)               /*          */
;       Which we may not be able to restore TsucceTsTsfully!    /*          */
;                                                               /*          */
        call    OutpChk                 ;Check index for wrap   /*          */
        .if     <z>                     ;If R/W: Else Tskip!    /*          */
;                                                               /*          */
;           Cannot call OutpIdxChkXchgData here                 /*          */
;           since read value changes!                           /*          */
;                                                               /*          */
            call    OutpIdxXchgData     ;Read indexed reg       /*          */
            mov     ah, al              ;Save old value         /*          */
            call    InpData             ;Read value 2nd time!
            and     al, 00fh            ; 
            xchg    al, ah              ;get old value back
            xor     al, 002h            ;flip bit
            call    OutpData            ;Write the new value, restore.
            cmp     ah, 002h            ;ZR => Trident, NZ => not
        .endif                          ;                       /*          */
        call    RestoreSave1            ;Restore the original index.
        leave                           ;          
        ret

IsTrident       ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = TsengSetATCMisc
;*
;* DESCRIPTION   = Point to Tseng ATC Misc and set the value.
;*
;* INPUT         = CX = 3x0 CrtcBase
;*               = AL = New Tseng ATC Misc Reg value
;* OUTPUT        = DX = 3c0 = ATC Index address
;* CLOBBERS      = AX
;*
;* RETURN-NORMAL = ZR (reads match writes).
;* RETURN-ERROR  = NZ (reads do not match writes).
;*
;* CALLED BY
;*      IsTseng
;*
;****************************************************************************/

TsengSetATCMisc PROC    Near
                PUBLIC  TsengSetATCMisc

        mov     ah, al                  ;Save new ATC Misc value.
        mov     al, 016h                ;Tseng ATC Misc index.
        call    ATCOutpIdx              ;Set index & test for read/writeable.
        .if     < z >                   ;If NO errors setting index:
            mov     al, ah              ;Restore new ATC Misc value.
            call    OutpIdxInpData      ;Write new ATC Misc value & reread it.
            cmp     al, ah
        .endif
        ret

TsengSetATCMisc    ENDP


;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = TsengEnableExt
;*
;* DESCRIPTION   =
;*
;* INPUT         = BP = Stack Frame Pointer
;* OUTPUT        = DX = 03c4 = SEQ index address
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

TsengEnableExt  PROC    Near
                PUBLIC  TsengEnableExt

        call    GetPortBase             ;Depends on mono/color  /*          */
        add     dl, 008h                ;Mode Ctrl (3b8/3d8)    /*          */
        call    GetSave2                ;           
;;JWK07        mov     ax, 02901h              ;Unlock values.
               mov     ax, 0a003h       ;JWK07 ;Correct Unlock values.
;       Now fall thru to (call and return):

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = TsengLock
;*
;* DESCRIPTION   = Lock or Unlock Tseng extended registers.
;*
;* INPUT         = AX = Lock 0a003h or Unlock 02901h
;*                 DX = Mode Ctrl (3b8/3d8)
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

TsengLock       PROC    Near
                PUBLIC  TsengLock

        push    dx
        mov     dl, 0bfh                ;Lock/Unlock extended regs
        call    OutpDelay               ;Write the new value.
        pop     dx
        mov     al, ah                  ; 
        call    OutpDelay               ;Write the new value.
        ret

TsengLock       ENDP

TsengEnableExt  ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = TsengDisableExt
;*
;* DESCRIPTION   =
;*
;* INPUT         = BP = Stack Frame Pointer
;* OUTPUT        = DX = 03c4 = SEQ index address
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

TsengDisableExt PROC    Near
                PUBLIC  TsengDisableExt

        mov     dx, [SaveReg2]          ;Mode Ctrl (3b8/3d8)    /*          */
        push    ax
        mov     al, [SaveValue2]        ; 
        mov     ah, al                  ; 
        and     al, 040h                ; 
        rol     al, 3                   ; 
        or      al, 001h                ; 
        call    TsengLock               ;Restore lock state     /*          */
        pop     ax
        ret

TsengDisableExt ENDP

;*                                                                /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = IsTseng
;*
;* DESCRIPTION   = Look for Tseng chip
;*
;*                 Use:
;*
;*                 read old reg value
;*                 write a new value
;*                 read the new value
;*                 write old value back
;*                 if new value written equals value read, chip is Tseng
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* USES:   AX, BX, DX
;*
;* CALLED BY
;*
;****************************************************************************/

IsTseng         PROC    Near
                PUBLIC  IsTseng

        enter   STACKBLOCK, 0           ;                       /*          */
        mov     dx, 003cdh              ;Tseng Tsegment Tselect /*          */
        mov     al, 0ffh                ;Test all bits for R/W  /*          */
        call    SaveXORChk              ;                       /*          */
        .if     <z>                     ;If R/W                 /*          */
            call    GetCrtcBaseSave1    ;(3d4)                  /*          */
;*          OUTPUT   = DX = 003x4 (CRTC index address)
;*                                                              /*          */
;*          We must eliminate this possibility to reject the Weitek VGA!
;*
            call    IsNoCrtcWrap        ;(3d4)                  /*          */
;*          OUTPUT   = DX = 003x4 (CRTC index address)
            .if     < z >               ;If no wrap:            /*          */
                mov     al, 033h        ;Point to extended start/*          */
                call    OutpChk         ;Extra sanity check for L40
                                        ; which ignores index set,
            .if     < z >               ; so check it worked:   /*          */
                inc     dl              ; 
                mov     al, 00fh        ;                       /*          */
                call    SaveXORChk      ;Test for read/writable./*          */
            .if     < z >               ;If read/write:         /*          */
;*                                                              /*          */
;*              We must eliminate this possibility to reject the WD90C24!
;*
                mov     dl, 0cdh        ;GDC Segment Select 1   /*          */
                mov     al, 0ffh        ;Test all bits          /*          */
                call    SaveXORChk      ;Test for read/writable./*          */
            .endif
            .endif
            .endif
            .if     < nz >              ;If NOT ET4000+:        /*          */
IsTsengExit:                            ;could be ET3000
;!!             Trident TR8900 passes ET3000 test!              /*          */
;!!             Can we TStrENGthen it somehow?
                mov     al, 016h        ;Tseng ATC Misc index.
                call    ATCOutpIdx      ;Set index & test for read/writeable.
                inc     dx
                call    InpDelay        ;Read the value.
                mov     bl, al          ;Save original value in bl
                xor     al, 10h         ;Toggle bit             /*          */
                call    TsengSetATCMisc ;Write new ATC Misc val /*          */
                .if     < z >           ;If read/writeable:     /*          */
                    mov     al, bl      ;Get original value
                    call    TsengSetATCMisc ;Restore ATC Misc   /*          */
                .endif
            .endif
MustBeTseng:
            pushf                       ;Save flags
            mov     al, 20h             ;Turn palette back on
            call    ATCOutpIdx          ;Set ATC index reg      /*          */
            popf                        ;restore flags
            call    RestoreSave1        ;Restore the original index.
        .endif                          ;                       /*          */
        leave                           ;                       /*          */
        ret                             ; 

IsTseng         ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = Video7EnableExt
;*
;* DESCRIPTION   =
;*
;* INPUT         = BP = Stack Frame Pointer
;* OUTPUT        = DX = 03c4 = SEQ index address
;*
;* RETURN-NORMAL = ZR (reads do not match writes).
;* RETURN-ERROR  = NZ (reads match writes).
;*
;* CALLED BY
;*
;****************************************************************************/

Video7EnableExt PROC    Near
                PUBLIC  Video7EnableExt

        mov     dx, 03c4h               ;SEQ index address (3c4)/*          */
        call    GetSave2                ;           
        mov     ax, 0ea06h              ;write 0eah to reg 6    /*          */
;       Don't check index, since we want failure for output chk!/*          */
        call    OutpIdxChkXchgData      ;Read indexed reg       /*          */
;       Current SEQ06 value now saved globally!                 /*          */
;       But at least TRY to restore it as soon as possible!     /*          */
;       mov     [SaveValue2], al        ;In case NOT Video7!    /*          */
        lahf                            ;Did reads match writes?/*          */
        test    ah,040h                 ;NZ=>Z, Z=>NZ           /*          */
        ret

Video7EnableExt ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = Video7DisableExt
;*
;* DESCRIPTION   =
;*
;* INPUT         = BP = Stack Frame Pointer
;*                 FL = ZR = Video7, NZ = not Video7
;* OUTPUT        = DX = 03c4 = SEQ index address
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

Video7DisableExt PROC   Near
                PUBLIC  Video7DisableExt

        mov     dx, 03c4h               ;SEQ index address (3c4)/*          */
;We do not want to lock it now, we want to restore the lock state!
;       mov     ax, 0ae06h              ;write 0aeh to reg 6    /*          */
;       call    OutpwDelay              ;Write the new value.   /*          */
;       mov     dx, [SaveReg2]          ;                       /*          */
;       Current SEQ06 value now saved globally!                 /*          */
;       But at least TRY to restore it as soon as possible!     /*          */
        mov     al, 006h                ;                       /*          */
        mov     ah, [SEQ06]             ;Use global lock restore/*          */
        call    OutpwDelay              ;Restore original lock  /*          */
        mov     al, [SaveIndex2]        ;           
        call    OutpDelay               ;Restore the index.
        ret

Video7DisableExt ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = IsVideo7
;*
;* DESCRIPTION   = Look for Headland chip (Video7)
;*
;*                 read value of Start Address High (SAH) register
;*                 read Identification register (ID field)
;*                 if (SAH ^ 0EAH == ID reg) its a Video7 chip
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

IsVideo7        PROC    Near
                PUBLIC  IsVideo7

        enter   STACKBLOCK, 0           ;          
        call    Video7EnableExt         ;enable extended registers
        jnz     IsVideo7Exit            ;Exit if read/write     /*          */
        call    GetCrtcBaseSave1        ;(3d4)                  /*          */
;*      OUTPUT   = DX = 003x4 (CRTC index address)
;       mov     bx, dx                  ;save copy              /*          */
        xor     bh, bh                  ;Default value          /*          */
        mov     ax, 0550ch              ;select Start Address High reg
        call    OutpIdxChkXchgData      ;Read indexed reg       /*          */
        mov     bl, al                  ;Save previous value
        .if     < z >                   ;If read/write:         /*          */
;           call    InpDelay            ;Read the value back.   /*          */
            mov     al, 01fh            ;select ID register
            call    OutpIdxInpData      ;Read indexed reg       /*          */

            mov     bh, al              ;                       /*          */
        .endif                          ;Else not read/write    /*          */
        mov     al, 00ch                ;select SAH register
        mov     ah, bl                  ;Get back old value     /*          */
        call    OutpwDelay              ;Write old value back
        cmp     bh, 055h xor 0eah       ;ZR => Video7, NZ => not/*          */
        call    RestoreSave1            ;Restore the original index.
IsVideo7Exit:                           ;                       /*          */
        call    Video7DisableExt        ;disable extended regs
        leave                           ;          
        ret

IsVideo7        ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = WDDisableExt
;*
;* DESCRIPTION   = Relock WD private registers.
;*                 Maintain Z/NZ
;*
;* INPUT         = BP = Stack frame pointer.
;*                 DX = 3x4 port base address.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*      IsWesternDig
;*      WhichWesternDig
;*
;****************************************************************************/

WDDisableExt    PROC    near
                PUBLIC  WDDisableExt

        pushf                           ;Save results flags.    /*          */
        call    GetCrtcBase             ;(3d4)                  /*          */
;*      OUTPUT   = DX = 003x4 (CRTC index address)
        call    IsNoCrtcWrap            ;(3d4)                  /*          */
;*      OUTPUT   = DX = 003x4 (CRTC index address)
        .if     < z >                   ;If no wrap:            /*          */
            mov     al, 035h            ;PR30/Mapping RAM Unlock/*          */
            mov     ah, [SaveValue3]    ;                       /*          */
            call    OutpwDelay          ;Restore lock/unlock    /*          */
            mov     al, 034h            ;PR1B/Flat Panel Unlock /*          */
            mov     ah, [SaveIndex3]    ;                       /*          */
            call    OutpwDelay          ;Restore lock/unlock    /*          */
        .endif                                                  /*@V2.1MNH01*/
        popf                            ;Restore results flags  /*          */
        call    RestoreSave2
        mov     al, 000h                ;Lock extensions        /*          */
;       Now fall thru to (call and return):

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = WDLock
;*
;* DESCRIPTION   = Lock/Unlock WD private registers.
;*
;* INPUT         = AL = Lock (000h)/Unlock(080h) bit.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

WDLock          PROC    Near
                PUBLIC  WDLock
;
;       Which adapter needs this lock/unlock?                   /*          */
;       And does this code really work?                         /*          */
;       Shouldn't this be 001h->0102h instead of 080h->0103h?   /*          */
;
;       This routine must be removed since the WD90C24A2B       /*          */
;       & WD90C24A2C have a     which causes all output to      /*          */
;       003c3 to put the chip to sleep.                         /*          */
;
;       Since historically this routine has output to the       /*          */
;       address and the       bit, it is effectively a nop      /*          */
;       anyway.  So it should not be missed.                    /*          */
;
;       mov     ah, al                  ;Save lock/unlock bit
;       mov     dx, 003c3h              ;Same as 046e8h!
;       push    dx                      ;
;       call    InpDelay                ;
;       push    ax                      ;Save Subsys Enable
;       or      al, 010h                ;Add Setup bit
;       call    OutpDelay               ;Write new value, enter setup mode.
;       mov     dx, 00103h              ;!!What is this addr?!  (102?)
;       call    InpDelay                ;
;       pushf                           ;Save results flags.
;       or      al, ah                  ;Add in lock/unlock bit
;       popf                            ;Restore results flags
;       call    OutpDelay               ;Write new value, unlock extensions.
;       pop     ax                      ;Restore Subsys Enable
;       pop     dx                      ;(003c3h)
;       call    OutpDelay               ;Write new value, exit setup mode.
        ret

WDLock          ENDP

WDDisableExt    ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = WDEnableExt
;*
;* DESCRIPTION   = Unlock WD private registers.
;*
;* INPUT         = BP = Stack frame pointer.
;* OUTPUT        = DX = 003x4 (CRTC index address)
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

WDEnableExt     PROC    near
                PUBLIC  WDEnableExt

;!!     mov     al, 080h                ;Unlock extensions      /*          */
;!!     call    WDLock                  ;Is this the right bit? /*          */
        mov     ax, 08529h              ;Set PR10, RW enable PR11-PR1A  /*          */
        call    GetCrtcBaseSave2        ;(3d4)                  /*          */
;*      OUTPUT   = DX = 003x4 (CRTC index address)
;*                                      ;Write the new value, RW enable PR11-PR1A.
;                                                               /*          */
;       Cannot check the following because PVGA1A only has      /*          */
;       PR0-PR5, and the 029h index is not read/writable!       /*          */
;                                                               /*          */
;       jnz     WDEnableExtExit         ;Exit if not read/write./*          */
;                                                               /*          */
;*                                                              /*          */
;*      We must eliminate this possibility to reject the Weitek VGA!
;*
        call    IsNoCrtcWrap            ;(3d4)                  /*          */
        jnz     WDEnableExtExit         ;Exit if wraps!         /*          */
        mov     ax, 05934h              ;Set PR1B/Flat Panel Unlock
        call    OutpIdxChkXchgData      ;Write new value, lock for read ID!
        mov     [SaveIndex3],al         ;Save for non-WDs!      /*          */
        mov     ax, 04335h              ;Set PR30/Mapping RAM Unlock
        call    OutpIdxChkXchgData      ;Write new value, lock for read ID!
        mov     [SaveValue3],al         ;Save for non-WDs!      /*          */
        cmp     al, al                  ;WD's MAY not read!     /*          */
WDEnableExtExit:
        ret

WDEnableExt     ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = WDRegPairString
;*
;* DESCRIPTION   = Test for WD string presence at CRTC reg pair.
;*
;* INPUT         = AL = index of first CRTC reg in pair.
;*               = DX = 003x4 (CRTC index address)
;* OUTPUT        = AL = First reg
;*                 AH = Second reg
;*
;* RETURN-NORMAL = (zr if WD string found)
;* RETURN-ERROR  = (nz if WD string NOT found)
;*
;* CALLED BY
;*
;****************************************************************************/

WDRegPairString PROC    Near
                PUBLIC  WDRegPairString

        mov     ah, al                  ;Save register index.
        call    OutpIdxInpData          ;Read high byte of chip 90cxx
        xchg    ah, al                  ;Save high byte, restore index.
        inc     al                      ;Get next index.
        call    OutpIdxInpData          ;Read low byte of chip 90cxx
        cmp     ax, 05744h              ;"WD"
        ret

WDRegPairString ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = IsWesternDig
;*
;* DESCRIPTION   =
;*      At index 30 thru 3f, the WD90cxx chips have an encoded device id.
;*      Certain unlocks must be done to allow it to be read.
;*      This is NOT documented in ALL of their data books.
;*      It IS documented in the data book for the WD90C26.
;*      It IS hinted at ("reserved") in other data books.
;*
;*                  3333333333333333
;*                  0123456789ABCDEF
;*      PVGA1A    ->################ #=0ffh or 000h
;*      WD90c00   ->COPYRIGHT1989WDC
;*      WD90c24   ->#WD90C24REVC0892 #=varies        Toshiba T4700CT
;*      WD90c24a2a->#WD90C24AREVA293 #=varies z=000h WD90C24 Demo Board
;*      WD90c24a2b->#WD90C24AREVB293 #=varies z=000h IBM ThinkPad
;*      WD90c24a2c->#WD90C24AREVC### #=varies        WD program checks this!
;*      WD90c26   ->#WD90C26REV#199# #=varies        WD ref documents this!
;*      WD90c31   ->#WD90C310200zzzz #=varies z=000h WD program checks this!
;*      WD90c31A  ->#WD90C31050zzzzz #=varies z=000h WD program checks this!
;*      WD90c33   ->#WD90C33######## #=varies z=000h WD program checks this!
;*      WD90c34   ->#WD90C34######## #=varies z=000h WD program checks this!
;*      WD90cxx   ->#WD90Cxx######## #=varies x=chip
;*
;*      So for PVGA1A, Look for string 'VGA=' at BIOS location C000:007D
;*      Physical address = C007D or E007D
;*      For the other adapters, look for a 'WD' at either possible port pair.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ZR if found.
;* RETURN-ERROR  = NZ if not found.
;*
;* CALLED BY
;*
;****************************************************************************/

IsWesternDig    PROC    Near
                PUBLIC  IsWesternDig

        enter   STACKBLOCK, 0           ;          
        call    WDEnableExt             ;Unlock needed registers.
;*      OUTPUT   = DX = 003x4 (CRTC index address)
        jnz     ExitWD                  ;Exit if wraps!         /*          */
        mov     al, 03dh                ;                       /*          */
        call    WDRegPairString         ;Test reg pair for "WD" /*          */
        jz      ExitWD                  ;Yes, it's a WD!        /*          */
        mov     al, 031h                ;                       /*          */
        call    WDRegPairString         ;Test reg pair for "WD" /*          */
        jz      ExitWD                  ;Yes, it's a WD!        /*          */
;*
;*      Now test for PVGA1A:            ;                       /*          */
;*              WD test program suggests the following for all WD chips:
;*                      and 3cf.e, 0fd
;*                      and 3cf.c, not 040 to reset out of NON-VGA mode
;*                      lock 3cf.f=000
;*                      test 3cf.9 NOT writable==>next test
;*                      unlock 3cf.f=005
;*                      test 3cf.9 writable==>WD chip!
;*                      restore all regs
;*
        push    di
        mov     bx, 0007dh              ;Search target offset.
        mov     cx, 4                   ;Search string length.
        mov     di, OFFSET DGROUP :WDSig ;Search string value.
        call    FindString              ;See if string is there in ROM.
        pop     di
ExitWD:
        call    WDDisableExt
        leave                           ;          
        ret

IsWesternDig    ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = IsChips
;*
;* DESCRIPTION   = Read value of XR00 register. If value is NOT 00 or FF,
;*                 then C&T SVGA exists.
;*                 Some non-C&T adapters may carry over the last value set
;*                 from a previous instruction when querying 3c6, so use
;*                 the cursor reg for test.   s3 964 did this.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ZR if found.
;* RETURN-ERROR  = NZ if not found.
;*
;* CALLED BY
;*
;****************************************************************************/

IsChips         PROC    Near
                PUBLIC  IsChips

        enter   STACKBLOCK, 0

        mov     ax, 0000fh              ;Write 00 to cursor reg               
        call    GetCrtcBaseSave2        ;(3d4)                                

        mov     dx, 03d6h               ;XR extension index register (3d6)
        call    GetSave1                ;Read original index & save it.

        mov     al, 00h                 ;XR00
        call    OutpIdxInpData          ;Read indexed reg

        cmp     al,00h                  ;          
        je      NotChips                ;          
        cmp     al,0FFh
        je      NotChips                ;          
        cmp     al,al                   ;found one!!!
        jz      @F
NotChips:
        cmp     al,01h                  ;set nz flag              
@@:
        call    RestoreSave1            ;Restore the original values.
        call    RestoreSave2            ;Restore the original values.           
        leave
        ret

IsChips         ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = IsWeitek
;*
;* DESCRIPTION   =
;*                      Setting the index at 3c4, or setting the 3c5.11 20 bit
;*                      (a second time) locks (reads as zero)
;*                      3c5.11 when the 3c5.11 20 bit is already set.
;*                      Two outputs to 3c5.11 (of any value) when the hidden
;*                      3c5.11 20 bit is set unlock 3c5.11.
;*                      Setting the 3c5.11 20 bit also locks (reads as zero)
;*                      3c5.12.  In spite of documentation, ALL bits in the
;*                      3c5.12 register are writable when unlocked.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ZR if found.
;* RETURN-ERROR  = NZ if not found.
;*
;* CALLED BY
;*
;****************************************************************************/

IsWeitek        PROC    Near
                PUBLIC  IsWeitek

        enter   STACKBLOCK, 0
        mov     dx, 03c4h               ;SEQ index address (3c4)/*          */
        call    GetSave1                ;Read original index & save it.
        mov     al, 011h                ;SEQ misc index.
        call    OutpIdxInpData          ;Read POSSIBLY locked value.
        test    al, 020h                ;Test SEQ Misc CRLOCK.
        .if     < z >                   ;Only W5x86 if zero!
            call    OutpData            ;Output twice to unlock.
            call    OutpData            ; 
            call    InpData             ;Read UNlocked original value.
            mov     ah, al              ;Save value to restore.
            and     al, not 020h        ;Unlock Output register.
            call    OutpData            ; 
            mov     al, 010h            ;SEQ W5x86 ID Register.
            call    OutpIdxInpData      ; 
            and     al, 0f0h            ;Extract W5x86 ID bits.
            cmp     al, 050h            ;Only W5x86 if equal!
            mov     al, 011h            ;SEQ misc index.
            call    OutpwDelay          ;Restore original lock/unlock.
        .endif
        call    RestoreSave1            ;Restore the original values.
        leave
        ret

IsWeitek        ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = WeitekP9000Chk
;*
;* DESCRIPTION   = Check physical memory addresses for Weitek 9000
;*
;*                 ONLY 9000 PASSES THIS TEST, NOT 9100!
;*
;*                 INTERRUPT REG @ ADDR 00100008+xxx00000 (xxx=top 10 bits)
;*                 xxx usually C00,D00,E00,F00 in Weitek implementation
;*                 xxx usually 800,A00,200 for Diamond Viper
;*                        Bits 31-6 always zero.
;*                        Bit pairs 5-4,3-2,1-0 must set high bit to chg low.
;*                        Safe to change other bits momentarily in text modes
;*                        for testing existence.
;*                        Works strangely enough to be a reasonable test.
;*                 SYS CONFIG REG @ ADDR 00100004+xxx00000 (xxx=top 10 bits)
;*                        Bits 31-26,8-3 always zero.
;*                        Bits 2-0 are chip version
;*                        Safe to change other bits momentarily in text modes
;*                        for testing existence.
;*                        Decent redundancy check for first test.
;*
;* INPUT         = DI == high word of address to check
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ZR if found.
;* RETURN-ERROR  = NZ if not found.
;*
;* CALLED BY
;*      IsWeitek9x00
;*
;****************************************************************************/

ifndef SVGAUTIL

WeitekP9000Chk  PROC    Near            ;                       /*@V3.0MNH04*/
                PUBLIC  WeitekP9000Chk  ;                       /*@V3.0MNH04*/

        xor     bx, bx                  ;Low word of physical address.
        mov     cx, WEITEK_P9000_REGLENGTH  ;Length of area selected
        push    es
        mov     ax, di                  ;High word of physical address.
        call    SVGAPhysToUVirt
        mov     ax, 000h                ;Convert nc to z, c to nz
        rcl     ax, 001h                ; 
        .if     < z >                   ;If selector returned:
            mov     ax, word ptr es:[bx][WEITEK_P9000_SYSCONFIG][word]
            and     ax, 0fe80h
            .if     < z >
            mov     ax, word ptr es:[bx][WEITEK_P9000_SYSCONFIG]
            and     ax, 001f8h
            .if     < z >
            mov     ax, word ptr es:[bx][WEITEK_P9000_ENABLE][word]
            and     ax, ax
            .if     < z >
            mov     ax, word ptr es:[bx][WEITEK_P9000_ENABLE]
            and     ax, 0ffaah
            .if     <ax e 000aah>
            mov     ax, word ptr es:[bx][WEITEK_P9000_INTERRUPT][word]
            and     ax, ax
            .if     < z >
            cli
            mov     ax, word ptr es:[bx][WEITEK_P9000_INTERRUPT]
            mov     dx, ax              ;Save a copy for restore.
            and     ax, 0ffeah
            .if     <ax e 0002ah>
;
;                   These XOR'd bits should be read only!
;
                xor     word ptr es:[bx][WEITEK_P9000_INTERRUPT], 0ffffh
                .if     <dx e es:[bx][WEITEK_P9000_INTERRUPT]>  ;Same?
                    mov     ax, 00015h  ;Only these bits should change!
                    xor     word ptr es:[bx][WEITEK_P9000_INTERRUPT], ax
                    xor     ax, dx
                    cmp     ax, es:[bx][WEITEK_P9000_INTERRUPT]  ;Same?
                .endif
                mov     es:[bx][WEITEK_P9000_INTERRUPT], dx  ;Restore non-WEITEK_P9000!
            .endif                      ;Else already nz for not found.
            .endif                      ;Else already nz for not found.
            .endif                      ;Else already nz for not found.
            .endif                      ;Else already nz for not found.
            .endif                      ;Else already nz for not found.
            .endif                      ;Else already nz for not found.
            sti
            call    SVGAUnPhysToUVirt   ;ES=selector to free.
        .endif                          ;Else already nz for not found.
        pop     es
        ret

WeitekP9000Chk  ENDP                    ;                       /*@V3.0MNH04*/

endif ;/* SVGAUTIL */

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = IsWeitekP9x00
;*
;* DESCRIPTION   = Hunt thru physical memory addresses for Weitek
;*                 INTERRUPT REG @ ADDR 00100008+xxx00000 (xxx=top 10 bits)
;*                 xxx usually C00,D00,E00,F00 in Weitek implementation
;*                 xxx usually 800,A00,200 for Diamond Viper
;*                        Bits 31-6 always zero.
;*                        Bit pairs 5-4,3-2,1-0 must set high bit to chg low.
;*                        Safe to change other bits momentarily in text modes
;*                        for testing existence.
;*                        Works strangely enough to be a reasonable test.
;*                 SYS CONFIG REG @ ADDR 00100004+xxx00000 (xxx=top 10 bits)
;*                        Bits 31-26,8-3 always zero.
;*                        Bits 2-0 are chip version
;*                        Safe to change other bits momentarily in text modes
;*                        for testing existence.
;*                        Decent redundancy check for first test.
;*
;*                      For Diamond Viper, the P9x00 chip must first be
;*                      mapped into the address space.
;*                      Setting the index at 3c4, or setting the 3c5.11 20 bit
;*                      (a second time) locks (reads as zero)
;*                      3c5.11 when the 3c5.11 20 bit is already set.
;*                      Two outputs to 3c5.11 (of any value) when the hidden
;*                      3c5.11 20 bit is set unlock 3c5.11.
;*                      Setting the 3c5.11 20 bit also locks (reads as zero)
;*                      3c5.12.  In spite of documentation, ALL bits in the
;*                      3c5.12 register are writable when unlocked.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ZR if found.
;* RETURN-ERROR  = NZ if not found.
;*
;* CALLED BY
;*
;****************************************************************************/

IsWeitekP9x00   PROC    Near            ;                       /*@V3.0MNH04*/
                PUBLIC  IsWeitekP9x00   ;                       /*@V3.0MNH04*/

        enter   STACKBLOCK, 0
        push    di
        mov     bx, 00037h              ;Search target offset.
        mov     cx, 5                   ;Search string length.
        mov     di, OFFSET DGROUP :DiamondViperSig ;Search string value.
        call    FindString              ;See if string is there in ROM.
        .if     < z >                   ;If Diamond Viper.
;*
;*              Diamond Viper does not map the P9x00 into memory
;*              until you indicate where by outputting where to (locked)
;*              SEQ register 012.  One bit value means unmapped.
;*              So we cannot just hunt thru memory for the P9x00!
;*              This test works for both real DOS and OS/2.
;*
            mov     dx, 03c4h           ;SEQ index address (3c4)/*          */
            call    GetSave1            ;Read original index & save it.
            mov     al, 011h            ;SEQ misc index.
            call    OutpIdxInpData      ;Read POSSIBLY locked value.
            test    al, 020h            ;Test SEQ Misc CRLOCK.
            .if     < z >               ;Only Diamond Viper if zero!
                mov     [SvgaOEMInfo.Manufacturer], DIAMOND_MANUFACTURER ; 1 ;
                call    OutpData        ;Output twice to unlock.
                call    OutpData        ; 
                call    InpData         ;Read UNlocked original value.
                mov     ah, al          ;Save value to restore.
                and     al, not 020h    ;Unlock Output register.
                call    OutpData        ; 
                mov     al, 012h        ;SEQ Output index.
                call    OutpIdxInpData  ; 
                or      al, 003h        ;Set base address to 80000000.
                call    OutpData        ;So following test works!
                mov     al, 011h        ;SEQ misc index.
                call    OutpwDelay      ;Restore original lock/unlock.
                mov     di, 08000h+WEITEK_P9000_REGISTERS ;Indicate base address.
                xor     ax, ax          ;Always successful here!
            .endif
            call    RestoreSave1        ;Restore the original values.
        .endif                          ;Endif Diamond Viper.
        .if     < nz >                  ;If NOT Diamond Viper.
;*
;*              Since unextended real DOS cannot peek and poke the P9x00,
;*              we need a reasonable facsimile.
;*              Also since poking in memory can be dangerous,
;*              it would be helpful to have some hints that we will find it,
;*              before we go off and poke into a possible NMI handler.
;*              Besides checking for the "WEITEK" string,
;*              Another possibility would be to also check for a Weitek VGA!
;*              Weitek VGA existence could also justify P9x00 memory search or
;*              could also presumably "imply" P9x00 existence (for real DOS).
;*              For WPOS, we might not have a BIOS, so we should just
;*              do the hunt or require a Weitek VGA.
;*
            .if     <[_sSVGA.AdapterType] ne WEITEK_ADAPTER>
                mov     cx, 6           ;Search string length.
                mov     di, OFFSET DGROUP:WeitekSig ;Search string value.
                call    LookString      ;See if string is anywhere in ROM.
            .endif
;                                       ;Indicate presumed addr./*@V3.0MNH04*/
             mov     di, 0c000h+WEITEK_P9000_REGISTERS ;        /*@V3.0MNH04*/
        .endif                          ;Endif NOT Diamond Viper.
        .if     < z >                   ;If we found a Weitek P9000:
            mov word ptr [SvgaBaseAddr][word], di ;Save addr.   /*@V3.0MNH04*/
        .endif
        pop     di
        leave
        ret

IsWeitekP9x00   ENDP                    ;                       /*@V3.0MNH04*/

;/****************************************************************************
;*
;* FUNCTION NAME = LastAttempt
;*
;* DESCRIPTION   = This function attempts to detect chipsets of the
;*                 manufacturers which we don't successfuly identify
;*                 in "IsAdapter" functions. For example:
;*                 WD adapters are identified depending on the presence
;*                 of VGA= string in the BIOS. For many OEM implementations,
;*                 this test would fail. The code must not trash VGA registers.
;*
;* INPUT         = NONE
;* OUTPUT        = AX = usAdapterType
;*                 BX = ChipType
;*
;* RETURN-NORMAL = non zero AX
;* RETURN-ERROR  = AX zero
;*
;* CALLED BY
;*
;****************************************************************************/

LastAttempt     PROC    Near
                PUBLIC  LastAttempt

        enter   STACKBLOCK, 0           ;          
;       I doubt that the WD code is necessary any longer!       /*          */
        xor     ax, ax                  ;No identifiable VGA.   /*          */
        leave                           ;          
        ret

LastAttempt     ENDP

;*****************************************************************************
;
;
;
;*****************************************************************************

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = WhichATIUnaccelerated
;*
;* DESCRIPTION   = Test ATI chip for Unaccelerated.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = 1 - ATI18800-x chip
;*                 2 - ATI28800-x chip
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*      WhichATI
;*
;****************************************************************************/

WhichATIUnaccelerated   PROC    near    ;                       /*          */
        PUBLIC  WhichATIUnaccelerated

        push    ds              ; 
        mov     ax, 0ch         ; ROM Address high
        xor     bx, bx          ; ROM Address low
        mov     cx, 100h        ; 
        call    SVGAPhysToVirt  ; 

        ASSUME  DS:NOTHING

        xor     ah, ah          ; 
        mov     al, ds:[si+43h] ; Chip version number
        sub     al, '0'         ; 
        pop     ds              ; 

        ASSUME  DS:DGROUP

        call    SVGAUnPhysToVirt        ; 
        mov     dx, 01ceh               ;ATI Extended regs index
        mov     ah, al                  ;Save version number
        call    InpDelay                ;Get current index reg  /*          */
        or      al, 080h                ;This bit not readable  /*          */
        push    ax                      ;Save index & version
        .if     <ah be 2>               ;Not Ver 3 or higher    /*          */
            mov     al, 0bbh            ;                       /*          */
            call    OutpIdxInpData      ;Read indexed reg       /*          */
            mov     cx, 4               ;assume 256k            /*          */
            test    al, 20h             ; 
            .if     < nz >              ;                       /*          */
                shl     cx, 1           ;                       /*          */
            .endif                      ;                       /*          */
        .else                                                   /*@V2.1MNH13*/
ATIV3:
            mov     al, 0b0h            ;                       /*          */
            call    OutpIdxInpData      ;Read indexed reg       /*          */
            mov     cx, 4               ;assume 256k            /*          */
            test    al, 18h             ; 
            .if     < nz >              ;                       /*          */
                shl     cx, 1           ;make it 512k           /*          */
                test    al, 10h         ; 
                .if     < z >           ;                       /*          */
                    shl     cx, 1       ;make it 1M             /*          */
                .endif                  ;                       /*          */
            .endif                      ;                       /*          */
        .endif                          ;                       /*          */
ATIMEM:                                 ;                       /*          */
        mov     word ptr [_sSVGA.Memory][1*word], cx ;          /*          */
;                                                                ;           start
        pop     ax                      ;Restore index & ver.
        call    OutpDelay               ;Restore original index /*          */
;!!     .if < ah b 5 >                  ;Was this in SVGAROUT but not SVGAID!
        .if < ah b 3 >                  ;Was this in SVGAID but not SVGAROUT!
            mov     ax, ATI_18800_CHIP  ; 
        .else                           ; 
            mov     ax, ATI_28800_CHIP  ; 
        .endif                          ; 
ATIExit:                                ; 
        ret

WhichATIUnaccelerated   ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = WhichATI
;*
;* DESCRIPTION   = ATI Wonder boards V3, V4, V5 use ATI18800-x chips
;*                                   V6, +, XL  use ATI28800-x chips
;*                 ATI "Ultra" boards use Mach 8 == ATI38800-x chips
;*                 ATI "Graphics Ultra" uses Mach 32 == ATI68800-x chips
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = 1 - ATI18800-x chip
;*                 2 - ATI28800-x chip
;*                 3 - ATI38800-x chip                          /*          */
;*                 4 - ATI68800-x chip                          /*          */
;*                 5 - ATI88800-x chip                          /*          */
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

WhichATI        PROC    Near            ; 
                PUBLIC  WhichATI        ; 

        call    ATI8514                 ;Test for ATI 8514      /*          */
        .if     < z >                   ;If ATI 8154:
            mov     ax,0aaaah AND 003ffh;Must limit to 11 bits!
            call    ATIDestXOutpChk     ; 
            .if     < z >               ;If OK so far:
                mov     ax,05555h AND 003ffh ;Must limit to 11 bits!
                call    ATIDestXOutpChk ; 
            .endif                      ; 
            .if     < z >               ;If 68800 (Mach 32)
                mov     dx, 036eeh      ;Misc_Options           /*          */
                mov     cl, 002h        ;Get shift count        /*          */
                mov     bx, ATI_68800_CHIP ;                    /*          */
            .else                       ;Else 38800 (Mach 8)
                mov     dx, 012eeh      ;Config_Status_1        /*          */
                mov     cl, 005h        ;Get shift count        /*          */
                mov     bx, ATI_38800_CHIP ;                    /*          */
            .endif                      ; 
            call    InpwDelay           ;                       /*          */
            shr     al, cl              ;Shift to low bits      /*          */
            and     al, 003h            ;Get memory size bits.  /*          */
            mov     cl, al              ;Use as shift count     /*          */
            mov     ax, 00008h          ;Start with 64K*8=512K  /*          */
            shl     ax, cl              ;                       /*          */
            mov     word ptr [_sSVGA.Memory][1*word], ax ;      /*          */
            mov     ax, bx              ;Set chiptype           /*          */
        .else                           ;If NOT ATI 8514:
;                                                               /*          */
;           Check for Mach64 AFTER Mach8/32:                    /*          */
;               ValuePoint AMBRA system has Mach32 which        /*          */
;               responds to 0x02ec + ? * 0x0400                 /*          */
;               when it should not.                             /*          */
;               Problem is that it hangs the system when you    /*          */
;               write to such an address!                       /*          */
;                                                               /*          */
;               Since it did not happen with all Mach32s        /*          */
;               it is probably a hardware problem.              /*          */
;                                                               /*          */
;               Changing the Mach64 test itself would probably  /*          */
;               not help get past this problem, since           /*          */
;               we would still have to write to SOME port!      /*          */
;                                                               /*          */
;               Fortunately, we already know that the Mach64    /*          */
;               does not pass the test for a Mach32 or Mach8!   /*          */
;                                                               /*          */
            call    ATIMach64           ;Is it a Mach 64?
            .if     < z >               ;If ATI Mach 64:
                mov     dx, 052ech      ;MEM_CTRL reg addr.
                call    InpwDelay       ;Read the current value.
                and     ax, 007h        ;Get memory size bits.
                test    al, 004h
                .if     < nz >          ;If below boundary:
                    mov     cl, al      ; 
                    mov     ax, 00008h  ;Set for 64K*8=512K.
                    shl     ax, cl      ;Shift to actual size.
                .else                   ;Else above boundary:
                    dec     ax          ;Get count of 2M units.
                    shl     ax, 005h    ;Shift to 64K units.
                .endif                  ; 
                mov     word ptr [_sSVGA.Memory][1*word], ax ; 
                mov     ax, ATI_88800_CHIP ; 
            .else                       ;Else NOT ATI Mach 64:
                call    WhichATIUnaccelerated ;                 /*          */
            .endif                      ; 
        .endif                          ; 
        ret
;                                                                ;           end
WhichATI        ENDP                    ; 

;/****************************************************************************
;*
;* FUNCTION NAME = WhichCirrus
;*
;* DESCRIPTION   =  Cirrus chips: GD5422, GD5424, GD5426, GD5428, etc.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = 0 - any other Cirrus chip, not supported by SVGA
;*                 1 - GD5420 chip                                          
;*                 2 - GD5422 chip
;*                 3 - GD5424 chip
;*                 4 - GD5426 chip
;*                 5 - GD5428 chip                                          
;*                 6 - GD5429 chip                                          
;*                 7 - GD543X chip                                          
;*                 8 - GD5434 chip                                          
;*
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/
;          
WhichCirrus     PROC    Near
                PUBLIC  WhichCirrus

        enter   STACKBLOCK, 0           ;          
        mov     dx, 03c4h               ;SEQ index address (3c4)/*          */
        call    GetSave1                ;Read original index & save it.
        mov     ax, 01206h              ; sr6 register index and unlock.
        mov     [SaveReg2], dx          ;                       /*          */
        mov     [SaveIndex2], al
        call    OutpIdxChkXchgData      ;Try setting SEQ SR6.   /*          */
        mov     [SaveValue2], al        ;Save old value.        /*          */
        mov     ah, 0                   ; set return to 0
        jne     cirrus_exit             ; Unable to unlock, assume GD5401
        call    GetCrtcBase             ;(3d4)                  /*          */
;*      OUTPUT   = DX = 003x4 (CRTC index address)
        mov     al, 27h                 ; Chip ID register index
        call    OutpIdxInpData          ;Read indexed reg       /*          */
        mov     dx, 03c4h               ;SEQ index address (3c4)/*          */
;           mov     ah, 0                   ; asuume one of the older ones
;           cmp     al, 8ah                 ; GD5420
;           je  cirrus_exit
        shr     al, 1
        shr     al, 1
        mov     ah, CIRRUS_5420_CHIP    ; 1                                  
        cmp     al, 022h                ; GD5420                             
        je      Mem2x                   ;                                    
        mov     ah, CIRRUS_5422_CHIP ;2                         /*          */
        cmp     al, 23h                 ; GD5422
        je      Mem2x                   ;                                    
        mov     ah, CIRRUS_5424_CHIP ;3                         /*          */
        cmp     al, 25h                 ; GD5424
        je      Mem2x                   ;                                    
        mov     ah, CIRRUS_5426_CHIP ;4                         /*          */
        cmp     al, 24h                 ; GD5426
        je      Mem2x                   ;                                    
        mov     ah, CIRRUS_5428_CHIP ;5 ;            ;           *          */
        cmp     al, 26h                 ; GD5428                             
        je      Mem2x                   ;                                    
        mov     ah, CIRRUS_5429_CHIP    ; 6                                  
        cmp     al, 027h                ; GD5429                             
        je      Mem2x                   ;                                    
        mov     ah, CIRRUS_5434_CHIP    ; 8                                  
        cmp     al, 02Ah                ; GD5434                             
        je      Mem3x                   ;                                    
        mov     ah, CIRRUS_543X_CHIP    ; 7                                  
        cmp     al, 028h                ; GD5430                             
        je      Mem3x                   ;                                    
        cmp     al, 029h                ; GD5430-like                        
        je      Mem3x                   ;                                    
        mov     ah, 0                   ; none of the above
        jmp     short cirrus_exit       ; exit                               
Mem2x:                                  ;                                    
        mov     al, 0ah                 ; memory reg for 2x                  
        call    OutpIdxInpData          ; get memory value                   
        shr     al, 03h                 ; shift bits 3,4 to end              
        and     al, 03h                 ; only look at bits 3,4              
        jmp     short GetCirrusMem      ; get memory                         
Mem3x:                                  ;                                    
        mov     al, 015h                ; memory reg for 3x                  
        call    OutpIdxInpData          ; get memory value                   
        and     al, 00fh                ; mask lower nibble                  
GetCirrusMem:                           ;                                    
        .if     <al ne 002h>            ;1 Meg ?                             
            mov     dx, 010h            ;Get default mem size=1M             
            .if     <al e 001h>         ;512K ?                              
                shr     dx, 1           ;adjust mem to 512k                  
            .endif                      ;                                    
            .if     <al e 003h>         ;2 Meg ?                             
                shl     dx, 1           ;adjust mem to 2 Meg                 
            .endif                      ;                                    
            .if     <al e 004h>         ;4 Meg ?                             
                shl     dx, 2           ;adjust mem to 4 Meg                 
            .endif                      ;                                    
            mov     word ptr [_sSVGA.Memory][1*word], dx  ;save it           
        .endif                          ;                                    
cirrus_exit:
        mov     al, ah
        cbw
        call    RestoreSave2            ;Restore the original values.
        leave                           ;          
        ret

WhichCirrus        ENDP

;/*****************************************************************             ;          
;*
;* FUNCTION NAME = WhichS3                                  
;*
;* DESCRIPTION   =  S3: xxxxxx, xxxxxx, xxxxxx
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = 0 - any other S3 chip, not supported by SVGA
;*                 1 - xxxxxx chip
;*                 2 - xxxxxx chip
;*                 3 - xxxxxx chip
;*
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/
WhichS3         PROC    Near            ;          
                PUBLIC  WhichS3

;!!Need to adjust memory sizes!
        enter   STACKBLOCK, 0           ;          
        mov     ax, 04838h              ;Unlock extensions.
        call    GetCrtcBaseSave2        ;(3d4)                  /*          */
;*      OUTPUT   = DX = 003x4 (CRTC index address)
;       mov     ax, 0a039h              ;unlock r39             /*          */
;       call    OutpIdxXchgData         ;Not needed for reads!  /*          */
;       mov     ah, al                  ;                       /*          */
;       push    ax                      ;Save original lock     /*          */
        mov     al, 030h                ;Chip ID/Rev index      /*          */
        call    OutpIdxInpData          ;Read indexed reg       /*          */
        and     al, 0f0h                ;mask out lower nibble  /*          */
        mov     cl, al                  ;Save chip id           /*          */
        mov     al, 036h                ;Configuration Reg 1 index
        call    OutpIdxInpData          ;Read indexed reg       /*          */
        and     al, 0e0h
        .if     <cl e 080h>             ;If 911/924:            /*          */
            or  al, 0c0h                ;Insure high bits set   /*          */
        .endif                          ;                       /*          */
        .if     <al ne 0c0h>            ;1 Meg ?                /*          */
            mov     dx, 010h            ;Get default mem size=1M/*          */
            .if     <al e 0e0h>         ;512K ?                 /*          */
                shr     dx, 1           ;adjust mem to 512k
            .endif                                              /*@V2.1MNH13*/
            .if     <al e 080h>         ;2 Meg ?                /*          */
                shl     dx, 1           ;adjust mem to 2 Meg
            .endif                                              /*@V2.1MNH13*/
            .if     <al e 040h>         ;3 Meg ?                /*          */
                mov     bx, dx          ;adjust mem to 3 Meg
                shl     dx, 1
                or      dx, bx
            .endif                                              /*@V2.1MNH13*/
            .if     <zero al>           ;4 Meg ?                /*          */
                shl     dx, 2           ;adjust mem to 4 Meg
            .endif                                              /*@V2.1MNH13*/
;                                       ;Save mem size:         /*          */
            mov     word ptr [_sSVGA.Memory][1*word], dx ;      /*          */
        .endif                                                  /*@V2.1MNH13*/
determine_S3:
        mov     al, S3_86C805_CHIP      ;                       /*          */
        cmp     cl, 0a0h                ;801/805
        je      S3_exit                 ;                       /*          */
        mov     al, S3_86C911_CHIP      ;                       /*          */
        cmp     cl, 080h                ;          
        je      S3_exit                 ;                       /*          */
        mov     al, S3_86C928_CHIP      ;                       /*          */
        cmp     cl, 090h                ;928
        je      S3_exit                 ;                       /*          */
        cmp     cl, 0b0h                ;928 PCI                            
        je      S3_exit                 ;                       /*          */
        mov     al, S3_86C864_CHIP      ;                       /*          */
        cmp     cl, 0c0h                ;Vision 864                         
        je      S3_exit                 ;                       /*          */
        mov     al, S3_86C964_CHIP      ;                       /*@V3.0YEE01*/
        cmp     cl, 0d0h                ;Vision 964               @V3.0YEE01
        je      S3_exit                 ;                       /*@V3.0YEE01*/
        xor     al, al                  ;                       /*          */
S3_exit:
        cbw
S3found:
;       mov     cx, ax                  ;                       /*          */
;       pop     ax                      ;Restore original lock. /*          */
;       mov     al, 039h                ;Not needed for reads!  /*          */
;       call    OutpwDelay              ;Write the new value.   /*          */
        call    RestoreSave2            ;Restore original value.
;       mov     ax, cx                  ;                       /*          */
        leave                           ;          
        ret

WhichS3            ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = WhichTrident
;*
;* DESCRIPTION   =
;*
;*         read Chip Version Register
;*         value in AL >= 3   8900 chip version
;*
;*         convert AL to:  AL = 1 => 8800
;*                         AL = 2 => 8900
;*
;*         Check memory on 8900 from 'Software Programming' register
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

WhichTrident    PROC    Near
                PUBLIC  WhichTrident

        mov     dx, 03c4h               ;SEQ index address (3c4)/*          */
        mov     ax, 0bh                 ;write 0 to version reg (0bh)
        call    OutpIdxInpData          ;Read indexed reg       /*          */
        cmp     al, 003h                ;                       /*          */
        mov     ax, TRIDENT_8800_CHIP   ;assume 8800            /*          */
        jl      short @F                ;                       /*          */
        call    GetCrtcBase             ;(3d4)                  /*          */
;*      OUTPUT   = DX = 003x4 (CRTC index address)
        mov     al, 01fh                ;Set up to read 'software programming'
                                        ; reg w/two bits w/amount of video memory.
        call    OutpIdxInpData          ;Read indexed reg       /*          */
        and     al, 003h                ;Isolate # 256K blks - 1/*          */
        inc     al                      ;al = # 256K blks       /*          */
        shl     al, 002h                ;al = # 64K blks        /*          */
        mov     byte ptr [_sSVGA.Memory][1*word], al ;          /*          */
        mov     ax, TRIDENT_8900_CHIP   ;make it 8900           /*          */
@@:     ret

WhichTrident    ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = _IdentifyCPU
;*
;* DESCRIPTION   =   figure out what type of Intel 80x8x is in use
;*
;*
;*
;* ENTRY POINT:  _IdentifyProcessorType
;*    LINKAGE:   Call Far
;*
;* INPUT:
;*       DS = DGROUP
;*
;* EXIT-NORMAL: AX = processor type
;* EXIT-ERROR:  NONE
;*
;* EFFECTS:
;*       AX
;*
;* USES ROUTINES:
;*
;* CALLED BY ROUTINES:
;*             INIT
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ax = processor type
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/



;JWK22

; The following procedure determines the type of processor present in the
; system it is running on.  This procedure was documented by INTEL in an
; APPLICATION NOTE (AP-485) as the 'official' way to determine processor
; type. Additionally note that if processor is not made by Intel, or by a
; vendor licensed to used Intel's masks, the results may not be valid.
;
; Returns:
;  10h - 8088 processor    \ the code to distinguish 8086 from 8088
;  11h - 8086 processor    / is NOT from Intel
;  20h - Intel 286 processor
;  30h - Intel386(TM) processor
;  40h - Intel486(TM) processor
;  50h - Pentium(TM) processor
;


NULPROC         equ      0h
PROCV20         equ      8h
PROC808x        equ     10h
PROC8088        equ     10h
PROC8086        equ     11h
PROC8018x       equ     18h
PROC80188       equ     18h
PROC80186       equ     19h
PROC80286       equ     20h
PROC80386       equ     30h
PROC80386SX     equ     38h
PROC80386SLC    equ     39h
PROC80386SL     equ     3ah
PROC80486       equ     40h
PROC80486DX     equ     40h
PROC80486DX2    equ     41h
PROC80486DX3    equ     42h
PROC80486SX     equ     45h
PROC80486SX2    equ     46h
PROC80486SX3    equ     47h
PROC80486SL     equ     49h
PROC80486SLC    equ     4ah
PROC80486SLC2   equ     4bh
PROC80486SLC3   equ     4ch
PROC80486BL2    equ     4dh
PROC80486BL3    equ     4eh
PROCPentium     equ     50h
PROCCYRIXDR2    equ    0c6h

CPUID   MACRO
        db      0fh                     ; opcode for CPUID instruction
        db      0a2h
        ENDM

MPUSHFD MACRO
        db      066h                    ; opcode for pushfd instruction
        db      09ch
        ENDM

MPOPFD  MACRO
        db      066h                    ; opcode for popfd instruction
        db      09dh
        ENDM

MPUSHEAX MACRO
        db      066h                    ; opcode for pusheax instruction
        db      050h
        ENDM

MPOPEAX MACRO
        db      066h                    ; opcode for pusheax instruction
        db      058h
        ENDM


FAMILY_MASK     equ     0f00h
FAMILY_SHIFT    equ     8
MODEL_MASK      equ     0f0h
MODEL_SHIFT     equ     4
STEPPING_MASK   equ     0fh


cpuid_step         EQU   <BYTE PTR [bp-06h]>       ; byte
cpuid_model        EQU   <BYTE PTR [bp-08h]>       ; byte
cpuid_type         EQU   <BYTE PTR [bp-0ah]>       ; byte
IDENTIFYCPUSTACKBLOCK EQU 0ah




IdentifyCPU   PROC                 ;JWK22

        enter   IDENTIFYCPUSTACKBLOCK,0
        push    ds

        push    dx
        push    cx
        push    bx



        pushf                           ; save flags
        xor     ax,ax                   ; clear AX
        push    ax                      ; push it on the stack
        popf                            ; zero the flags
        pushf                           ; try to zero flag bits 12-15
        pop     ax                      ; recover flags
        and     ax,0f000h               ; if flag bits 12-15 are 1
        cmp     ax,0f000h               ;  then processor is
        jz      is_0_1                  ;   8018x or 808x
        mov     ax,07000h               ; try to set flag bits 12-14
        push    ax
        popf
        pushf
        pop     ax
        mov     dx,PROC80386            ; load 386 value
        and     ax,07000h               ; if 12-14 are 0
        jz      is_80286                ;  processor is 80286

   ; allow 386 instructions
        .386

        ;;pushfd                        ; save all flags
        MPUSHFD

        mov     ax,0000fh               ; turn all upper bits on
        push    ax                      ; of EFLAGS.
        xor     ax,ax                   ; turn off all lower bits of EFLAGS.
        push    ax                      ; put flags on stack

        ;;popfd                         ; pop back into flags
        MPOPFD

        ;;pushfd                        ; push flags back to stack
        MPUSHFD

        pop     ax                      ; throw away lower part
        pop     ax                      ; we can see results in AX
        cmp     ax,0                    ; if AX == 0 then we have a 386
        jz      SHORT finishpop         ; otherwise we have a 486 or higher

        mov     dx,PROC80486            ; store a 486 value

        ;;pushfd                        ; push original EFLAGS
        MPUSHFD

        ;;pop     eax                   ; get original EFLAGS in EAX
        MPOPEAX

        mov     ecx,eax                 ; save original EFLAGS in ECX
        xor     eax,200000h             ; flip ID bit in EFLAGS

        ;;push    eax                   ; save for EFLAGS
        MPUSHEAX

        ;;popfd                         ; copy to EFLAGS
        MPOPFD

        ;;pushfd                        ; push EFLAGS
        MPUSHFD

        ;;pop     eax                   ; get new EFLAGS value
        MPOPEAX

        xor     eax,ecx
        jz      SHORT finishpop         ; if ID bit cannot be changed,
                                        ;   CPU = Intel486 without CPUID
                                        ;   instruction functionality
;
;    Otherwise, execute CPUID instruction to determine family.
;
cpuid_data:
        mov     eax,1
        CPUID
        mov     cpuid_step,al          ; isolate stepping info
        and     cpuid_step,STEPPING_MASK

        and     al,MODEL_MASK           ; isolate model info
        shr     al,MODEL_SHIFT
        mov     cpuid_model,al

        and     ax,FAMILY_MASK          ; mask everything but family
        shr     ax,FAMILY_SHIFT
        mov     cpuid_type,al
        mov     cx,16                   ; move 16 to CX
        mul     cx                      ; multiply AX by 16
        mov     dx,ax                   ; set cpu_type with family

finishpop:
        mov     ax, dx                  ; get return value

        ;;popfd                         ; restore extended flags
        MPOPFD


  ; restore processor instructions allowed

        ifdef SVGAUTIL
           .286
        else ;/* SVGAUTIL */
           .386p
        endif ;/* SVGAUTIL */


        mov     dx,ax                   ; 
        jmp     short IdentifyCPUdone

is_80286:
        mov     dx,PROC80286            ; point to processor id string
        jmp     short IdentifyCPUdone

is_0_1:
        push    cx                      ; save CX for test of shift
        mov     ax,0ffffh               ; set all AX bits
        mov     cl,33                   ; will shift only once on 80186
        shl     ax,cl                   ;  or 33 times on 8086
        pop     cx                      ; restore CX
        jnz     is_80186                ; non-zero means 80186

is_8086:
; Is it an 8086?
; Returns ax == 0 for 8088, ax == 1 for 8086
; Code takes advantage of the 8088's 4-byte prefetch queues and 8086's
; 6-byte prefetch queues. By self-modifying the code at location exactly
; 5 bytes away from IP, and determining if the modification took effect,
; you can differentiate between 8088s and 8086s.
; Note this code was taken from Dr. Dobb's Journal, June 1993.
        mov     ax,cs                   ; ES == code segment
        mov     es,ax

        std                             ; cause stosb to count backwards

        mov     dx,1                    ; DX is flag and we'll start at 1
        mov     di,OFFSET IdentifyCPUEndLabel      ; DI == offset of code tail to modify
        mov     al,090h                 ; AL == nop instruction opcode
        mov     cx,3                    ; set for 3 repetitions
        REP     stosb                   ; store the bytes

        cld                             ; clear the direction flag
        nop                             ; three nops in a row
        nop                             ; provide dummy instructions
        nop
        dec     dx                      ; decrement flag (only with 8088)
        nop                             ; dummy instruction--6 bytes
IdentifyCPUEndLabel:
        nop

        mov     ax,dx                   ; get value in AX
        mov     dx,PROC8088             ; indicate 8088
        cmp     ax,0                    ; if AX == 0 then we have a 8088
        jz      is_8086_done            ; otherwise we have a 8086
        mov     dx,PROC8086             ; indicate 8086

is_8086_done:
        jmp     short IdentifyCPUdone

is_80186:
        mov     dx,PROC8018x

IdentifyCPUdone:
        popf                            ; restore original flags
        mov     ax,dx                   ; put processor type into AX
        pop     bx
        pop     cx
        pop     dx
        pop     ds
        leave
        ret

IdentifyCPU   ENDP                ; JWK22


_IdentifyCPU   PROC    far          ;JWK22
               PUBLIC  _IdentifyCPU

        call IdentifyCPU
        ret

_IdentifyCPU   ENDP                ; JWK22


;/****************************************************************************
;*
;* FUNCTION NAME = TsengGetVRAMSize                     /*          */
;*                                   ;;JWK07 replace entire routine to use
;*                                   ;;      iodelay, correct unlock, use write to flush cache
;*                                   ;;      needed for PCI and VLB
;* DESCRIPTION   = Determine how much VRAM is installed by read/write of VRAM
;*
;* INPUT         = AX = chiptype
;*                 DX = CRTC index (3c4 or 3b4)
;* OUTPUT        = AX = number of VRAM 64k blocks
;*                      all other registers restored
;* RETURN-NORMAL = AX = number of VRAM 64k blocks
;* RETURN-ERROR  = AX = 0
;*
;* CALLED BY     WhichTseng
;*
;* ASSUMPTIONS  1) tseng already 'found'
;*              2) extended registers enabled
;*
;****************************************************************************/

TTESTA  equ 00000h
TTESTB  equ 0aaaah
TTESTC  equ 0f0f0h
TTESTD  equ 00707h

WBINVD  MACRO            ; JWK22
  local skiplabel
        cmp     Tcpu_id, PROC80486      ; invalid opcode if < 486
        jl      short skiplabel
        db      0fh      ; write back and invalidate cache command
        db      09h      ; 
  skiplabel:
        ENDM

Tsave0              EQU   <WORD PTR [bp-02h]>       ; WORD
Tsave1              EQU   <WORD PTR [bp-04h]>       ; WORD
Tsave2              EQU   <WORD PTR [bp-06h]>       ; WORD
Tsave3              EQU   <WORD PTR [bp-08h]>       ; WORD
Ttest0              EQU   <WORD PTR [bp-0ah]>       ; WORD
Ttest1              EQU   <WORD PTR [bp-0ch]>       ; WORD
Ttest2              EQU   <WORD PTR [bp-0eh]>       ; WORD
Ttest3              EQU   <WORD PTR [bp-10h]>       ; WORD
Tpeek0              EQU   <WORD PTR [bp-12h]>       ; WORD
Tpeek1              EQU   <WORD PTR [bp-14h]>       ; WORD
Tpeek2              EQU   <WORD PTR [bp-16h]>       ; WORD
Tpeek3              EQU   <WORD PTR [bp-18h]>       ; WORD
Tchiptype           EQU   <WORD PTR [bp-1ah]>       ; WORD
TCRTCIndex          EQU   <WORD PTR [bp-1ch]>       ; WORD
Tseg                EQU   <WORD PTR [bp-1eh]>       ; WORD
Tseg_3cd            EQU   <WORD PTR [bp-20h]>       ; WORD
Tseg_3cb            EQU   <WORD PTR [bp-22h]>       ; WORD
Tcpu_id             EQU   <WORD PTR [bp-24h]>       ; WORD
Tmap                EQU   <BYTE PTR [bp-26h]>       ; BYTE
Tsave_3cb           EQU   <BYTE PTR [bp-28h]>       ; BYTE
Tsave_3cd           EQU   <BYTE PTR [bp-2ah]>       ; BYTE
TSENGSTACKBLOCK     EQU   2ah


TsengGetVRAMSize  PROC    Near
                  PUBLIC  TsengGetVRAMSize


    enter   TSENGSTACKBLOCK, 0

    push  si
    push  bx
    push  cx
    push  es
    push  ds

    mov Ttest0, TTESTA
    mov Ttest1, TTESTB
    mov Ttest2, TTESTC
    mov Ttest3, TTESTD
    mov Tchiptype, ax
    mov TCRTCIndex,dx
    mov Tseg, 0                     ; preset return value
    mov Tcpu_id, 0                  ; clear cpu id


    call  IdentifyCPU               ; get cpu type in AX

    mov Tcpu_id, ax                 ; save cpu type


    ; Set the 'key' (ie, unlock)
    mov    dx, 03bfh
    mov    al, 03h
    call   OutpDelay
    mov    dx, 03b8h
    mov    al, 0a0h
    call   OutpDelay
    mov    dx, 03d8h
    mov    al, 0a0h
    call   OutpDelay


;   Save the state of the TS GDC and CRTC36 registers so we can restore after
;   setting up linear mapping.
;
;  just push save on stack

    mov    cx, 1
SaveTS:
    mov    dx, 03C4h
    mov    ax, cx
    call   OutpIdxInpData
    push   ax
    inc    cx
    cmp    cx, 6
    jle    SaveTS

    mov    cx, 0
SaveGDC:
    mov    dx, 03CEh
    mov    ax, cx
    call   OutpIdxInpData
    push   ax
    inc    cx
    cmp    cx, 8
    jle    SaveGDC

SaveCRTC36:
    mov    dx, 03D4h
    mov    ax, 036h
    call   OutpIdxInpData
    push   ax
SaveCRTC34:
    mov    dx, 03D4h
    mov    ax, 034h
    call   OutpIdxInpData
    push   ax


;   Set up for linear access.
;   Enable writes to all planes.

    mov   dx, 03C4h
    mov   al, 02h
    call  OutpIdxInpData ;;out   dx, al
     or   al, 0fh
    inc   dx
    call  OutpDelay ;;out   dx, al


;   blank the screen to enable fast host VRAM access

    mov   dx, 03C4h
    mov   al, 01h
    call  OutpIdxInpData
    or    al, 20h
    inc   dx
    call  OutpDelay


;   set write plane mask for all planes

    mov   dx, 03C4h
    mov   al, 02h
    call  OutpIdxInpData
     or   al, 0fh
    inc   dx
    call  OutpDelay


;   set Chain 4 mode, disable font selection

    mov   dx, 03C4h
    mov   al, 04h
    call  OutpIdxInpData
    or    al, 0ch
    and   al, 0fdh
    inc   dx
    call  OutpDelay

;   make sure fast r/w disabled
                                                                  ;JWK11
    mov   dx, 03C4h                                               ;JWK11
    mov   al, 06h                                                 ;JWK11
    call  OutpIdxInpData                                          ;JWK11
    and   al, 0cfh                ; disable 'early address info'  ;JWK11
     or   al, 040h                ;  disable zero wait state      ;JWK11
    inc   dx                                                      ;JWK11
    call  OutpDelay                                               ;JWK11

;   Disable set/reset

    mov   dx, 03CEh
    mov   al, 01h
    call  OutpIdxInpData
    and   al, 0f0h
    inc   dx
    call  OutpDelay


;   No rop or rotate.

    mov   dx, 03CEh
    mov   al, 03h
    call  OutpIdxInpData
    and   al, 0e0h
    inc   dx

;   select plane 0

    mov   dx, 03CEh
    mov   al, 04h
    call  OutpIdxInpData
    and   al, 0fch
    inc   dx
    call  OutpDelay

;   Normal read/write modes

    mov   dx, 03CEh
    mov   al, 05h
    call  OutpIdxInpData
    and   al, 0e4h
    inc   dx
    call  OutpDelay



;   disable PCI Memory Burst

    mov   dx, 03D4h         ;jwk11
    mov   al, 34h           ;jwk11
    call  OutpIdxInpData    ;jwk11
    and   al, 0efh          ;jwk11
    inc   dx                ;jwk11
    call  OutpDelay         ;jwk11

;   disable MMU and linear flat addressing

    mov   dx, 03D4h
    mov   al, 36h
    call  OutpIdxInpData
    and   al, 0c7h          ;jwk11 was c3 WRONG
    inc   dx
    call  OutpDelay


;   Use existing mapping
;   Disable odd/even

    mov   dx, 03CEh
    mov   al, 06h
    call  OutpIdxInpData
    mov   Tmap, al
    and   al, 0fdh
    inc   dx
    call  OutpDelay


;   Enable all bits

    mov   dx, 03CEh
    mov   al, 08h
    call  OutpIdxInpData
    mov   al, 0ffh
    inc   dx
    call  OutpDelay


;   Address where the VGA memory happens to be mapped

    mov  al, Tmap
    shr  al, 2
    and  al, 03h

    cmp  al, 03h
    jnz  @f
    mov  ax, 000Bh
    mov  bx, 8000h
    jmp  SHORT BreakMapSwitch
@@:
    cmp  al, 02
    jnz  @f
    mov  ax, 000Bh
    mov  bx, 0000h
    jmp SHORT BreakMapSwitch
@@:                                     ;; must be 0 or 1
    mov  ax, 000Ah
    mov  bx, 0000h

BreakMapSwitch:

    mov cx, 16*1024    ; request 16k memory

    push    ds
    pop     es
    ASSUME  DS:NOTHING, ES:DGROUP

    push    ds                      ;save values for unphystovirt
    push    ax                      ;save values for unphystovirt
    push    bx
    push    cx
    call    SVGAPhysToVirt          ;Get virtual address into DS:SI.
    jnc     @f
    jmp     breaktestloop
@@:


;   Save the GDC segment select registers

    mov  dx, 03CBh
    in   al, dx
    mov  Tsave_3cb, al
    mov  dx, 03CDh
    in   al, dx
    mov  Tsave_3cd, al

;   Select the first segment and save what we find there

    ;flush cach
    WBINVD            ;WBINVD write-back and invalidate cach

    xor  al, al
    mov  dx, 03CBh
    call OutpDelay
    mov  dx, 03CDh
    xor  al, al
    call OutpDelay


    ;flush cach
    WBINVD            ;WBINVD write-back and invalidate cach   ;JWK22


;   force fifo empty read                       ;JWK08
;   force fifo empty read                       ;JWK08
                                                ;JWK08
        push  cx                                ;JWK08
                                                ;JWK08
        mov   cx, 512                           ;JWK08
        mov   bx, 100  ;offset 100 bytes so we flush 'elsewhere'
   loopa1:                                      ;JWK08
        mov   ax, WORD PTR ds:[si+bx]           ;JWK08
        add   bx, 2                             ;JWK08
        loop  loopa1                            ;JWK08
                                                ;JWK08
                                                ;JWK08
        pop   cx                                ;JWK08
                                                ;JWK08

; read inital values to be restored later

    mov  ax, WORD PTR ds:[si+0]
    mov  Tsave0, ax
    mov  ax, WORD PTR ds:[si+2]
    mov  Tsave1, ax
    mov  ax, WORD PTR ds:[si+4]
    mov  Tsave2, ax
    mov  ax, WORD PTR ds:[si+6]
    mov  Tsave3, ax

;   set the initial values of the first segment
;   these should not change unless a wrap occurred

    mov ax, Ttest0
    mov WORD PTR ds:[si+0], ax
    mov ax, Ttest1
    mov WORD PTR ds:[si+2], ax
    mov ax, Ttest2
    mov WORD PTR ds:[si+4], ax
    mov ax, Ttest3
    mov WORD PTR ds:[si+6], ax

    ;flush cach
    WBINVD            ;WBINVD write-back and invalidate cach   ;JWK22


;   force fifo empty read                       ;JWK08
                                                ;JWK08
        push  cx                                ;JWK08
                                                ;JWK08
        mov   cx, 512                           ;JWK08
        mov   bx, 100  ;offset 100 bytes so we flush 'elsewhere'
   loopb1:                                      ;JWK08
        mov   ax, WORD PTR ds:[si+bx]           ;JWK08
        add   bx, 2                             ;JWK08
        loop  loopb1                            ;JWK08
                                                ;JWK08
                                                ;JWK08
        pop   cx                                ;JWK08



;   Probe memory in 128k increments

    xor    cx, cx
ForSegLoop:

;
;   Construct the GDC segment selector values for the segment
;       seg_3cd = seg & 0x0F;
;       seg_3cd |= seg_3cd << 4;
;       seg_3cb = seg & 0x30;
;       seg_3cb |= seg_3cb >> 4;

   mov  bx, cx                    ; cx has current segment
   and  bx, 0fh
   mov  ax, bx
   shl  bx, 4
   or   ax, bx
   mov  Tseg_3cd, ax

   mov  bx, cx
   and  bx, 30h
   mov  ax, bx
   shr  bx, 4
   or   ax, bx
   mov  Tseg_3cb, ax


    ;flush cach
    WBINVD            ;WBINVD write-back and invalidate cach   ;JWK22


;   force fifo empty read                       ;JWK08
                                                ;JWK08
        push  cx                                ;JWK08
                                                ;JWK08
        mov   cx, 512                           ;JWK08
        mov   bx, 100  ;offset 100 bytes so we flush 'elsewhere'
   loopc1:                                      ;JWK08
        mov   ax, WORD PTR ds:[si+bx]           ;JWK08
        add   bx, 2                             ;JWK08
        loop  loopc1                            ;JWK08
                                                ;JWK08
                                                ;JWK08
        pop   cx                                ;JWK08

;  Select the 64k segment to test

   mov  dx, 03CDh
   mov  ax, Tseg_3cd
   call OutpDelay

   mov  dx, 03CBh
   mov  ax, Tseg_3cb
   call OutpDelay

    ;flush cach
    WBINVD            ;WBINVD write-back and invalidate cach  ;JWK22


;   force fifo empty read                       ;JWK08
                                                ;JWK08
        push  cx                                ;JWK08
                                                ;JWK08
        mov   cx, 512                           ;JWK08
        mov   bx, 100  ;offset 100 bytes so we flush 'elsewhere'
   loopd1:                                      ;JWK08
        mov   ax, WORD PTR ds:[si+bx]           ;JWK08
        add   bx, 2                             ;JWK08
        loop  loopd1                            ;JWK08
                                                ;JWK08
                                                ;JWK08
        pop   cx                                ;JWK08
                                             ;JWK08
                                             ;JWK08
; read current VRAM values so we can restore

   mov ax, WORD PTR ds:[si+0]
   mov Tpeek0, ax
   mov ax, WORD PTR ds:[si+2]
   mov Tpeek1, ax
   mov ax, WORD PTR ds:[si+4]
   mov Tpeek2, ax
   mov ax, WORD PTR ds:[si+6]
   mov Tpeek3, ax


;  Write the test values

   mov ax, Ttest0
   mov WORD PTR ds:[si+0], ax
   mov ax, Ttest1
   mov WORD PTR ds:[si+2], ax
   mov ax, Ttest2
   mov WORD PTR ds:[si+4], ax
   mov ax, Ttest3
   mov WORD PTR ds:[si+6], ax

    ;flush cach
    WBINVD            ;WBINVD write-back and invalidate cach  ;JWK22


;   force fifo empty read                       ;JWK08
                                                ;JWK08
        push  cx                                ;JWK08
                                                ;JWK08
        mov   cx, 512                           ;JWK08
        mov   bx, 100  ;offset 100 bytes so we flush 'elsewhere'
   loope1:                                      ;JWK08
        mov   ax, WORD PTR ds:[si+bx]           ;JWK08
        add   bx, 2                             ;JWK08
        loop  loope1                            ;JWK08
                                                ;JWK08
                                                ;JWK08
        pop   cx                                ;JWK08


;  Make sure data in segment 0 is still valid (no wrap)

    xor  al, al
    mov  dx, 03CBh
    call OutpDelay
    mov  dx, 03CDh
    xor  al, al
    call OutpDelay

    ;flush cach
    WBINVD            ;WBINVD write-back and invalidate cach  ;JWK22


;   force fifo empty read                       ;JWK08
                                                ;JWK08
        push  cx                                ;JWK08
                                                ;JWK08
        mov   cx, 512                           ;JWK08
        mov   bx, 100  ;offset 100 bytes so we flush 'elsewhere'
   loopf1:                                      ;JWK08
        mov   ax, WORD PTR ds:[si+bx]           ;JWK08
        add   bx, 2                             ;JWK08
        loop  loopf1                            ;JWK08
                                                ;JWK08
                                                ;JWK08
        pop   cx                                ;JWK08

;  check test values

   mov ax, WORD PTR ds:[si+0]
   cmp ax, TTESTA
   jz  @f
   jmp  breaktestloop
@@:
   mov ax, WORD PTR ds:[si+2]
   cmp ax, TTESTB
   jz  @f
   jmp  breaktestloop
@@:
   mov ax, WORD PTR ds:[si+4]
   cmp ax, TTESTC
   jz  @f
   jmp breaktestloop                    ;short fails on screendd
@@:
   mov ax, WORD PTR ds:[si+6]
   cmp ax, TTESTD
   jz  @f
   jmp breaktestloop                    ;short fails on screendd
@@:


;  Try to read back the test values in the test segment

    ;flush cach
    WBINVD            ;WBINVD write-back and invalidate cach  ;JWK22


;   force fifo empty read                       ;JWK08
                                                ;JWK08
        push  cx                                ;JWK08
                                                ;JWK08
        mov   cx, 512                           ;JWK08
        mov   bx, 100  ;offset 100 bytes so we flush 'elsewhere'
   loopg1:                                      ;JWK08
        mov   ax, WORD PTR ds:[si+bx]           ;JWK08
        add   bx, 2                             ;JWK08
        loop  loopg1                            ;JWK08
                                                ;JWK08
                                                ;JWK08
        pop   cx                                ;JWK08

   mov  dx, 03CDh
   mov  ax, Tseg_3cd
   ;;out  dx, al
   call OutpDelay

   mov  dx, 03CBh
   mov  ax, Tseg_3cb
   ;;out  dx, al
   call OutpDelay

    ;flush cach
    WBINVD            ;WBINVD write-back and invalidate cach  ;JWK22


;   force fifo empty read                       ;JWK08
                                                ;JWK08
        push  cx                                ;JWK08
                                                ;JWK08
        mov   cx, 512                           ;JWK08
        mov   bx, 100  ;offset 100 bytes so we flush 'elsewhere'
   looph1:                                      ;JWK08
        mov   ax, WORD PTR ds:[si+bx]           ;JWK08
        add   bx, 2                             ;JWK08
        loop  looph1                            ;JWK08
                                                ;JWK08
                                                ;JWK08
        pop   cx                                ;JWK08

;  test the new values (end if not same as written)

   mov ax, WORD PTR ds:[si+0]
   cmp ax, Ttest0
   jnz  breaktestloop
   mov ax, WORD PTR ds:[si+2]
   cmp ax, Ttest1
   jnz  breaktestloop

   mov ax, WORD PTR ds:[si+4]
   cmp ax, Ttest2
   jnz  breaktestloop
   mov ax, WORD PTR ds:[si+6]
   cmp ax, Ttest3
   jnz  breaktestloop


; restore peeked values since we altered them

   mov ax, Tpeek0
   mov WORD PTR ds:[si+0], ax
   mov ax, Tpeek1
   mov WORD PTR ds:[si+2], ax
   mov ax, Tpeek2
   mov WORD PTR ds:[si+4], ax
   mov ax, Tpeek3
   mov WORD PTR ds:[si+6], ax

    ;flush cach
    WBINVD            ;WBINVD write-back and invalidate cach  ;JWK22


;   force fifo empty read                       ;JWK08
                                                ;JWK08
        push  cx                                ;JWK08
                                                ;JWK08
        mov   cx, 512                           ;JWK08
        mov   bx, 100  ;offset 100 bytes so we flush 'elsewhere'
   loopi1:                                      ;JWK08
        mov   ax, WORD PTR ds:[si+bx]           ;JWK08
        add   bx, 2                             ;JWK08
        loop  loopi1                            ;JWK08
                                                ;JWK08
                                                ;JWK08
        pop   cx                                ;JWK08

;  Use a new test pattern for the next location.


   mov ax, Ttest2
   add ax, 03h
   mov Ttest2, ax

   mov ax, Ttest3
   add ax, 07h
   mov Ttest3, ax

   add  cx, 4                  ; 256k increments
   mov Ttest0, cx              ; low order word = segment number
   mov   Tseg, cx              ; update successful block count

   cmp  cx, 64                 ; support up to 4 meg
   jg   @f
   jmp  ForSegLoop
@@:
breaktestloop:                  ; seg has last valid value

;  Restore the values in the first segment

    ;flush cach
    WBINVD            ;WBINVD write-back and invalidate cach  ;JWK22

    xor  al ,al
    mov  dx, 03CBh
    call OutpDelay
    xor  al ,al
    mov  dx, 03CDh
    call OutpDelay


    mov  ax, Tsave0
    mov  WORD ptr ds:[si+0], ax
    mov  ax, Tsave1
    mov  WORD ptr ds:[si+2], ax
    mov  ax, Tsave2
    mov  WORD ptr ds:[si+4], ax
    mov  ax, Tsave3
    mov  WORD ptr ds:[si+6], ax

    ;flush cach
    WBINVD            ;WBINVD write-back and invalidate cach  ;JWK22


;   Restore the segment selector values

    mov  dx, 03CBh
    mov  al, Tsave_3cb
    ;;out  dx, al
    call OutpDelay
    mov  dx, 03CDh
    mov  al, Tsave_3cd
    ;;out  dx, al
    call OutpDelay

    pop     cx                      ; restore virttophys registers
    pop     bx
    pop     ax
    pop     ds
    ASSUME  DS:DGROUP, ES:NOTHING

    call    SVGAUnPhysToVirt        ;Unmap AX:BX.


;   Restore CR0
;   pop  eax
;   mov  CR0, eax


;   Restore the state of the TS CRTC36 and GDC registers
;   just pop off the stack and write in reverse order of how we saved


RestoreCRTC34:
    mov    dx, 03D4h
    mov    ax, 034h
    call   OutpDelay
    pop    ax
    inc    dx
    call   OutpDelay

RestoreCRTC36:
    mov    dx, 03D4h
    mov    ax, 036h
    call   OutpDelay
    pop    ax
    inc    dx
    call   OutpDelay

    mov    cx, 8
RestoreGDC:
    mov    dx, 03CEh
    mov    ax, cx
    ;;out    dx, al
    call OutpDelay
    pop    ax
    ;;out    dx, al
    inc    dx
    call OutpDelay
    dec    cx
    cmp    cx, 0
    jge    RestoreGDC

    mov    cx, 6
RestoreTS:
    mov    dx, 03C4h
    mov    ax, cx
    ;;out    dx, al
    call OutpDelay
    pop    ax
    ;;out    dx, al
    inc    dx
    call OutpDelay
    dec    cx
    cmp    cx, 1
    jge    RestoreTS

;   Return the size based on the last segment write/read passed

    mov  ax, Tseg

;   Restore calling register values

    pop  ds
    pop  es
    pop  cx
    pop  bx
    pop  si

    leave
    ret


TsengGetVRAMSize  ENDP


;/****************************************************************************
;*
;* FUNCTION NAME = WhichTseng
;*
;* DESCRIPTION   = Determine which Tseng chip we're using ET3000/ET4000
;*                 Distinguish the two by availability of Extended Start Addr.
;*                 Register (CRTC index 33h) which only exists on ET4000.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

;!! Actually, this should be 0210ah + IOD<2:0>*010h:
TSENG_CRTCB_ADDRESS     equ     0217ah  ;Index port for W32 CRTCB regs
TSENG_CRTCB_ROW_OFF_HI  equ     0ech    ;CRTCB/Sprite Row Offset High Reg

WhichTseng      PROC    Near
                PUBLIC  WhichTseng

        enter   STACKBLOCK, 0           ;                       /*          */
        call    TsengEnableExt          ;enable extended regs   /*          */
        call    GetCrtcBase             ;(3d4)                  /*          */
;*      OUTPUT   = DX = 003x4 (CRTC index address)
;       mov     bx, dx                  ;keep copy              /*          */
        mov     al, 037h                ;Video System Config 2
        call    OutpIdxInpData          ;Read indexed reg       /*          */
;                                       ;Can determine mem size /*          */
;                                       ;only AFTER know chip   /*          */
        mov     bl, al                  ;Save memory config     /*          */
        mov     al, 033h                ;CRTC reg index 33h
        call    OutpDelay               ;Write the new index value.
        inc     dx                      ;Point to the data register.
        mov     al, 0ffh                ;All bits first.        /*          */
        call    SaveXORChk              ;Test for read/writable./*          */
        .if     < z >                   ;If read/writable:      /*          */
            mov     dx, TSENG_CRTCB_ADDRESS ;                   /*          */
            call    GetSave1            ;                       /*          */
            mov     al, TSENG_CRTCB_ROW_OFF_HI  ;               /*          */
            call    OutpIdxInpData      ;                       /*          */
            and     al, 0f0h            ;Extract Chip revision  /*          */
            .if     < z >               ;                       /*          */
                mov     ax, TSENG_ET4000W32_CHIP   ;            /*          */
            .elseif     <al eq 010h>,short ;                    /*          */
                mov     ax, TSENG_ET4000W32I_CHIP  ;            /*          */
            .elseif     <al eq 020h>,short ;                    /*          */
                mov     ax, TSENG_ET4000W32PA_CHIP ;            /*          */
            .elseif     <al eq 030h>,short ;                    /*          */
                mov     ax, TSENG_ET4000W32IB_CHIP ;            /*          */
            .elseif     <al eq 050h>,short ;                    /*          */
                mov     ax, TSENG_ET4000W32PB_CHIP ;            /*          */
            .elseif     <al eq 060h>,short ;                    /*          */
                mov     ax, TSENG_ET4000W32PD_CHIP ;            /*          */
            .elseif     <al eq 070h>,short ;                    /*          */
                mov     ax, TSENG_ET4000W32PC_CHIP ;            /*          */
            .elseif     <al eq 0B0h>,short ;                    /*          */
                mov     ax, TSENG_ET4000W32IC_CHIP ;            /*          */
            .else                   ,short ;                    /*          */
;;JWK23 Tseng has assured us that there will be no new W32I chips
;;JWK23 and that all future revisions will be W32P Rev C compatable.
;;JWK23 Handle Unknown chips as W32Pc.  No need to identify new revisions
;;JWK23 accept to support some new function.
;;JWK23
;;JWK23         mov     ax, UNKNOWN_CHIP;             JWK07     /*          */
                mov     ax, TSENG_ET4000W32PX_CHIP;   JWK23
            .endif                      ;                       /*          */
            call    RestoreSave1        ;                       /*          */
        .else                           ;                       /*          */
            mov     al, 00fh            ;Low 4 bits next.       /*          */
            call    SaveXORChk          ;Test for read/writable./*          */
            .if     < z >               ;If read/writable:      /*          */
                mov ax, TSENG_ET4000_CHIP ;                     /*          */
            .else                       ;                       /*          */
                mov ax, TSENG_ET3000_CHIP ;                     /*          */
WT3000:                                 ; 
                pushf                   ; 
                push    ax              ; 
                mov     al, 6           ;set up index port to zoom reg
                mov     dl, 0c4h        ;SEQ index address (3c4)/*          */
                call    OutpIdxInpData  ;Read indexed reg       /*          */
                and     al, 01111111B   ; 
                call    OutpData        ;Turn off zoom enable bit.
                pop     ax              ; 
                popf                    ; 
            .endif                      ;                       /*          */
        .endif                          ;                       /*          */
WTExit:                                 ; 
;                                       ;Can determine mem size /*          */
;                                       ;only AFTER know chip   /*          */

        push  ax                                          ;     /*          */
        call TsengGetVRAMSize           ;Try VRAM Search  ;     /*          */
        .if <ax ne 0>                   ;if value, use it ;     /*          */
            mov     word ptr [_sSVGA.Memory][word], ax    ;     /*          */
            pop     ax                                    ;     /*          */
        .else                           ;else try old method    /*          */
            pop     ax                                    ;     /*          */
            .if <ax b TSENG_ET4000W32_CHIP> ;ET4000/3000            /*          */
                test    bl, 081h            ;VRAM=1/DRAM=0 :7,1M :0./*          */
                .if     < z >               ;If can determine memory/*          */
;                                           ;Adjust mem to 512k     /*          */
                    shr     word ptr [_sSVGA.Memory][word], 1 ;     /*          */
                .endif                      ;                       /*          */
            .elseif < e >                   ;ET4000W32              /*          */
                test    bl, 001h            ;No VRAM/DRAM bit       /*          */
                .if < z >                   ;Bus width?             /*          */
;                                           ;Adjust mem to 512k     /*          */
                    shr     word ptr [_sSVGA.Memory][word], 1 ;     /*          */
                .endif                                              /*@V2.1JWK01*/
            .else                           ;< a > ET4000W32I/W32P  /*          */
                test    bl, 008h            ;Ram length 1M or 256K  /*          */
                .if < z >                   ;If 1M:                 /*          */
                    shl  word ptr [_sSVGA.Memory][word], 001h ;     /*          */
                .endif                      ;                       /*          */
                test    bl, 001h            ;Bus width 16 or 32?    /*          */
                .if < nz >                  ;If 32:                 /*          */
                    shl  word ptr [_sSVGA.Memory][word], 001h ;     /*          */
                .endif                      ;                       /*          */
            .endif                          ; 
        .endif                              ;end if ax          /*          */
        call    TsengDisableExt         ;disable extended regs  /*          */
        leave                           ;                       /*          */
        ret

WhichTseng      ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = WhichVideo7
;*
;* DESCRIPTION   =
;*     Determine which chip we're using
;*
;*     Chip Revision Register contents
;*             HT205   71H                     up to 800x600x16
;*             HT208   42H     0111xxxxB       up to 1024x768x16
;*             HT209   52H/51H 0101xxxxB       up to 1024x768x256 (1Meg memory)
;*
;*     Determining amount of video memory on Video7 adapter.
;*     Requires the folllowing procedure:
;*
;*             o Set card into a planar mode.
;*             o Ensure all planes enabled
;*             o Force card into 32-bit memory width (ext reg 0xcc)
;*             o Write pattern to %%A0000 (say 5Ah)
;*             o Enable read from plane 3 (reg 03ceh)
;*             o Read back value
;*             o If value is same, we have 1Meg Memory
;*             o Otherwise set 16-bit memory width
;*             o Read back same value
;*             o If value is same, we have 512k Memory
;*             o Otherwise default to 256k
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

WhichVideo7     PROC    Near
                PUBLIC  WhichVideo7

        enter   STACKBLOCK, 0           ;                       /*          */
        mov     al, [SEQ06]             ;Use Video7 lock restore/*          */
;       Since bit 0 goes on when unlocked, reread != ea!        /*          */
        and     al, 001h                ;0=locked, 1=unlocked   /*          */
        mov     al, 0eah                ;Assume unlocked        /*          */
        .if     < z >                                           /*@V2.1MNH21*/
            mov     al, 0aeh            ;Locked instead         /*          */
        .endif                          ;0aeh=lock, 0eah=unlock /*          */
        mov     [SEQ06], al             ;Instead of value read  /*          */
        call    Video7EnableExt         ;enable extended registers
        mov     al, 08eh                ; 
;       mov     dl, 0c4h                ;SEQ index address (3c4)/*          */
        call    OutpIdxInpData          ;Read indexed reg       /*          */
        shr     al, 4                   ;has value 04h to 0fh
        mov     bl, al                  ; 
        mov     ax, VIDEO7_HT205_CHIP   ;AX = 1  (HT205)            label miss.
        cmp     bl, 7                   ; 
        je      WhichV7Exit             ; 
        inc     ax                      ;AX = 2  (HT208)
        cmp     bl, 4                   ; 
        je      WhichV7Exit             ; 
        inc     ax                      ;AX = 3  (HT209)
        cmp     bl, 5                   ; 
        je      WhichV7Exit             ; 
;       inc     ax                      ;AX = 4  (HT216)        /*          */
;       cmp     bl, 6                   ;
;       je      WhichV7Exit             ;
        xor     ax, ax                  ;AX = 0 (don't know)
WhichV7Exit:
        mov     dx, 2                   ; 
        mov     cl, al                  ; 
        shl     dx, cl                  ; 
        mov     word ptr [_sSVGA.Memory][1*word], dx ;          /*          */
        push    ax
        cmp     al, al                  ;Indicate IS Video7     /*          */
        call    Video7DisableExt        ;disable extended registers
        pop     ax
        leave                           ;                       /*          */
        ret

WhichVideo7     ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = WhichWeitek
;*
;* DESCRIPTION   = Determine which Weitek SVGA chip we're using.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

WhichWeitek     PROC    Near
                PUBLIC  WhichWeitek

        enter   STACKBLOCK, 0
        mov     dx, 03c4h               ;SEQ index address (3c4)/*          */
        call    GetSave1                ;Read original index & save it.
        mov     al, 007h                ;SEQ W5x86 Revision Reg
        call    OutpIdxInpData          ;Read W5x86 Revision Reg.
        shr     al, 5                   ;Get Device ID bits low.
        and     al, 007h                ;Extract just Device ID bits.
        .if     < nz > AND
        .if     <al be 002h>
            inc     al
        .else                           ;Else W5086 or unknown W5x86.
            xor     al, al
        .endif
        cbw                             ;Extend to word.
        call    RestoreSave1            ;Restore the original values.
        leave
        ret

WhichWeitek     ENDP


ifndef SVGAUTIL

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = WeitekMemConfig
;*
;* DESCRIPTION   = Set Weitek MemConfig register.
;*                      Currently just determine the memory size.
;*
;* INPUT         = AX = new MemConfig register value.
;* OUTPUT        = AX = old MemConfig register value.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

WeitekMemConfig PROC    Near
                PUBLIC  WeitekMemConfig

        push    es
        push    bx
        push    cx
        push    ax
        mov     ax, word ptr [SvgaBaseAddr][word] ;Get base address.
        add     ax, WEITEK_P9000_REGISTERS  ;High word of physical addr.
        xor     bx, bx                  ;Low word of physical address.
        mov     cx, WEITEK_P9000_REGLENGTH  ;Length of area selected
        call    SVGAPhysToUVirt
        pop     ax                      ;Get back new value.
        .if     < nc >                  ;If selector returned:
            xchg    ax, word ptr es:[bx][WEITEK_P9000_MEMCONFIG]
            call    SVGAUnPhysToUVirt   ;ES=selector to free.
        .endif                          ;Endif selector returned.
        pop     cx
        pop     bx
        pop     es
        ret

WeitekMemConfig ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = WeitekVRAMMap
;*
;* DESCRIPTION   = Map first word at selected address.
;*
;* INPUT         = AX = selected frame buffer offset high bits.
;*               = BX = selected frame buffer offset low bits.
;* OUTPUT        = ES:BX = pointer to frame buffer word.
;*
;* RETURN-NORMAL = NC if no errors.
;* RETURN-ERROR  = CR if errors.
;*
;* CALLED BY
;*
;****************************************************************************/

WeitekVRAMMap   PROC    Near
                PUBLIC  WeitekVRAMMap

        push    ax                      ;Save offset high.
        add     ax, word ptr [SvgaBaseAddr][word] ;Get base address.
        add     ax, WEITEK_P9000_VRAM   ;High word of physical addr.
        push    cx
        xor     cx, cx                  ;Whole segment.
        sub     cx, bx                  ;Less low bits.
        call    SVGAPhysToUVirt
        pop     cx
        pop     ax                      ;Restore offset high.
        ret

WeitekVRAMMap    ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = WeitekGetSelWord
;*
;* DESCRIPTION   = Get word at selected address.
;*
;* INPUT         = AX = selected frame buffer offset high bits.
;*               = BX = selected frame buffer offset low bits.
;* OUTPUT        = DX = word at selected address.
;*
;* RETURN-NORMAL = NC if no errors.
;* RETURN-ERROR  = CR if errors.
;*
;* CALLED BY
;*
;****************************************************************************/

WeitekGetSelWord PROC    Near
                PUBLIC  WeitekGetSelWord

        push    es
        push    bx
        call    WeitekVRAMMap           ;Map the word.
        .if     < nc >                  ;If selector returned:
            mov     dx, word ptr es:[bx]
            call    SVGAUnPhysToUVirt   ;ES=selector to free.
        .endif                          ;Endif selector returned.
        pop     bx
        pop     es
        ret

WeitekGetSelWord ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = WeitekSetSelWord
;*
;* DESCRIPTION   = Set word at selected address.
;*
;* INPUT         = AX = selected frame buffer offset high bits.
;*               = BX = selected frame buffer offset low bits.
;*                 DX = word to set at selected address.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NC if no errors.
;* RETURN-ERROR  = CR if errors.
;*
;* CALLED BY
;*
;****************************************************************************/

WeitekSetSelWord PROC    Near
                PUBLIC  WeitekSetSelWord

        push    es
        push    bx
        call    WeitekVRAMMap           ;Map the word.
        .if     < nc >                  ;If selector returned:
            mov     word ptr es:[bx], dx
            call    SVGAUnPhysToUVirt   ;ES=selector to free.
        .endif                          ;Endif selector returned.
        pop     bx
        pop     es
        ret

WeitekSetSelWord ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = WeitekGet1stWord
;*
;* DESCRIPTION   = Get first word from frame buffer.
;*
;* INPUT         = NONE
;* OUTPUT        = DX = word at selected address.
;*
;* RETURN-NORMAL = NC if no errors.
;* RETURN-ERROR  = CR if errors.
;*
;* CALLED BY
;*
;****************************************************************************/

WeitekGet1stWord PROC    Near
                PUBLIC  WeitekGet1stWord

        push    ax
        push    bx
        xor     ax, ax                  ;Get buffer start selector.
        xor     bx, bx                  ;Get buffer first word.
        call    WeitekGetSelWord
        pop     bx
        pop     ax
        ret

WeitekGet1stWord ENDP

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = WeitekChkSelWord
;*
;* DESCRIPTION   = Check read/writability of word at selected address.
;*
;* INPUT         = AX = selected frame buffer offset high bits.
;*               = BX = selected frame buffer offset low bits.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = (zr if reads match writes)
;* RETURN-ERROR  = (nz if reads do NOT match writes)
;*
;* CALLED BY
;*
;****************************************************************************/

WeitekChkSelWord PROC    Near
                PUBLIC  WeitekChkSelWord

        call    WeitekGetSelWord        ;Get word original value.
        push    dx                      ;Save original value.
        .if     <nc> AND                ;If no mapping errors:
            call    WeitekGet1stWord
        .if     <nc> AND                ;If no mapping errors:
            xor     dx, 0aaaah          ;Toggle half the bits.
            mov     cx, dx              ;Save new value.
            call    WeitekSetSelWord
            call    WeitekGet1stWord    ;Force actual memory read.
        .if     <dx ne cx>              ;If starting word did not change:
            call    WeitekGetSelWord    ;See if word changed as set.
            cmp     dx, cx              ;Not floating, high, or low.
        .else                           ;Else wrap occured!
            or      cx, 00001h          ;Set NZ for failure.
        .endif
        pop     dx                      ;Restore original value.
        pushf                           ;Save success indicator.
        call    WeitekSetSelWord
        popf                            ;Restore success indicator.
        ret

WeitekChkSelWord ENDP

endif ;/* SVGAUTIL */

;*                                                              /*          */
;/****************************************************************************
;*
;* FUNCTION NAME = WhichWeitekP9x00
;*
;* DESCRIPTION   = Determine which Weitek chip were using.
;*                      Currently just determine the memory size.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

WhichWeitekP9x00 PROC    Near
                PUBLIC  WhichWeitekP9x00

        enter   STACKBLOCK, 0           ;                       /*          */

ifdef   TSU02                           ;          

ifndef SVGAUTIL
        mov     ax, 00002h              ;Set for 2 banks.
        call    WeitekMemConfig
        push    ax                      ;Save original memory configuration.
;*
;*      Now find chip length by testing for
;*      address wrap or end of chip at high addresses.
;*      Assume chips are at least 64K/4=16K bits long.
;!!Should there be an assumed length for REAL DOS? =256K? =1M?  /*          */
;*      Starting value here determines "default" size given under real DOS
;*      Size will be 1/2 of first test, since first (and any) test fails.
;*
        mov     ax, 00008h              ;Start with 128K bits long=512K buffer.
        xor     bx, bx                  ;Offset low is always zero.
        .repeat
            push    ax
            shr     ax, 1               ;Test wrap after previous chip size.
            call    WeitekChkSelWord    ;Check for word read/writable.
            pop     ax
        .until  < nz > or               ;Until memory test fails or...
            shl     ax, 1               ;Get next chip size.
        .until  <ax a 00010h>           ;Until > largest possible length=256K.
        shr     ax, 1                   ;Failed at this size, but not prev=1/2!
        mov     word ptr [_sSVGA.Memory][1*word], ax ;          /*          */
;*
;*      Now find out how many banks by testing
;*      bank bits (2:3) in addresses in 4 bank mode.
;*
        mov     ax, 00004h              ;Set for 4 banks.
        call    WeitekMemConfig
        xor     ax, ax                  ;High word of physical address.
        mov     bx, dword               ;Check second bank.
        call    WeitekChkSelWord        ;Check for word read/writable.
        .if     < z >                   ;If at least two banks:
            shl     word ptr [_sSVGA.Memory][word], 1 ;         /*          */
            shl     bx, 1               ;Check third bank.
            call    WeitekChkSelWord    ;Check for word read/writable.
            .if     < z >               ;If at least three(&four) banks:
                shl     word ptr [_sSVGA.Memory][word], 1 ;     /*          */
            .endif
        .endif
;*
        pop     ax                      ;Restore original memory configuration.
        call    WeitekMemConfig

else ;/* SVGAUTIL */
;*      Leave default memory size at 1M
endif ;/* SVGAUTIL */

endif                                   ;          

        mov di, word ptr [SvgaBaseAddr][word] ;Get presumed base address.

ifndef SVGAUTIL                         ;                       /*@V3.0MNH04*/
        call    WeitekP9000Chk          ;                       /*@V3.0MNH04*/
        .if     < nz >                  ;If not P9000 base:     /*@V3.0MNH04*/
            mov     di, 00000h+WEITEK_P9000_REGISTERS ;Hunt!    /*@V3.0MNH04*/
            .repeat                     ;                       /*@V3.0MNH04*/
                call    WeitekP9000Chk  ;                       /*@V3.0MNH04*/
            .leave  < z >               ;                       /*@V3.0MNH04*/
                add     di, WEITEK_P9000_INCREMENT ;Leaves nz!  /*@V3.0MNH04*/
            .until  < c >               ;Until addr hi word wrap/*@V3.0MNH04*/
        .endif                          ;                       /*@V3.0MNH04*/
        mov     ax, WEITEK_P9000_CHIP   ; 1                     /*          */
        .if     < nz >                  ;No 9000 found:         /*@V3.0MNH04*/
            mov     ax, WEITEK_P9100_CHIP   ; 4                 /*@V3.0MNH04*/
        .endif                          ;                       /*@V3.0MNH04*/
else ;/* SVGAUTIL */                    ;                       /*@V3.0MNH04*/
;*                                                              /*@V3.0MNH04*/
;*      We do not have a way to use 32 bit addr's in real DOS!  /*@V3.0MNH04*/
;*      So we can only guess...                                 /*@V3.0MNH04*/
;*                                                              /*@V3.0MNH04*/
        mov     ax, WEITEK_P9000_CHIP   ; 1                     /*          */
endif ;/* SVGAUTIL */                   ;                       /*@V3.0MNH04*/

        and di, not WEITEK_P9000_REGISTERS ;Remove register part, leave base.
        mov word ptr [SvgaBaseAddr][word], di ;Save base address.

        leave                           ;                       /*          */
        ret

WhichWeitekP9x00 ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = WhichWesternDig
;*
;* DESCRIPTION   =
;*      At index 30 thru 3f, the WD90cxx chips have an encoded device id.
;*      Certain unlocks must be done to allow it to be read.
;*      This is NOT documented in ALL of their data books.
;*      It IS documented in the data book for the WD90C26.
;*      It IS hinted at ("reserved") in other data books.
;*
;*                  3333333333333333
;*                  0123456789ABCDEF
;*      PVGA1A    ->################ #=0ffh or 000h
;*      WD90c00   ->COPYRIGHT1989WDC
;*      WD90c24   ->#WD90C24REVC0892 #=varies        Toshiba T4700CT
;*      WD90c24a2a->#WD90C24AREVA293 #=varies z=000h WD90C24 Demo Board
;*      WD90c24a2b->#WD90C24AREVB293 #=varies z=000h IBM ThinkPad
;*      WD90c24a2c->#WD90C24AREVC### #=varies        WD program checks this!
;*      WD90c26   ->#WD90C26REV#199# #=varies        WD ref documents this!
;*      WD90c31   ->#WD90C310200zzzz #=varies z=000h WD program checks this!
;*      WD90c31A  ->#WD90C31050zzzzz #=varies z=000h WD program checks this!
;*      WD90c33   ->#WD90C33######## #=varies z=000h WD program checks this!
;*      WD90c34   ->#WD90C34######## #=varies z=000h WD program checks this!
;*      WD90cxx   ->#WD90Cxx######## #=varies x=chip
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

WhichWesternDig PROC    Near
                PUBLIC  WhichWesternDig

        enter   STACKBLOCK, 0           ;                       /*          */
        mov     dx, 03c4h               ;SEQ index address (3c4)/*          */
        call    InpDelay                ;Read original index    /*          */
        push    ax                      ;Save original index    /*          */
        mov     ax, 04806h              ;Everyone's fav lock!   /*          */
        call    OutpwDelay              ;Unlock                 /*          */
        call    WDEnableExt             ;Unlock needed registers.
;*      OUTPUT   = DX = 003x4 (CRTC index address)
        mov     al, 036h
        call    WDRegPairString         ;Read chip id char pair for 90cxx
        mov     bx, WESTERNDIG_PVGA1A_CHIP ;BX has value to return
        cmp     ax, 0ffffh              ;Registers do not exist!
        jz      WhichWDEasy             ;It's a PVGA1A
        cmp     ax, 00000h              ;Registers do not exist!
        jz      WhichWDEasy             ;It's a PVGA1A
        inc     bx                      ;Assume WD90c00
        cmp     ax, 04748h              ;"GH"
        jz      WhichWDEasy             ;It's a WD90c00
        and     ax, 00f0fh
        mov     cl, 004h
        shl     ah, cl
        or      al, ah
        cmp     al, 000h
        jz      WhichWDEasy             ;It's a WD90c00
        cmp     al, 020h
        jz      WhichWDEasy             ;It's a WD90c00
        cmp     al, 022h
        jz      WhichWDEasy             ;It's a WD90c00
        inc     bx                      ;Assume WD90c11
        cmp     al, 011h
        jz      WhichWDEasy             ;It's a WD90c11
        inc     bx                      ;Assume WD90c30
        cmp     al, 030h
        jz      WhichWDEasy             ;It's a WD90c30
        inc     bx                      ;Assume WD90c26
        cmp     al, 026h
        jz      WhichWDEasy             ;It's a WD90c26
        inc     bx                      ;Assume WD90c27
        cmp     al, 027h
        jz      WhichWDEasy             ;It's a WD90c27
        inc     bx                      ;Assume WD90c31
        cmp     al, 031h
        jz      WhichWDEasy             ;It's a WD90c31
        inc     bx                      ;Assume WD90c24
        cmp     al, 024h
        jz      WhichWDEasy             ;It's a WD90c24
        inc     bx                      ;Assume WD90c33
        cmp     al, 033h
        jz      WhichWDEasy             ;It's a WD90c33
        jmp     short @F
WhichWDEasy:
ifdef SVGAUTIL
        jmp     short WhichWDExit1
else ;/* SVGAUTIL */
        jmp     WhichWDExit1
endif ;/* SVGAUTIL */
@@:
;!! I doubt that the following tests will remain necessary!     /*          */
;       mov     bx, WESTERNDIG_WD9000_CHIP ;Assume WD90c00
;       mov     dl, 0c4h                ;SEQ index address (3c4)/*          */
;       mov     [SaveReg4], dx
;       call    InpDelay                ;Read the original index.
;       mov     [SaveIndex4], al
;       mov     ax, 04806h              ;extended sequencers.
;       call    OutpwDelay              ;Write the new value.
;                                       ;Distinguish between
;       mov     al, 012h                ; WD90c00 and WD90c11 & later
;       call    OutpIdxInpData          ;Read indexed reg       /*          */
;                                       ; by using bit 6 of Misc Control Reg
;                                       ;If chip doesn't respond to changes
;                                       ; in the bit, its a WD90c00
;       mov     ah, al                  ;
;       and     al, NOT 01000000B       ;
;       call    OutpData                ;Replace with bit 6 set to 0.
;       call    InpData                 ;Read the value back.
;       xchg    al, ah                  ;
;       call    OutpData                ;Write the original value.
;       xchg    ah, al                  ;
;       test    al, 01000000B           ;if bit IS NOT zero,
;       jnz     WhichWDExit2            ; its a 90c00
;       or      al, 01000000B           ;
;       call    OutpData                ;Replace with bit 6 set to 1.
;       call    InpData                 ;Read the value back.
;       xchg    al, ah                  ;
;       call    OutpData                ;Write back the original value.
;       xchg    ah, al                  ;
;       test    al, 01000000B           ;if bit IS zero,
;       jz      WhichWDExit2            ; its a 90c00
;       inc     bx                      ;Assume WD90c11
;       mov     dl, 0c4h                ;SEQ index address (3c4)/*          */
;                                       ;Look for scratch pad reg
;       mov     ax, 0aa09h              ; at index 09h, found on
;       call    SaveOutpwChk            ; 90c30, not 90c11
;       jnz     WhichWDExit2            ;Its probably a 90c11
;       inc     bx                      ;Call it at least a WD90c30...
;       mov     dx, 023c0h              ;Check for extended index control reg
;       mov     al, 0ffh                ;Value to XOR with for test.
;       call    SaveXORChk              ;
;       jnz     WhichWDExit2            ;Its probably a 90c30.
;       mov     bx, WESTERNDIG_WD9031_CHIP ;Call it at least a WD90c31.
WhichWDExit2:
;       mov     dx, [SaveReg4]
;       mov     al, [SaveIndex4]
;       out     dx, al
WhichWDExit1:
        .if     <bx e WESTERNDIG_WD9024_CHIP> ;                 /*          */
            mov     al, 03ch            ;Id string byte         /*          */
            call    OutpIdxInpData      ;Read indexed reg       /*          */
;                                                               /*          */
;           Because of STN displays only capable of using 1/2M  /*          */
;           even on the newer chips, memory path is a better    /*          */
;           indication of usable display memory.                /*          */
;                                                               /*          */
;           .if     <al ae 'C'>         ;                       /*          */
;               mov     al, 02ah        ;PR11 EGA Switches      /*          */
;           .else                       ;Else not WD90C24C:     /*          */
;                                                               /*          */
;               Yes, strangely 32 bit path implies 1/2M!        /*          */
;               And 16 bit path implies 1M!                     /*          */
;                                                               /*          */
                mov     dl, 0c4h        ;SEQ index address (3c4)/*          */
                mov     al, 010h        ;                       /*          */
;           .endif                      ;                       /*          */
            call    OutpIdxInpData      ;Read indexed reg       /*          */
            not     al                  ;Extra mem if bit 5 OFF /*          */
            and     al, 020h            ;Was bit 5 OFF? now ON? /*          */
            shr     al, 2               ;512K Extra (1M Total)  /*          */
            add     al, 008h            ;512K Otherwise         /*          */
        .else                           ;Else not WD90C24:      /*          */
            xor     al, al              ;Assume size not found  /*          */
;*
;*          WARNING:                                            /*          */
;*              PR18 for LCD/FLAT PANELS is 3x5.31 Flat Panel Status (C24)
;*              PR18 for desktops is 3x5.3e Vertical Timing Overflow  (C31/C33)
;*              PR18A for LCD/FLAT PANELS is 3x5.3d Vertical Timing Overflow (C24)
;*
;*          WARNING:                                            /*          */
;*              3x5.3e is PR18 Vertical Timing Overflow for desktops (C31/C33)
;*              3x5.3e is PR39 Flat Panel Blinking for LCD/FLAT PANELS (C24)
;*
;*          So we cannot just read 3x5.3e and expect the Vertical
;*          Timing Overflow, without knowing which chip we have!
;*
            .if     <bx e WESTERNDIG_WD9033_CHIP> ;             /*          */
                mov     al, 03eh        ;PR18 Vert Timing Ovrflw/*          */
                call    OutpIdxInpData  ;Read indexed reg       /*          */
                and     al, 080h        ;Get 90C33 2M bit       /*          */
                shr     al, 2           ;Shift to 2M position   /*          */
            .endif                      ;Else not WD90C33:      /*          */
            .if     <zero al>           ;If not 2M then what?   /*          */
                mov     dl, 0ceh        ;Determine on-board memory
                mov     al, 00bh        ;Memory size
                call    OutpIdxInpData  ;Read indexed reg       /*          */
                shr     al, 006h        ;top 2 bits have mem size;           
                .if     < nz >          ;zero means 256k        /*          */
                    dec     al          ;make count zero-based  /*          */
                .endif                                          /*@V2.1MNH01*/
                mov     cl, al          ;                       /*          */
                mov     al, 0100B       ;256KB with no shift    /*          */
                shl     al, cl          ;Shift to correct size. /*          */
            .endif                      ;Endif not 2M.          /*          */
        .endif                          ;Endif not WD90C24      /*          */
        cbw                             ;Extend to fullword     /*          */
        mov     word ptr [_sSVGA.Memory][word], ax ;            /*          */
        mov     al, 006h                ;Everyone's fav lock!   /*          */
        mov     ah, [SEQ06WD]           ;Use WD lock restore    /*          */
        mov     [SEQ06], ah             ;Instead of value read  /*          */
        mov     dl, 0c4h                ;SEQ index address (3c4)/*          */
        call    OutpwDelay              ;Restore original lock  /*          */
        pop     ax                      ;Restore original index /*          */
        call    OutpDelay               ;Restore original index /*          */
        push    bx                      ;Save return code       /*          */
        call    WDDisableExt            ;                       /*          */
        pop     ax                      ;Get return code        /*          */
        leave                           ;                       /*          */
        ret

WhichWesternDig ENDP

ifndef SVGAUTIL

;/****************************************************************************
;*
;* FUNCTION NAME = IdentifyPCIAdapter
;*
;* DESCRIPTION   =
;*      Process the array of identified PCI video devices and find the preffered
;*      one (supported) and assign it our private device id. If none found, return
;*      generic_pci_adapter as the SVGA type.
;*
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = _sSVGA and SvgaOEMInfo structures are set.
;* RETURN-ERROR  = NONE
;*
;* CALLED BY    IdentifyAdapter
;*
;****************************************************************************/

IdentifyPCIAdapter   PROC    near
     mov     [_sSVGA.AdapterType], UNKNOWN_ADAPTER ; 0 ;     /*          */
     mov     [_sSVGA.ChipType], UNKNOWN_CHIP ; 0 ;           /*          */
     mov     word ptr [_sSVGA.Memory][0*word], 0 ;           /*          */
     mov     word ptr [_sSVGA.Memory][1*word], 0010h ;       /*          */
     mov     [SvgaOEMInfo.Manufacturer], UNKNOWN_MANUFACTURER ; 0 ;
     mov        cx, PCI_Num
device_loop:
     dec     cx
     mov     si, offset PCI_DeviceTbl           ;ulong hw: Vendor ID, lw Device ID
     mov     ax, cx
     shl     ax, 2
     add     si, ax
     mov     ax, word ptr ds:[si]
     cmp     ax, 01002h                      ;ATI
     jnz     short @F
     call    IsATI                           ;           
     jnz     BadDetection                    ;           
     mov     [_sSVGA.AdapterType], ATI_ADAPTER ; 
     call    WhichATI
     jmp     DonePCI

@@:
     cmp     ax, 0100ch                      ;TSENG
     jnz     short @F
     call    IsTseng                         ;           
     jnz     BadDetection                    ;           
     mov     [_sSVGA.AdapterType], TSENG_ADAPTER ; 
     call    WhichTseng
     jmp     DonePCI

@@:
     cmp     ax, 010beh                      ;TSENG
     jnz     short @F
     call    IsTseng                         ;           
     jnz     BadDetection                    ;           
     mov     [_sSVGA.AdapterType], TSENG_ADAPTER ; 
     call    WhichTseng
     jmp     DonePCI

@@:
     cmp     ax, 0100eh                      ;WEITEK
     jnz     short @F
;     call    IsWeitek                                  
;     jnz     BadDetection                              
     mov     [_sSVGA.AdapterType], WEITEK_ADAPTER ; 
     mov     si, offset PCI_DeviceTbl           ;ulong hw: Vendor ID, lw Device ID
     mov     ax, cx
     shl     ax, 2
     add     ax, 2
     add     si, ax
     mov     ax, word ptr ds:[si]
     cmp     ax, 09100h                ; device ID for 9100
     jnz     NextWTChip
     mov     ax, WEITEK_P9100_CHIP
     jmp     DonePCI
NextWTChip:
     cmp     ax, 09001h                ; device ID for 9000
     jnz     NextDevice
     mov     ax, WEITEK_P9000_CHIP
     jmp     SHORT DonePCI

@@:
     cmp     ax, 0101ch                      ;WD
     jnz     short @F
     call    IsWesternDig                    ;           
     jnz     short BadDetection              ;           
     mov     [_sSVGA.AdapterType], WESTERNDIG_ADAPTER ; 
     call    WhichWesternDig         ; 
     jmp     SHORT DonePCI

@@:
     cmp     ax, 01013h                      ;Cirrus
     jnz     short @F
     call    IsCirrus                        ;           
     jnz     short BadDetection              ;           
     mov     [_sSVGA.AdapterType], CIRRUS_ADAPTER ; 
     call    WhichCirrus             ; 
     jmp     SHORT DonePCI

@@:
     cmp     ax, 05333h                      ;S3
     jnz     short @F
     call    IsS3                            ;           
     jnz     short BadDetection              ;           
     mov     [_sSVGA.AdapterType], S3_ADAPTER ; 
     call    WhichS3                 ; 
     jmp     SHORT DonePCI

@@:
     cmp     ax, 01023h                      ;TRIDENT
     jnz     short @F
     call    IsTrident                       ;           
     jnz     short BadDetection              ;           
     mov     [_sSVGA.AdapterType], TRIDENT_ADAPTER ; 
     call    WhichTrident            ; 
     jmp     SHORT NextDevice

@@:
     cmp     ax, 01005h                      ;AVANCE
     jnz     short @F
;     mov     [_sSVGA.AdapterType], GENERIC_PCISVGA_ADAPTER            
     mov     [_sSVGA.AdapterType],  UNKNOWN_ADAPTER         ;          
     mov     ax, 02301h
     jmp     SHORT NextDevice

@@:
     cmp     ax, 0102ch                      ;C&T
     jnz     short @F
     mov     [_sSVGA.AdapterType], CHIPS_ADAPTER ; 
     mov     ax, CHIPS_FIRST_CHIP    ; return a chiptype

@@:
NextDevice:
     jcxz    DonePCI
     jmp     device_loop
DonePCI:
     mov     [_sSVGA.ChipType], ax
     ret
BadDetection:                             ;           
     mov     ax, 0ffh                     ;           
     ret                                  ;           
IdentifyPCIAdapter ENDP

endif

;/****************************************************************************
;*
;* FUNCTION NAME = _IdentifySVGA
;*
;* DESCRIPTION   =
;*
;*      Identify SVGA and its VRAM size from:
;*
;*                                            Return in AH    AL
;*        o Indeterminate chip set                       0     0
;*
;*        o Headland/Video 7     HT205                   1     1
;*                               HT208                   1     2
;*                               HT209                   1     3
;*
;*        o Trident Microsystems 8800                    2     1
;*                               8900                    2     2
;*
;*        o Tseng                ET3000                  3     1
;*                               ET4000                  3     2
;*                               ET4000/W32              3     3
;*                               ET4000/W32i             3     4/*          */
;*                               ET4000/W32p             3     5/*          */
;*
;*        o Western Digital      PVGA1A                  4     1
;*                               WD90c00                 4     2
;*                               WD90c11                 4     3
;*                               WD90c30                 4     4
;*                               WD90c26                 4     5/*          */
;*                               WD90c27                 4     6/*          */
;*                               WD90c31                 4     7/*          */
;*                               WD90c24                 4     8/*          */
;*                               WD90c33                 4     9/*          */
;*
;*        o ATI                  ATI18800                5     1
;*                               ATI28800                5     2
;*                               ATI38800==MACH8         5     3/*          */
;*                               ATI68800==MACH32        5     4/*          */
;*                               ATI68800AX              5     5/*          */
;*                               ATI68800GX              5     6/*          */
;*
;*        o IBM Speedway         VGA-256C                6     1
;*
;*
;*        o CIRRUS               GD5422                  7     1
;*                               GD5424                  7     2
;*                               GD5426                  7     3
;*                               GD5428                  7     4/*          */
;*
;*        o S3                   801, 805                8     1
;*                               928                     8     2
;*                               864                     8     3/*          */
;*                               964                     8     4/*          */
;*                               911                     8     5/*          */
;*
;*        o CHIPS&TECHNOLOGY                             9      /*          */
;*
;*        o WEITEK               P9000                  10     1/*          */
;*                               W5186                  10     2/*          */
;*                               W5286                  10     3/*          */
;*
;* ENTRY POINT:  _IdentifySVGA
;*    LINKAGE:   Call Far
;*
;* INPUT:
;*       ES:BX = request packet address
;*       DS = DGROUP
;*
;* EXIT-NORMAL: AX = Status to return to OS
;* EXIT-ERROR:  NONE
;*
;* EFFECTS:
;*       AX
;*
;* USES ROUTINES:
;*
;* CALLED BY ROUTINES:
;*             INIT
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = adapter type and chip type.
;* RETURN-ERROR  = NONE
;*
;* CALLED BY
;*
;****************************************************************************/

_IdentifySVGA   PROC    far             ;to far                 /*          */
                PUBLIC  _IdentifySVGA   ;                       /*          */

        enter   0,0                     ;                       /*          */
        pusha                           ;                       /*          */
        push    ds                      ;                       /*          */
ifndef SVGAUTIL
        cmp     word ptr PCI_Num, 0     ;@senja
        jz      short @F                ;@senja
        call    IdentifyPCIAdapter      ;will set both _sSVGA and SvgaOEMInfo structures
        cmp     ax, 0ffh                ;           
        jnz     IdentifyExit            ;           
@@:
endif
        mov     [_sSVGA.AdapterType], UNKNOWN_ADAPTER ; 0 ;     /*          */
        mov     [_sSVGA.ChipType], UNKNOWN_CHIP ; 0 ;           /*          */
        mov     word ptr [_sSVGA.Memory][0*word], 0 ;           /*          */
        mov     word ptr [_sSVGA.Memory][1*word], 0010h ;       /*          */
        mov     [SvgaOEMInfo.Manufacturer], UNKNOWN_MANUFACTURER ; 0 ;
        mov     dx, 03c4h               ;SEQ index address (3c4)/*          */
        call    InpDelay                ;Read original index    /*          */
        push    ax                      ;Save original index    /*          */
        mov     al, 048h                ;                       /*          */
        call    OutpInp                 ;Test WD PR20 lock state/*          */
        or      al, 040h                ;Create WD lock restore /*          */
        mov     [SEQ06WD], al           ;Save just in case WD!  /*          */
        mov     al, 006h                ;Everyone's fav lock!   /*          */
        call    OutpIdxInpData          ;Read original value.   /*          */
        mov     [SEQ06], al             ;Save in case not WD!   /*          */
        pop     ax                      ;Restore original index /*          */
        call    OutpDelay               ;Restore original index /*          */
@@:                                     ;                       /*          */
        call    IsSpeedWay
        jnz     @F
        mov     [_sSVGA.AdapterType], IBM_ADAPTER ; 6           /*          */
        mov     ax, IBM_SVGA_CHIP ;1    ;                       /*          */
        jmp     SetChipType             ;                       /*          */

@@:     call    IsVideo7                ; 
        jnz     short @F                ; 
        mov     [_sSVGA.AdapterType], VIDEO7_ADAPTER ;1         /*          */
        call    WhichVideo7             ; 
        jmp     SetChipType

@@:     call    IsTrident               ; 
        jnz     short @F                ; 
        mov     [_sSVGA.AdapterType], TRIDENT_ADAPTER ;2        /*          */
        call    WhichTrident            ; 
        jmp     short SetChipType

@@:     call    IsTseng                 ; 
        jnz     short @F                ; 
        mov     [_sSVGA.AdapterType], TSENG_ADAPTER ;3          /*          */
        call    WhichTseng              ; 
        jmp     short SetChipType

@@:     call    IsWesternDig            ; 
        jnz     short @F                ; 
        mov     [_sSVGA.AdapterType], WESTERNDIG_ADAPTER ;4     /*          */
        call    WhichWesternDig         ; 
        jmp     short SetChipType

@@:     call    IsATI                   ; 
        jnz     short @F                ; 
        mov     [_sSVGA.AdapterType], ATI_ADAPTER ;5            /*          */
        call    WhichATI                ; 
        jmp     short SetChipType

@@:     call    IsCirrus                ;                       /*          */
        jnz     short @F                ; 
        mov     [_sSVGA.AdapterType], CIRRUS_ADAPTER ;7         /*          */
        call    WhichCirrus             ; 
        jmp     short SetChipType

@@:     call    IsS3                    ;                       /*          */
        jnz     short @F                ; 
        mov     [_sSVGA.AdapterType], S3_ADAPTER ;8             /*          */
        call    WhichS3                 ; 
        jmp     short SetChipType

@@:     call    IsChips                 ;                       /*          */
        jnz     short @F                ; 
        mov     [_sSVGA.AdapterType], CHIPS_ADAPTER ;9
        mov     ax, CHIPS_FIRST_CHIP    ; return a chiptype
        jmp     short SetChipType

@@:     call    IsWeitek                ;                       /*          */
        jnz     short @F                ;                       /*          */
        mov     [_sSVGA.AdapterType], WEITEK_ADAPTER ; 10       /*          */
        call    WhichWeitek             ;                       /*          */
        jmp     short SetChipType       ;                       /*          */

@@:     call    LastAttempt             ;                       /*          */
        or      ax, ax
        jz      SVGAExit                ;AX is 0 if adapter not identified.
                                        ;if successful ax= adapter, bx=chiptype.
        mov     [_sSVGA.AdapterType], ax ;                      /*          */
        mov     ax, bx
SetChipType:                            ;                       /*          */
        mov     [_sSVGA.ChipType], ax   ;                       /*          */
SVGAExit:
;*                                                              /*          */
;*      Since WEITEK P9000 can be married to any VGA,
;*      we test for it last and if we find it,
;*      we move the current adapter and chip type to SvgaOEMInfo
;*
@@:     call    IsWeitekP9x00           ;                       /*@V3.0MNH04*/
        jnz     short IdentifyExit      ;@senja
        mov     ax, [_sSVGA.AdapterType] ;                      /*          */
        mov     word ptr [SvgaOEMInfo.ManufacturerData][0*word], ax  ; 
        mov     ax, [_sSVGA.ChipType]   ;                       /*          */
        mov     word ptr [SvgaOEMInfo.ManufacturerData][1*word], ax ; 
        mov     [_sSVGA.AdapterType], WEITEK_ADAPTER ; 10       /*          */
        call    WhichWeitekP9x00        ;                       /*@V3.0MNH04*/
        mov     [_sSVGA.ChipType], ax   ;                       /*          */
IdentifyExit:
        pop     ds                      ;                       /*          */
        popa                            ;                       /*          */
        leave                           ;                       /*          */
        ret                             ;                       /*          */

_IdentifySVGA   ENDP                    ;                       /*          */

BiosSeg ends

        end
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG       APAR    CHANGE DESCRIPTION
;*   --------  ---------- -----   --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx xxxxx   xxxxxxx
;*   11/12/92                     Dale  More specific Speedway detection.
;*   12/28/92                     Senja Cirrus Logic support.
;*   01/20/93                     Senja WD detection logic enhanced.
;*   01/21/93                     XGA doesn't boot because Aperture Index gets trashed.
;*   02/10/93                     Manufacturer info IOCTL.
;*   02/18/93                     UpdateMemoryInfo IOCTL.
;*   03/05/93                     Do not identify XGA as Speedway.
;*   03/10/93                     Identification of MC Orchid.
;*   03/12/93                     Changed BANK packet interface to be more consistent.
;*   03/16/93                     Making SCREENDD more consistent.
;*   03/23/93                     Fixing bank packet validation.
;*   04/03/93                     Attach to OEMHLP.
;*   04/14/92                     If XGA detected, do not proceed with the detection.
;*   05/02/93              68723  Improve Speedway checks
;*   06/03/93              69461  Lock the extended sequencer before exit
;*   06/03/93              63910  ACER M3125 SVGA fix
;*   06/04/93             F69306  Add support for S3
;*   08/12/93              72760  Enhance S3 chip detection
;*   08/30/93              73465  Only need 1 manufacturer value for Diamond
;*   08/31/93                     Recognize Cirrus Logic GD5428 chip
;*   10/06/93              72687  Support Number Nine adapters with S3
;*   10/13/93              74175  Fix SVGA conflict on Gateway VLB
;*   11/01/93             D75458  Merge r206v, r205, r206, r207 S3 code
;*   11/19/93             D74047  Add support for S3 911/924
;*   02/24/94             D79562  Recognize additional WD chipsets
;*   03/17/94             D80921  Fix WD DOS started in background
;*   03/18/94             D       Fix WD DOS started in background
;*   04/26/94             D82003  WD90C24 preserve locks for BIOS setmodes
;*   05/13/94             F74819  ATI Mach8/32 check in files
;*   05/14/94                     Support more Cirrus chipsets
;*   05/17/94                     Support S3 Vision 864/964
;*   06/14/94                     Make Video7 lock check not affect Cirrus
;*   06/15/94                     Add ATI Mach 64 Identification
;*   07/15/94                     enhance Tseng VRAM size determination
;*   07/16/94                     ATI Mach64 detection clear RS2 & restore
;*   07/16/94             D89152  WD/Video7/Cirrus SEQ06 lock preservation
;*   07/28/94              88172  Detect Chips and Technologies adapter
;*   08/04/94              92358  Set zero flag off if CHIPS not found
;*   08/12/94              92809  Tseng MemorySize determination not always correct (VLB, PCI)
;*   08/16/94             D93790  Fix WD C24 memory detection
;*   08/18/94              82945  Enable TSENGW32 with Diamond
;*   08/26/94             D93217  Fix ATI Mach32 memory detection
;*   08/25/94             D       Add PCI detection via a BIOS call.
;*   09/19/94              92593  Actix S3864 returns       vender ID
;*   09/22/94              99400  Avance card causes trap in DOS full screen
;*   09/22/94                     Strengthen CHIPS test
;*   09/23/94                     Detect memory size for Cirrus
;*   09/25/94              99760  Compudyne w/ Weitek IPE during installation
;*   10/20/94                     Add write back invalidate cache commands
;*   10/25/94             103192  TSENG Rev D wont install
;*   11/16/94  @V3.0JLO01 104565  ATI Mach32 microchannel version not recognized
;*   11/30/94  @V3.0YEE01 105950  Support S3 964
;*   01/12/95  @V3.0MNH04 102314  Put back Weitek Hunt to id 9000 vs 9100
