        PAGE    ,132
        NAME    PTD
        TITLE   Physical Timer Device Driver


;***    Physical Timer Device Driver (PTD)
;
;       SCCSID = @(#)ptdbeep.asm        6.6 91/10/22
;       Copyright (c) 1988 Microsoft Corporation
;       Copyright (c) 1988, 1997 IBM Corporation
;
;       DESCRIPTION
;       This module contains the PTD's beep services.
;
;       MODIFICATION HISTORY
;       04/07/89 MTS    Created.
; 138704 5/21/97 PAT    Converge SMP/UNI clock01 driver.  Use runtime check
;                       for SMP rather than ifdef.
; 182895 11/12/97 WHH   Fixed to use single driver for UNI/SMP.
;                       do NOT build with SMP flag.
;
        .xlist
INCL_MI         EQU     1
        include mvdm.inc        ;mvdm definitions for dos macros
        include ptimer.inc      ;physical timer public constants
        include timer.inc       ;timer hardware constants
INCL_ERRORS     EQU     1
        include bseerr.inc      ;error numbers
        include clkseg.inc      ;segment definitions
        include clkdata.inc     ;physical timer constants
        include vtdptd.inc      ;ptimer/vtimer interface constants
        include devhlp.inc
        include psd.inc
        .list
;
; d182895 start
;
; inc\devsym.inc uses an ifdef SMP around the below def.
; Instead of changing devsym.inc at this time, I have defined
; DevHlp_Port_IO here.  The clock drivers are no longer built with
; the SMP flag
;
DevHlp_Port_IO          EQU     118     ; 76H Port I/O
;
; d182895 end
;

;***    Exports
;
        PUBLIC  PTBeep,PTBeepOff

;***    Imports
;
        EXTRN   fpfnVTProc:FWORD
        EXTRN   fsPTFlags:WORD
        EXTRN   Use_SMP_PortIO:BYTE

ClkData SEGMENT
        EXTRN   DevHlp:DWORD
ClkData ENDS

ClkCode SEGMENT


BeepFuncTable label word
        dw      offset ClkCode:PTBeepOff
        dw      offset ClkCode:PTBeepOn
        dw      offset ClkCode:PTBeepFreq
        dw      offset ClkCode:PTBeepOpen
        dw      offset ClkCode:PTBeepClose
BeepMaxFunc     EQU     ($-BeepFuncTable)/2-1


;***LP  PTBeep(ulFunc, ulParam) - Device Beep Service
;
;       PTBeep provides the primitive functions which is needed
;       in generating tone from the system speaker.
;
;       ENTRY
;           ulFunc  = beep services: BEEP_OFF, BEEP_ON, BEEP_FREQ
;           ulParam = parameter for the beep service
;                       BEEP_OFF:  ulParam = 0
;                       BEEP_ON:   ulParam = 0
;                       BEEP_FREQ: ulParam = ulFreq (freq. of the beep)
;
;       EXIT
;           SUCCESS
;               (eax) = 0
;           FAILURE
;               (eax) = error code - ERROR_INVALID_FUNCTION
;
;       USES
;           None
;
;       CONTEXT
;           Task
;           Interrupt
;
;       PSEUDOCODE
;           rc = 0;
;           switch(usFunc) {
;               case BEEP_OFF:
;                   PTBeepOff();
;                   break;
;               case BEEP_ON:
;                   PTBeepOn();
;                   break;
;               case BEEP_FREQ:
;                   PTBeepFreq(usParam);
;                   break;
;               default:
;                   rc = ERROR_INVALID_FUNCTION;
;           }
;           return rc;


        ASSUME  CS:ClkCode,DS:NOTHING,ES:NOTHING,SS:NOTHING
Procedure PTBeep,FAR

        .386p

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

        EnterProc
        SaveReg <bx>

        mov     ax,WORD PTR [ulFunc]    ;(ax)=ulFunc
        mov     bx,WORD PTR [ulParm]    ;(bx)=ulParm

        cmp     ax,BeepMaxFunc          ;is it a valid function?
        ja      pbe                     ;NO, goto error exit

        push    si                      ;save si
        mov     si,ax                   ;(si)=usFunc
        shl     si,1                    ;adjust si as word index
        call    cs:BeepFuncTable[si]    ;process requested function
        pop     si                      ;restore si

        xor     eax,eax                 ;(eax)=ERROR_NONE

pbx:    RestoreReg <bx>
        ASSUME  DS:NOTHING

        LeaveProc

        retfd   ?aframe                 ;%%%

pbe:    mov     eax,ERROR_INVALID_FUNCTION
        jmp     short pbx

        CpuMode reset

EndProc PTBeep


;***LP  PTBeepOn() - Turn Speaker On
;
;       Turn the system speaker on by enabling it.
;
;       ENTRY
;           None
;
;       EXIT
;           None
;
;       USES
;           None
;
;       CONTEXT
;           Any
;
;       PSEUDOCODE
;           read SysB;
;           enable speaker bits;
;           write SysB;

        ASSUME  CS:ClkCode,DS:NOTHING,ES:NOTHING,SS:NOTHING
Procedure PTBeepOn,NEAR

        .386p

LocalVar io,<size port_io_s>

        EnterProc
        SaveReg <eax,edx,edi,ds,es>

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

        cmp     Use_SMP_PortIO,0
        jne     BeepOnSMP

        in      al,PORT_SYSB            ;(al) = SYSB
        IODelay
        or      al,SYSB_SPKGATE+SYSB_SPKENABLE;turn on speaker enable bits
        out     PORT_SYSB,al            ;enable speaker

        jmp     short BeepOnRet

BeepOnSMP:
        mov     ax,ss
        mov     es,ax
        lea     di,io

        mov     dl,DevHlp_Port_IO
        mov     io.port_io_port,PORT_SYSB

        mov     io.port_io_flags,IO_READ_BYTE
        call    [DevHlp]
        mov     al,byte ptr io.port_io_data

        IODelay
        or      al,SYSB_SPKGATE+SYSB_SPKENABLE;turn on speaker enable bits

        mov     byte ptr io.port_io_data,al
        mov     io.port_io_flags,IO_WRITE_BYTE
        call    [DevHlp]

BeepOnRet:
        RestoreReg <es,ds,edi,edx,eax>
        ASSUME  DS:NOTHING
        LeaveProc

        CpuMode reset

        ret

EndProc PTBeepOn


;***LP  PTBeepOff() - Turn Speaker Off
;
;       Turn the system speaker off by disabling it.
;
;       ENTRY
;           None
;
;       EXIT
;           None
;
;       USES
;           None
;
;       CONTEXT
;           Any
;
;       PSEUDOCODE
;           read SysB;
;           disable speaker bits;
;           write SysB;

        ASSUME  CS:ClkCode,DS:NOTHING,ES:NOTHING,SS:NOTHING
Procedure PTBeepOff,NEAR

        .386p

LocalVar io,<size port_io_s>

        EnterProc
        SaveReg <eax,edx,edi,ds,es>

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

        cmp     Use_SMP_PortIO,0
        jne     BeepOffSMP

        in      al,PORT_SYSB            ;(al) = SYSB
        IODelay
        and     al,NOT(SYSB_SPKGATE+SYSB_SPKENABLE);turn off speaker enable bits
        out     PORT_SYSB,al            ;disable speaker

        jmp     short BeepOffRet

BeepOffSMP:
        mov     ax,ss
        mov     es,ax
        lea     di,io

        mov     dl,DevHlp_Port_IO
        mov     io.port_io_port,PORT_SYSB

        mov     io.port_io_flags,IO_READ_BYTE
        call    [DevHlp]
        mov     al,byte ptr io.port_io_data

        IODelay
        and     al,NOT(SYSB_SPKGATE+SYSB_SPKENABLE);turn off speaker enable bits

        mov     byte ptr io.port_io_data,al
        mov     io.port_io_flags,IO_WRITE_BYTE
        call    [DevHlp]

BeepOffRet:
        RestoreReg <es,ds,edi,edx,eax>
        ASSUME  DS:NOTHING
        LeaveProc

        CpuMode reset

        ret

EndProc PTBeepOff


;***LP  PTBeepFreq(usFreq) - Set Beep Frequency
;
;       Set the speaker timer with the given frequency in Hz.
;
;       ENTRY
;           (bx) - usFreq = beep frequency in Hz
;
;       EXIT
;           None
;
;       USES
;           None
;
;       CONTEXT
;           Any
;
;       PSEUDOCODE
;           if (usFreq < BEEPFREQ_LO)
;               usFreq = BEEPFREQ_LO;
;           convert usFreq to usTicks;
;           program speaker timer with usTicks;

        ASSUME  CS:ClkCode,DS:NOTHING,ES:NOTHING,SS:NOTHING
Procedure PTBeepFreq,NEAR

        .386p

LocalVar io,<size port_io_s>

        EnterProc
        SaveReg <eax,edx,edi,ds,es>

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

        cmp     Use_SMP_PortIO,0
        jne     BeepFreqSMP

        cmp     bx,BEEPFREQ_LO          ;below minimum frequency?
        jae     pbf10                   ;NO, continue

        mov     bx,BEEPFREQ_LO          ;set usFreq to minimum frequency

pbf10:  mov     al,SC_CNT2+RW_LSBMSB+CM_MODE3
        out     PORT_CW,al              ;reset the byte index
        mov     dx,TIMERFREQ_HI
        mov     ax,TIMERFREQ_LO         ;(dx:ax) = TIMERFREQ (1.19MHz)
        div     bx                      ;(ax) = usTick in timer counts

        out     PORT_CNT2,al            ;program low byte of timer count
        IODelay
        xchg    al,ah                   ;(al) = high byte of timer count
        out     PORT_CNT2,al            ;program high byte of timer count

        jmp     short BeepFreqRet

BeepFreqSMP:
        mov     ax,ss
        mov     es,ax
        lea     di,io

        cmp     bx,BEEPFREQ_LO          ;below minimum frequency?
        jae     pbf11                   ;NO, continue

        mov     bx,BEEPFREQ_LO          ;set usFreq to minimum frequency
pbf11:  mov     al,SC_CNT2+RW_LSBMSB+CM_MODE3
        mov     io.port_io_port,PORT_CW
        mov     byte ptr io.port_io_data,al
        mov     io.port_io_flags,IO_WRITE_BYTE
        mov     dl,DevHlp_Port_IO
        call    [DevHlp]

        mov     dx,TIMERFREQ_HI
        mov     ax,TIMERFREQ_LO         ;(dx:ax) = TIMERFREQ (1.19MHz)
        div     bx                      ;(ax) = usTick in timer counts

        push    ax
        mov     io.port_io_port,PORT_CNT2
        mov     byte ptr io.port_io_data,al
        mov     io.port_io_flags,IO_WRITE_BYTE
        mov     dl,DevHlp_Port_IO
        call    [DevHlp]
        pop     ax

        IODelay
        xchg    al,ah
        mov     byte ptr io.port_io_data,al
        call    [DevHlp]

BeepFreqRet:
        RestoreReg <es,ds,edi,edx,eax>
        ASSUME  DS:NOTHING
        LeaveProc

        CpuMode reset

        ret

EndProc PTBeepFreq


;***LP  PTBeepOpen() - Get beep access
;
;       If vtimer has the speaker ownership, call vtimer to get
;       the speaker access.
;
;       ENTRY
;           None
;
;       EXIT
;           None
;
;       USES
;           All except ds,es
;
;       CONTEXT
;           Any
;
;       PSEUDOCODE
;           if vtimer has the speaker ownership
;               call vtimer to get it;

        ASSUME  CS:ClkCode,DS:NOTHING,ES:NOTHING,SS:NOTHING
Procedure PTBeepOpen,NEAR

        SaveReg <ds,es>
        mov     ax,ClkData
        mov     ds,ax
        ASSUME  DS:ClkData

        test    fsPTFlags,PTF_OWNT2     ;ptimer already has the ownership?
        jnz     ptbox                   ;YES, exit

        or      fsPTFlags,PTF_OWNT2
        .386p
        xor     eax,eax
        push    DWORD PTR VTDCMD_PREEMPTT2;(TOS+8)=VTDCMD_PREEMPTT2
        push    eax                     ;(TOS+4)=0
        push    eax                     ;(TOS)=0

        ;Should ASSERTNONZERO(fpfnVTProc)
        call    FWORD PTR [fpfnVTProc]
        CpuMode reset

ptbox:  RestoreReg <es,ds>
        ASSUME  DS:NOTHING

        ret

EndProc PTBeepOpen


;***LP  PTBeepClose() - Release beep access
;
;       If ptimer has the speaker ownership, call vtimer to release
;       the speaker.
;
;       ENTRY
;           None
;
;       EXIT
;           None
;
;       USES
;           All except ds,es
;
;       CONTEXT
;           Any
;
;       PSEUDOCODE
;           if ptimer has the speaker ownership and there is a vtimer
;               call vtimer to release ownership;

        ASSUME  CS:ClkCode,DS:NOTHING,ES:NOTHING,SS:NOTHING
Procedure PTBeepClose,NEAR

        SaveReg <ds,es>
        mov     ax,ClkData
        mov     ds,ax
        ASSUME  DS:ClkData

        test    fsPTFlags,PTF_OWNT2     ;ptimer has the ownership?
        jz      ptbcx                   ;NO, exit

        .386p
        cmp     DWORD PTR fpfnVTProc,0  ;vtimer exist?
        je      ptbcx                   ;NO, exit

        and     fsPTFlags,NOT PTF_OWNT2
        xor     eax,eax
        push    DWORD PTR VTDCMD_RELEASET2;(TOS+8)=VTDCMD_RELEASET2
        push    eax                     ;(TOS+4)=0
        push    eax                     ;(TOS)=0

        call    FWORD PTR [fpfnVTProc]
        CpuMode reset

ptbcx:  RestoreReg <es,ds>

        ret

EndProc PTBeepClose

ClkCode ENDS


        END
