;*DDK*************************************************************************/
;
; 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.;
;*****************************************************************************/
        PAGE    ,132
        TITLE   Virtual Video SVGA I/O Processing

;/*****************************************************************************
;*
;* SOURCE FILE NAME = VVSVGAIO.ASM
;*
;* DESCRIPTIVE NAME = Virtual Video Device Driver CRT I/O Processing
;*
;*
;* VERSION      V2.0
;*
;* DATE         02/08/92
;*
;* DESCRIPTION  This module contains the VVD's SVGA I/O handlers.
;*
;* FUNCTIONS    VVWriteTsengUnlock1Fgnd()       Write Tseng Unlock register
;*              VVWriteTsengUnlock1Bgnd()       Write Tseng Unlock register
;*              VVWriteTsengUnlock2Fgnd()       Write Tseng Unlock register
;*              VVWriteTsengUnlock2Bgnd()       Write Tseng Unlock register
;*              VVReadTsengSegSelectFgnd()      Read Tseng Seg Select
;*              VVReadTsengSegSelectBgnd()      Read Tseng Seg Select
;*              VVWriteTsengSegSelectFgnd()     Write Tseng Segment Select register
;*              VVWriteTsengSegSelectBgnd()     Write Tseng Bank Select register
;*              VVGetTridentRegDef              Return the current definition of the extended sequencer
;*              VVWriteVVReservedFgnd()         Write ???
;*              VVWriteVVReservedBgnd()         Write Tseng Unlock register
;*              VVReadVVReservedFgnd()          Read Tseng Seg Select
;*              VVReadVVReservedBgnd()          Read Tseng Seg Select
;*              VVWriteIBMApertureCtrlFgnd()    Write XGA-compatible Aperture register
;*              VVWriteIBMApertureCtrlBgnd()    Write register
;*              VVReadIBMApertureCtrlBgnd()     Read register
;*              VVWriteIBMRegistersBgnd()       Write register
;*              VVReadIBMRegistersBgnd()        Read register
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   07/06/92                     253000  - Disallowed SVGA.EXE exec in
;*                                windowed VDM
;*   07/07/92                     Added SPEEDWAY support
;*   10/15/92                     Background virtualisation.
;*   11/11/92                     Add Orchid Clock select register
;*   12/04/92                     Move reg shadowing before vvMapBank call - can
;*                                return when VDM is foreground if freeze occurs.
;*   02/08/93                     Diamond SpeedStar modifications.
;*   02/08/93                     Fix table index for 640x480 modes.
;*   03/17/93                     OEMINFO structure changed.
;*   06/04/93             F69306  Add external clock support for Diamond Stealth 24
;*   06/17/93              70710  Hi-color support for S3
;*   07/26/93                     Add Diamond clock support for 1280
;*   10/06/93              72687  Add Number Nine clock support for S3
;*   10/20/93              74941  Avoid infinite loop in Diamond's clock stuff
;*   10/21/93              74890  Use hi-color entries in ext clock tbl for 24bpp
;*   10/22/93              75044  Remove YEE05 fix
;*   11/02/93              75458  S3 Merge
;*   02/02/94              77051  Fix WD90C30 flickering
;*   02/17/94             D78589  72Hz Refresh Rate for Diamond: Clock Index
;*
;*****************************************************************************/


        .xlist
        include mvdm.inc
        include vddseg.inc
        .list
        include vvd.inc
        include vvdp.inc


        DefData     IMPORT,SWAP,C
        ULONG       TKSSBase            ;required for SSToDS macro
       IFDEF SVGA                                       ;          
        PULONG      sOEMData                            ;          
        ULONG       ulSVGAAdapterType                   ;          
       ENDIF                                            ;          
        EndData


        DefCode     IMPORT,SWAP,PASCAL
        DefFn       vvFreezeVDM
        DefFn       vvAddEvent
        DefFn       vvUpdateScreenState
        DefFn       vvUpdateAll                                         ;          
        DefFn       VVEnableBuffer                                      ;          
       IFDEF SVGA                                                       ;          
        DefFn       vvMapBank                                           ;          
       ENDIF                                                            ;          
        EndCode


        DefCode     EXPORT,SWAP,PASCAL

       IFDEF SVGA                               ;SVGA
        DefFn       VVWriteTsengUnlock1Fgnd     ;SVGA
        DefFn       VVWriteTsengUnlock1Bgnd     ;SVGA
        DefFn       VVWriteTsengUnlock2Fgnd     ;SVGA
        DefFn       VVWriteTsengUnlock2Bgnd     ;SVGA
        DefFn       VVWriteTsengSegSelectFgnd   ;SVGA
        DefFn       VVWriteTsengSegSelectBgnd   ;SVGA
        DefFn       VVReadTsengSegSelectBgnd    ;SVGA
        DefFn       VVGetTridentRegDef          ;SVGA

        DefFn       VVWriteVVReservedFgnd       ;SVGA                   ;          
        DefFn       VVWriteVVReservedBgnd       ;SVGA                   ;          
        DefFn       VVReadVVReservedFgnd        ;SVGA                   ;          
        DefFn       VVReadVVReservedBgnd        ;SVGA                   ;          
        DefFn       VVWriteIBMApertureCtrlFgnd  ;SVGA                   ;          
        DefFn       VVReadIBMApertureCtrlBgnd   ;SVGA                   ;          
        DefFn       VVWriteIBMApertureCtrlBgnd  ;SVGA                   ;          
        DefFn       VVReadIBMRegistersBgnd      ;SVGA                   ;          
        DefFn       VVWriteIBMRegistersBgnd     ;SVGA                   ;          

        DefFn       VVReadOrchidClockSelectFgnd ;SVGA                   ;          
        DefFn       VVReadOrchidClockSelectBgnd ;SVGA                   ;          
        DefFn       VVWriteOrchidClockSelectFgnd;SVGA                   ;          
        DefFn       VVWriteOrchidClockSelectBgnd;SVGA                   ;          

        DefFn       SETDIAMONDCLK               ;          
        DefFn       Prog_Clock                  ;          
        DefFn       Send_Serial                 ;          
        DefFn       GetCRTCAddr                 ;          
        DefFn       GetDACTypeRtn               ;          
        DefFn       SetDACCMDReg                ;          
        DefFn       WaitVertRetrace             ;          

        PUBLIC      SETNUMBER9CLK               ;          
        PUBLIC      Set_Frequency
        PUBLIC      New_Refresh_Selected

       ENDIF                                    ;SVGA


;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteTsengUnlock1Fgnd()
;*
;* DESCRIPTION   = Write Tseng Unlock register
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM writes a word to the Tseng unlock register (0x3bf).
;*                 (see VDHInstallIOHook for complete semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (0x3bf)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVWriteTsengUnlock1Fgnd
        OUTB    dx,al                       ;output data
        FallInto VVWriteTsengUnlock1Bgnd
EndProc   VVWriteTsengUnlock1Fgnd


;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteTsengUnlock1Bgnd()
;*
;* DESCRIPTION   = Write Tseng Unlock register
;*
;*                 This registered subroutine is called whenever a background
;*                 VDM writes a word to the Tseng unlock register (0x3bf).
;*                 (see VDHInstallIOHook for complete semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (0x3bf)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVWriteTsengUnlock1Bgnd
        FallFrom VVWriteTsengUnlock1Fgnd
;       mov     VDMData.regTsengUnlock1,al      ;stash Tseng Unlock1 register
        ExitProc
EndProc   VVWriteTsengUnlock1Bgnd


;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteTsengUnlock2Fgnd()
;*
;* DESCRIPTION   = Write Tseng Unlock register
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM writes a word to the Tseng unlock register (0x3d8).
;*                 (see VDHInstallIOHook for complete semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (0x3d8)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/


Procedure VVWriteTsengUnlock2Fgnd
        OUTB    dx,al                       ;output data
        FallInto VVWriteTsengUnlock2Bgnd
EndProc   VVWriteTsengUnlock2Fgnd


;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteTsengUnlock2Bgnd()
;*
;* DESCRIPTION   = Write Tseng Unlock register
;*
;*                 This registered subroutine is called whenever a background
;*                 VDM writes a word to the Tseng unlock register (0x3d8).
;*                 (see VDHInstallIOHook for complete semantics).
;*
;* INPUT         =  AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (0x3d8)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVWriteTsengUnlock2Bgnd
        FallFrom VVWriteTsengUnlock2Fgnd
;       mov     VDMData.regTsengUnlock2,al      ;stash Tseng Unlock2 register
        ExitProc
EndProc   VVWriteTsengUnlock2Bgnd


       IFNDEF VGA

;/***************************************************************************
;*
;* FUNCTION NAME = VVReadTsengSegSelectFgnd()
;*
;* DESCRIPTION   = Read Tseng Seg Select
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM reads a byte from the Tseng Seg Select register (see
;*                 VDHInstallIOHook for complete semantics).
;*
;* INPUT         = EBX -> VDM register frame
;*                 EDX == port number (PORT_MONOCRTINDX or PORT_COLRCRTINDX)
;*
;* OUTPUT        = AL  == data read
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;* PSEUDO-CODE
;*                 case VGA:
;*                   none
;*                 case OTHER:
;*                   return CRT index value
;*
;**************************************************************************/

Procedure VVReadTsengSegSelectFgnd
        FallInto VVReadTsengSegSelectBgnd
EndProc   VVReadTsengSegSelectFgnd

       ENDIF ;VGA


;/***************************************************************************
;*
;* FUNCTION NAME = VVReadTsengSegSelectBgnd()
;*
;* DESCRIPTION   = Read Tseng Seg Select
;*
;*                 This registered subroutine is called whenever a background
;*                 VDM reads a byte from the Tseng Seg Select register (see
;*                 VDHInstallIOHook for complete semantics).
;*
;* INPUT         = EBX -> VDM register frame
;*                 EDX == port number (PORT_MONOCRTINDX or PORT_COLRCRTINDX)
;*
;* OUTPUT        = AL  == data read
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVReadTsengSegSelectBgnd
        mov     al,VDMData.regTsengSegSelect  ;return Tseng Seg Select
        ExitProc
EndProc   VVReadTsengSegSelectBgnd


;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteTsengSegSelectFgnd()
;*
;* DESCRIPTION   = Write Tseng Segment Select register
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM writes a word to the Tseng seg select register (0x3cd).
;*                 (see VDHInstallIOHook for complete semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (0x3d8)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVWriteTsengSegSelectFgnd
        OUTB    dx,al                       ;output data
        FallInto VVWriteTsengSegSelectBgnd
EndProc   VVWriteTsengSegSelectFgnd


;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteTsengSegSelectBgnd()
;*
;* DESCRIPTION   = Write Tseng Bank Select register
;*
;*                 This registered subroutine is called whenever a background
;*                 VDM writes a word to the Tseng seg select register (0x3cd). (see
;*                 VDHInstallIOHook for complete semantics).
;*
;*            SVGA: Added code to remap the current A000 aperture to the
;*                  appropriate portion of the shadow buffer. Also mark the
;*                  previous bank as dirty to enable a dirty buffer event to
;*                  be generated.
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (0x3d8)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVWriteTsengSegSelectBgnd
        FallFrom VVWriteTsengSegSelectFgnd

        mov     cl,VDMData.regTsengSegSelect            ;          
        mov     VDMData.regTsengSegSelect,al            ;          
        cmp     VDMData.regTsengSegSelect,cl            ;          
        je      @F                                      ;          
        test    VDMData.flVDMVideo,VDM_FGND             ;          
        jnz     @F                                      ;          
        cmp     VDMData.mstateVideo,MEMORY_GRFX256      ;          
        jne     @F                                      ;          
        push    eax                                     ;          
        and     eax,0fh                                 ;          
        push    eax                                     ;          
        mov     al,cl                                   ;          
        and     eax,0fh                                 ;          
        mov     VDMData.ulDirtyBankEvent,eax            ;          
        call    vvMapBank                               ;          
        pop     eax                                     ;          
@@:
        ExitProc
EndProc   VVWriteTsengSegSelectBgnd


;/***************************************************************************
;*
;* FUNCTION NAME = VVGetTridentRegDef
;*
;* DESCRIPTION   = Return the current definition of the extended sequencer
;*                 registers.
;*
;* INPUT         = None
;*
;* OUTPUT        = EAX = TRUE  - registers are in 'new' mode
;*                     = FALSE - registers are in 'old' mode
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVGetTridentRegDef

                mov     dx, PORT_SEQINDX
                cli
                in      al, dx
                mov     ah, al          ;save index
                mov     al, 0eh         ; 
                out     dx, al          ;select Mode Control Reg 1
                inc     dx              ; 
                in      al, dx          ;get current contents
                mov     cl, al          ; 
                out     dx, al          ;write out again
                in      al, dx          ;get contents
                out     dx, al          ;guarantee the same
                xor     ch, ch          ; 
                cmp     al, cl          ;reverse page bit ?
                jne     GetDefNew       ; 
                dec     dx              ; 
                mov     al, 0bh         ;read version => set 64K mode
                out     dx, al          ; 
                inc     dx              ; 
                in      al, dx          ; 
                jmp     short GetDefDone
GetDefNew:
                inc     ch              ; 
GetDefDone:
                dec     dx              ; 
                mov     al, ah          ; 
                out     dx, al          ; 

                mov     dl, 0cch        ; 
                in      al, dx          ; 

                mov     ah, al          ; 
                mov     dl, 0c2h        ; 
                or      al, 20h         ;select low page memory
                out     dx, al          ;set Misc Output

                sti                     ; 
                movzx   eax, ch         ; 

                ExitProc

EndProc   VVGetTridentRegDef


;/*
;**  added for ptr           
;*/


;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteVVReservedFgnd()
;*
;* DESCRIPTION   = Write ???
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM writes a word to the Tseng unlock register (0x3d6).
;*                 (see VDHInstallIOHook for complete semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (0x3d6)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVWriteVVReservedFgnd
        OUTB    dx,al                       ;output data
        FallInto VVWriteVVReservedBgnd
EndProc   VVWriteVVReservedFgnd


;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteVVReservedBgnd()
;*
;* DESCRIPTION   = Write Tseng Unlock register
;*
;*                 This registered subroutine is called whenever a background
;*                 VDM writes a word to the Tseng unlock register (0x3d6).
;*                 (see VDHInstallIOHook for complete semantics).
;*
;* INPUT         =  AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (0x3d6)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVWriteVVReservedBgnd
        FallFrom VVWriteVVReservedFgnd
        ExitProc
EndProc   VVWriteVVReservedBgnd


;/***************************************************************************
;*
;* FUNCTION NAME = VVReadVVReservedFgnd()
;*
;* DESCRIPTION   = Read Tseng Seg Select
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM reads a byte from the Tseng Seg Select register (see
;*                 VDHInstallIOHook for complete semantics).
;*
;* INPUT         = EBX -> VDM register frame
;*                 EDX == port number (PORT_MONOCRTINDX or PORT_COLRCRTINDX)
;*
;* OUTPUT        = AL  == data read
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVReadVVReservedFgnd
;       FallInto VVReadVVReservedBgnd
        mov     al,1                          ;return TRUE (fgnd)
;       mov     al,byte ptr VDMData.flVDMVideo
        ExitProc
EndProc   VVReadVVReservedFgnd


;/***************************************************************************
;*
;* FUNCTION NAME = VVReadVVReservedBgnd()
;*
;* DESCRIPTION   = Read Tseng Seg Select
;*
;*                 This registered subroutine is called whenever a background
;*                 VDM reads a byte from the Tseng Seg Select register (see
;*                 VDHInstallIOHook for complete semantics).
;*
;* INPUT         = EBX -> VDM register frame
;*                 EDX == port number (PORT_MONOCRTINDX or PORT_COLRCRTINDX)
;*
;* OUTPUT        = AL == data read
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVReadVVReservedBgnd
        mov     al,0                          ;return FALSE (not fgnd)
;       mov     al,byte ptr VDMData.flVDMVideo
        ExitProc
EndProc   VVReadVVReservedBgnd


;/*
;** added for ptr           
;*/

;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteIBMApertureCtrlFgnd()
;*
;* DESCRIPTION   = Write XGA-compatible Aperture register
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM writes to the Aperture Control register (0x2101). (see
;*                 VDHInstallIOHook for complete semantics).
;*
;* INPUT         =  AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVWriteIBMApertureCtrlFgnd
        OUTB    dx,al                       ;output data

        test    al, 011B                    ;only if aperture is enabled
        jz      @F                          ; 
        push    eax                         ;save output data
        CallFn  vvUpdateAll,<CURRENT_VDM, TRUE>
        CallFn  VVEnableBuffer,<FALSE, ebx>
        pop     eax                         ;restore output data
@@:
        FallInto VVWriteIBMApertureCtrlBgnd
EndProc   VVWriteIBMApertureCtrlFgnd


;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteIBMApertureCtrlBgnd()
;*
;* DESCRIPTION   = Write register
;*
;*                 This registered subroutine is called whenever a background
;*                 VDM writes to the Aperture Control register (0x2101). (see
;*                 VDHInstallIOHook for complete semantics).
;*
;* INPUT         =  AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVWriteIBMApertureCtrlBgnd
        FallFrom VVWriteIBMApertureCtrlFgnd
        mov     VDMData.aregXGAData[AXGA_APERTURE_CONTROL],al
        ExitProc
EndProc   VVWriteIBMApertureCtrlBgnd


;/***************************************************************************
;*
;* FUNCTION NAME = VVReadIBMApertureCtrlBgnd()
;*
;* DESCRIPTION   = Read register
;*
;*                 This registered subroutine is called whenever a background
;*                 VDM reads from the Aperture Control register (0x2101).
;*                 (see VDHInstallIOHook for complete semantics).
;*
;* INPUT         =  AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVReadIBMApertureCtrlBgnd
        mov     al,VDMData.aregXGAData[AXGA_APERTURE_CONTROL]
        ExitProc
EndProc   VVReadIBMApertureCtrlBgnd


;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteIBMRegistersBgnd()
;*
;* DESCRIPTION   = Write register
;*
;*                 This registered subroutine is called whenever a background
;*                 VDM writes to a register (0x2100). (see VDHInstallIOHook
;*                 for complete semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVWriteIBMRegistersBgnd

        and     edx,0fh
        jnz     @F
        and     al,010101B                      ;mask unused bits in opmode reg
        test    al,000100B                      ;touching extra function bits
        jz      @F                              ;no, don't freeze
        push    eax                             ; 
        push    edx                             ; 
        push    0                               ;current VDM
        push    0                               ;freeze and return
        call    vvFreezeVDM                     ; 
        pop     edx                             ; 
        pop     eax                             ; 
@@:
        mov     cl,VDMData.aregXGAData[edx]     ;          
        mov     VDMData.aregXGAData[edx],al     ;stash away value

        cmp     dl,8                                    ;          
        jne     @F                                      ;          
        cmp     al,cl                                   ;          
        je      @F                                      ;          
        test    VDMData.flVDMVideo,VDM_FGND             ;          
        jnz     @F                                      ;          
        cmp     VDMData.mstateVideo,MEMORY_GRFX256      ;          
        jne     @F                                      ;          
        push    eax                                     ;          
        push    edx                                     ;          
        and     eax,0fh                                 ;          
        push    eax                                     ;          
        mov     al,cl                                   ;          
        and     eax,0fh                                 ;          
        mov     VDMData.ulDirtyBankEvent,eax            ;          
        call    vvMapBank                               ;          
        pop     edx                                     ;          
        pop     eax                                     ;          
@@:                                                     ;          

        ExitProc
EndProc   VVWriteIBMRegistersBgnd


;/***************************************************************************
;*
;* FUNCTION NAME = VVReadIBMRegistersBgnd()
;*
;* DESCRIPTION   = Read register
;*
;*                 This registered subroutine is called whenever a background
;*                 VDM writes to a register (0x2100). (see VDHInstallIOHook
;*                 for complete semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVReadIBMRegistersBgnd
        and     edx,0fh
        mov     al,VDMData.aregXGAData[edx]
        ExitProc
EndProc   VVReadIBMRegistersBgnd
;/***************************************************************************
;*
;* FUNCTION NAME = VVReadOrchidClockSelectFgnd
;*
;* DESCRIPTION   = Monitor the state of register 0x3DD.
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM reads a byte from the Orchid Clock Select register (see
;*                 VDHInstallIOHook for complete semantics).
;*
;* INPUT         = EBX -> VDM register frame
;*                 EDX == port number (0x3dd)
;*
;* OUTPUT        = AL  == data read
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVReadOrchidClockSelectFgnd
        in      al,dx
        FallInto VVReadOrchidClockSelectBgnd
EndProc   VVReadOrchidClockSelectFgnd

;/***************************************************************************
;*
;* FUNCTION NAME = VVReadOrchidClockSelectBgnd
;*
;* DESCRIPTION   = Monitor the state of register 0x3DD.
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM reads a byte from the Orchid Clock Select register (see
;*                 VDHInstallIOHook for complete semantics).
;*
;* INPUT         = EBX -> VDM register frame
;*                 EDX == port number (0x3dd)
;*
;* OUTPUT        = AL  == data read
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVReadOrchidClockSelectBgnd
        FallFrom VVReadOrchidClockSelectFgnd
        mov     VDMData.regOrchidClockSelect,0
        ExitProc
EndProc   VVReadOrchidClockSelectBgnd

;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteOrchidClockSelectFgnd
;*
;* DESCRIPTION   = Monitor the state of register 0x3DD.
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM writes to the Orchid clock select register (0x3dd).
;*                 (see VDHInstallIOHook for complete semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (0x3dd)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVWriteOrchidClockSelectFgnd
        OUTB    dx,al
        FallInto VVWriteOrchidClockSelectBgnd
EndProc   VVWriteOrchidClockSelectFgnd

;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteOrchidClockSelectBgnd
;*
;* DESCRIPTION   = Monitor the state of register 0x3DD.
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM writes to the Orchid clock select register (0x3dd).
;*                 (see VDHInstallIOHook for complete semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (0x3dd)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

Procedure VVWriteOrchidClockSelectBgnd
        FallFrom VVWriteOrchidClockSelectFgnd
        mov     VDMData.regOrchidClockSelect,1
        ExitProc
EndProc   VVWriteOrchidClockSelectBgnd

;/***************************************************************************
;*
;* FUNCTION NAME = SETNUMBER9CLK                                          
;*
;* DESCRIPTION   = Set the video clock on #9 adapter with S3
;*
;*                 ENTRY POINT: SetNumber9Clk
;*                 LINKAGE:   CALL FAR
;*
;* INPUT         = (Passed on stack)
;*                 horizontal resolution
;*                 text/graphics mode
;*
;* RETURN-NORMAL = Specified clock bits set serially.
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
 CLOCK_DELAY0           EQU     73              ; delay loop for 1/8 sec
 CLOCK_DELAY1           EQU     145             ; delay loop for 1/4 sec

 C_NONE                 EQU     0       ; for freq synth programming
 C_CLK                  EQU     1       ; for freq synth programming
 C_DATA                 EQU     2       ; for freq synth programming
 C_BOTH                 EQU     3       ; for freq synth programming
 CLOCK_DELAY            EQU     CLOCK_DELAY1

 DELAY_CLOCK_SETUP      EQU     1       ; Delay when changing freq

        align   4
Procedure SETNUMBER9CLK
        ArgVar  hvdm,HVDM
        ArgVar  N9HRes,ULONG

        EnterProc
        push    esi
        push    edi
        push    ecx
        push    edx

        mov     ecx,N9HRes              ;horizontal res

;****************************************************************
; Set the frequency generator to the desired VGA frequency.
; Read the register CR42 to determine the frequency to run at.
; This register is used as an offset into the frequency table.
;****************************************************************
;Set_Nine_VGAFreq        PROC    NEAR

        MOV     DX,03CCh                ; read clock bits in Misc Output reg
        IN      AL,DX
        TEST    AL,08h                  ; do we need to do this routine?
        JZ      SHORT No_Frequency_Setup; no, so just set m clock

;       PUSH    SI                      ; save SI before i use it
        CALL    Find_6845_Address       ; Get CRT index address
        CALL    New_Refresh_Selected    ; put higher refresh in SI:BX

Hi_Refresh:
        MOV     AL, 42h                 ; go to the mode ctrl reg (CR42)
        out     dx, al
        inc     dx
        IN      AL,DX                   ; and read it again
        dec     dx
        AND     AL,0F0h
        MOV     AH,AL                   ; save this for later
        OR      AH,2                    ; set the index to two
        CALL    Set_Frequency           ; set the frequency synthesizer
;       POP     SI                      ; restore the original contents

No_Frequency_Setup:
        pop     edx
        pop     ecx
        pop     edi
        pop     esi

;Set_Nine_VGAFreq        ENDP

        ExitProc
EndProc SETNUMBER9CLK

;****************************************************************
;
;
;****************************************************************
; Set the frequency synthesizer to the desired frequency.
; The frequency synthesizer is an IDC 2061a part.
; This code turns off the video display prior to setting
; the synthesizer, and then returns the display to the
; previous state.
;       Entry:  SI:BX   - pointer to 24 bit clock Number
;               AH      - contains the saved CR42 reg
;               dx      - 3?4
;****************************************************************
Procedure Set_Frequency
        PUSH    DX
;;      PUSH    AX                      ; save CR42

        PUSH    AX                      ; save CR42 (twice!)
;;;     CALL    Find_6845_Address       ; Get CRT index address
        MOV     AX, 0A039H              ; register lock 1 index
        OUT     DX, AX                  ; Unlock the soft switches
        POP     AX                      ; restore the saved CR42 in AX

        MOV     AL, 1                   ; To turn off video display
        MOV     DX, 03C4h               ; go to the Clocking Mode register
        OUT     DX, AL
        INC     DX
        IN      AL, DX                  ; read the Clocking Mode reg
        PUSH    AX                      ; save the Clocking Mode Reg
        OR      AL, 20h                 ; set video OFF bit
        OUT     DX, AL                  ; turn off video output

        MOV     DX, 03CCh               ; read clock bits in Misc Output reg
        IN      AL, DX
        PUSH    AX                      ; save this old value
        OR      AL, 0Ch                 ; enable CR42 bits 2 & 3
        MOV     DX, 03C2h
        OUT     DX, AL                  ; write new misc output value

        CALL    Find_6845_Address       ; Get CRT index address
        MOV     AL, 42h                 ; the Mode Control Reg (CR42)
        OUT     DX, AL                  ; write index to 3?4
        INC     DX                      ; Move DX to 3?5
        XCHG    AH,AL                   ; Swap Index/Data
        OUT     DX,AL                   ; Program the data

;**************************************************************************
;***************** START OF CRITICAL SECTION OF CODE **********************
;**************************************************************************
        PUSHF                   ; save the flags prior to critical section
        CLI                     ; no interupts please...

        MOV     AL, C_NONE      ; start programming ICD2061A
        OUT     DX, AL
        MOV     AL, C_DATA
        OUT     DX, AL
        MOV     CX, 6

unLockSeq:
        MOV     AL, C_BOTH       ; Unlock sequence
        OUT     DX, AL
        MOV     AL, C_DATA
        OUT     DX, AL
        LOOP    SHORT unLockSeq

        MOV     AL, C_NONE
        OUT     DX, AL
        MOV     AL, C_CLK
        OUT     DX, AL
        MOV     AL, C_NONE
        OUT     DX, AL
        MOV     AL, C_CLK
        OUT     DX, AL

        SAR     SI, 1            ; do shift (ignore 1st bit)
        RCR     BX, 1            ; set the carry flag
        MOV     CX, 24           ; Program the 24 bit value into REG0

programREG0:
        SAR     SI, 1            ; clock_value >>= 1
        RCR     BX, 1
        JNC     SHORT clock0

clock1:
        MOV     AL, C_CLK
        OUT     DX, AL
        MOV     AL, C_NONE
        OUT     DX, AL
        MOV     AL, C_DATA
        OUT     DX, AL
        MOV     AL, C_BOTH
        OUT     DX, AL
        JMP     SHORT programCont
clock0:
        MOV     AL, C_BOTH
        OUT     DX, AL
        MOV     AL, C_DATA
        OUT     DX, AL
        MOV     AL, C_NONE
        OUT     DX, AL
        MOV     AL, C_CLK
        OUT     DX, AL

programCont:
        LOOP    SHORT programREG0

        MOV     AL, C_BOTH
        OUT     DX, AL
        MOV     AL, C_DATA
        OUT     DX, AL
        MOV     AL, C_BOTH
        OUT     DX, AL

        POPF                    ; resore all flags
        STI                     ; ok for interupts now
;**************************************************************************
;******************* END OF CRITICAL SECTION OF CODE **********************
;**************************************************************************

        MOV     AL, AH          ; AH has contained the saved CR42 reg
        OUT     DX, AL          ; Select the VCLOCK index in CR42

;;IF      DELAY_CLOCK_SETUP
;;      MOV     CX,CLOCK_DELAY  ; Brief wait period (defined above)
;;      MOV     AL, 0           ; no tone during wait period
;;;     CALL    Gate_Timer      ; Wait for Clock Freq to synchronize
;;ENDIF

        POP     AX              ; old Misc Output reg value
        MOV     DX, 03C2h       ; write to write port
        OUT     DX, AL          ; reset the value

        MOV     DX, 03C4h       ; To set screen to previous state
        MOV     AL, 1           ; go to the Clocking Mode reg
        OUT     DX, AL
        INC     DX
        POP     AX              ; use old value pushed from Clk Mode Reg
        OUT     DX, AL          ; restore video

;;      POP     AX              ; restore the saved CR42 in AX
        POP     DX              ; Restore callers registers

        ExitProc

EndProc Set_Frequency
;****************************************************************
;
;
;****************************************************************
; If the scratch register calls for it, set the new refresh rate
; for the vesa modes (CR52 contains selected refresh rate)
; CR52 is initialized to 0AAh at init time.
;
; The structure for CR52 is:
;   Bits:  7 6| 5 4| 3 2| 1 0
;          x x| x x| x x| x x
;                       
;           ³    ³    ³    ÀÄ 640x480 resolutions
;           ³    ³    ÀÄÄÄÄÄÄ 800x600 resolutions
;           ³    ÀÄÄÄÄÄÄÄÄÄÄÄ 1024x768 resolutions
;           ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ- 1280x1024 and 1600x1200 resolutions
;
; where:    00 = 70 Hz
;           01 = 76 Hz
;           10 = 60/56 Hz (this is really Default Hz!)
;           11 = 72 Hz
;
;    cx = horizontal resolution
;    dx = 3?4
;****************************************************************
Procedure New_Refresh_Selected
;;      PUSH    AX
;;      PUSH    DI                      ; Dont destroy DI

        CMP     cx, 640                 ; which gross resolution?
        JE      SHORT Refresh_640
        CMP     cx, 800                 ; which gross resolution?
        JE      SHORT Refresh_800
        CMP     cx, 1024                ; which gross resolution?
        JE      SHORT Refresh_1024
        CMP     cx, 1280                ; which gross resolution?
        JE      SHORT Refresh_1280
        CMP     cx, 1600                ; which gross resolution?
        JE      SHORT Refresh_1600
        JMP     SHORT No_HiRefresh      ; fail-safe exit

Refresh_640:
        MOV     CL, 0                   ; offset in CR52 is 1'st position
        MOV     BL, 0                   ; offset in table is...
        JMP     SHORT Set_Refresh

Refresh_800:
        MOV     CL, 2                   ; offset in CR52 is 2'nd position
        MOV     BL, 4                   ; offset in table is...
        JMP     SHORT Set_Refresh

Refresh_1024:
        MOV     CL, 4                   ; offset in CR52 is 3'rd position
        MOV     BL, 8                   ; offset in table is...
        JMP     SHORT Set_Refresh

Refresh_1280:
        MOV     CL, 6                   ; offset in CR52 is 4'th position
        MOV     BL, 12                  ; offset in table is...
        JMP     SHORT Set_Refresh

Refresh_1600:
        MOV     CL, 6                   ; offset in CR52 is 4'th position
        MOV     BL, 16                  ; offset in table is...

Set_Refresh:
        MOV     AL, 52h
        OUT     DX, AL                  ; CR52 is the multiple mon-id reg.
        INC     dx
        in      al, dx
        dec     dx                      ; Get CRT index address

;;;     XCHG    AL, AH                  ; Get Monitor info in AL
        SHR     AL, CL                  ; Get the corresponding monitor-id
        AND     AL, 03                  ; Get the bits I want by themselves
        MOV     BH, AL                  ; store bits here...

        CMP     BH, 02                  ; is register set to 60 Hz?
        JE      SHORT No_New_HSync      ; user wants 60 Hz

        MOV     AL, 04h                 ; read the Horiz Sync Start Pos
        OUT     DX, AL                  ; Unlock the soft switches
        INC     dx
        in      al, dx
        DEC     AL                      ; by one character clock
        OUT     DX, AL                  ; to adjust screen position.
        dec     dx                      ; Get CRT index address

No_New_HSync:
        XOR     EAX, EAX                ; clear the EAX reg for add to ESI
        MOV     AL, BH                  ; get the value back now
        ADD     AL, BL                  ; add res jump for total index jump
        SHL     AL, 1                   ; convert to DWORD offset
        SHL     AL, 1                   ; convert to DWORD offset
        MOV     ESI,FLAToffset Hi_Refresh_Table ; Get offset for table
        ADD     ESI, EAX                ; increment to the refresh rate
        LODS    WORD PTR CS:[ESI]       ; Read the low clock word
        MOV     BX, AX                  ; low word goes in BX
        LODS    WORD PTR CS:[ESI]       ; Read the high clock word
        MOV     SI, AX                  ; SI,BX now has the 24-bit clock #
        STC                             ; indicate the new numbers in regs
        JMP     SHORT End_Refresh       ; skip to the end with carry set

No_HiRefresh:
        CLC                             ; use standard frequency

End_Refresh:
;;      POP     DI
;;      POP     AX

        ExitProc

;****************************************************************
Hi_Refresh_Table:
        DD      08FA170h        ; Index   0:  640 @ 70Hz  29.376 Mhz
        DD      093B16Ah        ; Index   1:  640 @ 76Hz  31.499 Mhz
        DD      08AC158h        ; Index   2:  640 @ 60Hz  28.325 Mhz
        DD      08F896Ah        ; Index   3:  640 @ 72Hz  30.198 Mhz
        DD      0AB5942h        ; Index   4:  800 @ 70Hz  44.999 Mhz
        DD      0AF8940h        ; Index   5:  800 @ 76Hz  48.850 Mhz
        DD      09AA942h        ; Index   6:  800 @ 56Hz  35.999 Mhz
        DD      0AEF138h        ; Index   7:  800 @ 72Hz  46.295 Mhz
        DD      0A2F846h        ; Index   8: 1024 @ 70Hz  75.847 Mhz
        DD      0A7804Ch        ; Index   9: 1024 @ 76Hz  82.329 Mhz
        DD      0968846h        ; Index  10: 1024 @ 60Hz  65.012 Mhz
        DD      0A26036h        ; Index  11: 1024 @ 72Hz  78.009 Mhz
        DD      093D86Eh        ; Index  12: 1280 @ 70Hz  126.5 / 2 Mhz
        DD      09B785Ah        ; Index  13: 1280 @ 76Hz  139.0 / 2 Mhz
        DD      08B486Eh        ; Index  14: 1280 @ 60Hz  108.5 / 2 Mhz
        DD      0937862h        ; Index  15: 1280 @ 72Hz  128.0 / 2 Mhz
        DD      0AAE03Ch        ; Index  16: 1600 @ 60Hz  170.028 Mhz
        DD      0AAE03Ch        ; Index  17: 1600 @ 60Hz  170.028 Mhz
        DD      0AAE03Ch        ; Index  18: 1600 @ 60Hz  170.028 Mhz
        DD      0AAE03Ch        ; Index  19: 1600 @ 60Hz  170.028 Mhz
;****************************************************************

EndProc New_Refresh_Selected

;/***************************************************************************
;*
;* FUNCTION NAME = SETDIAMONDCLK
;*
;* DESCRIPTION   = Set the video clock on diamond speedstar 24/24X on per
;*                 mode basis.
;*
;*                 ENTRY POINT: SetDiamondClk
;*                 LINKAGE:   CALL FAR
;*
;* INPUT         = (Passed on stack) 1. bios mode for this vdm if called for
;*                                   Tseng or Western Digital  OR....
;*                                   horizontal resolution if called for S3
;*                                   2. #colors
;*
;* RETURN-NORMAL = Specified clock bits set serially.
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        align   4
Procedure SETDIAMONDCLK                         ;          
        ArgVar  hvdm,HVDM
        ArgVar  biosmode,ULONG
        ArgVar  nColor,ULONG                    ;          

        EnterProc

        jmp     program_clk_chip

        ;                                                  Monitor type
        ;NEC 5Fg -------------------------------------------------------- 8x
        ;NEC 4Fg ---------------------------------------------------- ax
        ;NEC 3Fgx ----------------------------------------------- 9x
        ;NEC 3Fg, SONY 1302 --------------------------------- 7x
        ;Fixed Freq, 8514 ------------------------------- fx
        ; 
clk_data:
; BIOS verions 1.xx (>=1.00 and <2.00)
; supports ICD 2061 clock chip
; 24-bit serial data for clock frequency
table_2061      label   byte
 ;       bits 8-15, bits 0-7,  bits 15-23                |fx |7x |9x |ax |8x
 ;                                                       |---|---|---|---|---
 db      00010101b,00111101b,10100010b   ;0  - 25.175    |   |   |   |   |
 db      00000110b,00110101b,10010010b   ;1  - 28.322    |   |   |   |   |
 db      00011011b,10101101b,11010010b   ;2  - 31.5      |   |480|480|480|480
 db      00101010b,10000101b,11110010b   ;3  - 36.0      |600|   |   |   |
 db      00101010b,10111100b,11000010b   ;4  - 40.0      |   |   |   |   |
 db      00010000b,01010100b,11000010b   ;5  - 44.9      |768|768|   |   |
 db      00110101b,10111100b,10100010b   ;6  - 50.0      |   |   |600|600|600
 db      00011011b,10101100b,11010010b   ;7  - 63.0      |   |   |   |   |
 db      00100010b,11000100b,10110010b   ;8  - 65.0      |   |   |768|   |
 db      00101010b,10000100b,11110010b   ;9  - 72.0      |   |   |   |   |
 db      00110101b,00010100b,11110010b   ;10 - 75.00     |   |   |   |768|
 db      00100011b,10010100b,11110010b   ;11 - 77.25     |   |   |   |   |768
 db      00001101b,00010100b,11110010b   ;12 - 75.68     |   |   |   |   |
 db      00010101b,00111100b,10100010b   ;13 - 50.35     |   |   |   |   |

 db      00101010b,10111100b,10100010b   ;14 - xx.xx     |   |600|   |   |
 db      00011110b,10101100b,10100110b   ;15 - xx.xx     |480|   |   |   |

clk_data1:

; BIOS verions 2.xx (>=2.00)
; supports ICD 2061A clock chip
; 24-bit serial data for clock frequency
table_2061A     label   byte
 ;      ;bits 8-15, bits 0-7,  bits 15-23                |fx |7x |9x |ax |8x
 ;      ;                                                |---|---|---|---|---
 db      00010101b,00111101b,10000000b   ;0  - 25.175    |   |   |   |   |
 db      00000110b,00110101b,10100001b   ;1  - 28.322    |   |   |   |   |
 db      00011011b,10101101b,10010010b   ;2  - 31.5      |   |480|480|480|480
 db      00101010b,10000101b,10110010b   ;3  - 36.0      |600|   |   |   |
 db      00001110b,00000101b,10001010b   ;4  - 40.0      |   |   |   |   |
 db      00010000b,00101001b,10101010b   ;5  - 44.9      |768|768|   |   |
 db      00110101b,10111100b,10000010b   ;6  - 50.0      |   |   |600|600|600
 db      00011011b,10101100b,10010010b   ;7  - 63.0      |   |   |   |   |
 db      00100010b,11000100b,11010010b   ;8  - 65.0      |   |   |768|   |
 db      00101010b,10000100b,10110010b   ;9  - 72.0      |   |   |   |   |
 db      00110101b,00010100b,11110010b   ;10 - 75.00     |   |   |   |768|
 db      00100011b,10010100b,10001010b   ;11 - 77.25     |   |   |   |   |768
 db      00001101b,00010100b,10001010b   ;12 - 75.68     |   |   |   |   |
 db      00010101b,00111100b,10000010b   ;13 - 50.35     |   |   |   |   |

 db      00111101b,00000101b,11101110b   ;14 - xx.xx     |   |600|   |   |
 db      00011110b,10101100b,10000110b   ;15 - xx.xx     |480|   |   |   |
 db      00011011b,10111100b,10100110b   ;16 - xx.xx

color_256:
 db      00001001b,11110100b,11100110b   ;2nd pass for 256 color graphics modes

clk_data2:

; BIOS verions 5.xx (>=5.00 and <6.00)
; supports ICD 2061A clock chip
; 24-bit serial data for clock frequency
;table_2061A     label   byte
 ;      ;bits 8-15, bits 0-7,  bits 15-23
 ;      ;
 db      00010101b,00111101b,10100010b   ;0  - 25.175
 db      00000110b,00110101b,10010010b   ;1  - 28.322
 db      00110101b,00010100b,11110010b   ;2  - 75.00
 db      00101010b,10000100b,11110010b   ;3  - 72.0
 db      00001110b,00000100b,11110010b   ;4  - 80.0
 db      00010000b,01010100b,11000010b   ;5  - 44.9
 db      00110101b,10111100b,10100010b   ;6  - 50.0
 db      00100010b,11000100b,10110010b   ;7  - 65.0
 db      00100111b,00110100b,11110010b   ;8  - 77.16

 db      00001110b,00000100b,10001010b   ;9  - xx.xx

clk_data3:

; BIOS verions 6.xx (>=6.00)
; supports ICD 2061A clock chip
; 24-bit serial data for clock frequency
;table_2061A     label   byte
 ;      ;bits 8-15, bits 0-7,  bits 15-23
 ;      ;
 db      00010101b,00111101b,10000010b   ;0  - 25.175
 db      00000110b,00110101b,10100010b   ;1  - 28.322
 db      00110101b,00010100b,11110010b   ;2  - 75.00
 db      00101010b,10000100b,10110010b   ;3  - 72.0
 db      00001110b,00000100b,10001010b   ;4  - 80.0
 db      00010000b,00101001b,10101010b   ;5  - 44.9
 db      00110101b,10111100b,10000010b   ;6  - 50.0
 db      00100010b,11000100b,11010010b   ;7  - 65.0
 db      00011110b,01000100b,10001010b   ;8  - 77.16

 db      00001110b,00000100b,10001010b   ;9  - xx.xx

program_clk_chip:

        push    esi
        push    edi
        push    ecx
        push    edx

        mov     ebx,[hvdm]              ;EBX -> VDM
        mov     edx,biosmode            ;bios mode in edx if tseng/WD
;           mov     edx,HRes                ;horizontal res if s3
        mov     ecx,nColor              ;#colors                            

        cmp     ulSVGAAdapterType, S3_ADAPTER
        jne     get_mon
        call    s3_proc
        jmp     s3_done

get_mon:
        call    GetMonitorType

        mov     edx,biosmode            ;bios mode in edx        /          */
        cmp     edx, 0105h              ;1024x768x256 (cmn)
        je      mode_1024_cmn
        cmp     edx, 0104h              ;1024x768x16 (cmn)
        je      mode_1024_cmn
        jmp     hres_800_cmn
mode_1024_cmn:
        mov     edx,2
        jmp     set_index
hres_800_cmn:
        cmp     edx, 0103h              ;800x600x256 (cmn)
        je      mode_800_cmn
        cmp     edx, 0102h              ;800x600x16 (cmn)
        je      mode_800_cmn
        jmp     hres_640_cmn
mode_800_cmn:
        mov     edx,1
        jmp     set_index
hres_640_cmn:
        cmp     edx, 0101h              ;640x480x256 (cmn)
        je      mode_640_cmn
        cmp     edx, 12h                ;640x480x16 (cmn)
        je      mode_640_cmn
        cmp     edx, 11h                ;640x480x2 (cmn)
        je      mode_640_cmn
        jmp     mode_80
mode_640_cmn:
        mov     edx,0                   ;          
        jmp     set_index
mode_80:
        cmp     edx, 3                  ;80 column mode
        jne     mode_40
        mov     edx, 4
        jmp     set_index
mode_40:
        cmp     edx, 1                  ;40 column mode
        jne     speedstar_24
        mov     edx, 5
        jmp     set_index

speedstar_24:
        cmp     ulSVGAAdapterType, TSENG_ADAPTER
        jne     speedstar_24x           ;must be Western Digital

        cmp     edx, 38h                ;1024x768x256
        je      mode_1024_24
        cmp     edx, 37h                ;1024x768x16
        je      mode_1024_24
        jne     hres_800_24
mode_1024_24:
        mov     edx,2
        jmp     set_index
hres_800_24:
        cmp     edx, 30h                ;800x600x256
        je      mode_800_24
        cmp     edx, 29h                ;800x600x16
        je      mode_800_24
        jne     hres_640_24
mode_800_24:
        mov     edx,1
        jmp     set_index
hres_640_24:
        cmp     edx, 2eh                ;640x480x256
        je      mode_640_24
        cmp     edx, 12h                ;640x480x16
        je      mode_640_24
        cmp     edx, 11h                ;640x480x2
        je      mode_640_24
        jmp     text_mode_24
mode_640_24:
        mov     edx,0
        jmp     set_index

text_mode_24:
        cmp     edx, 19h                ;132 column mode (25 row 4-color)
        je      mode_132
        cmp     edx, 1ah                ;132 column mode (28 row 4-color)
        je      mode_132
        cmp     edx, 18h                ;132 column mode (43 row 4-color)
        je      mode_132
        cmp     edx, 23h                ;132 column mode (25 row 16-color)
        je      mode_132
        cmp     edx, 24h                ;132 column mode (28 row 16-color)
        je      mode_132
        cmp     edx, 22h                ;132 column mode (43 row 16-color)
        je      mode_132
        jne     not_hires
mode_132:
        mov     edx, 3
        jmp     short set_index

;-----------------------------------------------------------------------------
; End of Tseng specific code
;-----------------------------------------------------------------------------

speedstar_24x:

        cmp     edx, 60h                ;1024x768x256
        je      mode_1024_24x
        cmp     edx, 5dh                ;1024x768x16
        je      mode_1024_24x
        jne     hres_800_24x
mode_1024_24x:
        mov     edx,2
        jmp     set_index
hres_800_24x:
        cmp     edx, 5ch                ;800x600x256
        je      mode_800_24x
        cmp     edx, 58h                ;800x600x16
        je      mode_800_24x
        jne     hres_640_24x
mode_800_24x:
        mov     edx,1
        jmp     short set_index
hres_640_24x:
        cmp     edx, 5fh                ;640x480x256
        je      mode_640_24x
        jmp     text_mode_24x
mode_640_24x:
        mov     edx,0
        jmp     short set_index

text_mode_24x:
        cmp     edx, 55h                ;132 column mode (25 row)
        je      mode_132_24x
        cmp     edx, 47h                ;132 column mode (28 row)
        je      mode_132_24x
        cmp     edx, 54h                ;132 column mode (43 row)
        je      mode_132_24x
        jne     not_hires
mode_132_24x:
        mov     edx, 3

;-----------------------------------------------------------------------------
; End of Western Digital specific code
;-----------------------------------------------------------------------------

set_index:
        add     edi,edx
        xor     eax,eax
        mov     al,byte ptr [edi]       ;mode index pointer

        mov     cx,3                    ;width of data table
        mul     cx                      ;ax is now table aligned

        mov     cx,WORD PTR sOEMData+6  ;          
        cmp     cx,1                    ;BIOS Rev 1 (Major)
        jne     clk1
        mov     esi, FLAToffset clk_data
        jmp     short supported
clk1:
        cmp     cx,2                    ;BIOS Rev 2 (Major)
        jne     clk5                    ;bios rev not currently supported
        mov     esi, FLAToffset clk_data1
        jmp     short supported

clk5:
        cmp     cx,5                    ;BIOS Rev 5 (Major)
        jne     clk6
        mov     esi, FLAToffset clk_data2
        jmp     short supported
clk6:
        cmp     cx,6                    ;BIOS Rev 6 (Major)
        jne     not_hires               ;bios rev not currently supported
        mov     esi, FLAToffset clk_data3

supported:
        add     esi,eax                 ;point to serial data

        mov     dx,3cch
        in      al, dx
        push    eax

        mov     ecx, 256
ploop:
        push    ecx
        call    Prog_Clock

        mov     cx,WORD PTR sOEMData+6  ;          
        cmp     cx,2                    ;BIOS Rev 2 (Major)
        jne     short done_prog

        mov     esi, FLAToffset color_256 ;2nd pass for 256 color graphics modes
        call    Prog_Clock
done_prog:
        pop     ecx
        in      al,dx
        test    al, 10h
        jnz     ppp_done
        sub     si,2
        loop    ploop

ppp_done:
        pop     eax
        out     dx,al

        call    WaitVertRetrace         ;wait for vertical retrace

not_hires:
s3_done:
        pop     edx
        pop     ecx
        pop     edi
        pop     esi

        ExitProc

EndProc SETDIAMONDCLK

s3_proc:
        mov     ax,eeprom_tab_l*index_m1024
        cmp     dx, 1024
        jne     short res_800

        cmp     cx, 16                  ;check for hi-color               
        jne     @F
        mov     ax,eeprom_tab_l*index_m1024h

@@:
        jmp     update_eeprom

res_800:
        cmp     dx, 800
        jne     short res_640
        cmp     cx, 16                  ;check for hi-color               
        jne     @F
        mov     ax,eeprom_tab_l*index_m800h
        jmp     short   update_eeprom

@@:
        cmp     cx, 24                  ;check for true-color             
        jne     @F
        mov     ax,eeprom_tab_l*index_m800t                    ;          
        jmp     short   update_eeprom

@@:
        mov     ax,eeprom_tab_l*index_m800
        jmp     short   update_eeprom

res_640:
        cmp     dx, 640
        jne     res_1280                ;check for 1280 res               
        cmp     cx, 16                  ;check for hi-color               
        jne     @F
        mov     ax,eeprom_tab_l*index_m640h
        jmp     short   update_eeprom

@@:
        cmp     cx, 24                  ;check for true-color             
        jne     @F
        mov     ax,eeprom_tab_l*index_m640t                    ;          
        jmp     short   update_eeprom

@@:
        mov     ax,eeprom_tab_l*index_m640
        jmp     short   update_eeprom

res_1280:                               ;          
        cmp     dx, 1280
        jne     @F
;;;;;;; Index_m1280_256 (10 = computed value of 64h) yields a flickering or   ;          
;;;;;;; strobe effect on the OS/2 and WinOS/2 desktop after a save/restore    ;          
;;;;;;; on 1280x1024x256.  Index_m1280_16 (9 = computed value of 5Ah) works   ;          
;;;;;;; for all refresh rates supported by the StlMode Utility (43.5, 60, 72) ;          
;;      mov     ax,eeprom_tab_l*index_m1280_256                               ;          
        mov     ax,eeprom_tab_l*index_m1280_16                                ;          
        jmp     short   update_eeprom

@@:
        cmp     dx, 1056
        jne     @F
        mov     ax,eeprom_tab_l*index_m5455
        jmp     short   update_eeprom
@@:

update_eeprom:
        call    upd_crtc_eeprom

        ret

;/***************************************************************************
;*
;* FUNCTION NAME = GetMonitorType
;*
;* DESCRIPTION   =
;*
;*
;* ENTRY POINT: GetMonitorType
;* LINKAGE:     CALL NEAR
;*
;* INPUT         = EBX = HVDM
;*
;* RETURN-NORMAL = EDI = offset to supported modes              /*          */
;*                       per current monitor type               /*          */
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

Procedure GetMonitorType

;equates for SpeedSTAR 24 supported monitor types or compatibles

MONITOR_NEC2A           equ     0
MONITOR_IBM8514         equ     1
MONITOR_NEC3FGX         equ     2
MONITOR_NEC3FG          equ     3
MONITOR_NEC4FG          equ     4
MONITOR_FIXED           equ     5
MONITOR_CS1572FS        equ     6
MONITOR_CS1024NI        equ     7

UNSUPPORTED_MONITOR     equ     254


        jmp     short getmon_cont

;/*************************************************************************
;* Monitor table for SpeedStar 24x
;**************************************************************************/

                       ;+----------------------------------------- 640x480g
                       ;|       +--------------------------------- 800x600g
                       ;|       |       +------------------------- 1024x768g
                       ;|       |       |       +----------------- 132 col text
                       ;|       |       |       |       +--------- 80 col text
                       ;|       |       |       |       |       +- 40 col text
                       ;|       |       |       |       |       |
fixed_freq:     db    15,      3,      5,      5,     15,      15
nec3fg:         db     2,     14,      5,      5,     15,      15
nec3fgx:        db     2,      6,      8,      5,     15,      15
nec4fg:         db     2,      6,     10,      5,     15,      15
nec5fg:         db     2,      6,     11,      5,     15,      15

;/*************************************************************************
;* Monitor table for SpeedStar 24
;**************************************************************************/

nec2a_24:       db   255,      3,      5,      9
ibm8514_24:     db   255,      3,      5,      9
nec3fg_24:      db     7,      9,      5,      9
nec3fgx_24:     db     7,      6,      7,      9
nec4fg_24:      db     7,      6,      2,      9
fixed_24:       db   255,      7,      4,      9
cs1572fs_24:    db     7,      6,      8,      9
cs1024ni_24:    db   255,      6,      7,      9

unknown:        db   UNSUPPORTED_MONITOR

getmon_cont:

        cmp     ulSVGAAdapterType, TSENG_ADAPTER
        jne     getmon_24x              ;must be Western Digital

        call    GetCRTCAddr
        mov     al, 31h
        out     dx, al
        inc     dx
        in      al, dx
        and     al, 1

        movzx   ecx,VDMBase.rb_bVFlags[ebx]     ;scratch reg (SpeedSTAR 24)
        and     cl, 60h
        shr     cl, 4
        or      cl, al

        cmp     cx,MONITOR_NEC2A
        jne     mon_ibm8514
        mov     edi, FLAToffset nec2a_24
        jmp     mon_exit
mon_ibm8514:
        cmp     cx,MONITOR_IBM8514
        jne     mon_nec3fg
        mov     edi, FLAToffset ibm8514_24
        jmp     mon_exit
mon_nec3fg:
        cmp     cx,MONITOR_NEC3FG
        jne     mon_nec3fgx
        mov     edi, FLAToffset nec3fg_24
        jmp     mon_exit
mon_nec3fgx:
        cmp     cx,MONITOR_NEC3FGX
        jne     mon_nec4fg
        mov     edi, FLAToffset nec3fgx_24
        jmp     mon_exit
mon_nec4fg:
        cmp     cx,MONITOR_NEC4FG
        jne     mon_fixed
        mov     edi, FLAToffset nec4fg_24
        jmp     mon_exit
mon_fixed:
        cmp     cx,MONITOR_FIXED
        jne     mon_cs1572fs
        mov     edi, FLAToffset fixed_24
        jmp     mon_exit
mon_cs1572fs:
        cmp     cx,MONITOR_CS1572FS
        jne     mon_cs1024ni
        mov     edi, FLAToffset cs1572fs_24
        jmp     short   mon_exit
mon_cs1024ni:
        cmp     cx,MONITOR_CS1024NI
        jne     unknown_monitor
        mov     edi, FLAToffset cs1024ni_24
        jmp     short   mon_exit

unknown_monitor:
        mov     edi, FLAToffset unknown
        jmp     short   mon_exit

getmon_24x:

        call    GetCRTCAddr
        mov     al,2bh
        out     dx,al
        inc     dx
        in      al,dx
        and     al,0f0h
        cmp     al,0f0h
        jne     nec3fg_mon
        jmp     short default_mon

nec3fg_mon:
        cmp     al,70h
        jne     nec3fgx_mon
        mov     edi, FLAToffset nec3fg
        jmp     short mon_exit

nec3fgx_mon:
        cmp     al,90h
        jne     nec4fg_mon
        mov     edi, FLAToffset nec3fgx
        jmp     short mon_exit

nec4fg_mon:
        cmp     al,0a0h
        jne     nec5fg_mon
;        lea     edi, nec4fg
        mov     edi, FLAToffset nec4fg
        jmp     short mon_exit

nec5fg_mon:
        cmp     al,80h
        jne     default_mon
        mov     edi, FLAToffset nec5fg
        jmp     short mon_exit

default_mon:
        mov     edi, FLAToffset fixed_freq

mon_exit:
        ExitProc

EndProc GetMonitorType

;/***************************************************************************
;*
;* FUNCTION NAME = Prog_Clock
;*
;* DESCRIPTION   = Program the speedstar 24 clock using 24 bit data
;*                 for desired clock frequency
;*
;* ENTRY POINT: Prog_Clock
;* LINKAGE:     CALL NEAR
;*
;* INPUT         = NONE
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

Procedure Prog_Clock

        push    bx
        mov     dx,3cch
        in      al,dx
        mov     dx,3c2h

        or      al,8
        mov     cx,6
        cli

kk_1:
        and     al, 0fbh                ;clock low
        out     dx,al
        or      al,4                    ;clock high
        out     dx,al
        loop    kk_1

        and     al, 0fbh
        out     dx,al
        and     al, 0f3h                ;clock low data low
        out     dx,al
        or      al,4                    ;clock high

        out     dx,al
        and     al,0f3h                 ;clock low data low
        out     dx,al
        or      al,4                    ;clock high
        out     dx,al

        mov     bx,8000h                ;program first 16 bits
        call    Send_Serial
        add     si,2                    ;update pointer
        mov     bx,80h                  ;program last 8 bits
        call    Send_Serial

        or      al,8
        out     dx,al
        and     al,0fbh                 ;clock low
        out     dx,al
        or      al,4                    ;clock high
        out     dx,al

        sti
        pop     bx

        ExitProc

EndProc Prog_Clock

;/***************************************************************************
;*
;* FUNCTION NAME = Send_Serial
;*
;* DESCRIPTION   = Program the speedstar 24/24X clock using 24 bit data
;*                 for desired clock frequency
;*
;*                 ENTRY POINT: Send_Serial
;*                 LINKAGE:   CALL NEAR
;*
;* INPUT         = NONE
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

Procedure Send_Serial

send_serial_data:

        and     al, 0f7h
        test    word ptr [esi],bx
        jnz     send_serial_1
        or      al,8

send_serial_1:

        out     dx,al
        and     al, 0fbh
        out     dx,al

        xor     al,8
        out     dx,al
        or      al,4
        out     dx,al
        shr     bx,1
        jnc     send_serial_data

        ExitProc

EndProc Send_Serial

;/***************************************************************************
;*
;* FUNCTION NAME = WaitVertRetrace
;*
;* DESCRIPTION   = Wait for vertical retrace
;*
;*
;*
;*                 ENTRY POINT: WaitVertRetrace
;*                 LINKAGE:   CALL NEAR
;*
;* INPUT         = NONE
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

Procedure WaitVertRetrace

        push    ax
        push    cx
        push    dx

        call    GetCRTCAddr
        add     dl,6
        sub     cx,cx

wait_notv_loop:
        in      al,dx
        and     al,8
        jz      exit_wait_notv_loop
        loop    wait_notv_loop
        jmp     short wait_v_exit

exit_wait_notv_loop:
        sub     cx,cx

wait_v_loop:
        in      al,dx                           ; read input status 1 reg
        and     al,8                            ; vertical retrace bit 3
        jnz     wait_v_exit
        loop    wait_v_loop

wait_v_exit:

        pop     dx
        pop     cx
        pop     ax

        ExitProc

EndProc WaitVertRetrace

;/***************************************************************************
;*
;* FUNCTION NAME = GetCRTCAddr
;*
;* DESCRIPTION   = Get CRTC Addr adjusted for color or monochrome
;*
;*                 ENTRY POINT: GetCRTCAddr
;*                 LINKAGE:   CALL NEAR
;*
;* INPUT         = NONE
;*
;* RETURN-NORMAL = CRTC Addr in DX
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

Procedure GetCRTCAddr

        push    ax
        mov     dx,3cch
        in      al,dx
        test    al,1
        mov     dx,3d4h
        jnz     get_crtc_1
        mov     dl,0b4h
get_crtc_1:
        pop     ax

        ExitProc

EndProc GetCRTCAddr

;/***************************************************************************
;*
;* FUNCTION NAME = program_clk_chip_s3
;*
;* DESCRIPTION   = Program the S3 clock using 24 bit data
;*                 for desired clock frequency
;*
;* ENTRY POINT: program_clk_chip
;* LINKAGE:     CALL NEAR
;*
;* INPUT         = NONE
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

program_clk_chip_s3:            ;          
        push    bx
        push    cx
        push    dx

        call    unlock_sc       ;unlock sc regs
        call    unlock_s3       ;unlock sc regs

        mov     ah,40h
        call    in_crtc
        push    ax              ;save crtc reg 40h value
        or      al,1            ;enable enhanced command
        call    out_crtc

        mov     ah,42h          ;use bits 1-0 of enhanced clock select
        call    in_crtc         ;this is done to ensure same state as 3C2h
        and     al,0fch         ;cs1 and cs0
        mov     ah,al

        mov     dx,3cch         ;read misc. out reg
        in      al,dx
        push    ax              ;save misc. out reg value
        and     al,0ch          ;mask off cs1 and cs0
        shr     al,1
        shr     al,1
        or      ah,al           ;same clock selection as misc out.
        mov     al,42h          ;get crtc addr, dx has been changed
        call    GetCRTCAddr     ;ret dx=crtc addr 3x4h
        out     dx,ax
        pop     ax
        push    ax              ;misc out reg value
        or      al,0ch          ;set for enhanced clock
        mov     dx,3c2h
        out     dx,al

        mov     cx,25           ;try 25 times if error
skip_0:
        push    cx
        call    p_clock_s3      ;program 24-bit data
        sub     si,2            ;update pointer to clock data for retry
        pop     cx              ;if error

        mov     ah,43h          ;check for alternate i/o enable
        call    in_crtc         ;to read clock programming error bit
        mov     dx,42e8h
        test    al,10h
        jz      skip_1
        mov     dx,4148h
skip_1:
        in      ax,dx           ;use bit 1 from monitor id bits in
        test    al,40h          ;subsystem  status register for clock
        jnz     skip_2          ;if error
        loop    skip_0
skip_2:
        pop     ax
        mov     dx,3c2h         ;restore misc out reg
        or      al,0ch
        out     dx,al
        pop     ax              ;restore crtc reg 40h value
        call    out_crtc
        mov     ah,42h
        call    in_crtc
        or      al,3            ;force enhaced clock
        call    out_crtc
;       call    lock_s3         ;lock s3 regs
;       call    lock_sc         ;lock sc regs

        call    wait_vertical_retrace_stl24
        call    wait_vertical_retrace_stl24
;       call    VGAWait                 ;wait for vertical retrace
;       call    VGAWait                 ;wait for vertical retrace

        pop     dx
        pop     cx
        pop     bx
        ExitProc


p_clock_s3:
        mov     ah,42h          ;sc2
        call    in_crtc         ;setup dx for crtc 3x4h
        xchg    al,ah
        push    ax              ;previous vclock selection
                                ;unlock seq
        or      ah,2            ;data high
        mov     cx,6            ;toggle clk 6 times
        cli
kk_1_s3:
        and     ah,0feh         ;clock low
        out     dx,ax
        or      ah,1            ;clock high
        out     dx,ax
        loop    kk_1_s3

        and     ah,0feh
        out     dx,ax
        and     ah,0fch         ;clock low data low
        out     dx,ax
        or      ah,1            ;clock high
        out     dx,ax
        and     ah,0fch         ;clock low data low
        out     dx,ax
        or      ah,1            ;clock high
        out     dx,ax

        mov     bx,8000h        ;16 bits to send
        call    s3_send_serial
        add     si,2
        mov     bx,80h          ;8 bits to send
        call    s3_send_serial
                                ;stop bit
        or      ah,2            ;data_high
        out     dx,ax
        and     ah,0feh         ;clock low
        out     dx,ax
        or      ah,1            ;clock high
        out     dx,ax
        pop     ax
        out     dx,ax           ;restore prev. clock for vertical retrace

        sti
        ret


s3_send_serial:
        and     ah,0fdh         ;send inverted data first
        test    word ptr cs:[si],bx
        jnz     s3_send_serial_1
        or      ah,2
s3_send_serial_1:
        out     dx,ax           ;not data out
        and     ah,0feh         ;clock low
        out     dx,ax

        xor     ah,2            ;now real data out
        out     dx,ax
        or      ah,1            ;clock high
        out     dx,ax
        shr     bx,1            ;next data bit
        jnc     s3_send_serial
        ret

; input  ah     internal register to set
;        dx     port address of indexed register (data = index+1)
; output al     register value
in_crtc:
        call    GetCRTCAddr             ;get crtc address 3x4h
in_crtc_1:
        xchg    al,ah
        out     dx,al
        inc     dx
        jmp     $+2
        xchg    al,ah
        in      al,dx
        dec     dx
        ExitProc

; input  ah     internal register to set
;        al     value to output
;        dx     port of index register (data register must be index + 1)
out_crtc:
        call    GetCRTCAddr             ;get crtc address 3x4h
out_crtc_1:
        xchg    al,ah
        out     dx,al
        inc     dx
        jmp     $+2
        xchg    al,ah
        out     dx,al
        dec     dx
        ExitProc


; unlock s3 extended regs
unlock_s3:
        mov     ax,3848h
        jmp     short out_crtc

; unlock sc extended regs
unlock_sc:
        mov     ax,39a0h
        jmp     short out_crtc

; lock s3 extended regs
lock_s3:
        mov     ax,3800h
        jmp     short out_crtc

; lock sc extended regs
lock_sc:
        mov     ax,3900h
        jmp     short out_crtc

;;;;;;;;;;begin code for stealth 24
;
eeprom_tab_l            equ     20/2            ;10 words
index_m640              equ     0
index_m640h             equ     1
index_m640t             equ     2
index_m800              equ     3
index_m800h             equ     4
index_m800t             equ     5
index_m1024             equ     6
index_m1024h            equ     7
index_m960              equ     8
index_m1280_16          equ     9
index_m1280_256         equ     10
index_m5455             equ     11

COUNTER                 equ     7fh             ; 2K x 1
mon_port                equ     3c2h
mon_bit                 equ     10h
Read_Miscellaneous      EQU     03CCH           ;Misc output read register

Sequencer               EQU     03C4H           ;Sequencer index register

CRT_3B4                 EQU     03B4H           ;Monochrome CRT index addr
CRT_3D4                 EQU     03D4H           ;Monochrome CRT index addr
BT_FIX                  equ     1

;org_5c                  db      0
;---------------------------------------------------------------------------
;       EEPROM Data Format (Each entry 20 bytes)
;       db      0       ;bit7=vpol. bit6=hpol. bit5=interlace
;                        bit4,3   = reserved
;                        bit2,1,0 = entry
;       db      0,0,0   ;clock data (3 bytes)
eeprom_reg_index        label   byte
        db      3bh,0,1,2,3,4,5,6,7,10h,11h,16h,17h,5Dh,33h,0ffh
;
;---------------------------------------------------------------------------
;       input   (al)=eeprom table entry address
;       output  all registers saved except (ax)
upd_crtc_eeprom:
;htotal adjust
        push    ebx
        push    cx
        push    dx
        push    ax
        call    Find_6845_Address
        mov     ax,0011h                ;unlock crtc
        out     dx,ax
        pop     ax
        mov     ebx, FLAToffset eeprom_reg_index
        push    ax              ;(al)=address of eeprom +0
        inc     al              ;(al)=address of eeprom +1
;       inc     al              ;(al)=address of eeprom +2
pp_1:   inc     al              ;(al)=address of eeprom +3
        push    ax
        call    read_eeprom
        mov     cx,ax
        mov     al,cs:[ebx]
        cmp     al,0ffh
        jz      pp_2
        mov     ah,cl
        out     dx,ax
        inc     bx
        mov     al,cs:[ebx]
        cmp     al,0ffh
        jz      pp_2
        mov     ah,ch
        out     dx,ax
        inc     bx
        pop     ax
        jmp     pp_1

pp_2:   pop     ax
        pop     ax
        push    ax
        call    read_eeprom
        mov     cx,ax
        ;--------------------------------------------;
        ;  update vclk params & interlaced bit       ;
        ;--------------------------------------------;
;set interlace & clock select
        mov     ah,cl
        and     ah,28h          ;entry.5 interlace bit of cr42.5
                                ;entry.3 clk3 bit of cr42.3
        or      ah,3            ;clock select 0,1
        mov     al,42h          ;crtc 42 (clock & interlace)
        out     dx,ax
;set polarity
        push    dx
        mov     dx,3cch
        in      al,dx
        and     al,3fh
        and     cl,0c0h         ;polarity
        or      al,cl
        or      al,0ch          ;clock force to extended
        mov     dx,3c2h
        out     dx,al
        pop     dx
;clock program
        mov     bh,ch           ;1st byte
        pop     ax
        inc     al              ;offset +1
        call    read_eeprom
        mov     cl,al           ;2nd byte
        mov     bl,ah           ;3rd byte
;
        call    program_clk_chip_stl24

        pop     dx
        pop     cx
        pop     ebx
        ExitProc
;
;---------------------------------------------------------------------------
;       input   (cl)= 2nd byte, (bh)=1st byte, (bl)= 3rd byte
;       output  bx,cx destroed
;
;;      public  program_clk_chip_stl24
program_clk_chip_stl24 :
        push    ax
        push    dx

        mov     dx,3c4h
        mov     al,1
        out     dx,al
        mov     ah,al
        inc     dx
        in      al,dx
        push    ax
        or      al,20h
        out     dx,al           ;screen off

        call    Find_6845_Address
        mov     ax,0a039h       ;unlock sc regs
        out     dx,ax
        mov     ax,04838h       ;unlock s3 regs
        out     dx,ax

        mov     ch,80h          ;25     ;1000   ;25
skip_0_stl24:
        push    bx
        push    cx
        call    p_clock_stl24
        pop     cx
        pop     bx
        mov     dx,3c2h
        in      al,dx
        test    al,10h
        jnz     skip_2_stl24
        dec     ch
        jnz     skip_0_stl24
skip_2_stl24:

        mov     dx,3c4h
        mov     al,1
        out     dx,al
        inc     dx
        pop     ax              ;screen recover
        out     dx,al           ;LIN fix 12/17/92 should be al ; not ax

        call    wait_vertical_retrace_stl24
        call    wait_vertical_retrace_stl24

        pop     dx
        pop     ax
        ExitProc

;
;---------------------------------------------------------------------------
;public p_clock
p_clock_stl24:
        mov     dx,3cch         ;read misc. out reg
        in      al,dx
        push    ax              ;save value
        or      al,0ch
        mov     dx,3c2h
        out     dx,al
        call    Find_6845_Address
        mov     al,42h          ;sc2
        out     dx,al
        xchg    al,ah
        inc     dx
        in      al,dx
        xchg    al,ah
        dec     dx
        push    ax              ;previous vclock selection

;unlock seq
        or      ah,2            ;data high
        mov     ch,6    ;5      ;toggle clk 5 times
        cli
kk_1_stl24:
        and     ah,0feh         ;clock low
        out     dx,ax
        out     dx,ax
        or      ah,1            ;clock high
        out     dx,ax
        out     dx,ax
        dec     ch
        jnz     kk_1_stl24

        and     ah,0feh
        out     dx,ax
        out     dx,ax
        and     ah,0fch         ;clock low data low
        out     dx,ax
        out     dx,ax
        or      ah,1            ;clock high
        out     dx,ax
        out     dx,ax
        and     ah,0fch         ;clock low data low
        out     dx,ax
        out     dx,ax
        or      ah,1            ;clock high
        out     dx,ax
        out     dx,ax
;
        mov     ch,24
send_serial_stl24:
        and     ah,0fdh         ;send inverted data first
        shl     bx,1
        rcl     cl,1
        jc      send_serial_1_stl24
        or      ah,2
send_serial_1_stl24:
        out     dx,ax           ;not data out
        out     dx,ax
        and     ah,0feh         ;clock low
        out     dx,ax
        out     dx,ax
        xor     ah,2            ;now real data out
        out     dx,ax
        out     dx,ax
        or      ah,1            ;clock high
        out     dx,ax
        out     dx,ax
        dec     ch
        jnz     send_serial_stl24
;stop bit
        or      ah,2            ;data_high
        out     dx,ax
        out     dx,ax
        and     ah,0feh         ;clock low
        out     dx,ax
        out     dx,ax
        or      ah,1            ;clock high
        out     dx,ax
;
        pop     ax
        out     dx,ax           ;restore prev. clock for vertical retrace
        out     dx,ax
;
        pop     ax              ;save value
        mov     dx,3c2h         ;misc. out reg for vclock recover
        out     dx,al
        sti
        ExitProc
;
;----------------------------------------------------------------------------
;        public  wait_vertical_retrace
;
wait_vertical_retrace_stl24:
        push    ax
        push    cx
        push    dx
        call    Find_6845_Address               ;Get CRTC address
        add     dl,6

        mov     cx,10                           ;          
wv_0:   in      al,dx
        test    al,8
        jnz     wv_1
        loop    wv_0

        mov     cx,10                           ;          
wv_1:   in      al,dx
        test    al,8
        jz      wv_2
        loop    wv_1

wv_2:   pop     dx
        pop     cx
        pop     ax
        ExitProc
;
;---------------------------------------------------------------------------
        ;input cs:(si) = dat table start address to read
        ;all registers save except (ax)
read_eeprom_all:
        push    si
        push    bx
        push    cx
        push    dx
        mov     bl,00h
vcr_3:  push    bx
        call    read_conf
        mov     cs:[si],ax
        pop     bx
        add     si,2
        inc     bl
        and     bl,COUNTER
        jnz     vcr_3
        pop     dx
        pop     cx
        pop     bx
        pop     si
        ExitProc

;---------------------------------------------------------------------------
        ;input al=adress, unlocked
        ;output ax=data
        ;all registers reserved
read_eeprom:
        push    bx
        mov     bx,ax
        call    read_conf
        pop     bx
        ExitProc
;
;---------------------------------------------------------------------------
        ;input bl=adress
        ;output ax=data
        ;all registers reserved
read_conf:
        push    bx
        push    cx
        push    dx
        call    init_ports      ;video disabled ,crtc 41 bit1 set
                                ;(dx)=3d5/3b5   crtc index = 5ch selected
                                ;(al)=crtc 5ch data
;
        mov     bh,bl
        push    bx
        mov     cx,4
        mov     bx,0110000000000000b
        call    send_data_stl24 ;send read command
        pop     bx

        mov     cx,9
        call    send_data_stl24 ;send address
        mov     cx,16
        mov     bx,0
rc_1:
        and     al,0efh         ;clock low
        call    del_out
        shl     bx,1

        push    dx
        push    ax
        mov     dx,mon_port
        in      al,dx
        test    al,mon_bit
        pop     ax
        pop     dx

        jz      rc_2
        or      bl,1
rc_2:
        or      al,10h          ;clock high
        call    del_out
        loop    rc_1

        and     al,0efh         ;clock low
        call    del_out
;LIN    and     al,0bfh          ;chip select low
;LIN    call    del_out
        call    recover_ports
        mov     ax,bx
        pop     dx
        pop     cx
        pop     bx
        ExitProc

;
;---------------------------------------------------------------------------
init_ports:
        mov     dx,3c4h
        mov     al,1
        out     dx,al
        inc     dx
        in      al,dx
        or      al,20h          ;screen off
        out     dx,al

        mov     dx,3cch
        in      al,dx
        mov     dx,3d4h
        test    al,1
        jnz     init_1
        mov     dx,3b4h
init_1:
        mov     ax,04838h
        out     dx,ax           ;unlock s3
        mov     ax,0a539h
        out     dx,ax           ;unlock sc

        mov     al,5ch
        out     dx,al
        inc     dx
        in      al,dx

;       push    ebx
;       mov     ebx,[hvdm]              ;EBX -> VDM
;       mov     byte ptr VDMData.regCRTC5C[ebx],al
;       mov     byte ptr [org_5c] ,al           ; save the original cr.5c
;       pop     ebx

        or      al,40h          ;enable chip
        and     al,0cfh
        out     dx,al
        ret
;
;---------------------------------------------------------------------------
recover_ports:
        push    ebx
        mov     ebx,[hvdm]              ;EBX -> VDM
        mov     al, byte ptr VDMData.aregCRTData[5Ch][ebx]
;       mov     al, byte ptr VDMData.regCRTC5C[ebx]
;       mov     al, byte ptr [org_5c]          ; recover the original cr.5c
        pop     ebx

        and     al,0bfh         ;chip select low
        call    del_out         ;out dx(3d5.5c),al

        dec     dx              ;3d4/3b4
        mov     ax,038h
        out     dx,ax           ;lock s3
        mov     ax,039h
        out     dx,ax           ;lock sc

        mov     dx,3c4h
        mov     al,1
        out     dx,al
        inc     dx
        in      al,dx
        and     al,0dfh         ;screen on
        out     dx,al
        ExitProc

        ;input bl=adress, (ax)=data
        ;output  all registers reserved
write_conf:
        push    bx
        push    cx
        push    dx
        push    ax              ;data
        call    init_ports      ;video disabled ,crtc 41 bit1 set
                                ;(dx)=3d5/3b5   crtc index = 5ch selected
                                ;(al)=crtc 5ch data
                                ;out dx(3d5.5c),al
        mov     bh,bl
        push    bx
        mov     cx,12
        mov     bx,0100110000000000b
        call    send_data_stl24 ;out dx(3d5.5c),al write enable command
        call    a_clock
;       and     al,7fh          ;chip select low
        and     al,0bfh         ;chip select low
        call    del_out         ;out dx(3d5.5c),al
        call    a_clock
;       or      al,80h          ;chip select high
        or      al,40h          ;chip select high
        call    del_out         ;out dx(3d5.5c),al
        mov     cx,4
        mov     bx,0111000000000000b
        call    send_data_stl24 ;out dx(3d5.5c),al  erase command
        pop     bx              ;address
        push    bx
        mov     cx,8
        call    send_data_stl24
        call    a_clock
        and     al,0bfh         ;chip select low
        call    del_out         ;out dx(3d5.5c),al
        call    a_clock
        or      al,40h          ;chip select high
        call    del_out         ;out dx(3d5.5c),al
        call    chk_ready
        mov     cx,4
        mov     bx,0101000000000000b
        call    send_data_stl24 ;out dx(3d5.5c),al   write command
        pop     bx              ;address
        mov     cx,8
        call    send_data_stl24 ;out dx(3d5.5c),al
        mov     cx,16
        pop     bx              ;data
        call    send_data_stl24 ;out dx(3d5.5c),al
        call    a_clock
        and     al,0bfh         ;chip select low
        call    del_out         ;out dx(3d5.5c),al
        call    a_clock         ;clock high to low
        or      al,40h          ;chip select high
        call    del_out         ;out dx(3d5.5c),al
        call    chk_ready
        mov     cx,12
        mov     bx,0100000000000000b
        call    send_data_stl24 ;out dx(3d5.5c),al   write disable command
        call    a_clock
        and     al,0bfh         ;chip select low
        call    del_out         ;out dx(3d5.5c),al
        call    a_clock
        call    recover_ports
        pop     dx
        pop     cx
        pop     bx
        ExitProc

chk_ready:
        push    dx
        push    ax
wait_1: mov     dx,mon_port
        in      al,dx
        test    al,mon_bit
        jz      wait_1
        pop     ax
        pop     dx
        ExitProc

a_clock:
        and     al,0dfh         ;data low
        or      al,10h          ;clock high
        call    del_out
        and     al,0efh         ;clock low
        call    del_out
        ExitProc
;
;---------------------------------------------------------------------------
send_data_stl24:
        and     al,0cfh
        shl     bx,1
        jnc     send_data_1_stl24
        or      al,20h
send_data_1_stl24:
        call    del_out         ;data & clock low
        or      al,10h
        call    del_out         ;clock high
        loop    send_data_stl24
        ExitProc

del_out:
        out     dx,al
        out     dx,al
        out     dx,al
        out     dx,al
        out     dx,al
        out     dx,al
        out     dx,al
        out     dx,al
        out     dx,al
        out     dx,al
        ExitProc
;
;---------------------------------------------------------------------------
Find_6845_Address PROC    NEAR
        PUSH    AX
        MOV     DX,Read_Miscellaneous           ;Get Misc read register
        IN      AL,DX                           ;Read the register
        MOV     DX,CRT_3B4                      ;Set Mono
        TEST    AL,01                           ;0 - MONO 1 - Color
        JE      Set_Mono                        ;Return Mono
        MOV     DX,CRT_3D4                      ;Set Color

Set_Mono:
        POP     AX
        ExitProc
Find_6845_Address ENDP
;
;end code for stealth 24

;/***************************************************************************
;*
;* FUNCTION NAME = GetDACTypeRtn (currently unused)
;*
;* DESCRIPTION   = Diamond specific DAC routine
;*
;*                 ENTRY POINT: GetDACTypeRtn
;*                 LINKAGE:   CALL NEAR
;*
;* INPUT         = NONE
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

Procedure GetDACTypeRtn

        push    bx
        push    dx

        call    cmd_off
        in      al,dx

ddd_1:
        mov     ah,al
        in      al,dx
        cmp     al,ah
        jnz     ddd_1
        mov     bl,al

        mov     ah,8
        call    cmd_on
        cmp     al,8eh
        jz      music_dac

ddd_2:

        in      al,dx
        cmp     al,8eh
        jz      music_dac
        dec     ah
        jnz     ddd_2

        call    cmd_on
        in      al,dx
        mov     bh,al
        call    cmd_off
        mov     al,0ffh
        out     dx,al

        mov     ah,055h

ddd_3:
        call    cmd_on
        mov     al,ah
        out     dx,al
        call    cmd_off
        in      al,dx
        cmp     al,ah
        sub     ah,ah

ddd_4:
        call    cmd_on
        mov     al,bh
        out     dx,al
        call    cmd_off
        mov     al,bl
        out     dx,al

ddd_5:
        pop     dx
        pop     bx
        ExitProc

music_dac:
        call    cmd_off
        mov     ah,2
        jmp short ddd_5

;enable access to dac command register

cmd_on:
        mov     dx,3c9h
        in      al,dx           ;reset sequencer
        mov     dx,3c6h
        in      al,dx
        jmp     $+2
        in      al,dx
        jmp     $+2
        in      al,dx
        jmp     $+2
        in      al,dx
        ExitProc

;disable access to dac command register

cmd_off:
        mov     dx,3c9h
        in      al,dx           ;reset sequencer
        mov     dx,3c6h

        ExitProc

EndProc GetDACTypeRtn

;/***************************************************************************
;*
;* FUNCTION NAME = SetDACCMDReg
;*
;* DESCRIPTION   = Diamond specific DAC routine (currently unused)
;*
;*                 ENTRY POINT: SetDACCMDReg
;*                 LINKAGE:   CALL NEAR
;*
;* INPUT         = NONE
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

Procedure SetDACCMDReg

        push    ax
        call    GetDACTypeRtn
        or      ah,ah
        jz      set_cmd_ret
        cmp     ah,2
        jz      set_cmd_music

        call    cmd_on
        pop     ax
        out     dx,al
        call    cmd_off

set_cmd_ret:
        ExitProc

set_cmd_music:

        mov     ah,10h
        call    cmd_on
        cmp     al,8eh
        jz      qqq_3

qqq_2:
        in      al,dx
        cmp     al,8eh
        jz      qqq_3
        dec     ah
        jnz     qqq_2
        pop     ax
        ExitProc

qqq_3:

        pop     ax
        out     dx,al
        ExitProc

EndProc SetDACCMDReg


        EndCode     EXPORT,SWAP,PASCAL


        END
