1 /* 2 * PROJECT: ReactOS HAL 3 * LICENSE: GNU GPL - See COPYING in the top level directory 4 * FILE: hal/halx86/apic/rtctimer.c 5 * PURPOSE: HAL APIC Management and Control Code 6 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org) 7 * REFERENCES: 8 */ 9 10 /* INCLUDES *******************************************************************/ 11 12 #include <hal.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 #if defined(ALLOC_PRAGMA) && !defined(_MINIHAL_) 17 #pragma alloc_text(INIT, HalpInitializeClock) 18 #endif 19 20 /* GLOBALS ********************************************************************/ 21 22 const UCHAR HalpClockVector = 0xD1; 23 BOOLEAN HalpClockSetMSRate; 24 UCHAR HalpNextMSRate; 25 UCHAR HalpCurrentRate = 9; /* Initial rate 9: 128 Hz / 7.8 ms */ 26 ULONG HalpCurrentTimeIncrement; 27 static UCHAR RtcMinimumClockRate = 6; /* Minimum rate 6: 16 Hz / 62.5 ms */ 28 static UCHAR RtcMaximumClockRate = 10; /* Maximum rate 10: 256 Hz / 3.9 ms */ 29 30 31 FORCEINLINE 32 ULONG 33 RtcClockRateToIncrement(UCHAR Rate) 34 { 35 ULONG Freqency = ((32768 << 1) >> Rate); 36 return (1000000 + (Freqency/2)) / Freqency; 37 } 38 39 VOID 40 RtcSetClockRate(UCHAR ClockRate) 41 { 42 UCHAR RegisterA; 43 44 /* Update the global values */ 45 HalpCurrentRate = ClockRate; 46 HalpCurrentTimeIncrement = RtcClockRateToIncrement(ClockRate); 47 48 /* Acquire CMOS lock */ 49 HalpAcquireCmosSpinLock(); 50 51 // TODO: disable NMI 52 53 /* Read value of register A */ 54 RegisterA = HalpReadCmos(RTC_REGISTER_A); 55 56 /* Change lower 4 bits to new rate */ 57 RegisterA &= 0xF0; 58 RegisterA |= ClockRate; 59 60 /* Write the new value */ 61 HalpWriteCmos(RTC_REGISTER_A, RegisterA); 62 63 /* Release CMOS lock */ 64 HalpReleaseCmosSpinLock(); 65 } 66 67 INIT_FUNCTION 68 VOID 69 NTAPI 70 HalpInitializeClock(VOID) 71 { 72 ULONG_PTR EFlags; 73 UCHAR RegisterB; 74 75 /* Save EFlags and disable interrupts */ 76 EFlags = __readeflags(); 77 _disable(); 78 79 // TODO: disable NMI 80 81 /* Acquire CMOS lock */ 82 HalpAcquireCmosSpinLock(); 83 84 /* Enable the periodic interrupt in the CMOS */ 85 RegisterB = HalpReadCmos(RTC_REGISTER_B); 86 HalpWriteCmos(RTC_REGISTER_B, RegisterB | RTC_REG_B_PI); 87 88 /* Release CMOS lock */ 89 HalpReleaseCmosSpinLock(); 90 91 /* Set initial rate */ 92 RtcSetClockRate(HalpCurrentRate); 93 94 /* Restore interrupt state */ 95 __writeeflags(EFlags); 96 97 /* Notify the kernel about the maximum and minimum increment */ 98 KeSetTimeIncrement(RtcClockRateToIncrement(RtcMaximumClockRate), 99 RtcClockRateToIncrement(RtcMinimumClockRate)); 100 101 102 DPRINT1("Clock initialized\n"); 103 } 104 105 VOID 106 FASTCALL 107 HalpClockInterruptHandler(IN PKTRAP_FRAME TrapFrame) 108 { 109 ULONG LastIncrement; 110 KIRQL Irql; 111 112 /* Enter trap */ 113 KiEnterInterruptTrap(TrapFrame); 114 #ifdef _M_AMD64 115 /* This is for debugging */ 116 TrapFrame->ErrorCode = 0xc10c4; 117 #endif 118 119 /* Start the interrupt */ 120 if (!HalBeginSystemInterrupt(CLOCK_LEVEL, HalpClockVector, &Irql)) 121 { 122 /* Spurious, just end the interrupt */ 123 KiEoiHelper(TrapFrame); 124 } 125 126 /* Read register C, so that the next interrupt can happen */ 127 HalpReadCmos(RTC_REGISTER_C); 128 129 /* Save increment */ 130 LastIncrement = HalpCurrentTimeIncrement; 131 132 /* Check if someone changed the time rate */ 133 if (HalpClockSetMSRate) 134 { 135 /* Set new clock rate */ 136 RtcSetClockRate(HalpNextMSRate); 137 138 /* We're done */ 139 HalpClockSetMSRate = FALSE; 140 } 141 142 /* Update the system time -- on x86 the kernel will exit this trap */ 143 KeUpdateSystemTime(TrapFrame, LastIncrement, Irql); 144 } 145 146 VOID 147 FASTCALL 148 HalpProfileInterruptHandler(IN PKTRAP_FRAME TrapFrame) 149 { 150 __debugbreak(); 151 } 152 153 ULONG 154 NTAPI 155 HalSetTimeIncrement(IN ULONG Increment) 156 { 157 UCHAR Rate; 158 159 /* Lookup largest value below given Increment */ 160 for (Rate = RtcMinimumClockRate; Rate <= RtcMaximumClockRate; Rate++) 161 { 162 /* Check if this is the largest rate possible */ 163 if (RtcClockRateToIncrement(Rate + 1) > Increment) break; 164 } 165 166 /* Set the rate and tell HAL we want to change it */ 167 HalpNextMSRate = Rate; 168 HalpClockSetMSRate = TRUE; 169 170 /* Return the real increment */ 171 return RtcClockRateToIncrement(Rate); 172 } 173