SCCSID  equ     "@(#)devhlp2.asm        6.4 91/04/28"
;
;       IBM/Microsoft Confidential
;
;       Copyright (c) IBM Corporation 1987, 1989
;       Copyright (c) Microsoft Corporation 1987, 1989
;
;       All Rights Reserved
;
PAGE    ,132
TITLE   DevHlp2 - Dos routines to help device drivers

;********************************************************************
;*                                                                  *
;*      SOURCE FILE NAME: DEVHLP2.ASM                               *
;*                                                                  *
;*      DESCRIPTIVE NAME: Device Driver Helper Routines             *
;*                                                                  *
;*      STATUS: Version 1.0                                         *
;*                                                                  *
;*      FUNCTION:                                                   *
;*                                                                  *
;*      This module provides WINTHORN support for device drivers.   *
;*                                                                  *
;*      Some subfunctions are only valid at task-time, some at      *
;*      interrupt time, and some both.  Most of these subfunctions  *
;*      are offered as a convenience, it may be required that some  *
;*      be used... see the individual documentation.                *
;*                                                                  *
;*      ENTRY POINTS: dh_RealToProt - Switch from Real to           *
;*                                    Protect Mode                  *
;*                    dh_ProtToReal - Switch from Protect to        *
;*                                    Real Mode                     *
;*                    dh_VerifyAccess - Verify access to memory     *
;*                    dh_RAS - Put info in RAS trace buffer         *
;*                    dh_AttachDD - Attach to a device driver       *
;*                    dh_InternalError - Signal an internal error   *
;*                    dh_Beep - Device beep                         *
;*                    dh_RegisterBeep - Register beep device entry  *
;*                    dh_RegisterFreq - Register freq device entry  *
;*                                                                  *
;*      EXTERNAL REFERENCES:                                        *
;*               ROUTINES: ProtMode                                 *
;*                         RealMode                                 *
;*                         ProbeBuff                                *
;*                         K_S_Systrace                             *
;*        DATA STRUCTURES:                                          *
;*                                                                  *
;*  80030 3/2/94 RAC Modify dh_RAS to set cary flag and return      *
;*               when RAS flag is not set                           *
;*                                                                  *
;********************************************************************

.xlist
.xcref
include basemid.inc
include dosseg.inc
include basemaca.inc
include osmaca.inc
include fnodev.inc
include devsym.inc
include error.inc
include mi.inc
include pmode.inc
include struc.inc
;
; Below added for CP20 DCR 1152
;
include infoseg.inc
INCL_ERROR_H    EQU     1               ; for error.inc  EQUates
INCL_ERROR2_H   EQU     1               ; for error2.inc EQUates
include bseerr.inc

include beep.inc
.cref
.list

        ModName , FNO_DEVHLP2_ASM

        extrn           ProtMode:near           ; in modesw.asm
        extrn           RealMode:near           ; in modesw.asm
        extrn           SelToSeg:near           ; in modesw.asm
        extrn           SYISaveMessage:near     ; in iniproc1.asm, DCR 847 cp20

        EXTRNFAR        _InternalError
        ;
        ; Taken out for CP20 DCR 1152
        ;
        ;EXTRNFAR        KernelLogEntry          ; Log Data
        EXTRNFAR        ProbeBuff               ; in setfetum.asm
        EXTRNFAR        ProcRun                 ; run a blocked procedure

        EXTRN32         _BeepPreempt            ; in beep.c

IF RAS
        EXTRNFAR        K_S_Systrace            ; in rasstrp.asm
ENDIF
        ReferGlobal     CONdev,DWORD

if RAS
        ReferGlobal     ras_stda_addr,WORD      ; Trace selector
endif ;RAS

        ;
        ; Taken out for CP20 DCR 1152
        ;
        ;ReferGlobal     LogBufferSelector,WORD  ; Log selector
        ;
        ; Added reference to shadow global info seg for DCR 1152
        ;
        EXTRN            SISData:WORD            ; InfoSeg
        ReferGlobal      _Sis2,BYTE              ; Infoseg copy

        ReferGlobal     VideoPauseFlag,BYTE     ; flag for VideoPause
        ReferGlobal     VPUserSelector,WORD     ; Ring 3 selector for flag
        ReferFlat       _f32pfnPTDBeep,fword    ; in kbeep.c
        ReferFlat       _f32pfnCLKFreq,fword    ; in kclock.c

dhFrame struc                           ; stack frame for device drivers
        dh_procBP       dw ?            ; proc's BP
        dh_saveAX       dw ?            ; caller's AX
        dh_saveBP       dw ?            ; area to hold bp
        dh_EnterProc    dw ?            ; saved BP from enterproc
        dh_saveHY       dw ?            ; IP value from DevHlp Router
        dh_IP           dw ?            ; device driver's IP
        dh_CS           dw ?            ; device driver's CS
dhFrame ends

IDCFrame struc
        IDCRealOff      dw ?            ; Real mode IDC entry point
        IDCRealCS       dw ?            ; Real mode CS
        IDCRealDS       dw ?            ; Real mode DS
        IDCProtOff      dw ?            ; Protect mode IDC entry point
        IDCProtCS       dw ?            ; Protect mode CS
        IDCProtDS       dw ?            ; Protect mode DS
IDCFrame ends


;
; Added below for CP20 DCR 1152
; ..\task\errlog.asm also uses these fields
;
Public  LogDDCS,LogDDIdc,LogDDDS

DATA segment

EVEN
LogDDCS           dw 0                  ; CS for LOG$ device driver
LogDDIdc          dw 0                  ; Offset of LOG$ IDC routine
LogDDDS           dw 0                  ; DS for LOG$ device driver

DATA ends



        FARCODE LOW
CODE    SEGMENT


BREAK <dh_RealToProt - Switch from Real to Protect Mode>
;********************** START OF SPECIFICATIONS **********************
;* SUBROUTINE NAME:  dh_RealToProt                                   *
;*                                                                   *
;* DESCRIPTIVE NAME: Switch from Real to Protect Mode                *
;*                                                                   *
;* FUNCTION:                                                         *
;*                                                                   *
;*   Changes the machine's execution mode from Real to Protected.    *
;*   This call is used by a device driver which has recieved control *
;*   in Real mode but which has GDT selectors filled in by a         *
;*   PhysToGDTSelector request it must access.  Callable only at     *
;*   interrupt time.                                                 *
;*                                                                   *
;*         This routine performs the necessary operations required   *
;*         to switch the processor from Real to Protect mode.        *
;*         The ES register will contain zero upon exit.              *
;*         The SS register will point to the interrupt stack.        *
;*                                                                   *
;* NOTES:                                                            *
;*                                                                   *
;* ENTRY POINT: dh_RealToProt                                        *
;*    LINKAGE:  NEAR                                                 *
;*                                                                   *
;* INPUT:       DS:SI  = Device Header of Requesting Device Driver   *
;*                                                                   *
;* EXIT-NORMAL: CF = 0                                               *
;*              ES = 0                                               *
;*              CS = Caller's Protect Mode CS                        *
;*              DS = Caller's Protect mode DS                        *
;*              SS = Interrupt stack                                 *
;*                                                                   *
;* EXIT-ERROR:  CF = 1                                               *
;*              Processor is already in Protect Mode                 *
;*                                                                   *
;* EFFECTS:     All other registers preserved                        *
;*              Processor is placed in Protect Mode                  *
;*                                                                   *
;* INTERNAL REFERENCES:                                              *
;*    ROUTINES:                                                      *
;*                ProtMode                                           *
;*                                                                   *
;* EXTERNAL REFERENCES:                                              *
;*    ROUTINES:                                                      *
;*********************** END OF SPECIFICATIONS ***********************

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

Procedure dh_RealToProt

InternalError <dh_RealToProt was called.>
ret

EndProc dh_RealToProt


BREAK <dh_ProtToReal - Switch from Protect to Real Mode>
;********************** START OF SPECIFICATIONS **********************
;*                                                                   *
;* SUBROUTINE NAME:  dh_ProtToReal                                   *
;*                                                                   *
;* DESCRIPTIVE NAME: Switch from Protect to Real Mode                *
;*                                                                   *
;* FUNCTION:                                                         *
;*                                                                   *
;*   Changes the machine's execution mode from Protected back        *
;*   to Real.  This call is used following device driver processing  *
;*   which was done in Protected mode as a result of an earlier      *
;*   RealToProt request.  Callable only at interrupt time.           *
;*                                                                   *
;*         This routine performs the necessary operations required   *
;*         to switch the processor from Protect to Real mode.        *
;*         If present, ABIOS will be used to perform the mode        *
;*         switch.  If ABIOS is not present the Mode Switch Manager  *
;*         will perform the mode switch using the Personal Computer  *
;*         AT ROM shut down facility.  This routine should only      *
;*         be called when the processor is in protect mode.          *
;*                                                                   *
;* NOTES:                                                            *
;*   none                                                            *
;*                                                                   *
;* ENTRY POINT: dh_ProtToReal                                        *
;*    LINKAGE:  NEAR                                                 *
;*                                                                   *
;* INPUT:       DS:SI  = Device Header of Requesting Device Driver   *
;*                                                                   *
;* EXIT-NORMAL: CF = 0                                               *
;*              ES = Same as DS                                      *
;*              CS = Caller's Real mode CS                           *
;*              DS = Caller's Real mode DS                           *
;*              SS = Interrupt stack                                 *
;*                                                                   *
;* EXIT-ERROR:  CF = 1                                               *
;*              Processor is already in Real Mode                    *
;*                   AX = ERROR_STACK_IN_HIGH_MEMORY                 *
;*                                                                   *
;* EFFECTS:     All other registers preserved                        *
;*              Processor is placed in Real Mode                     *
;*                                                                   *
;* INTERNAL REFERENCES:                                              *
;*    ROUTINES:                                                      *
;*                    RealMode                                       *
;*                                                                   *
;* EXTERNAL REFERENCES:                                              *
;*    ROUTINES:                                                      *
;*                                                                   *
;*********************** END OF SPECIFICATIONS ***********************

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

Procedure dh_ProtToReal

InternalError <dh_ProtToReal was called.>
ret

EndProc dh_ProtToReal

BREAK <dh_RAS - Put info in RAS trace buffer>
;********************** START OF SPECIFICATIONS **********************
;*                                                                   *
;* SUBROUTINE NAME:  dh_RAS                                          *
;*                                                                   *
;* DESCRIPTIVE NAME: Put info in RAS trace buffer                    *
;*                                                                   *
;* FUNCTION: Record data to RAS trace buffer.  The device driver     *
;*           must check to see if tracing is turned on for the       *
;*           major event code being traced before calling dh_RAS.    *
;*           The macro 'TESTDD <major event code>' is a facility     *
;*           to do this.                                             *
;*                                                                   *
;* NOTES:                                                            *
;*                                                                   *
;* ENTRY POINT: dh_RAS                                               *
;*    LINKAGE:  NEAR (from DosCode)                                  *
;*                                                                   *
;* INPUT:       AX    = Major event code                             *
;*              BX    = Data length (bytes)                          *
;*              CX    = Minor event code                             *
;*              DS:SI = -> data to be passed to K_S_Systrace         *
;*                                                                   *
;* EXIT-NORMAL: CF = 0                                               *
;*              SYSTEM TRACE DATA AREA MODIFIED                      *
;*                                                                   *
;* EXIT-ERROR:  CF = 1                                               *
;*                                                                   *
;* EFFECTS: Flags                                                    *
;*                                                                   *
;*          FS and GS must be preserved (DevHelp requirement)        *
;*                                                                   *
;* INTERNAL REFERENCES:                                              *
;*    ROUTINES:                                                      *
;*                    K_S_SYSTRACE                                   *
;*                                                                   *
;* EXTERNAL REFERENCES:                                              *
;*    ROUTINES:                                                      *
;*                                                                   *
;*********************** END OF SPECIFICATIONS ***********************


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

Procedure dh_RAS

IF RAS
        push dx
        push es
        DosContext es
        cmp  es:ras_stda_addr,1        ; Is tracing available?
                                       ; carry set if addr is 0
        jb   tx0010                    ; NO, leave procedure
        mov  dx,cx
        CALLFAR K_S_Systrace
tx0010:
        pop  es
        pop  dx
                                       ; 80030 Start
ELSE
        stc                            ; Set carry flag and return if
                                       ; we don't support RAS
ENDIF ;RAS                             ; 80030 End

        ret


EndProc dh_RAS

BREAK <dh_AttachDD - Attach to a device driver>
;********************** START OF SPECIFICATIONS **********************
;*                                                                   *
;* SUBROUTINE NAME:  dh_Attach                                       *
;*                                                                   *
;* DESCRIPTIVE NAME: Attach to a device driver                       *
;*                                                                   *
;* FUNCTION:                                                         *
;*                                                                   *
;*   Get the addressability to the Inter-device driver communication *
;*   (IDC) entry point to the specified device driver.               *
;*                                                                   *
;* NOTES:                                                            *
;*                                                                   *
;* ENTRY POINT: dh_AttachDD                                          *
;*    LINKAGE:  NEAR                                                 *
;*                                                                   *
;* INPUT:       BX = OFFSET DS:ddname  (Name of other device driver) *
;*              DI = OFFSET DS:dd@     (Data area to hold address)   *
;*                                                                   *
;* EXIT-NORMAL: CF = 0   Data Area filled in                         *
;*                                                                   *
;* EXIT-ERROR:  CF = 1   Device driver not found or                  *
;*                       no IDC entry point                          *
;*                                                                   *
;* EFFECTS:     All registers preserved                              *
;*              FS and GS must be preserved (DevHelp requirement)    *
;*                                                                   *
;* INTERNAL REFERENCES:                                              *
;*    ROUTINES:                                                      *
;*                                                                   *
;* EXTERNAL REFERENCES:                                              *
;*    ROUTINES:                                                      *
;*                                                                   *
;*********************** END OF SPECIFICATIONS ***********************

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

Procedure dh_AttachDD

LocalVar found,WORD                             ; Found boolean operator

EnterProc

SaveReg         <ax,cx,es,si>
DosContext      es
mov     [found], 0
push    di
mov     di,OFFSET DOSGROUP:CONdev               ; ES:DI = 1st DevHdr
mov     si, bx                                  ; DS:SI = Name of DD
cld
push    di
lea     di, [di].SDevName                       ; ES:DI = Name of 1st DD
mov     cx, 8
SaveReg         <si>
repe    cmpsb
RestoreReg      <si>
pop     di                                      ; ES:DI = Pointer to next DD
.while  < [found] eq 0 > and
.while  < es:[di] ne 0ffffH >
        mov     ax, es:[di+2]
        mov     di, es:[di]
        mov     es, ax
        push    di
        lea     di, [di].SDevName               ; ES:DI = Name of DD
        mov     cx, 8
        SaveReg         <si>
        repe    cmpsb
        RestoreReg      <si>
        .if < eq >
                mov     [found], 1
        .endif
        pop     di                              ; ES:DI = Pointer to next DD
.endwhile
mov     si, di
pop     di
.if     < [found] eq  1 >
        mov     ax, es:[si].SDevInt
        mov     ds:[di].IDCRealOff, ax
        mov     ax, es:[si].SDevRealCS
        mov     ds:[di].IDCRealCS, ax
        mov     ax, es:[si].SDevRealDS
        mov     ds:[di].IDCRealDS, ax
        mov     ax, es:[si].SDevInt
        mov     ds:[di].IDCProtOff, ax
        mov     ax, es:[si].SDevProtCS
        mov     ds:[di].IDCProtCS, ax
        mov     ax, es:[si].SDevProtDS
        mov     ds:[di].IDCProtDS, ax
        clc
.else
        stc
.endif
RestoreReg      <si,es,cx,ax>

LeaveProc

ret

EndProc dh_AttachDD


BREAK <dh_InternalError - Signal an internal error>
;********************** START OF SPECIFICATIONS **********************
;* SUBROUTINE NAME:  dh_InternalError                                *
;*                                                                   *
;* DESCRIPTIVE NAME: Signal an internal error                        *
;*                                                                   *
;* FUNCTION:                                                         *
;*                                                                   *
;*   For reliability, if a device driver detects an internal         *
;*   inconsistancy during normal operation, the safest thing         *
;*   may be for the device driver to shut down the entire            *
;*   system.                                                         *
;*                                                                   *
;*   This DevHlp routine should only be used when an internal        *
;*   inconsistancy is detected.  This is a panic situation,          *
;*   where the system might be unable to continue safely.            *
;*   This should only be used when the operation of the system       *
;*   is questionable.  A minor device driver (printer, com, etc.)    *
;*   probably would never use this routine.                          *
;*                                                                   *
;*   The message display code is very limited.  The message should   *
;*   contain ASCII characters in the range 0x20-0x7E, with optional  *
;*   0x0D and 0x0A to break the text into multiple lines.            *
;*                                                                   *
;*   The message text must be prefaced with the device driver name.  *
;*                                                                   *
;* NOTES:                                                            *
;*                                                                   *
;* ENTRY POINT: dh_InternalError                                     *
;*    LINKAGE:  NEAR                                                 *
;*                                                                   *
;* INPUT:       DS:SI  = message_text of '$' terminated string       *
;*              DI     = message_text_length                         *
;*                                                                   *
;* EXIT-NORMAL: This routine NEVER returns to the caller.            *
;*                                                                   *
;* EFFECTS:                                                          *
;*                                                                   *
;* INTERNAL REFERENCES:                                              *
;*    ROUTINES:       _InternalError                                 *
;*                                                                   *
;* EXTERNAL REFERENCES:                                              *
;*    ROUTINES:                                                      *
;*********************** END OF SPECIFICATIONS ***********************

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

Procedure dh_InternalError
        mov     cx,di
        CALLFAR _InternalError
        ret                     ; allows debugger tracing
EndProc dh_InternalError


BREAK <dh_LogEntry - Place Data in the Log Buffer>

;*************** START OF SPECIFICATIONS ******************************
;
; SUBROUTINE NAME: dh_LogEntry
;
; DESCRIPTIVE NAME: DevHelp Routine to place data in OS/2 log buffer
;
; FUNCTION: This routine is called by Device Drivers to place
;           data in the kernel error log circular buffer.
;
; NOTE:     Callable at interrupt, user, or task time.
;
; ENTRY POINT: dh_LogEntry
;    LINKAGE:  CALL near from CODE segment
;
; INPUT:
;        CX    -  Function code
;              0x00  -  Reserved
;              0x01  -  Log Data to buffer(format 1.x)
;              0x90  -  Log Data to buffer(format 2.x)
;                     ES:BX -> Pointer to data to be placed in error log buffer
;              0x80  -  Init logging(store log.sys ptr to header)
;                     ES:BX -> Pointer to LOG$ device driver header
;              0x81  -  Suspend logging(clear global infoseg bit)
;              0x82  -  Resume  logging(set global infoseg bit)
;
; EXIT-NORMAL:  Carry Clear
;
; EXIT-ERROR:   Carry Set  AX = error code
;
; EFFECTS:
;    Uses:  None
;
;           FS and GS must be preserved (DevHelp requirement)
;
; EXTERNAL REFERENCES:
;    ROUTINES: KernelLogEntry - place data in log buffer
;*************** END OF SPECIFICATIONS ********************************


Procedure dh_LogEntry
ASSUME  ds:nothing, es:nothing, ss:nothing

; First Set up the parameters as required by the LogEntry Kernel
; procedure.  We will then change modes if neccessary.

LocalVar logdd,DWORD                             ; Addr of LOG$ IDC

EnterProc

    SaveReg <ds,es,fs,gs,bx,cx,dx,si,di>

    .386p
    NullContext <fs,gs>,di              ; zero FS and GS in case we block
    CpuMode reset

    DosContext ds                       ; DOSGROUP
    mov  ax,ERROR_LF_INVALID_FUNCTION   ; Init Error code

    cmp  cx,90h                         ; Add 2.x Log Entry packet?
    je   ddentry
    cmp  cx, 1h                         ; Add 1.x Log Entry packet?
    je   ddentry
    cmp  cx,80h                         ; Init Logging?
    je   initlog1
    cmp  cx,81h                         ; Suspend Logging?
    je   suspendlog
    cmp  cx,82h                         ; Resume Logging?
    je   resumelog
    jmp     ex0010                      ; error, get out
;
; First check to see if Error Logging is available (Initialized).
; If it isn't return an error.
;
ddentry:
    mov  ax,ERROR_LF_NOT_AVAIL                  ; Assume not available
    test ds:SISData.SIS_SysLog,LF_LOGAVAILABLE  ; Test for available
    .if <nz>                                    ; Is Logging available?
      ;
      ; Make sure logging is enabled, if it is suspended, return an error
      ;
      mov ax,ERROR_LF_SUSPENDED                 ; Yes, Init Error code
      test ds:SISData.SIS_SysLog,LF_LOGENABLE
      .if <nz>                                  ; Is Logging available?
         .if <LogDDCS ne 0>                      ; Is Device CS OK?
           ;
           ; Get CS:offset and DS of LOG$ IDC
           ;
           mov     ax,LogDDIdc                    ; IDC offset
           mov WORD PTR logdd,ax                  ; store IDC offset to call
           mov     ax,LogDDCS                     ; get CS
           mov WORD PTR logdd[2],ax               ; store cs of LOG$
           mov     ax,LogDDDS
           mov     ds,ax                          ; change DS - to LOG$ DS
           ;
           ; Call LOG$ IDC routine with CX=function(type of record)
           ;           ES:BX -> log packet
           ;           Return: AX = 0 or error code
           ;
           call    DWORD PTR [logdd]              ; call using local var(SS)
        .endif
      .endif
    .endif
    jmp     ex0010                                ; done, get out

suspendlog:
    mov     es,[_Sis2].is_sel                   ; get GINFO copy selector
    and DOSGROUP:SISData.SIS_SysLog,not LF_LOGENABLE ; Yes, Suspend
    and es:SIS_SysLog,not LF_LOGENABLE               ; update copy
    xor     ax,ax
    jmp     ex0010
resumelog:
    mov     es,[_Sis2].is_sel                   ; get GINFO copy selector
    or  DOSGROUP:SISData.SIS_SysLog,LF_LOGENABLE ; Resume bit
    or  es:SIS_SysLog,LF_LOGENABLE               ; update copy
    xor     ax,ax
    jmp     ex0010
initlog1:
    ;
    ; Caller was LOG$ device driver to initialize kernel variables
    ;        ES:BX -> device header for LOG$
    ;        Store Device Header DS, CS and IDC offset
    ;
    .if <LogDDCS eq 0>
            ;
            ; es - selector for LOG$ device header
            ; bx - offset of device header for LOG$
            ;
            mov     si, bx
            ;
            ; Store CS:IDC offset and DS of LOG$ device driver
            ;
            mov     ax, es:[si].SDevInt      ; Store LOG$ IDC offset
            mov     LogDDIdc,ax
            mov     ax, es:[si].SDevProtCS   ; Store LOG$ CS
            mov     LogDDCS,ax
            mov     ax, es:[si].SDevProtDS   ; Store LOG$ DS
            mov     LogDDDS,ax
            ;
            ; Update both copies of Global Info Seg to enable logging
            ;
            mov  es,[_Sis2].is_sel           ; shadow GINFO
       or   DOSGROUP:SISData.SIS_SysLog,LF_LOGENABLE+LF_LOGAVAILABLE ; Enable
       or   es:SIS_SysLog,LF_LOGENABLE+LF_LOGAVAILABLE          ; update copy
            xor     ax,ax                    ; clear error
    .endif
ex0010:
    cmp ax,1                                   ; set carry if AX = zero
    cmc                                        ; reverse carry flag

    RestoreReg <di,si,dx,cx,bx,gs,fs,es,ds>

LeaveProc
    ret

EndProc dh_LogEntry

;********************** START OF SPECIFICATIONS **********************
;*                                                                   *
;* SUBROUTINE NAME:  Save_Message                                    *
;*                                                                   *
;* DESCRIPTIVE NAME: Save and Display Initialization Messages        *
;*                                                                   *
;* FUNCTION: Right after system has been initialized previously      *
;*           saved messages will be displayed.                       *
;*                                                                   *
;* NOTES:                                                            *
;*                                                                   *
;* ENTRY POINT: Save_Messages                                        *
;*    LINKAGE:  NEAR                                                 *
;*                                                                   *
;* INPUT:       DS:SI = address of SysInit Message Table (SMT)       *
;*                      containing the following data:               *
;*                        SMT_Message_ID = message ID                *
;*                        SMT_No_Vars    = number of insertion items *
;*                        SMT_Var_Ptr    = address of ASCIIZ string  *
;*                                         (repeated n times)        *
;*                                                                   *
;* EXIT-NORMAL:                                                      *
;*                                                                   *
;* EXIT-ERROR:                                                       *
;*                                                                   *
;* EFFECTS:     All registers preserved                              *
;*                                                                   *
;*          FS and GS need not be preserved (DevHelp requirement)    *
;*            since devhlp does not block.                           *
;*                                                                   *
;* INTERNAL REFERENCES:                                              *
;*    ROUTINES:                                                      *
;*                                                                   *
;* EXTERNAL REFERENCES:                                              *
;*    ROUTINES:                                                      *
;*                                                                   *
;*********************** END OF SPECIFICATIONS ***********************

Procedure  Save_Message
        SaveReg <es,si,bx>
        call    SYISaveMessage
        RestoreReg <bx,si,es>
        ret
EndProc     Save_Message

;********************** START OF SPECIFICATIONS **********************
;*                                                                   *
;* SUBROUTINE NAME:  dh_VideoPause                                   *
;*                                                                   *
;* DESCRIPTIVE NAME: Start/Stop Video pause Daemon                   *
;*                                                                   *
;* FUNCTION: Will start or stop a high priority daemon (currently in *
;*           session manger which will halt video activity to DMA    *
;*                                                                   *
;* NOTES:                                                            *
;*                                                                   *
;* ENTRY POINT: dh_VideoPause                                        *
;*    LINKAGE:  NEAR                                                 *
;*                                                                   *
;* INPUT:       AL = 1 activate video pause                          *
;*                 = 0 deactive video pause                          *
;*                                                                   *
;* EXIT-NORMAL: CF = 0   OK                                          *
;*                                                                   *
;* EXIT-ERROR:  CF = 1   Daemon not active                           *
;*                       Too many 0s (underflow)                     *
;*                                                                   *
;* EFFECTS:     All registers preserved                              *
;*                                                                   *
;*          FS and GS must be preserved (DevHelp requirement)        *
;*                                                                   *
;* INTERNAL REFERENCES:                                              *
;*    ROUTINES:                                                      *
;*                                                                   *
;* EXTERNAL REFERENCES:                                              *
;*    ROUTINES:                                                      *
;*                                                                   *
;*********************** END OF SPECIFICATIONS ***********************
;   New Code for DCR 607
ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING  ;
Procedure dh_VideoPause         ;

SaveReg <gs, fs>                ; Preserved in case we block
NullContext <fs,gs>             ; zero FS and GS in case we block

SaveReg <ds,es,ax,bx>           ;
DosContext ds                   ; set up DS
.if <VPUserSelector eq 0>       ; see if user selector exists
    stc                         ; not been set up yet - error
    jmp short VPdone            ; leave
.endif                          ;
.if <al eq 0>                   ; if parm is zero "Turn Off"
    .if <VideoPauseFlag eq 0>   ; if the flag is zero
        stc                     ; error - underflow
        jmp short VPdone        ; leave
    .else                       ;
        dec VideoPauseFlag      ; dec the flag
    .endif                      ;
.else                           ; "Turn On" videopause
    inc VideoPauseFlag          ; inc the flag
    mov ax,ds                   ; id is addr of VideoPauseFlag
    mov bx,offset DOSGROUP:VideoPauseFlag   ;
    CALLFAR ProcRun             ; wake up daemon
.endif                          ;
VPdone:                         ;
RestoreReg <bx,ax,es,ds>        ;

RestoreReg <fs, gs>             ; We saved them in case we blocked.

ret                             ;
EndProc dh_VideoPause           ;


;***LP  dh_Beep(usFreq, usDuration) - Device Help Beep Service
;
;       This DevHelp service is called by other PDDs to generate
;       preempt beeps.
;
;       ENTRY
;           (bx) - usFreq = beep freq. in Hz
;           (cx) - usDuration = beep duration in msec.
;
;       EXIT-SUCCESS
;           (ax) = 0
;       EXIT-FAILURE
;           (ax) = error code
;
;       USES
;           None
;           FS and GS must be preserved (DevHelp requirement)
;
;       CONTEXT
;           Task
;           Interrupt
;
;       PSEUDOCODE
;

        ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING
Procedure dh_Beep,NEAR

        .386p
        SaveReg <ds,es,fs,gs>                   ;save registers
        NullContext <fs,gs>
        FlatContext <ds,es>

        mov     eax,BEEP_TIMED
        movzx   ebx,bx                          ;(ebx)=ulFreq
        movzx   ecx,cx                          ;(ecx)=ulDuration
;BeepPreempt(eax=usFunc,ebx=ulParam1,ecx=ulParam2)
        CCALL32 _BeepPreempt,<eax,ebx,ecx>      ;(eax)=error code

        RestoreReg <gs,fs,es,ds>                ;restore registers
        CpuMode reset
        ret

EndProc dh_Beep


;***LP  dh_RegisterBeep(f16pfn) - Register the PDD beep service entry point
;
;       This DevHelp service is called by the clock device driver
;       during initialization time to register the beep service
;       entry point so that other device drivers or the kernel
;       can generate prempt beeps.
;
;       ENTRY
;           (cx:di)->f16pfn = entry point to PTDBeep
;
;       EXIT
;           (ax) = 0
;
;       USES
;           None
;
;           FS and GS must be preserved (DevHelp requirement)
;
;       PSEUDOCODE
;           store PTDBeep entry point into f32pfnPTDBeep;

        ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING
Procedure dh_RegisterBeep,NEAR

        .386p
        push    ds                      ;save ds
        FlatContext <ds>

        movzx   edi,di
        mov     DWORD PTR [_f32pfnPTDBeep],edi
        mov     WORD PTR [_f32pfnPTDBeep+4],cx;store the entry point
        xor     ax,ax                   ;return code=0

        pop     ds                      ;restore ds
        CpuMode reset
        ret

EndProc dh_RegisterBeep


;***LP  dh_RegisterFreq(f16pfn) - Register the PDD Freq service entry point
;
;       This DevHelp service is called by the clock device driver
;       during initialization time to register the Freq service
;       entry point so the kernel can change the periodic interrupt
;       frequency.
;
;       ENTRY
;           (ax) = initial periodic frequency in cycles per second (Hz)
;           (cx:di)->f16pfn = entry point to CLKFreq
;
;       EXIT
;           (ax) = 0
;
;       USES
;           None
;
;           FS and GS must be preserved (DevHelp requirement)
;
;       PSEUDOCODE
;           store CLKFreq entry point into f32pfnCLKFreq;

        ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING
Procedure dh_RegisterFreq,NEAR

        .386p
        push    ds                      ;save ds
        FlatContext <ds>

        movzx   edi,di
        mov     DWORD PTR [_f32pfnCLKFreq],edi
        mov     WORD PTR [_f32pfnCLKFreq+4],cx;store the entry point
        xor     ax,ax                   ;return code=0

        pop     ds                      ;restore ds
        CpuMode reset
        ret

EndProc dh_RegisterFreq

CODE    ENDS

        END
