;       SCCSID = @(#)clkvdm.asm  6.6 91/10/22
   PAGE  ,132
   NAME  CLOCK
   TITLE Physical Clock Device Driver

;***  Physical Clock Device Driver (CLK)
;
;  SCCSID = @(#)clkvdm.asm 6.6 91/10/22
;
;  IBM/Microsoft Confidential
;
;  Copyright (c) IBM Corporation 1987, 1989
;  Copyright (c) Microsoft Corporation 1987, 1989
;
;  All Rights Reserved
;
;  CLK-VCMS Communication Interface
;
;  DESCRIPTION
;      This module contains all the CLK-VCMOS communication
;      interface procedures.
;
;  MODIFICATION HISTORY
;  02/02/90 MTS   Created.


   .xlist
INCL_MI EQU 1
   include mvdm.inc  ;mvdm definitions for dos macros
   include cmos.inc  ;cmos hardware constants
   include vcmospdd.inc ;definitions common to both cmos VDD and PDD
   include clkseg.inc   ;segment definitions
   .list

   .386p

ClkCode SEGMENT

EVEN              ;make sure it's word aligned
ClkFuncTable label word
   dw offset ClkCode:ClkRegister
   dw offset ClkCode:ClkReadCMOS
ClkMaxFunc  EQU   ($-ClkFuncTable)/2-1


;***LP   ClkVDDProc(ulFunc, ul1, ul2) - VDD request router
;
;  This subroutine is registered by the PDD during system initialization
;  via DevHlp_RegisterPDD, and is called by the VDD to perform various
;  services.  See all the CLKCMD_* equates for a brief list of those
;  services.
;
;  ENTRY
;      (TOS+8) = ulFunc
;      (TOS+4) = ul1
;      (TOS)   = ul2
;
;      Refer to vcmospdd.h for details of ul1 and ul2.
;
;  EXIT
;      SUCCESS
;     (eax) = TRUE
;      FAILURE
;     (eax) = FALSE
;
;  USES
;      All except bx,si,di,bp,ds,es
;
;  CONTEXT
;      VDD Init-time
;      VDM Task-time
;
;  PSEUDOCODE
;      route to appropriate Clk* worker function;
;
;  NOTE
;      Assume function code can be used as direct function table index.

   ASSUME   CS:ClkCode,DS:NOTHING,ES:NOTHING,SS:NOTHING
Procedure ClkVDDProc,far

   ?abase   = 8 + 2     ;%%% ret. addr. is 8 bytes, bp 2 bytes
   ArgVar   ul2,ULONG      ;BUGBUG Procedure, EndProc should
   ArgVar   ul1,ULONG      ;  be changed to support 16:32
   ArgVar   ulFunc,ULONG      ;  type of procedure calling.

   EnterProc
   SaveReg <bx,si,di,ds,es>

   mov   ax,ClkData
   mov   ds,ax
   ASSUME   DS:ClkData

   sub   eax,eax     ;assume failure

   mov   bx,WORD PTR [ulFunc] ;(bx)=ulFunc
   sub   bx,CLKCMD_REGISTER   ;don't make assumptions on register equ
   cmp   bx,ClkMaxFunc     ;is it a valid function?
   ja cvpx        ;NO, goto error exit

   shl   bx,1        ;adjust bx as word index

   mov   cx,WORD PTR [ul1+2]
   mov   si,WORD PTR [ul1] ;(cx:si)=ul1
   mov   dx,WORD PTR [ul2+2]
   mov   di,WORD PTR [ul2] ;(dx:di)=ul2

   call  cs:ClkFuncTable[bx]  ;process requested function

cvpx: RestoreReg <es,ds,di,si,bx>
   ASSUME   DS:NOTHING

   LeaveProc

   retfd ?aframe     ;%%%

EndProc ClkVDDProc


;***LP   ClkRegister() - VDD registration
;
;  Record the entry point being registered for the VDD.  This is in
;  response to CLKCMD_REGISTER and is invoked by the VDM manager
;  in VDHOpenPDD.
;
;  ENTRY
;      (si:dx,di) = NULL -> VDD entry point
;
;  EXIT
;      SUCCESS
;         (eax) = TRUE  //always successful
;
;  USES
;      None
;
;  CONTEXT
;      VDD Init-time
;
;  NOTE
;      Currently, we don't need a VCMOS entry point.
;      So we just store it and forget about it.  This routine
;      must be present because VDM manager will call us no matter
;      we have a valid entry point or not.
;
;  PSEUDO-CODE

   ASSUME   CS:ClkCode,DS:ClkData,ES:NOTHING,SS:NOTHING
Procedure ClkRegister,near

   mov   eax,CTRUE         ;return success

   ret

EndProc ClkRegister


;***LP   ClkReadCMOS() - VDD Read CMOS
;
;  The VDD call this procedure to read the CMOS locations.
;
;  ENTRY
;      (cx:si) -> ReadReq
;      (dx:di) -> CMOSArray
;
;  EXIT
;      SUCCESS
;     (eax) = TRUE
;
;  USES
;      All
;
;  CONTEXT
;      VDM Task
;
;  NOTE
;      This function always succeeds because we will enforce a
;      valid CMOS address range by masking the extra address bits.
;
;  PSEUDOCODE
;      fChanged = FALSE;
;      do {
;     for each byte in the range specified {
;         read CMOS;
;         if it has been changed since the last iteration {
;        fChanged = TRUE;
;        store the new value;
;         }
;     }
;      } while (fChanged);

   ASSUME   CS:ClkCode,DS:ClkData,ES:NOTHING,SS:NOTHING
Procedure ClkReadCMOS,hybrid

   mov   ds,cx       ;(ds:si)->ReadReq packet
   mov   es,dx       ;(es:di)->CMOS array

crc10:   mov   bx,di       ;(es:bx)->CMOS array
   mov   al,[si].rdrq_CMOSAddr   ;(al)=start CMOS address
   and   al,ADDR_MASK      ;make sure address within range
   xor   ch,ch
   mov   cl,[si].rdrq_nbCMOS  ;(cx)=number of bytes to read
   xor   dx,dx       ;(dx)=fChanged=FALSE

crc20:  pushf
   cli
   out   PORT_ADDRLATCH,al ;set port address
   inc   al       ;(al)=next port
   xchg  al,ah       ;(ah)=next port address
   IODelay
   in al,PORT_DATALATCH ;(al)=value of CMOS location
   popf
   cmp   al,es:[bx]     ;is this byte the same as before?
   je crc30       ;YES, continue

   inc   dx       ;set fChanged flag
   mov   es:[bx],al     ;store new value

crc30:   inc   bx       ;increment buffer pointer
   xchg  ah,al       ;(al)=next port address
   loop  crc20       ;read next byte if we are not done yet

   cmp   dx,0        ;have CMOS values changed?
   jne   crc10       ;YES, try again

   mov   al,ADDR_DIAGS+ADDR_NMIENABLE;re-enable NMI
   pushf
   cli
   out   PORT_ADDRLATCH,al
   IODelay
   in al,PORT_DATALATCH ;dummy read
   popf

   mov   eax,CTRUE      ;return TRUE
   ret

EndProc ClkReadCMOS

ClkCode ENDS


   END
