;*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.;
;*****************************************************************************/
;       SCCSID = @(#)svgarout.asm       6.1 90/11/17
; ****************************************************************************
; *                                                                          *
; *                                                                          *
; *                                                                          *
; ****************************************************************************
        PAGE    58,132
        TITLE   Screen Device Driver - (svgarout.Asm)
        .386p

;/***********************************************************************/
;/*                                                                     */
;/* SOURCE FILE NAME: svgarout.Asm      STATUS: Version 1.1             */
;/*                                                                     */
;/* DESCRIPTIVE NAME:  Base Video Subsystem Screen Device Driver        */
;/*                                                                     */
;/* FUNCTION:   Provide SVGA routines, called by category 80H,          */
;/*             SVGA_IOCTL listed below                                 */
;/*               GetSVGABank                                           */
;/*               SetSVGABank                                           */
;/*               GetSVGATrapIOList                                     */
;/*               SetSVGATrapIOList                                     */
;/*               GetSVGALockUnlock                                     */
;/*               SetSVGALockUnlock                                     */
;/*               GetSVGACleanup                                        */
;/*               SetSVGACleanup                                        */
;/*               GetSVGAInfo                                           */
;/*                                                                     */
;/*                                                                     */
;/* NOTES:  Executes on Level 0                                         */
;/*                                                                     */
;/* ENTRY POINT:  Screen_Strategy                                       */
;/*   LINKAGE: Far Call                                                 */
;/*                                                                     */
;/* INPUT:  ES:BX = request packet address                              */
;/*       DS = BIODATA                                                  */
;/*                                                                     */
;/* EXIT-NORMAL:                                                        */
;/*       AX = Status to return to OS                                   */
;/*                                                                     */
;/*              Error Code             Cause                           */
;/*              ------------------------------------------             */
;/*              ERROR_I24_BAD_PARAMETER Invalid Parameter              */
;/*                                                                     */
;/* EFFECTS:  None                                                      */
;/*                                                                     */
;/*   ROUTINES:  Device_Help                                            */
;/*                                                                     */
;/************************ END OF SPECIFICATIONS ************************/

.xlist
        INCLUDE basemaca.inc            ;;;;;; 2.0 unique (dosmac replacement)
        INCLUDE devhlp.inc              ; Define DevHlp functions
        INCLUDE devsym.inc              ; Define DOS equates
        INCLUDE error.inc               ; Define Error Messages
        INCLUDE struc.inc               ; Define STRUC macros
        include iodelay.inc
        include svgadefs.inc            ;              ;          
.list


EGA_BIT         EQU     4                ; EGA
VGA_BIT         EQU     8                ; VGA
EGAVGA_BIT      EQU     EGA_BIT+VGA_BIT  ; EGA/VGA

;
; Structure definitions
;
FAR_POINTER     STRUC
        _OFF    DW      (?)             ; OFFSET OF FAR POINTER
        _SEG    DW      (?)             ; SEGMENT OF FAR POINTER
FAR_POINTER     ENDS

;VVID_IDC argument structure. Return address is 8 bytes and save bp takes 2 bytes
;Pascal calling convention function.
ulFunc          EQU     [bp+18]
ulParam1        EQU     [bp+14]
ulParam2        EQU     [bp+10]

Flat_Pointer    struc
        fp_offlo        DW      ?
        fp_offhi        DW      ?
        fp_sel          DW      ?
Flat_Pointer    ends
IDC_SUCCESS     EQU     1

IDC_CMD_REGISTER_STACK_PROC     EQU     0       ; stack based IDC VDD-PDD EP.
IDC_CMD_REGISTER_EPREGISTER     EQU     1       ; register based IDC VDD-PDD EP.

GetLinear_Packet        STRUC
        PacketLength    DD     0H               ; total size of data packet
        PhysicalAddress DD     0H               ; Physical address of aperture
        ApertureSize    DD     0H               ; Size of aperture
        LinearAddress   DD     0H               ; Linear address of aperture (returned)
GetLinear_Packet        ENDS

GetLinear_Packet_Size   EQU     SIZE GetLinear_Packet

SvgaGenericPacket            STRUC
        DataPacketSize       DW 0H              ; total size of data packet
        ReturnDataPacketSize DD 0H              ; pointer to required size for data packet (ge trap list).
        PacketDirection      DW 0H              ; Lock/unlock packet only.
SvgaGenericPacket            ENDS

PARAMETER_PACKET_SIZE   EQU     SIZE SvgaGenericPacket

SvgaBankPacket          STRUC
        PacketLen       DD     0H               ; total size of data packet (min 10)            
        Bank            DW     0H               ; bank number
        Mode            DW     0H               ; graphic/text mode
        Direction       DW     0H               ; read/write bank
SvgaBankPacket          ENDS

BANK_PARAM_PACKET_SIZE  EQU     SIZE SvgaBankPacket

SvgaConfiguration       STRUC                   ; matches OEMSVGAINFO (bvhsvga)
        AdapterType     DW      0
        ChipType        DW      0
        Memory          DD      0100000H        ; no of bytes video RAM (1MB)
SvgaConfiguration       ENDS
VIDEO_SIZE      EQU     SIZE SvgaConfiguration
;
; SVGA BANK ROUTINES
; SCREENDD knows how to set or get current bank for all supported chipsets
; Routine depends on the current video mode and direction.
;
SVGA_GET_BANK           EQU   0h
SVGA_SET_BANK           EQU   1h

; parameter packet format is of SvgaBankPacket.
; SVGA_GET_BANK returns current Bank in the param packet Bank field.
; Minimum length of the packet is 8. Functions fail if less.

READ_BANK               EQU    0H
WRITE_BANK              EQU    1H
MODE_TEXT               EQU    0H
MODE_PLANAR             EQU    1H
MODE_LINEAR             EQU    2H
;
; SVGA TRAP_IO_REGISTERS ROUTINES
; SCREENDD doesn't understand the format of the list and serves as a
; communicator only. It can not perform any operation on the list.
;
SVGA_GET_TRAPIO_LIST    EQU   2h                ; if passed size of data insufficient,
                                                ; error returned and ReturnDataPacketSize set!
SVGA_SET_TRAPIO_LIST    EQU   3h

; parameter packet format is SvgaGenericPacket

; data packet format: pointer to array of bytes of DataPacketSize.
; Only first ReturnDataPacketSize valid

;
; SVGA LOCK/UNLOCK COMMAND SECTION ROUTINES
; SCREENDD doesn't understand the format of the lock/unlock and serves as a
; communicator only. It can not perform any operation on the command list.
;
SVGA_GET_LOCK_UNLOCK    EQU   4h                ; if passed size of data insufficient,
                                                ; error returned and ReturnDataPacketSize set!

SVGA_SET_LOCK_UNLOCK    EQU   5h

; parameter packet format SvgaGenericPacket

; data packet format: pointer to array of bytes of DataPacketSize.
; Only first ReturnDataPacketSize valid

LOCK_COMMANDS           EQU    0H
UNLOCK_COMMANDS         EQU    1H
;
; SVGA CLEANUP COMMAND SECTION ROUTINES
; SCREENDD doesn't understand the format of the cleanup and serves as a
; communicator only. It can not perform any operation on the command list.
;
SVGA_GET_CLEANUP_SECT   EQU   6h                ; if passed size of data insufficient,
                                                ; error returned and ReturnDataPacketSize set!
SVGA_SET_CLEANUP_SECT   EQU   7h

; parameter packet format SvgaGenericPacket

; data packet format: pointer to array of bytes of DataPacketSize.
; Only first ReturnDataPacketSize valid

;
; SVGA_GET_INFO
;
SVGA_GET_INFO           EQU   8h

;data packet format is SvgaConfiguration
;           all important indecies and values are saved on the stack
; STACK FRAME for identify routines
SaveIndex1      EQU   <[bp-1]>                  ; BYTE
SaveIndex2      EQU   <[bp-2]>                  ; BYTE
SaveIndex3      EQU   <[bp-3]>                  ; BYTE
SaveIndex4      EQU   <[bp-4]>                  ; BYTE
SaveValue1      EQU   <[bp-5]>                  ; BYTE
SaveValue2      EQU   <[bp-6]>                  ; BYTE
SaveValue3      EQU   <[bp-7]>                  ; BYTE
SaveValue4      EQU   <[bp-8]>                  ; BYTE
SaveReg1        EQU   <[bp-10]>                 ; WORD
SaveReg2        EQU   <[bp-12]>                 ; WORD
SaveReg3        EQU   <[bp-14]>                 ; WORD
STACKBLOCK      EQU   16

;
; SVGA_GET_MANUFACTURER
;
SVGA_GET_MANUFACTURER_INFO           EQU   9h   ;           
;no parameter packet
;data packet format must contain total length in bytes as its first word.
;The rest of it can be in manufacturer/adapter specific format.
SvgaOEMPacket           STRUC                   ; 
        DataSize        DD 0H                   ; total size of data packet (min 10).           
        Manufacturer    DW 0H                   ; Adapter manufacturer ID.
        ManufacturerData DD 0H                  ; manufacturer specific
SvgaOEMPacket           ENDS
; Diamond format for Manufacturer data
BIOSMajor           EQU     6H                  ; BIOS revision major
BIOSMinor           EQU     8H                  ; BIOS revision minor

DIAMOND_MANUFACTURER EQU     1                  ;                         ;          
IFDEF FAMILY2
  ORCHID_MC_ADAPTER EQU     2                   ;           
  ORCHID_MC_ID      EQU     86H                 ;           
ENDIF
NUMBER_NINE_ADAPTER EQU     3                   ;             ;          
ARTIST_GRAPHICS_MANUFACTURER EQU 4              ;           
DELIMITER      EQU     '('
PERIOD         EQU     '.'

;
; SVGA_UPDATE_MEMORY
;
SVGA_UPDATE_MEMORY      EQU    0Ah              ;           
;no data packet
;parameter packet is a pointer to ULONG containing new SVGAMemory.           

;                       end of SVGA support

        EXTRN NOPSetBank   : WORD               ; all bank routines in SVGABANK.ASM
        EXTRN Video7SetBank: WORD
        EXTRN TridentSetBank:WORD
        EXTRN TsengSetBank : WORD
        EXTRN WDSetBank    : WORD
        EXTRN ATISetBank   : WORD
        EXTRN IBMSetBank   : WORD
        EXTRN CirrusSetBank: WORD
        EXTRN S3SetBank    : WORD               ;             ;          
        EXTRN NOPGetBank   : WORD
        EXTRN Video7GetBank: WORD
        EXTRN TridentGetBank:WORD
        EXTRN TsengGetBank : WORD
        EXTRN WDGetBank    : WORD
        EXTRN ATIGetBank   : WORD
        EXTRN IBMGetBank   : WORD
        EXTRN CirrusGetBank: WORD
        EXTRN S3GetBank    : WORD               ;              ;          
        EXTRN DevHelp: DWORD
        IFDEF FAMILY2                           ;           
        EXTRN LID    : WORD
        ENDIF


DGROUP  GROUP   BioData

BioData SEGMENT WORD PUBLIC 'DATA' USE16
        ASSUME  DS:BioData

PUBLIC          SVGAInfo
PUBLIC          XGAInstance

SVGAInfo        SvgaConfiguration <,,>    ; 
WDSig           DB      'VGA='                  ; 
DiamondWDSig    DB      'SPEEDSTAR 24X'         ;           
DiamondETSig    DB      'SPEEDSTAR 24'          ;           
DiamondS324Sig  DB      'STEALTH 24'            ;              ;          
DiamondS3PROSig DB      'STEALTH PRO'           ;           
Number9S3Sig    DB      10111101b,00110011b     ;           
ArtistS3Sig     DB      'WINSPRINT 900'         ;           
ATISig          DB      ' 761295520'            ; 
ADAPTER_TYPE    DB      0                       ; Adapters found
XGAInstance     DW      0                       ; XGA instance for Speedway           

        align 2
SVGA_FUNCTION_TABLE LABEL WORD          ; SVGA category IOCTL functions
        DW      GetSVGABank             ; 0h return current bank
        DW      SetSVGABank             ; 1h set current bank
        DW      FutureSVGAFunc          ; 2h return TRAP IO list for current chipset
        DW      FutureSVGAFunc          ; 3h save TRAP IO list for current chipset
        DW      FutureSVGAFunc          ; 4h return (un)lock section for current chipset
        DW      FutureSVGAFunc          ; 5h save (un)lock section for current chipset
        DW      FutureSVGAFunc          ; 6h return cleanup section for current chipset
        DW      FutureSVGAFunc          ; 7h save cleanup section for current chipset
        DW      GetSVGAInfo             ; 8h return chipset and vram size information
        DW      GetOEMInfo              ; 9h return chipset and vram size information
        DW      UpdateMemoryInfo        ; Ah return chipset and vram size information           
        DW      GetLinearAccess         ; Bh return linear address mapped to given physical           
SVGA_FUNCTION_TABLE_SIZE        EQU ($-OFFSET SVGA_FUNCTION_TABLE)/2

SVGA_SET_BANK_TABLE     LABEL   WORD
        DW     NOPSetBank
        DW     Video7SetBank
        DW     TridentSetBank
        DW     TsengSetBank
        DW     WDSetBank
        DW     ATISetBank
        DW     IBMSetBank
        DW     CirrusSetBank
        DW     S3SetBank                ;             ;          

SVGA_GET_BANK_TABLE     LABEL   WORD
        DW     NOPGetBank
        DW     Video7GetBank
        DW     TridentGetBank
        DW     TsengGetBank
        DW     WDGetBank
        DW     ATIGetBank
        DW     IBMGetBank
        DW     CirrusGetBank
        DW     S3GetBank                ;             ;          

IF 0

ChipInfoBlock    DB      2048   DUP (0)         ; this block contains following sections
                                                ; Trap
                                                ; Cleanup
                                                ; Lock
                                                ; Unlock

                                                ; offsets of the sections in ChipInfo
SVGATrapBegin    LABEL    WORD
                 DW     WORD PTR ChipInfoBlock
SVGATrapEnd      DW     ?                       ; should always be CleanupBegin - 2
SVGACleanupBegin DW     ?
SVGACleanupEnd   DW     ?                       ; should always be LockBegin - 2
SVGALockBegin    DW     ?
SVGALockEnd      DW     ?                       ; should always be UnlockBegin - 2
SVGAUnlockBegin  DW     ?
SVGAUnlockEnd    DW     ?                       ; should always < ChipInfoBlock+2048

ENDIF
ScreenDDName    DB      "SCREEN$",0             ; 
OemName         DB      "OEMHLP$ ",0            ;            must be 8 chars.
IDC_ENTRY       STRUC
        RealEntry   DD  ?                       ; DD Real Mode Entry Pt (Seg:Offset)
        RealDS      DW  ?                       ; DD Real Mode Data Segment
        ProtEntry   DD  ?                       ; DD Protect Mode Entry Pt (Sel:Offset)
        ProtDS      DW  ?                       ; DD Protect Mode Data Selector
IDC_ENTRY       ENDS
OemDDEntry      IDC_ENTRY       <>              ;           
OemDDRequest    Packet          <>              ;           
FlatPointer     DD      0                       ; Used for GetLinearAccess
FlatPtrOffset   DD      0                       ; Used for GetLinearAccess

DATA_END LABEL  BYTE

BioData ends

BiosSeg SEGMENT WORD Public 'CODE' USE16
        ASSUME  CS:BiosSeg

        extrn   MemoryInit  : near                                      ;J-TS920924

PUBLIC  GetSVGABank
PUBLIC  SetSVGABank
IF      0
  PUBLIC  GetSVGATrapIOList
  PUBLIC  SetSVGATrapIOList
  PUBLIC  GetSVGALockUnlock
  PUBLIC  SetSVGALockUnlock
  PUBLIC  GetSVGACleanup
  PUBLIC  SetSVGACleanup
ENDIF
PUBLIC  GetSVGAInfo
PUBLIC  GetOEMInfo
PUBLIC  UpdateMemoryInfo
PUBLIC  SVGA_IOCTL
PUBLIC  GetLinearAccess

PUBLIC  IdentifySVGA
PUBLIC  AttachOEM                               ;           

;--------------------------------------------------------------------------
; SUBROUTINE NAME:      SVGA_IOCTL
;
; DESCRIPTIVE NAME:     SVGA IOCTL Routine
;
; FUNCTION:     Performs SVGA specific function requests
;
; ENTRY POINT:  SVGA_IOCTL
;    LINKAGE:   Call Near
;
; INPUT:
;       ES:BX = request packet address
;       DS = BIODATA
;
; EXIT-NORMAL:
;       AX = Status to return to OS
;
; EXIT-ERROR:
;       None
;
; EFFECTS:
;       AX
;
;    USES ROUTINES:
;               GetSVGABank
;               SetSVGABank
;               GetSVGATrapIOList
;               SetSVGATrapIOList
;               GetSVGALockUnlock
;               SetSVGALockUnlock
;               GetSVGACleanup
;               SetSVGACleanup
;               GetSVGAInfo
;               GetOEMInfo
;               UpdateMemoryInfo
;
;
;
; CALLED BY ROUTINES:
;               SCREEN_STRATEGY
;

SVGA_IOCTL      PROC    NEAR

ASSUME  DS:BioData , ES:NOTHING, SS:NOTHING

;
; Get packet function and use appropriate table
;
        mov     al,es:[bx].giofunction          ; command code
        cmp     al,svga_function_table_size-1   ; if command is supported
        jbe     svga_function                   ; else
        mov     ax,STERR + ERROR_I24_BAD_COMMAND; unknown cmd err + error bit
        jmp     short endif_svga                ; 
svga_function:
        mov     si,offset SVGA_FUNCTION_TABLE   ; use standard routines
        cbw                                     ; make command code a word
        shl     ax,1                            ; make command code a table offset
        add     si,ax                           ; si = command table offset
        call    [si]                            ; go do request
;
; exit
;
endif_svga:
        ret                                     ; return to caller.

SVGA_IOCTL      ENDP

;--------------------------------------------------------------------------
; SUBROUTINE NAME:      VerifyDataPacket
;
; DESCRIPTIVE NAME:     Verify data packet pointer.
;
; FUNCTION:     Verify data packet.
;
; ENTRY POINT:  VerifyDataPacket
;    LINKAGE:   Call Near
;
; INPUT:
;       ES:BX = request packet address
;       CX = length to verify
;       DH = 1 if write access required.
;
; EXIT-NORMAL:
;       C set if failure.
;
; EXIT-ERROR:
;       None
;
; EFFECTS:
;       AX, DI, DL
;
;    USES ROUTINES:
;
; CALLED BY ROUTINES:
;               Various.
;
VerifyDataPacket        PROC    NEAR
        mov     ax,es:[bx].GIODataPack._SEG     ; Make sure data packet
        mov     di,es:[bx].GIODataPack._OFF     ; selector is valid.
        mov     dh, 1                           ; read/write access
        mov     dl,DevHlp_VerifyAccess
        call    DevHelp
        ret
VerifyDataPacket        ENDP

;--------------------------------------------------------------------------
; SUBROUTINE NAME:      VerifyParaPacket
;
; DESCRIPTIVE NAME:     Verify parameter packet pointer.
;
; FUNCTION:     Verify parameter packet.
;
; ENTRY POINT:  VerifyParaPacket
;    LINKAGE:   Call Near
;
; INPUT:
;       ES:BX = request packet address
;       CX = length to verify
;       DH = 1 if write access required.
;
; EXIT-NORMAL:
;       C set if failure.
;
; EXIT-ERROR:
;       None
;
; EFFECTS:
;       AX, DI, DL
;
;    USES ROUTINES:
;
; CALLED BY ROUTINES:
;               Various.
;
VerifyParaPacket        PROC    NEAR
        mov     ax,es:[bx].GIOParaPack._SEG     ; Make sure parameter packet
        mov     di,es:[bx].GIOParaPack._OFF     ; selector is valid.
        mov     dh, 1                           ; read/write access
        mov     dl,DevHlp_VerifyAccess
        call    DevHelp
        ret
VerifyParaPacket        ENDP

;--------------------------------------------------------------------------
; SUBROUTINE NAME:      GetLinearAccess
;
; DESCRIPTIVE NAME:     Return linear address mapped to given physical
;
; FUNCTION:     Returns a linear address to a physical region of memory
;               of given size.
;
; ENTRY POINT:  GetLinearAccess
;    LINKAGE:   Call Near
;
; INPUT:
;       ES:BX = request packet address
;       DS = BIODATA
;
; EXIT-NORMAL:
;       AX = Status to return to OS
;
; EXIT-ERROR:
;       None
;
; EFFECTS:
;       AX
;
;    USES ROUTINES:
;
; CALLED BY ROUTINES:
;               SVGA_IOCTL

GetLinearAccess PROC    NEAR
        mov     cx,GetLinear_Packet_Size        ; 
        call    VerifyParaPacket                ; 
        jc      GetLinError                     ; 

        les     bx,es:[bx].GIOParaPack          ; 
        mov     edi,es:[bx].PhysicalAddress     ; 
        or      edi,edi                         ; 
        jz      GetLinError                     ; 
        mov     FlatPointer,edi                 ; 
        mov     edi,FlatPtrOffset               ; 
        or      edi,edi                         ; 
        jnz     @F                              ; 

        mov     ax,ds                           ; Convert selector:offset
        mov     esi,OFFSET FlatPointer          ; 
        mov     dl,DevHlp_VirtToLin             ; 
        call    DevHelp                         ; 
        jc      GetLinError                     ; 

        mov     FlatPtrOffset,eax               ; 
        mov     edi,eax                         ; 
@@:     mov     eax,00010000b                   ; Map physical to linear
        mov     ecx,es:[bx].ApertureSize        ; Size in bytes
        mov     dl,DevHlp_VMAlloc               ; 
        call    DevHelp                         ; 
        jc      GetLinError                     ; 
        mov     es:[bx].LinearAddress,eax       ; 
        xor     eax,eax                         ; 
        ret                                     ; return - no error

GetLinError:
        mov     ax,STERR + ERROR_I24_INVALID_PARAMETER
        ret                                     ; return - error code set
GetLinearAccess ENDP

;--------------------------------------------------------------------------
; SUBROUTINE NAME:      GetSVGAInfo
;
; DESCRIPTIVE NAME:     Return SVGA chip and its VRAM size information.
;
; FUNCTION:     Fill data packet with SVGA chip information.
;
; ENTRY POINT:  GetSVGAInfo
;    LINKAGE:   Call Near
;
; INPUT:
;       ES:BX = request packet address
;       DS = BIODATA
;
; EXIT-NORMAL:
;       AX = Status to return to OS
;
; EXIT-ERROR:
;       None
;
; EFFECTS:
;       AX
;
;    USES ROUTINES:
;
; CALLED BY ROUTINES:
;               SVGA_IOCTL
;
GetSVGAInfo      PROC    NEAR
        ASSUME  DS:BioData

        cmp     es:[bx].GIOFunction, SVGA_GET_INFO
        jne     short @F
        mov     cx,VIDEO_SIZE                   ; 
        call    VerifyDataPacket                ;           
        mov     ax,STERR + ERROR_I24_INVALID_PARAMETER
        jc      END_SVGA                        ; exit with error
        mov     al,es:[bx].GIOFunction          ; 
        les     di,es:[bx].GIODataPack
        mov     si, offset SVGAInfo
        movsw                                   ; SVGAAdapterType
        movsw                                   ; SVGAChipType
        movsw                                   ; SVGAMemory (LSW)
        movsw                                   ; SVGAMemory (MSW)
        xor     ax,ax                           ; Indicate success
        jmp short END_SVGA

@@:     mov     ax,STERR + ERROR_I24_BAD_COMMAND
END_SVGA:
        ret
GetSVGAInfo     ENDP

;--------------------------------------------------------------------------
; SUBROUTINE NAME:      GetOEMInfo
;
; DESCRIPTIVE NAME:     Return SVGA manufacturer and BIOS revision.
;
; FUNCTION:     Fill data packet with OEM information.
;
; ENTRY POINT:  GetSVGAInfo
;    LINKAGE:   Call Near
;
; INPUT:
;       ES:BX = request packet address
;       DS = BIODATA
;
; EXIT-NORMAL:
;       AX = Status to return to OS
;
; EXIT-ERROR:
;       None
;
; EFFECTS:
;       AX
;
;    USES ROUTINES:
;
; CALLED BY ROUTINES:
;               SVGA_IOCTL
;
GetOEMInfo      PROC    NEAR
        ASSUME  DS:BioData

        cmp     es:[bx].GIOFunction, SVGA_GET_MANUFACTURER_INFO
        jne     short @F
        mov     cx, 4                           ; verify length field first.
        call    VerifyDataPacket                ;           
        mov     ax,STERR + ERROR_I24_INVALID_PARAMETER
        jc      END_OEM                         ; exit with error
                                                ; read the first dword to get total length.
        push    es
        les     di, es:[bx].GIODataPack
        mov     cx, word ptr es:[di]            ; verify entire packet
        pop     es
        call    VerifyDataPacket                ;           
        mov     ax,STERR + ERROR_I24_INVALID_PARAMETER
        jc      END_OEM                         ; exit with error
        les     si, es:[bx].GIODataPack         ; load es:si with pointer to OEM info
        IFDEF   FAMILY2
        call    ProcessMC_OEM                   ;           
        ELSE
        call    ProcessOEM
        ENDIF
        xor     ax,ax                           ; Indicate success
        jmp short END_OEM

@@:     mov     ax,STERR + ERROR_I24_BAD_COMMAND
END_OEM:
        ret
GetOEMInfo     ENDP
;          
;--------------------------------------------------------------------------
; SUBROUTINE NAME:      UpdateMemoryInfo
;
; DESCRIPTIVE NAME:     Set SVGA memory to the value passed.
;
; FUNCTION:
;
; ENTRY POINT:  UpdateMemoryInfo
;    LINKAGE:   Call Near
;
; INPUT:
;       ES:BX = request packet address
;       DS = BIODATA
;
; EXIT-NORMAL:
;       AX = Status to return to OS
;
; EXIT-ERROR:
;       None
;
; EFFECTS:
;       AX
;
;    USES ROUTINES:
;
; CALLED BY ROUTINES:
;               SVGA_IOCTL
;
UpdateMemoryInfo      PROC    NEAR
        ASSUME  DS:BioData

        mov     ax,STERR + ERROR_I24_BAD_COMMAND
        cmp     es:[bx].GIOFunction, SVGA_UPDATE_MEMORY
        jne     short @F
        mov     cx,4                            ;           
        call    VerifyParaPacket                ;           
        mov     ax,STERR + ERROR_I24_INVALID_PARAMETER
        jc      short @F                        ; exit with error

        les     bx, es:[bx].GIOParaPack         ; 
        mov     eax, es:[bx]                    ; 
        mov     SVGAInfo.Memory, eax            ; 
        xor     eax, eax                        ; 
@@:
        ret
UpdateMemoryInfo     ENDP

;--------------------------------------------------------------------------
; SUBROUTINE NAME:      GetSVGABank
;
; DESCRIPTIVE NAME:     Return current chipset bank.
;
; FUNCTION:     Parameter packet contains direction and video mode.
;               Return bank thru data packet. All chipset routines expect
;               current video mode in DI and direction in DX. Bank returned
;               in AX. No error handling by the routines.
;
; ENTRY POINT:  GetSVGABank
;    LINKAGE:   Call Near
;
; INPUT:
;       ES:BX = request packet address
;       DS = BIODATA
;
; EXIT-NORMAL:
;       AX = Status to return to OS
;
; EXIT-ERROR:
;       None
;
; EFFECTS:
;       AX
;
;    USES ROUTINES:
;
; CALLED BY ROUTINES:
;               SVGA_IOCTL
;
GetSVGABank             PROC    NEAR
        mov     cx,BANK_PARAM_PACKET_SIZE       ; minimum length which should be valid.
        call    VerifyParaPacket                ;           
        .if     nc
                lfs     si, es:[bx].GIOParaPack ; verify the whole packet.
                mov     cx, word ptr fs:[si].PacketLen    ;           
                .if     <cx g BANK_PARAM_PACKET_SIZE>
                        call    VerifyParaPacket;            function requires es:bx=req.p.
                        jc      ERROR_BANK_EXIT ; and ds local data segment
                .endif
                mov     bx, si                  ; fs:bx points to the BankPacket
                mov     dx, fs:[bx].Direction   ; read/write
                cmp     dx, WRITE_BANK
                ja      ERROR_BANK_EXIT
                mov     di, fs:[bx].Mode        ; read/write
                cmp     di, MODE_LINEAR
                ja      ERROR_BANK_EXIT
                mov     ax, SVGAInfo.AdapterType
                mov     si,offset SVGA_GET_BANK_TABLE   ; 
                cbw                             ; Make adapter type a word
                shl     ax,1                    ; Make adapter type a table offset
                add     si,ax                   ; SI = get bank table offset
                call    [si]                    ; go do request
                                                ; AX = current bank
                mov    word ptr fs:[bx].Bank, ax;           
                xor    ax,ax                    ; Indicate success
                ret
        .endif
ERROR_BANK_EXIT:
        mov     ax,STERR + ERROR_I24_INVALID_PARAMETER
        ret
GetSVGABank             ENDP

;--------------------------------------------------------------------------
; SUBROUTINE NAME:      SetSVGABank
;
; DESCRIPTIVE NAME:     Return current chipset bank.
;
; FUNCTION:     Parameter packet contains length, bank, direction and video mode.
;               All chipset routines expect current video mode in DI,
;               direction in DX and bank in CX.
;               No error handling by the called routines.
;
; ENTRY POINT:  SetSVGABank
;    LINKAGE:   Call Near
;
; INPUT:
;       ES:BX = request packet address
;       DS = BIODATA
;
; EXIT-NORMAL:
;       AX = Status to return to OS
;
; EXIT-ERROR:
;       None
;
; EFFECTS:
;       AX
;
;    USES ROUTINES:
;
; CALLED BY ROUTINES:
;               SVGA_IOCTL
;
SetSVGABank             PROC    NEAR
        mov     cx,BANK_PARAM_PACKET_SIZE       ; mimimum size which should be valid.
        call    VerifyParaPacket;           
        .if     nc
                lfs     si, es:[bx].GIOParaPack ; validate the whole length
                mov     cx, word ptr fs:[si].PacketLen    ;           
                .if     <cx g BANK_PARAM_PACKET_SIZE>
                        call  VerifyParaPacket;           
                        jc    ERROR_BANK
                .endif
                mov     bx, si                  ;               fs:bx points to BankPacket
                mov     dx, fs:[bx].Direction   ; read/write
                cmp     dx, WRITE_BANK          ; is direction valid?
                ja      ERROR_BANK
                mov     di, fs:[bx].Mode        ; is video mode in valid range?
                cmp     di, MODE_LINEAR
                ja      ERROR_BANK
                mov     cx, fs:[bx].Bank        ; Bank
                mov     ax, SVGAInfo.AdapterType
                mov     si,offset SVGA_SET_BANK_TABLE   ; 
                cbw                             ; Make adapter type a word
                shl     ax,1                    ; Make adapter type a table offset
                add     si,ax                   ; SI = get bank table offset
                call    [si]                    ; go do request
                xor     ax,ax                   ; Indicate success
                ret
        .endif
ERROR_BANK:
        mov     ax,STERR + ERROR_I24_INVALID_PARAMETER
        ret
SetSVGABank             ENDP


; Future SVGA functions 2-7. Still undefined.
;GetSVGATrapIOList
;SetSVGATrapIOList
;GetSVGALockUnlock
;SetSVGALockUnlock
;GetSVGACleanup
;SetSVGACleanup
FutureSVGAFunc       PROC    NEAR               ;           
        mov     ax,STERR + ERROR_I24_BAD_COMMAND
        ret
FutureSVGAFunc       ENDP


IFDEF   FAMILY2
;--------------------------------------------------------------------------
; SUBROUTINE NAME:      ProcessMC_OEM
;
; DESCRIPTIVE NAME:     Identify MC SVGA manufacturer.
;
; FUNCTION:     Return manufacturer info in DATA packet.
;
; ENTRY POINT:  ProcessMC_OEM
;    LINKAGE:   Call Near
;
; INPUT:
;       ES:SI = data packet address
;       DS = BIODATA
;
; EXIT-NORMAL:
;       AX = Status to return to OS
;
; EXIT-ERROR:
;       None
;
; EFFECTS:
;       AX
;
;    USES ROUTINES:
;
; CALLED BY ROUTINES:
;               INIT
;
; OUTPUT:       Is in adapter specific format. For example:
;               Orchid Pro MC: returns slot in Manufacturer Data.
;

ProcessMC_OEM   PROC    Near
        cmp     SVGAInfo.AdapterType, 3         ; if not ET4000, exit without
        jne     ExitMC_OEM                      ; setting the Manufacturer ID
        push    es
        push    si                              ; preserve target address.
        mov     ax, ORCHID_MC_ID                ; load MC id for Orchid
        call    QueryMCSlot                     ; if z failed, nz AX contains the slot
        pop     si
        pop     es
        jz      ExitMC_OEM
        mov     es:[si].Manufacturer, ORCHID_MC_ADAPTER
        mov     word ptr es:[si].ManufacturerData, AX
ExitMC_OEM:
        ret
ProcessMC_OEM   ENDP

;--------------------------------------------------------------------------
; SUBROUTINE NAME:      QueryMCSlot
;
; DESCRIPTIVE NAME:     If an adapter with a matching MC-ID found,
;                       return the slot.
;
; FUNCTION:     Return adapter MC slot number in AX.
;
; ENTRY POINT:  QueryMCSlot
;    LINKAGE:   Call Near
;
; INPUT:
;       AX = MC ID
;
; EXIT-NORMAL:
;       Z flag set indicates not found.
;
; EXIT-ERROR:
;       None
;
; EFFECTS:
;       AX
;
;    USES ROUTINES:
;
; CALLED BY ROUTINES:
;               ProcessMC_OEM
;
; OUTPUT:       AX = Adapter's slot number
;

QueryMCSlot   PROC    Near
        push    di                              ; 
        mov     di, ax                          ; ID we are searching for
        in      al, 96h                         ; Read card slot setting
        mov     bl, al                          ; Save current card slot setting
        mov     cx, 08h                         ; Start with card slot 0 (bit 0-3)
        .repeat                                 ; Search up to 8 card slots
            mov     al, cl                      ; 
            out     96h, al                     ; Put card slot into setup mode
            mov     dx, 100h
            in      ax, dx                      ; Get POS ID from slot (IOdelay)
            in      ax, dx                      ; Get POS ID from slot
            cmp     ax, di                      ; found
            .if     <z>                         ; 
                mov     ax, cx                  ; Set SLOT number
            .else
                sub     ax, ax                  ; not found
            .endif                              ; 
        .until  <nonzero ax> or                 ; found
        inc     cx                              ; Next slot
        .until  <cx a 0Fh>                      ; Search all 8 slots?
        mov     cx, ax
        and     ax, 7h                          ; set the result slot to 0-7
        push    ax
        cmp     cx, 0                           ; set the result: z if not found, nz found.
        mov     al, bl                          ; 
        out     96h, al                         ; Restore card slot setting
        pop     ax
        pop     di
        ret
QueryMCSlot   ENDP
ENDIF

;--------------------------------------------------------------------------
; SUBROUTINE NAME:      ProcessOEM
;
; DESCRIPTIVE NAME:     Identify SVGA manufacturer.
;
; FUNCTION:     Return manufacturer info in DATA packet.
;
; ENTRY POINT:  ProcessOEM
;    LINKAGE:   Call Near
;
; INPUT:
;       ES:SI = data packet address
;       DS = BIODATA
;
; EXIT-NORMAL:
;       AX = Status to return to OS
;
; EXIT-ERROR:
;       None
;
; EFFECTS:
;       AX
;
;    USES ROUTINES:
;
; CALLED BY ROUTINES:
;               INIT
;
; OUTPUT:       Is in adapter specific format. For example:
;               Diamond Speedstar: returns SvgaOEMPacket structure
;
ProcessOEM      PROC    Near
        push    es
        push    si                              ; preserve target address.
        mov     ax, 0ch                         ; 
        cmp     SVGAInfo.AdapterType, 4         ; is it WD
        jne     ET4000
        mov     di, OFFSET BioData:DiamondWDSig
        mov     bx, 02E4h                       ; this is the offset where we expect it.
        mov     cx, 13                          ; length of the string
        call    FindString
        cmp     ax, 0
        jne      ExitOEM                        ; exit without setting any data
        mov     cx, DIAMOND_MANUFACTURER        ;             ;          
        mov     bx, 02F1h                       ; this is the offset where we should start looking.
        jmp     DetermineBIOSRev

ET4000:
        cmp     SVGAInfo.AdapterType, 3         ; if not ET4000, exit
        jne     S3                              ;             ;          
        mov     di, OFFSET BioData:DiamondETSig
        mov     bx, 0A71h                       ; this is the offset where we expect it.
        mov     cx, 12                          ; length of the string
        call    FindString
        mov     cx, DIAMOND_MANUFACTURER        ;             ;          
        cmp     ax, 0
        jne     ExitOEM                         ; exit without setting any data
        mov     bx, 0A85h                       ; this is the offset where we should start looking.
        jmp     DetermineBIOSRev                ;          
S3:                                             ;           
        cmp     SVGAInfo.AdapterType, 8         ; if not S3, exit
        jne     ExitOEM
        mov     di, OFFSET BioData:DiamondS324Sig
        mov     bx, 046h                        ; this is the offset where we expect it.
        mov     cx, 0Ah                         ; length of the string
        call    FindString
        mov     cx, DIAMOND_MANUFACTURER        ;           
        cmp     ax, 0
        jne     S3PRO                           ; is it Stealth Pro?
        mov     bx, 056h                        ; this is the offset where we should start looking.
        jmp     DetermineBIOSRev
S3PRO:                                          ;           
        mov     di, OFFSET BioData:DiamondS3PROSig
        mov     ax, 0ch                         ; BIOS address
        mov     bx, 046h                        ; this is the offset where we expect it.
        mov     cx, 0Bh                         ; length of the string
        call    FindString
        mov     cx, DIAMOND_MANUFACTURER        ;           
        cmp     ax, 0
        jne     Number9                         ; keep looking                 
        mov     bx, 058h                        ; this is the offset where we should start looking.
DetermineBIOSRev:
        push    cx
        mov     ax, 0ch                         ; 
        mov     cx, 100h                        ; get a lot
        call    GetBiosRev                      ; returns AX=0 if success or major, bx=minor
        pop     cx
        jz      ExitOEM
        pop     si
        pop     es
        mov     es:[si].Manufacturer, cx
        mov     es:[si].BIOSMajor, ax
        mov     es:[si].BIOSMinor, bx
        ret
Number9:                                        ;             ;          
        mov     di, OFFSET BioData:Number9S3Sig
        mov     ax, 0ch                         ; BIOS address
        mov     bx, 160h                        ; this is the offset where we expect it.
        mov     cx, 02h                         ; length of the string
        call    FindString
        mov     cx, NUMBER_NINE_ADAPTER
        cmp     ax, 0
        jne     ArtistGraphics                  ;           
        pop     si
        pop     es
        mov     es:[si].Manufacturer, cx
        ret
ArtistGraphics:                                   ;           
        mov     di, OFFSET BioData:ArtistS3Sig
        mov     ax, 0ch                         ; BIOS address
        mov     bx, 12Ch                        ; this is the offset where we expect it.
        mov     cx, 0dh                         ; length of the string
        call    FindString
        mov     cx, ARTIST_GRAPHICS_MANUFACTURER
        cmp     ax, 0
        jne     ExitOEM                         ; exit without setting any data
        pop     si
        pop     es
        mov     es:[si].Manufacturer, cx
        ret
ExitOEM:
        pop     si
        pop     es
        ret
ProcessOEM      ENDP
;***    TextDelay - instead of using the macro to save code space
;
; WARNING - trashes si

TextDelay PROC Near
        DevIODelay si
        ret
TextDelay ENDP

;***    GetPortBase
;
;           Return port base address in DX (3b0 or 3d0)
;           depending on mono/colour mode.

GetPortBase     PROC    Near
        mov     dx, 03cch                       ; 
        in      al, dx                          ; 
        mov     dx, 03b0h                       ; assume mono
        test    al, 1                           ; 
        jz      @F                              ; 
        add     dl, 20h                         ; bump up to colour (3d0)
@@:     ret
GetPortBase     ENDP

;***    Video7EnableExt
;
;
;

Video7EnableExt PROC    Near
        mov     dx, 03c4h                       ; Extension Control register
        mov     ax, 0ea06h                      ; write 0eah to reg 6
        out     dx, ax                          ; 
        ret
Video7EnableExt ENDP

;***    Video7DisableExt
;
;
;

Video7DisableExt PROC   Near
        mov     dx, 03c4h                       ; Extension Control register
        mov     ax, 0ae06h                      ; write 0aeh to reg 6
        out     dx, ax                          ; 
        ret
Video7DisableExt ENDP

;***    SVGAPhysToVirt/SVGAUnPhysToVirt
;
;

SVGAPhysToVirt  PROC    Near
        push    cx                              ; 
        mov     dh, 0                           ; 
        mov     dl, DevHlp_PhysToVirt
        call    DevHelp                         ; Leave result in DS:SI
        pop     cx                              ; 
        ret
SVGAPhysToVirt  ENDP

SVGAUnPhysToVirt PROC   Near
        mov    dl, DevHlp_UnPhysToVirt          ; Let DevHlp know we're done
        call   DevHelp                          ; using virtual addresses.
        ret
SVGAUnPhysToVirt ENDP
;          
;***    GetBiosRev
;
;       Entry:  AX = ROM address (high)
;               BX = ROM address (low)
;               CX = length of the area to search
;
;       Look for Vers. string at BIOS location.
;       Return major and minor.
;
;       NOTE:   This routine makes very few assumptions about the
;       BIOS signature format. The assumption is that the BIOS
;       revision must have at least 1 digit major, followed by a period
;       and at least 1 digit in the minor. If the major and minor are out-
;       side of the expected range, the caller can call us again with the ROM
;       address in AX which is original plus the returned CX and we will
;       search for another string of this format.
;       There are no delimiters assumed, and the routine
;       keeps the search within the bounds of what was converted into virtual.
;       Returns AX = 0 if the above format not found or
;       AX= major, BX= minor, CX=how far into the area did we search.
;
GetBiosRev      PROC    Near
        push    es                              ; 
        push    ds                              ; 
        push    dx                              ; used as a counter
        push    cx                              ; save our original length
        push    ds                              ; 
        pop     es                              ; 
        call    SVGAPhysToVirt                  ; will load DS:SI with BIOS address
        mov     dx, cx                          ; load length of the string
FindBIOS:
        call    FindNumber                      ; si contains next position, dx updated, bx contains value
SearchLoop:
        cmp     dx, 0                           ; don't overdo it.
        je      RevNotFound
        cmp     byte ptr ds:[si], PERIOD        ; is it followed by a period
        jz      short FoundMajor                ; have a major in bx
        call    IsItaNumber                     ; nz if number, ax value, si next
        jnz     AddNumberAndSearchLoop          ; if a number keep collecting
        jmp     FindBIOS                        ; definitelly not our format. Keep searching.
AddNumberAndSearchLoop:
        imul    bx, 10
        add     bx, ax
        jmp     SearchLoop                      ; continue collecting
FoundMajor:
        mov     di, bx                          ; preserve the major
        xor     bx, bx
        xor     cx, cx                          ; cx will be used as a test for valid minor format.
        inc     si                              ; process the minor
CollectMinor:
        cmp     dx, 0                           ; don't overdo the search
        je      RevNotFound
        call    IsItaNumber                     ; nz if a number, ax value, si updated.
        jz      short @F
        mov     cx, 10                          ; cx will be used as a test for valid minor format.
        imul    bx, 10
        add     bx, ax
        jmp     CollectMinor
@@:                                             ; if first pass thru here, not a
                                                ; valid format
        cmp     cx, 10
        jne     RevNotFound                     ; else we have complete minor
Processed:                                      ; di has major, bx minor.
        pop     cx
        sub     cx, dx                          ; return how far did we get.
        pop     dx
        mov     ax, di                          ; set the major
        pop     ds                              ; 
        call    SVGAUnPhysToVirt                ; 
        pop     es                              ; 
        ret
RevNotFound:
        pop     cx                              ; used as a counter
        sub     cx, dx                          ; return how far did we get.
        mov     bx, 0FFFFh                      ; set minor to bogus
        pop     dx
        pop     ds
        call    SVGAUnPhysToVirt
        pop     es
        xor     ax, ax
        ret
GetBiosRev      ENDP

IsItaNumber     PROC    Near
        xor     ax, ax
        mov     al, byte ptr ds:[si]
        cmp     al,'0'
        jl      NotaNumber
        cmp     al,'9'
        jg      NotaNumber
        dec     dx
        dec     dx
        sub     ax, '0'
        cmp     dx, 0                           ; use dx, which should never be 0 for test.
        inc     si                              ; pass the character
        ret
NotaNumber:
        xor     ax, ax
        inc     si                              ; pass the character
        cmp     ax, 0                           ; zr false
        ret
IsItaNumber     ENDP

FindNumber      PROC    Near
SearchForNumber:
        call    IsItANumber
        jnz     ExitFound
        jmp     SearchForNumber
ExitFound:
        mov     bx, ax
        ret
FindNumber      ENDP
;***    UpperCaseSearch
;          
;       Entry:  DS : SI Starting address of the string
;               CX = length of string
;
;       Capitalize the string at the location.
;       Restores all entry registers
;
UpperCaseSearch PROC    Near
        xor     bx, bx
UpperCaseLoop:
        jcxz    ExitUpperCase
        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
        dec     cx
        inc     si
        inc     di
        jmp     UpperCaseLoop

StringNotFound:
        inc     bx
ExitUpperCase:
        mov     ax, bx                          ; success
        ret
UpperCaseSearch ENDP
;***    FindString
;
;       Entry:  AX = ROM address (high)
;               BX = ROM address (low)
;               CX = length of string
;               DI -> string to compare (in BIODATA)
;
;       Look for string at BIOS location to identify a SVGA card.
;                  Capitalize the string searched as to make it case insensitive.
;       Returns AX = 0 if found
;

FindString      PROC    Near

        push    es
        push    ds
        push    ds
        pop     es
        call    SVGAPhysToVirt

        ASSUME  DS:NOTHING

        cld
        xor     ax, ax
        call    UpperCaseSearch
        ASSUME  DS:BioData

        pop     ds
        call    SVGAUnPhysToVirt
        pop     es
        ret

FindString      ENDP

PUBLIC  VVID_IDC
;/****************************************************************************
;*
;* FUNCTION NAME = VVID_IDC
;*
;* DESCRIPTION   = IDC Interface to VVID. This function is
;*                 registered at INIT time by calling DevHlp_RegisterPDD.
;*                 It is using a stack parameter interface and it is used
;*                 only to open and obtain the register entry point bank
;*                 IDC interface function VVID_BANK_REGISTER_ENTRY, which is
;*                 much faster/
;*                 Parameters:
;*                 [sp+8] = ulFunc DD   0 for open, 1 for obtain register entry point
;*                 [sp+12] = ul1    DD  16:16 Pointer to input structure:
;*                 [sp+16] = ul2    DD  16:16 Pointer to output structure: 16:16
;*                                      area for the register entry point address to be returned.
;*                 This function depends on parameter pointers
;*                 being in the sel:offset format. VVID must convert its linear pointers
;*                 prior to calling this entry point.
;*
;* INPUT         = see Parameters above.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = 1 as success
;* RETURN-ERROR  = 0 as failure.
;*
;****************************************************************************/

VVID_IDC        PROC    FAR
        push    bp
        mov     bp,sp
        push    ds
        push    es
        push    bx
        push    di
        push    si
        mov     ax, BioData
        mov     ds, ax
        ASSUME  DS:BioData

        mov     cx, word ptr [ulFunc]           ; higher word ignored
        .if     <cx e IDC_CMD_REGISTER_STACK_PROC>
                mov     ax, IDC_SUCCESS
        .else
        .if     <cx e IDC_CMD_REGISTER_EPREGISTER>
                mov     es,[ulParam1]._SEG      ; get pointer 1 selector
                mov     di,[ulParam1]._OFF      ; get pointer 1 offset
                mov     es:[di].fp_sel,cs       ; set the far pointer selector
                mov     es:[di].fp_offhi,0      ; set the far pointer high offset
                lea     ax,cs:VVID_BANK_REGISTER_ENTRY      ; get the far pointer low offset
                mov     es:[di].fp_offlo,ax     ; set the far pointer low offset
                mov     ax, IDC_SUCCESS
        .else
                xor     ax, ax
        .endif
        .endif
        pop    si
        pop    di
        pop    bx
        pop    es
        pop    ds

        mov     sp, bp
        pop     bp
;    RETURN (32 bit)
        db      66h
        ret     12
VVID_IDC        ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = VVID_BANK_REGISTER_ENTRY
;*
;* DESCRIPTION   = Register based IDC Interface to VVID. This function
;*                 called with parameters passed thru the stack:
;*                 BX = Function
;*                      SVGA_GET_BANK (0h),
;*                      SVGA_SET_BANK (1h)
;*                 For SetBank it calls appropriate routine with args:
;*                      CX Bank, DX Direction and DI video mode
;*                 For GetBank it calls appropriate routine with args:
;*                      DX Direction and DI video mode.
;*                      Bank returned in AX.
;* INPUT         = see Parameters above.
;* OUTPUT        = NONE
;*
;* LINKAGE:     Far 16:32
;*
;* RETURN-NORMAL = See above
;* RETURN-ERROR  =
;*
;****************************************************************************/
VVID_BANK_REGISTER_ENTRY PROC    FAR
        push    ds
        push    es
        mov     ax, BioData
        mov     ds, ax
        ASSUME  DS:BioData
        mov    ax, SVGAInfo.AdapterType
        .if <bx e SVGA_SET_BANK>
                mov    si,offset SVGA_SET_BANK_TABLE   ; 
        .else
        .if <bx e SVGA_GET_BANK>
                mov    si,offset SVGA_GET_BANK_TABLE   ; 
        .else                                          ; unsupported function.
                pop     es
                pop     ds
                ret
        .endif
        .endif
        cbw                                     ; Make adapter type a word
        shl     ax,1                            ; Make adapter type a table offset
        add     si,ax                           ; SI = get bank table offset
        call    [si]                            ; go do request
        pop     es
        pop     ds
        ret
VVID_BANK_REGISTER_ENTRY ENDP
;
; The following label defines the end of the Screen resident code.
;
DEVICE_END LABEL BYTE
;            start
;--------------------------------------------------------------------------
; SUBROUTINE NAME:      AttachOEM
;
; DESCRIPTIVE NAME:     Attach to OEMHLP PDD and retrieve ADAPTER TYPE.
;
; FUNCTION:     Call OEMHLP IOCTL 7 to obtain Adapter type.
;
; ENTRY POINT:  AttachOEM
;    LINKAGE:   Call Near
;
; INPUT:
;       ES:BX = request packet address
;       DS = BIODATA
;
; EXIT-NORMAL:
;       VOID function.
;
; EXIT-ERROR:
;       VOID function.
;
; EFFECTS:
;       All preserved.
;
;    USES ROUTINES:
;
; CALLED BY ROUTINES:
;               INIT
;
AttachOEM       PROC    NEAR
        push    es
        push    bx
        ; 
        ; Attach to OEMHLP and obtain the entry point into its IDC which
        ; represent the strategy routine entry point as well.
        ; 
        mov     bx, offset OemName
        mov     di, offset OemDDEntry
        mov     dl, DevHlp_AttachDD
        call    DevHelp
        jc      AttachExit
        ; Build a request packet suitable for function 7, category 80
        mov     OemDDRequest.PktLen, 25
        mov     OemDDRequest.PktCmd, CMDGenIOCtl
        mov     OemDDRequest.GIOCategory, 80H
        mov     OemDDRequest.GIOFunction, 7
        mov     dword ptr OemDDRequest.GIOParaPack, 0
        mov     ax, offset ADAPTER_TYPE
        mov     word ptr OemDDRequest.GIODataPack, ax
        mov     ax, ds
        mov     word ptr OemDDRequest.GIODataPack + 2, ax

        ; Execute IOCTL which will fill out our local ADAPTER_TYPE.
        ; save our DS, load DS with OEMHLP and load es:bx with Packet
        mov     es, ax
        mov     bx, offset OemDDRequest                 ; es:bx request packet.
        push    ds
        mov     ax, es:OemDDEntry.ProtDS
        mov     ds, ax
        call    dword ptr es:OemDDEntry.ProtEntry
        pop     ds
AttachExit:
        pop     bx
        pop     es
        ret
AttachOEM       ENDP
;            end
;--------------------------------------------------------------------------
; SUBROUTINE NAME:      IdentifySVGA
;
; DESCRIPTIVE NAME:     Identify SVGA chip and its VRAM size.
;
; FUNCTION:     Fill global data structure with SVGA chip information.
;
; ENTRY POINT:  IdentifySVGA
;    LINKAGE:   Call Near
;
; INPUT:
;       ES:BX = request packet address
;       DS = BIODATA
;
; EXIT-NORMAL:
;       AX = Status to return to OS
;
; EXIT-ERROR:
;       None
;
; EFFECTS:
;       AX
;
;    USES ROUTINES:
;
; CALLED BY ROUTINES:
;               INIT
;
; OUTPUT:
;       Identify SVGA in machine 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
;
;         o Western Digital      PVGA1A                    4     1
;                                WD90c00                   4     2
;                                WD90c11                   4     3
;                                WD90c30                   4     4
;
;         o ATI                  18800                     5     1
;                                28800                     5     2
;
;         o IBM Speedway         VGA-256C                  6     1
;
;         o Cirrus Logic         GD5422                    7     1
;                                GD5424                    7     2
;                                GD5426                    7     3
;
;         o S3                   801, 805                  8     1 ;          
;                                928                       8     2
;
IdentifySVGA    PROC    NEAR
        pusha
        mov     SVGAInfo.AdapterType, 0

        test    ADAPTER_TYPE, EGA_BIT
        jnz     SVGAExit

@@:     call    IsS3                            ;          
        jnz     @F                              ;          
        mov     SVGAInfo.AdapterType, 8         ;          
        call    WhichS3                         ;          
        jmp     SetChipType                     ;          

@@:     call    IsATI                           ;          
        jnz     @F                              ;          
        mov     SVGAInfo.AdapterType, 5         ;          
        call    WhichATI                        ;          
        jmp     SetChipType                     ;          

@@:     call    IsWesternDig                    ;          
        jnz     @F                              ;          
        mov     SVGAInfo.AdapterType, 4         ;          
        call    WhichWesternDig                 ;          
        jmp     SetChipType                     ;          

@@:     call    IsSpeedWay
        jz      Spdwy
        cmp     XGAInstance, 0                  ;XGA found, return.           
;            jz      SVGAExit                   ;             ;          
        jnz     SVGAExit                        ;          
        jmp     short @F                        ;not XGA, not Spdwy, continue.
Spdwy:  mov     SVGAInfo.AdapterType, 6
        mov     ax, 1
        jmp     SetChipType                     ;          

@@:     call    IsVideo7
        jnz     @F
        mov     SVGAInfo.AdapterType, 1
        call    WhichVideo7
        jmp     short SetChipType

@@:     call    IsTrident
        jnz     @F
        mov     SVGAInfo.AdapterType, 2
        call    WhichTrident
        jmp     short SetChipType

;                  call    IsS3                            ;               ;          
;                  jnz     @F
;                  mov     SVGAInfo.AdapterType, 8
;                  call    WhichS3
;                  jmp     short SetChipType

@@:     call    IsTseng
        jnz     @F
        mov     SVGAInfo.AdapterType, 3
        call    WhichTseng
        jmp     short SetChipType

;               @@:     call    IsWesternDig
;                       jnz     @F
;                       mov     SVGAInfo.AdapterType, 4
;                       call    WhichWesternDig
;                       jmp     short SetChipType

;               @@:     call    IsATI
;                       jnz     @F
;                       mov     SVGAInfo.AdapterType, 5
;                       call    WhichATI
;                       jmp     short SetChipType

@@:     call    IsCirrus
        jnz     @F
        mov     SVGAInfo.AdapterType, 7
        call    WhichCirrus
        jmp     short SetChipType

@@:     call    LastAttempt                     ;           
        or      ax, ax
        jz      SVGAExit                        ; AX is 0 if adapter not identified.
                                                ; if successful ax= adapter, bx=chiptype.
        mov     SVGAInfo.AdapterType, ax
        mov     ax, bx
SetChipType:
        mov     SVGAInfo.ChipType, ax
SVGAExit:
        popa
        ret

IdentifySVGA    ENDP

;/****************************************************************************
;*
;* 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 = AdapterType
;*                 BX = ChipType
;*
;* RETURN-NORMAL = non zero AX
;* RETURN-ERROR  = AX zero
;*
;* NOTE:          Currently, WD is the only problematic adapter. We
;*                have no safe methods of identifying WD90C00.
;*                WD90C1x and 90C3x have a peculiar extended sequencer
;*                lock mechanism. If 3c4,6 is loaded with value other
;*                than 48H, only 3 lower bits of the address are taken. This
;*                address wrap also happens on pure VGA's so the possibility
;*                of misidentifying VGA must be taken care of.
;*                Video7 and Cirrus use the same lock register, but mechanisms
;*                are different enough for successful WD identification.
;*
;****************************************************************************/
LastAttempt     PROC    Near
                PUBLIC  LastAttempt
        push    bp
        mov     bp,sp
        sub     sp,STACKBLOCK                   ;           

        xor     cx, cx                          ; adapter assumed none
        call    GetPortBase                     ; 
        add     dx, 04h                         ; 
        mov     WORD PTR SaveReg1, dx
        in      al, dx
        mov     BYTE PTR SaveIndex1, al

        mov     al, 09h                         ;            For those adapters
        out     dx, al                          ;            that wraps after
        call    TextDelay                       ;            1Fh, we have to
        inc     dx                              ;            save/restore the
        in      al, dx                          ;            appropriate data
        mov     BYTE PTR SaveIndex2, al         ;            register content
        dec     dx                              ;           

        mov     ax, 2929h
        out     dx, al
        in      al, dx
        cmp     ah, al                          ; if the index read and written don't match, not a WD
        jne     RestoreExit1
        inc     dx                              ; write some data
        in      al, dx                          ; first remember the contents
        push    ax
        mov     ax, 8585h
        out     dx, al
        in      al, dx
        cmp     al, ah
        pop     ax
        out     dx, al                          ; restore value

        pushf                                   ;           
        mov     dx, WORD PTR SaveReg1           ;           
        mov     al, 09h                         ;            For those adapters
        out     dx, al                          ;            that wraps after
        call    TextDelay                       ;            1Fh, we have to
        inc     dx                              ;            save/restore the
        mov     al, BYTE PTR SaveIndex2         ;            appropriate data
        out     dx, al                          ;            register content
        popf                                    ;           

        jne     RestoreExit1

        mov     dx, 03c4h
        in      ax, dx
        mov     WORD PTR SaveReg2, dx
        mov     BYTE PTR SaveIndex2, al
        mov     ax, 0F06h                       ; Lock the extended
        out     dx, ax                          ; sequencers
        mov     ax, 1212h                       ; use bit 4 of the address
        out     dx, al                          ; sequencers
        in      al, dx                          ; read the index
        cmp     ah, al
        je      short LastExit                  ; if we read what we wrote, it didn't lock
        mov     bx, 3                           ; assume WD90c1x
        mov     ax, 4806h                       ; unlock the extended
        out     dx, ax                          ; sequencers
        mov     ax, 0909h                       ; Scratch reg at index 09h, found on 90c31
        mov     BYTE PTR SaveIndex3, al
        out     dx, al
        call    TextDelay                       ; 
        in      al, dx
        cmp     ah, al
        jne     short LastExit                  ; if index doesn't match, not a WD
        inc     dx
        in      al, dx
        mov     BYTE PTR SaveValue3, al
        mov     ax, 0303h
        out     dx, al                          ; 
        call    TextDelay                       ; 
        in      al, dx                          ; 
        cmp     al, ah                          ; 
        jne     short @F
        inc     bx                              ; it is WD90c3x
@@:                                             ; it could be Wd90c3x but a VGA as well.
                                                ; on a VGA, write to seq 9 would write to seq 1
                                                ; if seq 1 reads as 3h, it is a VGA
        mov     ax, 0301h
        mov     dx, 03c4h
        out     dx, al
        inc     dx
        in      al, dx
        cmp     ah, al
        je      short @F                        ; it is a VGA

        mov     cx, 4                           ; it is WD
@@:     mov     dx, WORD PTR SaveReg2
        mov     al, BYTE PTR SaveIndex3
        mov     ah, BYTE PTR SaveValue3
        out     dx, ax

LastExit:
        mov     ax, 0F06h                       ; Lock the extended           
        out     dx, ax                          ; sequencers                  
        mov     al, BYTE PTR SaveIndex2
        mov     dx, WORD PTR SaveReg2
        out     dx, al                          ; restore index

RestoreExit1:
        mov     dx, WORD PTR SaveReg1
        mov     al, BYTE PTR SaveIndex1
        out     dx, al
        mov     ax, cx                          ; return adapter identified.

        mov     sp, bp                          ;           
        pop     bp
        ret
LastAttempt     ENDP


;***    IsTseng
;
;       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
;
;       ENTRY:
;
;       EXIT:
;
;       USES:   AX, BX, DX
;

IsTseng         PROC    Near
                PUBLIC  IsTseng
        push    bp
        mov     bp,sp
        sub     sp,STACKBLOCK                   ;           

        call    GetPortBase                     ; 
        mov     cx, dx                          ; 
        add     dx, 4                           ; 
        in      al, dx                          ;           
        mov     WORD PTR SaveReg1, dx           ;           
        mov     BYTE PTR SaveIndex1, al         ;           

        mov     al, 13h                         ;            For those adapters
        out     dx, al                          ;            that wraps after
        call    TextDelay                       ;            1Fh, we have to
        inc     dx                              ;            save/restore the
        in      al, dx                          ;            appropriate data
        mov     BYTE PTR SaveIndex2, al         ;            register content
        dec     dx                              ;           

        mov     ax, 3333h                       ; 
        out     dx, al                          ; 
        call    TextDelay
        in      al, dx                          ; Extra sanity check for L40
        cmp     al, ah                          ; which ignores index set,
        jnz     IsTsengExit                     ; so check it worked.
        inc     dl                              ; 
        in      al, dx                          ; 
        call    TextDelay
        mov     BYTE PTR SaveValue1, al         ; save previous contents           
        xor     al, 0fh                         ; 
        out     dx, al                          ; set some new value
        call    TextDelay
        mov     ah, al                          ; 
        in      al, dx                          ; read it back
        sub     ah, al                          ; 
        mov     al, BYTE PTR SaveValue1         ; get old value
        call    TextDelay
        out     dx, al                          ; restore it

IsTsengExit:
        or      ah, ah                          ; ZR => Tseng, NZ => not
        jz      MustBeTseng
        mov     dx, cx                          ; could be ET3000
        add     dx, 0ah
        in      al, dx
        mov     dx, 3c0h
        call    TextDelay
        mov     al, 16h
        out     dx, al
        inc     dx
        call    TextDelay
        in      al, dx
        mov     bl, al                          ; old value in bl
        push    bx

        mov     dx, cx
        add     dx, 0ah
        in      al, dx
        mov     dx, 3c0h
        call    TextDelay
        mov     al, 16h
        out     dx, al
        mov     al, bl
        xor     al, 10h
        mov     bl, al
        out     dx, al
        call    TextDelay

        mov     dx, cx
        add     dx, 0ah
        in      al, dx
        mov     dx, 3c0h
        mov     al, 16h
        out     dx, al
        call    TextDelay
        inc     dx
        in      al, dx
        mov     bh, al                          ; new value in bh

        mov     dx, cx
        add     dx, 0ah
        in      al, dx
        mov     dx, 3c0h
        mov     al, 16h
        out     dx, al
        call    TextDelay
        pop     ax                              ; original value from bl
        out     dx, al

        cmp     bh, bl                          ; set zero flag properly
MustBeTseng:
        pushf                                   ; save flags

        mov     dx, WORD PTR SaveReg1           ;           
        mov     al, 13h                         ;            For those adapters
        out     dx, al                          ;            that wraps after
        call    TextDelay                       ;            1Fh, we have to
        inc     dx                              ;            save/restore the
        mov     al, BYTE PTR SaveIndex2         ;            appropriate data
        out     dx, al                          ;            register content

        mov     dx, cx                          ; Get port base address
        add     dx, 0ah                         ; 
        in      al, dx                          ; dummy read to set index
        mov     dx, 3c0h                        ; 
        mov     al, 20h                         ; 
        out     dx, al                          ; turn palette back on
        popf                                    ; restore flags

        mov     dx, WORD PTR SaveReg1           ;           
        mov     al, BYTE PTR SaveIndex1         ;           
        out     dx, al                          ;            restore the index.
        mov     sp, bp                          ;           
        pop     bp
        ret                                     ; 
IsTseng         ENDP

;***    IsVideo7
;
;       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
;

IsVideo7        PROC    Near
                PUBLIC  IsVideo7
        push    bp
        mov     bp,sp
        sub     sp,STACKBLOCK                   ;           

        mov     dx, 03c4h                       ; Save the register value
        in      al, dx                          ;           
        mov     WORD PTR SaveReg1, dx           ;           
        mov     BYTE PTR SaveIndex1, al         ;           
        mov     al, 06h                         ; for the non-Video7 chips
        out     dx, al
        inc     dl
        in      al, dx
        push    ax

        call    Video7EnableExt                 ; enable extended registers

        call    GetPortBase                     ; 
        add     dl, 4                           ; port 3x4
        mov     bx, dx                          ; save copy

        in      al, dx                          ;           
        mov     WORD PTR SaveReg2, dx           ;           
        mov     BYTE PTR SaveIndex2, al         ;           
        mov     al, 0ch                         ; 
        out     dx, al                          ; select Start Address High reg
        inc     dl                              ; 
        call    TextDelay
        in      al, dx                          ; 
        mov     bl, al                          ; save previous value

        mov     al, 055h                        ; 
        out     dx, al                          ; write in a new value
        call    TextDelay
        in      al, dx                          ; 

        dec     dl                              ; to 3x4
        mov     al, 01fh                        ; 
        out     dx, al                          ; select ID register
        inc     dl                              ; 
        call    TextDelay
        in      al, dx                          ; read ID register

        xchg    al, bl                          ; restore old value
        dec     dl                              ; 
        push    ax
        mov     al, 0ch                         ; select SAH register
        out     dx, al                          ; 
        inc     dl                              ; 
        call    TextDelay
        pop     ax
        out     dx, al                          ; write old value back
        or      cl, cl                          ; if its zero                 
        jnz     short @F                        ; they were locked              
        call    Video7DisableExt                ; disable extended registers
@@:     mov     al, 055h                        ; 
        xor     al, 0eah                        ; 
        sub     al, bl                          ; ZR => Video7, NZ => not
        pop     bx
        jz      @F

        mov     dx, 03c4h                       ; Restore if it is not Video7,
        mov     al, 06h                         ; which is mainly for protecting
        out     dx, al                          ; the registers of ET3000 from
        inc     dl                              ; corrupting.
        mov     al, bl
        out     dx, al

@@:
        mov     dx, WORD PTR SaveReg1           ;           
        mov     al, BYTE PTR SaveIndex1         ;           
        out     dx, al                          ;            restore the index.
        mov     dx, WORD PTR SaveReg2           ;           
        mov     al, BYTE PTR SaveIndex2         ;           
        out     dx, al                          ;            restore the index.
        mov     sp, bp                          ;           
        pop     bp
        ret
IsVideo7        ENDP

;***    IsTrident
;
;       Look for Trident chip set
;
;           check for presence of inverting bit field in
;           Mode Control register 1

IsTrident       PROC    Near
                PUBLIC  IsTrident
        push    bp
        mov     bp,sp
        sub     sp,STACKBLOCK                   ;           

        mov     dx, 03c4h                       ; Mode Control register
        in      al, dx
        mov     WORD PTR SaveReg1, dx
        mov     BYTE PTR SaveIndex1, al         ;           

        mov     al, 0eh                         ; 
        out     dx, al                          ; 
        inc     dl                              ; 
        call    TextDelay
        in      al, dx                          ; 
        mov     ah, al                          ; save old value
        call    TextDelay
        xor     al, al                          ; 
        out     dx, al                          ; write all zeros
        call    TextDelay
        in      al, dx                          ; read new value
        and     al, 0fh                         ; 
        call    TextDelay
        xchg    al, ah                          ; get old value back
        xor     al, 2                           ; flip bit
        out     dx, al                          ; restore it
        cmp     ah, 2                           ; ZR => Trident, NZ => not

        mov     dx, WORD PTR SaveReg1           ;           
        mov     al, BYTE PTR SaveIndex1         ;           
        out     dx, al                          ;            restore the index.
        mov     sp, bp                          ;           
        pop     bp
        ret
IsTrident       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 = 0 if found
;* RETURN-ERROR  = NONE
;*
;****************************************************************************/
IsCirrus        PROC    Near
                PUBLIC  IsCirrus
        push    bp
        mov     bp,sp
        sub     sp,STACKBLOCK                   ;           

        mov     dx, 03c4h                       ; 
        in      al, dx
        mov     WORD PTR SaveReg1, dx
        mov     BYTE PTR SaveIndex1, al
        mov     al, 06h                         ; sr6 register index
        mov     BYTE PTR SaveIndex2, al
        out     dx, al
        inc     dx
        in      al, dx
        mov     BYTE PTR SaveValue2, al
        mov     al, 12h
        out     dx, al                          ; unlock extensions

        mov     dx, 03c4h                       ; 
                                                ; save current cursor position
        mov     al, 10h                         ; 
        out     dx, al                          ; 
        call    TextDelay
        in      al, dx                          ; read value is first 3 bits, shifted by 5
        mov     BYTE PTR SaveIndex3, al         ;           
                                                ; read data
        inc     dx
        call    TextDelay
        in      al, dx                          ; read value is bits 3-10 of the current position
        mov     BYTE PTR SaveValue3, al         ;           

        mov     dx, 03c4h                       ; do the detection logic now
        mov     al, 50h                         ; set cursor to position 26. This value chosen in
        out     dx, al                          ; case we have a VGA: all seq indeces wrap to 0!
        mov     ax, 03h
        inc     dx
        call    TextDelay
        out     dx, al                          ; cursor set.
                                                ; write index 70.
        mov     dx, 03c4h                       ; 
        mov     al, 70h                         ; write the index only
        out     dx, al
        call    TextDelay
        in      al, dx                          ; read value should be 50h
        sub     al, 50h                         ; if 0 it is Cirrus, else not

        mov     dx, WORD PTR SaveReg1
        mov     al, BYTE PTR SaveIndex3
        mov     ah, BYTE PTR SaveValue3
        out     dx,ax                           ; word operation
        mov     al, BYTE PTR SaveIndex2
        mov     ah, BYTE PTR SaveValue2
        out     dx,ax                           ; word operation
        mov     al, BYTE PTR SaveIndex1
        out     dx,al                           ; 

        mov     sp, bp                          ;           
        pop     bp
        ret
IsCirrus     ENDP

;/****************************************************************************  ;          
;*
;* FUNCTION NAME = IsS3                                     
;*
;* DESCRIPTION   =
;*
;*
;*
;*
;*
;*
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = 0 if found
;* RETURN-ERROR  = NONE
;*
;****************************************************************************/
IsS3         PROC    Near                       ;           
                PUBLIC  IsS3
                push    bp
                mov     bp,sp
                sub     sp,STACKBLOCK           ;          

                mov     dx, 03d4h               ; 
                in      al, dx
                mov     WORD PTR SaveReg1, dx
                mov     BYTE PTR SaveIndex1, al

                mov     al, 38h                 ; sr6 register index
                mov     BYTE PTR SaveIndex2, al
                out     dx, al
                inc     dx
                in      al, dx
                mov     BYTE PTR SaveValue2, al
                mov     al, 48h
                out     dx, al                  ; unlock extensions

                mov     dx, 03d4h               ; 
                mov     al, 30h                 ; 
                out     dx, al                  ; 
                call    TextDelay
                inc     dx
                in      al, dx

                and     al, 0f0h                ;mask out lower nibble           
                cmp     al, 0a0h                ;805 family
                je      S3exit
;               cmp     al, 80h                 ;80 is 911/924           
;               je      S3exit
                cmp     al, 90h                 ;928 family
                je      S3exit
                cmp     al, 0b0h                ;928 PCI
S3exit:
                mov     dx, WORD PTR SaveReg1
                mov     al, BYTE PTR SaveIndex2
                mov     ah, BYTE PTR SaveValue2
                out     dx,ax                   ; word operation

                mov     al, BYTE PTR SaveIndex1
                out     dx,al                   ; 

                mov     sp, bp                  ; 
                pop     bp
                ret
IsS3         ENDP

;***    IsWesternDig
;
;       Look for string 'VGA=' at BIOS location C000:007D
;       Physical address = C007D or E007D
;

IsWesternDig    PROC    Near
                PUBLIC  IsWesternDig
        mov     ax, 0ch
SearchWDBios:
        mov     di, OFFSET BioData:WDSig
        mov     bx, 07dh
        mov     cx, 4
        push    ax                              ; remember which address.
        call    FindString
        pop     dx
        or      ax, ax
        jz      ExitWD                          ; found it, exit
        cmp     dx, 0eh
        je      short NotWD                     ; already tried planar address
        mov     ax, 0eh
        jmp     SearchWDBios                    ; search planar BIOS.
NotWD:  mov     ax, 1
        or      ax, ax                          ; set to NZ for failure
ExitWD:
                ret
IsWesternDig    ENDP

;***    IsATI
;
;       Look for an ATI Wonder.
;
;           Check for product signature string at C000:30
;           which should read ' 761295520'
;
;       Assume DS -> DGROUP on entry
;

IsATI           PROC    Near
                PUBLIC  IsATI
        mov     di, OFFSET BioData:ATISig
        mov     ax, 0ch
        mov     bx, 030h
        mov     cx, 10
        call    FindString
        or      ax, ax
        ret
IsATI           ENDP

;***    IsSpeedWay
;
;       Look for IBM 'SVGA'
;

IsSpeedWay      PROC    Near
                PUBLIC  IsSpeedWay
        mov     dx, 2170h                       ; start from 8th instance OpMode Reg.
SWayNext:
        in      al, dx                          ; get the OpMode setting
        cmp     al, 0f0h                        ; valid value?
        jae     SWayNextPort                    ; 

        push    dx                              ;           
        and     dx, 0fffh                       ;           
        mov     ah, al                          ;           
        in      al, dx                          ;           
        cmp     al, ah                          ;           
        pop     dx                              ;           
        jz      SWayNextPort                    ;           

        xor     al, al                          ; indicate found
        mov     XGAInstance, dx                 ; remember XGA instance
        jmp     short @F                        ; indicate found
SWayNextPort:
        sub     dx, 10h                         ; next configuration
        cmp     dx, 2100h                       ; 
        jae     SWayNext                        ; still more ports to check
;           mov     XGAInstance, dx             ; remember XGA instance   ;          
@@:
        or      al, al                          ; ZR => found, NZ => not
        jnz     @F                              ;              
        or      dx, 09h                         ; Setup Memory Access             
        in      al, dx                          ; Get current pixel size
        push    ax                              ;            current content
        or      al, 07h                         ; bits 2 is invalid for Speedway
        out     dx, al                          ; write this one            
        in      al, dx                          ; get contents             
        in      al, dx                          ; use it as I/O Delay
        test    al, 04h                         ; ZR => Speedway present
        pop     ax                              ;            restore content
        out     dx, al                          ; Restore Memory Access
        jz      @F                              ; Speedway found, leave XGAInstance untouched.           
        mov     XGAInstance, 0                  ; nz: XGA found, indicated by XGAInstance=0              
@@:     ret                                     ;           
IsSpeedWay      ENDP

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

;***    WhichTseng
;
;       Determine which Tseng chip we're using ET3000/ET4000
;
;           Distinguish the two by availability of Extended Start Address
;           Register (CRTC index 33h) which only exists on ET4000.
;
;       ENTRY:
;
;       EXIT:
;
;       USES:   AX, BX, DX
;

WhichTseng      PROC    Near
                PUBLIC  WhichTseng
        mov     dx, 03bfh                       ; Unlock extended regs
        mov     al, 3                           ; 
        out     dx, al                          ; 
        mov     dx, 03d8h                       ; 
        mov     al, 0a0h                        ; 
        out     dx, al                          ; 
        call    GetPortBase                     ; 
        mov     bx, dx                          ; keep copy
        add     dl, 4                           ; Extended Start Address (3d4)
        mov     al, 37h                         ; Video System Config 2
        out     dx, al                          ; 
        inc     dl                              ; 
        in      al, dx                          ; Get value
        test    al, 80h                         ; Test VRAM=1/DRAM=0 bit 7
        jnz     @F                              ; can't determine memory easily
        test    al, 1                           ; 
        jnz     @F                              ; bit 0 set => 1Meg
        shr     word ptr SVGAInfo.Memory[2], 1  ; adjust mem to 512k
@@:     dec     dl                              ; 
        mov     al, 33h                         ; 
        out     dx, al                          ; CRTC reg index 33h
        inc     dl                              ; 
        in      al, dx                          ; 
        mov     bl, al                          ; save previous value
        xor     al, 0fh                         ; 
        out     dx, al                          ; write to 3x5
        call    TextDelay
        mov     ah, al                          ; save copy of byte written
        in      al, dx                          ; read it back
        sub     ah, al                          ; 
        mov     al, bl                          ; restore previous value
        out     dx, al                          ; write back to 3x5
        or      ah, ah                          ; ZR => ET4000, NZ => ET3000
        mov     ax, 1                           ; assume ET3000
        jnz     WT3000                          ; 
        inc     ax                              ; 
        jmp     short WTExit                    ; Is an ET4000
WT3000:
        pushf                                   ; 
        push    ax                              ; 
        mov     al, 6                           ; set up index port to zoom reg
        mov     dx, 03c4h                       ; 
        out     dx, al                          ; 
        call    TextDelay
        inc     dx                              ; 
        in      al, dx                          ; get data value
        and     al, 01111111B                   ; 
        out     dx, al                          ; turn off zoom enable bit
        pop     ax                              ; 
        popf                                    ; 

WTExit: push    ax                              ; 
        mov     dx, 03bfh                       ; Lock extended regs
        mov     al, 1                           ; 
        out     dx, al                          ; 
        mov     dl, 0d8h                        ; 
        mov     al, 029h                        ; 
        out     dx, al                          ; 
        pop     ax                              ; 
        ret
WhichTseng      ENDP

;***    WhichVideo7
;
;    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
;

WhichVideo7     PROC    Near
                PUBLIC  WhichVideo7
        mov     dx, 03c4h                       ;           
        mov     al, 6                           ;           
        out     dx, al                          ;           
        inc     dl                              ;           
        in      al, dx                          ;           
        mov     cl, al                          ;           

        call    Video7EnableExt                 ; enable extended registers
        mov     al, 08eh                        ; 
        mov     dx, 03c4h                       ; 
        out     dx, al                          ; 
        call    TextDelay
        inc     dl                              ; 
        in      al, dx                          ; 
        shr     al, 4                           ; has value 04h to 0fh
        mov     bl, al                          ; 
        or      cl, cl                          ;           
        jnz     short @F                        ;           
        call    Video7DisableExt                ; disable extended registers
@@:     mov     ax, 1                           ; 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                     ; 
        xor     ax, ax                          ; AX = 0 (don't know)
WhichV7Exit:
        mov     dx, 2                           ; 
        mov     cl, al                          ; 
        shl     dx, cl                          ; 
        mov     word ptr SVGAInfo.Memory[2], dx
        ret
WhichVideo7     ENDP

;***    WhichTrident
;
;               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
;

WhichTrident    PROC    Near
                PUBLIC  WhichTrident
        mov     dx, 03c4h                       ; 
        mov     ax, 0bh                         ; write 0 to version reg (0bh)
        out     dx, ax
        inc     dl
        call    TextDelay
        in      al, dx
        mov     dl, al
        mov     ax, 1                           ; assume 8800
        cmp     dl, 3
        jl      @F
        inc     ax                              ; make it 8900

        push    ax
        call    GetPortBase
        mov     al, 01fh                        ; Set up to read the
        add     dx, 04h                         ;'software programming'
        out     dx, al                          ; register. This has
        inc     dl                              ; two bits with amount
        in      al, dx                          ; of video memory.
        and     ax, 3                           ; Isolate memory size.
        mov     cl, al                          ; CL = no of 256k blocks - 1
        mov     al, 010B                        ; AX = 256k
        shl     ax, cl
        mov     word ptr SVGAInfo.Memory[2], ax
        pop     ax

@@:     ret
WhichTrident    ENDP

;***    WhichWesternDig
;

WhichWesternDig PROC    Near
                PUBLIC  WhichWesternDig
        push    bp
        mov     bp,sp
        sub     sp,STACKBLOCK                   ;           

        mov     bx, 1                           ; BX has value to return

        mov     al, 1eh                         ; 
        mov     dx, 3c3h                        ; 
        out     dx, al                          ; Enter setup mode

        mov     al, 80h                         ; 
        mov     dx, 0103h                       ; 
        out     dx, al                          ; Enable extended registers

        mov     al, 0eh                         ; 
        mov     dx, 3c3h                        ; 
        out     dx, al                          ; Exit setup mode

        call    GetPortBase                     ; 
        add     dx, 4h                          ; 
        mov     al, 2bh                         ; 
        mov     WORD PTR SaveReg1, dx
        mov     BYTE PTR SaveIndex1, al
        out     dx, al                          ; 
        inc     dl                              ; 
        in      al, dx                          ; 
        mov     BYTE PTR SaveValue1, al         ; 
        mov     ah, al                          ; save current contents
        mov     al, 0aah                        ; write new value
        out     dx, al                          ; 
        call    TextDelay
        in      al, dx                          ; 
        cmp     al, 0aah                        ; if value read != 0AAH
        jne     WhichWDExit1                    ; its PVGA1A

        xchg    al, ah                          ; save return, get old value
        call    TextDelay
        out     dx, al                          ; 
        inc     bx                              ; Assume WD90c00

        mov     dx, 03c4h                       ; Unlock
        mov     WORD PTR SaveReg2, dx
        in      al, dx
        mov     BYTE PTR SaveIndex2, al
        mov     ax, 4806h                       ; extended
        out     dx, ax                          ; sequencers
                                                ; Distinguish between
        mov     al, 12h                         ; WD90c00 and WD90c10
        out     dx, al                          ; by using bit 6 of
        call    TextDelay                       ; Misc Control Reg
        inc     dl                              ; If chip doesn't respond to
        in      al, dx                          ; changes in the bit, its a
        call    TextDelay                       ; WD90c00
        mov     ah, al                          ; 
        and     al, NOT 01000000B               ; 
        out     dx, al                          ; Replace with bit 6 set to 0
        call    TextDelay
        in      al, dx                          ; read back value set
        xchg    al, ah                          ; 
        out     dx, al                          ; Replace original value
        xchg    ah, al                          ; 
        test    al, 01000000B                   ; if bit IS NOT zero,
        jnz     WhichWDExit2                    ; its a 90c00
        or      al, 01000000B                   ; 
        out     dx, al                          ; Replace with bit 6 set to 1
        call    TextDelay
        in      al, dx                          ; read back value set
        xchg    al, ah                          ; 
        out     dx, al                          ; Replace original value
        xchg    ah, al                          ; 
        test    al, 01000000B                   ; if bit IS zero,
        jz      WhichWDExit2                    ; its a 90c00

        inc     bx                              ; Assume WD90c11

        mov     dx, 03c4h                       ; Look for scratch pad reg
        mov     al, 08h
        mov     BYTE PTR SaveIndex3, al
        out     dx, al
        inc     dx
        in      al, dx
        mov     BYTE PTR SaveValue3, al
        mov     al, 0aaH                        ; at index 08h, found on
        out     dx, al                          ; 90c30, not 90c11
        call    TextDelay
        in      al, dx                          ; 
        cmp     al, 0aah                        ; 
        jnz     WhichWDExit3                    ; Its probably a 90c11

        inc     bx                              ; Call it a WD90c30

WhichWDExit3:
        mov     dx, WORD PTR SaveReg2
        mov     al, BYTE PTR SaveIndex3
        mov     ah, BYTE PTR SaveValue3
        out     dx, ax
WhichWDExit2:
        mov     dx, WORD PTR SaveReg2
        mov     al, BYTE PTR SaveIndex2
        out     dx, al
WhichWDExit1:
        mov     dx, WORD PTR SaveReg1
        mov     al, BYTE PTR SaveIndex1
        mov     ah, BYTE PTR SaveValue1
        out     dx, ax

        xor     ah, ah                          ; 
        mov     dx, 03ceh                       ; Determine on-board memory
        mov     al, 0bh                         ; Memory size
        out     dx, al                          ; 
        inc     dl                              ; 
        call    TextDelay
        in      al, dx                          ; top 2 bits have memory size
        shr     al, 6                           ;           
        mov     cl, al                          ; 
        or      cl, cl                          ; zero means 256k
        jz      @F                              ; 
        dec     cl                              ; make count zero-based
@@:     mov     ax, 0100B                       ; 
        shl     ax, cl                          ; 
        mov     word ptr SVGAInfo.Memory[2], ax

        push    bx                              ; Save return code

        mov     al, 1eh                         ; 
        mov     dx, 3c3h                        ; 
        out     dx, al                          ; Enter setup mode

        mov     al, 0                           ; 
        mov     dx, 0103h                       ; 
        out     dx, al                          ; Disable extended registers

        mov     al, 0eh                         ; 
        mov     dx, 3c3h                        ; 
        out     dx, al                          ; Exit setup mode

        pop     ax                              ; 

        mov     sp, bp                          ;           
        pop     bp
        ret

WhichWesternDig ENDP

;***    WhichATI
;
;       Returns: AX = 1  -  Cards below Version 3
;                AX = 2  -  Version 3 and above
;

WhichATI        PROC    Near
                PUBLIC  WhichATI
        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'                         ; 

        ASSUME  DS:BioData

        pop     ds                              ; 
        call    SVGAUnPhysToVirt                ; 

        mov     dx, 01ceh                       ; ATI Extended regs
        push    ax                              ; 
        cmp     ax, 2                           ; 
;                  ja      ATIV3                           ; Version 3 card or higher
;                  mov     ax, 0bbh                        ;
;                  out     dx, al                          ;
;                  inc     dx                              ;
;                  in      al, dx                          ;
;                  mov     dx, 4                           ; assume 256k
;                  test    al, 20h                         ;
;                  jz      ATIMem                          ;
;                  shl     dx, 1                           ;
;                  jmp     short ATIMem                    ;

ATIV3:  mov     ax, 0b0h                        ; 
        out     dx, al                          ; 
        inc     dx                              ; 
        in      al, dx                          ; 
        mov     dx, 4                           ; assume 256k
;                  test    al, 18h                         ;
;                  jz      ATIMem                          ;
        shl     dx, 1                           ; make it 512k
        test    al, 10h                         ; 
        jnz     ATIMem                          ; 
        shl     dx, 1                           ; make it 1M

ATIMem: mov     word ptr SVGAInfo.Memory[2], dx
        pop     ax                              ; 
        cmp     ax, 5                           ; 
        jae     @F                              ; 
        mov     ax, 1                           ; ATI18800 chip
        jmp     short ATIExit                   ; 
@@:     mov     ax, 2                           ; ATI28800 chip
ATIExit:
        ret
WhichATI        ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = WhichCirrus
;*
;* DESCRIPTION   =  Cirrus chips: GD5422, GD5424, GD5426, GD5428
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = 0 - any other Cirrus chip, not supported by SVGA
;*                 1 - GD5422 chip
;*                 2 - GD5424 chip
;*                 3 - GD5426 chip
;*                 4 - GD5428 chip                                          
;*
;* RETURN-ERROR  = NONE
;*
;****************************************************************************/
;          
WhichCirrus     PROC    Near
                PUBLIC  WhichCirrus
        mov     dx, 03c4h                       ; 
        mov     ax, 1206h                       ; sr6 register index
        out     dx, ax                          ; unlock extensions
        inc     dx
        call    TextDelay
        in      al, dx
        mov     ah, 0                           ; set return to 0
        cmp     al, 12h
        jne     cirrus_exit                     ; Unable to unlock, assume GD5401
        call    GetPortBase                     ; 
        add     dx, 04h
        mov     al, 27h                         ; Chip ID register index
        out     dx, al
        inc     dx
        call    TextDelay
        in      al, dx
        mov     ah, 0                           ; asuume one of the older ones
        cmp     al, 8ah                         ; GD5420
        je      cirrus_exit
        shr     al, 1
        shr     al, 1
        mov     ah, 1
        cmp     al, 23h                         ; GD5422
        je      cirrus_exit
        mov     ah, 2
        cmp     al, 25h                         ; GD5424
        je      cirrus_exit
        mov     ah, 3
        cmp     al, 24h                         ; GD5426
        je      cirrus_exit
        mov     ah, 4                           ;                              ;          
        cmp     al, 26h                         ; GD5428                     
        je      cirrus_exit                     ;                            
        mov     ah, 0

cirrus_exit:
        mov     al, ah
        sub     ah, ah
        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
;*
;****************************************************************************/
WhichS3            PROC    Near                 ;           
                PUBLIC  WhichS3
                mov     dx, 03d4h
                mov     ax, 4838h               ;unlock r38
                out     dx, ax

                mov     ax, 0a039h              ;unlock r39
                out     dx, ax

                mov     al, 36h                 ; Configuration Reg 1
                out     dx, al
                inc     dx
                call    TextDelay
                in      al, dx
                and     al, 0e0h

                cmp     al, 0c0h                ;1 Meg ?
                jne     @F
                jmp     short determine_S3
@@:
                cmp     al, 0e0h                ;512K ?
                jne     @F
                shr     word ptr SVGAInfo.Memory[2], 1  ;adjust mem to 512k
@@:
                cmp     al, 80h                 ;2 Meg ?
                jne     @F
                shl     word ptr SVGAInfo.Memory[2], 1  ;adjust mem to 2 Meg
                jmp     short determine_S3
@@:
                cmp     al, 40h                 ;3 Meg ?
                jne     @F
                mov     dx, word ptr SVGAInfo.Memory[2] ;adjust mem to 3 Meg
                shl     word ptr SVGAInfo.Memory[2], 1
                or      word ptr SVGAInfo.Memory[2], dx
                jmp     short determine_S3
@@:
                cmp     al, 0                   ;4 Meg ?
                jne     @F
                shl     word ptr SVGAInfo.Memory[2], 2  ;adjust mem to 4 Meg
@@:

determine_S3:
                mov     dx, 03d4h
                mov     al, 30h                 ; Chip ID/Rev
                out     dx, al
                inc     dx
                call    TextDelay
                in      al, dx

                and     al, 0f0h                ;mask out lower nibble           
                cmp     al, 0a0h
                jne     @F
                mov     al, S3_86C805_CHIP
                jmp     short S3found
@@:
                cmp     al, 090h
                jne     @F
                mov     al, S3_86C928_CHIP
                jmp     short S3found
@@:
                cmp     al, 0b0h                ;928 PCI
                jne     @F
                mov     al, S3_86C928_CHIP
                jmp     short S3found
@@:
                xor     al, al

S3found:
                sub     ah, ah
                ret

WhichS3            ENDP
;*****************************************************************************

;**     INIT - Device Driver Initialization routine
;
;       ENTRY
;               ES:BX = Request Packet
;               DS    = ?
;       EXIT
;               Terminating Code Address Set
;               Terminating Data Address Set
;               BIOS palette save area initialized ;@@2
;               Status = OK
;               DevHelp Address Saved
;

PUBLIC  Init
Init    PROC    NEAR

; Save DevHelp Function Router Address

        mov     ax,word ptr ES:[bx.InitpEnd]
        mov     word ptr DevHelp,ax
        mov     ax,word ptr ES:[bx.InitpEnd+2]
        mov     word ptr DevHelp+2,ax

        ; 
        ; Attach to OEMHLP to determine adapter type
        ; 
        call    AttachOEM                       ;           
        ; 
        ; Determine Super VGA adapter type
        ; 
        call    IdentifySVGA                    ;           

        push    es
        ; 
        ; Register with VDM manager for communication with VVID.
        ; 
        mov     ax, SEG ScreenDDName
        mov     ds, ax
        ASSUME  DS:BioData
        lea     si, ScreenDDName
        mov     di, cs
        mov     es, di                          ; DS:SI = Pointer to name of PDD
        lea     di, VVID_IDC                    ; ES:DI = Pointer to IDC
        mov     dl,DevHlp_RegisterPDD
        call    DevHelp                         ; if the function fails, system halp occures.
        pop     es
        mov     word ptr es:[bx.InitpEnd],offset DEVICE_END-1 ;@@4
        mov     word ptr es:[bx.InitpEnd+2],offset DATA_END-1 ;@@4

        call    MemoryInit                                              ;J-TS920924

IFDEF  FAMILY2
        mov     al,3                            ; Video Device Id ???
        mov     bl,0                            ; First available LID
        mov     dh,0                            ; Device State = 0 (Reserved)
        mov     dl,DevHlp_GetLIDEntry
        Call    DevHelp
        sti
        .if     nc
            mov     LID,ax                      ; Save the LID number
        .endif
ENDIF
        sub     ax,ax                           ; DCR0226
        ret
Init    ENDP

BiosSeg ends
        end
;           12/28/92 Senja SVGA support. File created.
;           01/20/93 Senja Enhanced WD detection.
;           01/21/93 Senja XGA doesn't boot because Aperture Index gets trashed.
;           02/10/93 Senja Manufacturer info IOCTL.
;           02/18/93 Senja UpdateMemoryInfo IOCTL.
;           03/05/93 Senja Do not identify XGA as Speedway.
;           03/10/93 Senja Identification of MC Orchid.
;           03/12/93 Senja Changed BANK packet interface to be more consistent.
;           03/16/93 Senja Making SCREENDD more consistent.
;           03/23/93 Senja Fixing bank packet validation.
;           04/03/93 Senja Attach to OEMHLP.
;           04/14/92 Senja If XGA detected, do not proceed with the detection.
;           05/02/93       Improve Speedway checks, defect 68723.
;           06/03/93       Lock the extended sequencer before exit, defect 69461
;           06/03/93       ACER M3125 SVGA fix, defect 63910
;           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
;           08/06/93 Muta  Some chips was miss-identifyed on retail OS2KRNL.
;           08/19/93 Muta  We support only mach-8 or upper chips for ATI.
;           08/24/93 Saito S3
;           12/15/93  76685 Recognize Winsprint adapter by Artist Graphics
