mirror of
https://github.com/reactos/reactos.git
synced 2024-08-20 02:13:29 +00:00
![Timo Kreuzer](/assets/img/avatar_default.png)
* Add an NDK header to define INIT_FUNCTION/INIT_SECTION globally * Use _declspec(allocate(x)) and _declspec(code_seg(x)) on MSVC versions that support it * Use INIT_FUNCTION on functions only and INIT_SECTION on data only (required by MSVC) * Place INIT_FUNCTION before the return type (required by MSVC) * Make sure declarations and implementations share the same modifiers (required by MSVC) * Add a global linker option to suppress warnings about defined but unused INIT section * Merge INIT section into .text in freeldr
173 lines
4.1 KiB
C
173 lines
4.1 KiB
C
/*
|
|
* PROJECT: ReactOS HAL
|
|
* LICENSE: GNU GPL - See COPYING in the top level directory
|
|
* FILE: hal/halx86/apic/rtctimer.c
|
|
* PURPOSE: HAL APIC Management and Control Code
|
|
* PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
|
|
* REFERENCES:
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include <hal.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#if defined(ALLOC_PRAGMA) && !defined(_MINIHAL_)
|
|
#pragma alloc_text(INIT, HalpInitializeClock)
|
|
#endif
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
const UCHAR HalpClockVector = 0xD1;
|
|
BOOLEAN HalpClockSetMSRate;
|
|
UCHAR HalpNextMSRate;
|
|
UCHAR HalpCurrentRate = 9; /* Initial rate 9: 128 Hz / 7.8 ms */
|
|
ULONG HalpCurrentTimeIncrement;
|
|
static UCHAR RtcMinimumClockRate = 6; /* Minimum rate 6: 16 Hz / 62.5 ms */
|
|
static UCHAR RtcMaximumClockRate = 10; /* Maximum rate 10: 256 Hz / 3.9 ms */
|
|
|
|
|
|
FORCEINLINE
|
|
ULONG
|
|
RtcClockRateToIncrement(UCHAR Rate)
|
|
{
|
|
ULONG Freqency = ((32768 << 1) >> Rate);
|
|
return (1000000 + (Freqency/2)) / Freqency;
|
|
}
|
|
|
|
VOID
|
|
RtcSetClockRate(UCHAR ClockRate)
|
|
{
|
|
UCHAR RegisterA;
|
|
|
|
/* Update the global values */
|
|
HalpCurrentRate = ClockRate;
|
|
HalpCurrentTimeIncrement = RtcClockRateToIncrement(ClockRate);
|
|
|
|
/* Acquire CMOS lock */
|
|
HalpAcquireCmosSpinLock();
|
|
|
|
// TODO: disable NMI
|
|
|
|
/* Read value of register A */
|
|
RegisterA = HalpReadCmos(RTC_REGISTER_A);
|
|
|
|
/* Change lower 4 bits to new rate */
|
|
RegisterA &= 0xF0;
|
|
RegisterA |= ClockRate;
|
|
|
|
/* Write the new value */
|
|
HalpWriteCmos(RTC_REGISTER_A, RegisterA);
|
|
|
|
/* Release CMOS lock */
|
|
HalpReleaseCmosSpinLock();
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
VOID
|
|
NTAPI
|
|
HalpInitializeClock(VOID)
|
|
{
|
|
ULONG_PTR EFlags;
|
|
UCHAR RegisterB;
|
|
|
|
/* Save EFlags and disable interrupts */
|
|
EFlags = __readeflags();
|
|
_disable();
|
|
|
|
// TODO: disable NMI
|
|
|
|
/* Acquire CMOS lock */
|
|
HalpAcquireCmosSpinLock();
|
|
|
|
/* Enable the periodic interrupt in the CMOS */
|
|
RegisterB = HalpReadCmos(RTC_REGISTER_B);
|
|
HalpWriteCmos(RTC_REGISTER_B, RegisterB | RTC_REG_B_PI);
|
|
|
|
/* Release CMOS lock */
|
|
HalpReleaseCmosSpinLock();
|
|
|
|
/* Set initial rate */
|
|
RtcSetClockRate(HalpCurrentRate);
|
|
|
|
/* Restore interrupt state */
|
|
__writeeflags(EFlags);
|
|
|
|
/* Notify the kernel about the maximum and minimum increment */
|
|
KeSetTimeIncrement(RtcClockRateToIncrement(RtcMaximumClockRate),
|
|
RtcClockRateToIncrement(RtcMinimumClockRate));
|
|
|
|
|
|
DPRINT1("Clock initialized\n");
|
|
}
|
|
|
|
VOID
|
|
FASTCALL
|
|
HalpClockInterruptHandler(IN PKTRAP_FRAME TrapFrame)
|
|
{
|
|
ULONG LastIncrement;
|
|
KIRQL Irql;
|
|
|
|
/* Enter trap */
|
|
KiEnterInterruptTrap(TrapFrame);
|
|
#ifdef _M_AMD64
|
|
/* This is for debugging */
|
|
TrapFrame->ErrorCode = 0xc10c4;
|
|
#endif
|
|
|
|
/* Start the interrupt */
|
|
if (!HalBeginSystemInterrupt(CLOCK_LEVEL, HalpClockVector, &Irql))
|
|
{
|
|
/* Spurious, just end the interrupt */
|
|
KiEoiHelper(TrapFrame);
|
|
}
|
|
|
|
/* Read register C, so that the next interrupt can happen */
|
|
HalpReadCmos(RTC_REGISTER_C);
|
|
|
|
/* Save increment */
|
|
LastIncrement = HalpCurrentTimeIncrement;
|
|
|
|
/* Check if someone changed the time rate */
|
|
if (HalpClockSetMSRate)
|
|
{
|
|
/* Set new clock rate */
|
|
RtcSetClockRate(HalpNextMSRate);
|
|
|
|
/* We're done */
|
|
HalpClockSetMSRate = FALSE;
|
|
}
|
|
|
|
/* Update the system time -- on x86 the kernel will exit this trap */
|
|
KeUpdateSystemTime(TrapFrame, LastIncrement, Irql);
|
|
}
|
|
|
|
VOID
|
|
FASTCALL
|
|
HalpProfileInterruptHandler(IN PKTRAP_FRAME TrapFrame)
|
|
{
|
|
__debugbreak();
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
HalSetTimeIncrement(IN ULONG Increment)
|
|
{
|
|
UCHAR Rate;
|
|
|
|
/* Lookup largest value below given Increment */
|
|
for (Rate = RtcMinimumClockRate; Rate <= RtcMaximumClockRate; Rate++)
|
|
{
|
|
/* Check if this is the largest rate possible */
|
|
if (RtcClockRateToIncrement(Rate + 1) > Increment) break;
|
|
}
|
|
|
|
/* Set the rate and tell HAL we want to change it */
|
|
HalpNextMSRate = Rate;
|
|
HalpClockSetMSRate = TRUE;
|
|
|
|
/* Return the real increment */
|
|
return RtcClockRateToIncrement(Rate);
|
|
}
|