3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/generic/timer.c
5 * PURPOSE: HAL Timer Routines
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* GLOBALS *******************************************************************/
17 ULONG HalpPerfCounterCutoff
;
18 BOOLEAN HalpClockSetMSRate
;
19 ULONG HalpCurrentTimeIncrement
;
20 ULONG HalpCurrentRollOver
;
21 ULONG HalpNextMSRate
= 14;
22 ULONG HalpLargestClockMS
= 15;
24 LARGE_INTEGER HalpRolloverTable
[15] =
43 /* PRIVATE FUNCTIONS *********************************************************/
47 HalpInitializeClock(VOID
)
49 PKPRCB Prcb
= KeGetCurrentPrcb();
53 TIMER_CONTROL_PORT_REGISTER TimerControl
;
55 /* Check the CPU Type */
56 if (Prcb
->CpuType
<= 4)
58 /* 486's or equal can't go higher then 10ms */
59 HalpLargestClockMS
= 10;
63 /* Get increment and rollover for the largest time clock ms possible */
64 Increment
= HalpRolloverTable
[HalpLargestClockMS
- 1].HighPart
;
65 RollOver
= (USHORT
)HalpRolloverTable
[HalpLargestClockMS
- 1].LowPart
;
67 /* Set the maximum and minimum increment with the kernel */
68 HalpCurrentTimeIncrement
= Increment
;
69 KeSetTimeIncrement(Increment
, HalpRolloverTable
[0].HighPart
);
71 /* Disable interrupts */
72 Flags
= __readeflags();
75 /* Program the PIT for binary mode */
76 TimerControl
.BcdMode
= FALSE
;
79 * Program the PIT to generate a normal rate wave (Mode 3) on channel 0.
80 * Channel 0 is used for the IRQ0 clock interval timer, and channel
81 * 1 is used for DRAM refresh.
83 * Mode 2 gives much better accuracy than Mode 3.
85 TimerControl
.OperatingMode
= PitOperatingMode2
;
86 TimerControl
.Channel
= PitChannel0
;
88 /* Set the access mode that we'll use to program the reload value */
89 TimerControl
.AccessMode
= PitAccessModeLowHigh
;
91 /* Now write the programming bits */
92 __outbyte(TIMER_CONTROL_PORT
, TimerControl
.Bits
);
94 /* Next we write the reload value for channel 0 */
95 __outbyte(TIMER_CHANNEL0_DATA_PORT
, RollOver
& 0xFF);
96 __outbyte(TIMER_CHANNEL0_DATA_PORT
, RollOver
>> 8);
98 /* Restore interrupts if they were previously enabled */
101 /* Save rollover and return */
102 HalpCurrentRollOver
= RollOver
;
109 HalpClockInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
114 KiEnterInterruptTrap(TrapFrame
);
116 /* Start the interrupt */
117 if (HalBeginSystemInterrupt(CLOCK2_LEVEL
, PRIMARY_VECTOR_BASE
, &Irql
))
119 /* Update the performance counter */
120 HalpPerfCounter
.QuadPart
+= HalpCurrentRollOver
;
121 HalpPerfCounterCutoff
= KiEnableTimerWatchdog
;
123 /* Check if someone changed the time rate */
124 if (HalpClockSetMSRate
)
126 /* Not yet supported */
131 /* Update the system time -- the kernel will exit this trap */
132 KeUpdateSystemTime(TrapFrame
, HalpCurrentTimeIncrement
, Irql
);
135 /* Spurious, just end the interrupt */
136 KiEoiHelper(TrapFrame
);
141 HalpProfileInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
146 KiEnterInterruptTrap(TrapFrame
);
148 /* Start the interrupt */
149 if (HalBeginSystemInterrupt(PROFILE_LEVEL
, PRIMARY_VECTOR_BASE
+ 8, &Irql
))
151 /* Profiling isn't yet enabled */
156 /* Spurious, just end the interrupt */
157 KiEoiHelper(TrapFrame
);
163 /* PUBLIC FUNCTIONS ***********************************************************/
170 HalCalibratePerformanceCounter(IN
volatile PLONG Count
,
171 IN ULONGLONG NewCount
)
175 /* Disable interrupts */
176 Flags
= __readeflags();
179 /* Do a decrement for this CPU */
180 _InterlockedDecrement(Count
);
182 /* Wait for other CPUs */
185 /* Restore interrupts if they were previously enabled */
186 __writeeflags(Flags
);
194 HalSetTimeIncrement(IN ULONG Increment
)
196 /* Round increment to ms */
199 /* Normalize between our minimum (1 ms) and maximum (variable) setting */
200 if (Increment
> HalpLargestClockMS
) Increment
= HalpLargestClockMS
;
201 if (Increment
<= 0) Increment
= 1;
203 /* Set the rate and tell HAL we want to change it */
204 HalpNextMSRate
= Increment
;
205 HalpClockSetMSRate
= TRUE
;
207 /* Return the increment */
208 return HalpRolloverTable
[Increment
- 1].HighPart
;