windows-nt/Source/XPSP1/NT/base/hals/halacpi/i386/pmrtc.asm
2020-09-26 16:20:57 +08:00

329 lines
7.6 KiB
NASM

title "ACPI Real Time Clock Functions"
;++
;
; Copyright (c) 1989 Microsoft Corporation
;
; Module Name:
;
; pmclock.asm
;
; Abstract:
;
; This module implements the code for ACPI-related RTC
; functions.
;
; Author:
;
; Jake Oshins (jakeo) March 28, 1997
;
; Environment:
;
; Kernel mode only.
;
; Revision History:
;
; Split from pmclock.asm due to PIIX4 bugs.
;
;--
.386p
.xlist
include hal386.inc
include callconv.inc ; calling convention macros
include mac386.inc
include i386\ix8259.inc
include i386\ixcmos.inc
include xxacpi.h
.list
extrn _HalpFixedAcpiDescTable:DWORD
EXTRNP _DbgBreakPoint,0,IMPORT
EXTRNP _HalpAcquireCmosSpinLock ,0
EXTRNP _HalpReleaseCmosSpinLock ,0
extrn _HalpRtcRegA:BYTE
extrn _HalpRtcRegB:BYTE
extrn _HalpCmosCenturyOffset:DWORD
INIT SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
;++
;
; VOID
; HalpInitializeCmos(
; VOID
; )
;
; This routine reads CMOS and initializes globals required for
; CMOS access, such as the location of the century byte.
;
;--
cPublicProc _HalpInitializeCmos,0
cPublicFpo 0,0
;
; If the century byte is filled in, use it.
;
movzx eax, byte ptr [RTC_CENTURY]
or al, al
jnz short @f
;
; Assume default
;
mov eax, RTC_OFFSET_CENTURY
@@:
mov _HalpCmosCenturyOffset, eax
stdRET _HalpInitializeCmos
stdENDP _HalpInitializeCmos
INIT ends
_TEXT$03 SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
; NTSTATUS
; HalpSetWakeAlarm (
; IN ULONGLONG WakeSystemTime,
; IN PTIME_FIELDS WakeTimeFields OPTIONAL
; )
; /*++
;
; Routine Description:
;
; This routine sets the real-time clock's alarm to go
; off at a specified time in the future and programs
; the ACPI chipset so that this wakes the computer.
;
; Arguments:
;
; WakeSystemTime - amount of time that passes before we wake
; WakeTimeFields - time to wake broken down into TIME_FIELDS
;
; Return Value:
;
; status
;
; --*/
WakeSystemTime equ [esp + 4]
WakeTimeFields equ [esp + 12]
cPublicProc _HalpSetWakeAlarm, 3
cPublicFpo 3, 0
if DBG
hswawait0:
mov ecx, 100
hswawait:
push ecx
else
hswawait:
endif
stdCall _HalpAcquireCmosSpinLock
mov ecx, 100
align 4
hswa00: mov al, 0Ah ; Specify register A
CMOS_READ ; (al) = CMOS register A
test al, CMOS_STATUS_BUSY ; Is time update in progress?
jz short hswa10 ; if z, no, go write CMOS time
loop short hswa00 ; otherwise, try again.
;
; CMOS is still busy. Try again ...
;
stdCall _HalpReleaseCmosSpinLock
if DBG
pop ecx
loop short hswawait
stdCall _DbgBreakPoint
jmp short hswawait0
else
jmp short hswawait
endif
align 4
if DBG
hswa10:
pop ecx
else
hswa10:
endif
mov edx, WakeTimeFields ; (edx)-> TIME_FIELDS structure
mov al, [edx].TfSecond ; Read second in TIME_FIELDS
BIN_TO_BCD
mov ah, al
mov al, RTC_OFFSET_SECOND_ALARM
CMOS_WRITE
mov al, [edx].TfMinute ; Read minute in TIME_FIELDS
BIN_TO_BCD
mov ah, al
mov al, RTC_OFFSET_MINUTE_ALARM
CMOS_WRITE
mov al, [edx].TfHour ; Read Hour in TIME_FIELDS
BIN_TO_BCD
mov ah, al
mov al, RTC_OFFSET_HOUR_ALARM
CMOS_WRITE
; test to see if RTC_DAY_ALRM is supported
mov cl, byte ptr [RTC_DAY_ALRM]
or cl, cl
jz hswa20
mov al, [edx].TfDay ; Read day in TIME_FIELDS
BIN_TO_BCD
mov ah, al
mov al, cl
CMOS_WRITE
; test to see if RTC_MON_ALRM is supported
mov cl, byte ptr [RTC_MON_ALRM]
or cl, cl
jz hswa20
mov al, [edx].TfMonth ; Read month in TIME_FIELDS
BIN_TO_BCD
mov ah, al
mov al, cl
CMOS_WRITE
;
; Don't clobber the Daylight Savings Time bit in register B, because we
; stash the LastKnownGood "environment variable" there.
;
hswa20:
mov ax, 0bh
CMOS_READ
and al, 1
mov ah, al
or ah, REGISTER_B_ENABLE_ALARM_INTERRUPT or REGISTER_B_24HOUR_MODE
mov al, 0bh
CMOS_WRITE ; Initialize it
mov al,0CH ; Register C
CMOS_READ ; Read to initialize
mov al,0DH ; Register D
CMOS_READ ; Read to initialize
stdCall _HalpReleaseCmosSpinLock
xor eax, eax ; return STATUS_SUCCESS
stdRET _HalpSetWakeAlarm
stdENDP _HalpSetWakeAlarm
_TEXT$03 ends
PAGELK SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
;++
;
; VOID
; HalpSetClockBeforeSleep (
; VOID
; )
;
; Routine Description:
;
; This routine sets the RTC such that it will not generate
; periodic interrupts while the machine is sleeping, as this
; could be interpretted as an RTC wakeup event.
;
; Arguments:
;
; Return Value:
;
; None
;
;--
cPublicProc _HalpSetClockBeforeSleep, 0
cPublicFpo 0, 0
stdCall _HalpAcquireCmosSpinLock
mov al, 0ah
CMOS_READ
mov _HalpRtcRegA, al ; save RTC Register A
or al, al
jnz @f ; TEMP - debug stop
int 3 ; looking for reg-a corruption
@@:
mov al, 0bh
CMOS_READ
mov _HalpRtcRegB, al ; save RTC Register B
and al, not REGISTER_B_ENABLE_PERIODIC_INTERRUPT
or al, REGISTER_B_24HOUR_MODE
mov ah, al
mov al, 0bh
CMOS_WRITE ; Initialize it
mov al,0CH ; Register C
CMOS_READ ; Read to initialize
mov al,0DH ; Register D
CMOS_READ ; Read to initialize
stdCall _HalpReleaseCmosSpinLock
stdRET _HalpSetClockBeforeSleep
stdENDP _HalpSetClockBeforeSleep
;++
;
; VOID
; HalpSetClockAfterSleep (
; VOID
; )
;
; Routine Description:
;
; This routine sets the RTC back to the way it was
; before a call to HalpSetClockBeforeSleep.
;
; Arguments:
;
; Return Value:
;
; None
;
;--
cPublicProc _HalpSetClockAfterSleep, 0
cPublicFpo 0, 0
stdCall _HalpAcquireCmosSpinLock
mov ah, _HalpRtcRegA ; restore RTC Register A
mov al, 0ah
CMOS_WRITE
mov ah, _HalpRtcRegB ; restore RTC Register B
and ah, not REGISTER_B_ENABLE_ALARM_INTERRUPT
or ah, REGISTER_B_24HOUR_MODE
mov al, 0bh
CMOS_WRITE ; Initialize it
mov al,0CH ; Register C
CMOS_READ ; Read to initialize
mov al,0DH ; Register D
CMOS_READ ; Read to initialize
stdCall _HalpReleaseCmosSpinLock
stdRET _HalpSetClockAfterSleep
stdENDP _HalpSetClockAfterSleep
PAGELK ends
end