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 *********************************************************/
48 HalpInitializeClock(VOID
)
50 PKPRCB Prcb
= KeGetCurrentPrcb();
54 TIMER_CONTROL_PORT_REGISTER TimerControl
;
56 /* Check the CPU Type */
57 if (Prcb
->CpuType
<= 4)
59 /* 486's or equal can't go higher then 10ms */
60 HalpLargestClockMS
= 10;
64 /* Get increment and rollover for the largest time clock ms possible */
65 Increment
= HalpRolloverTable
[HalpLargestClockMS
- 1].HighPart
;
66 RollOver
= (USHORT
)HalpRolloverTable
[HalpLargestClockMS
- 1].LowPart
;
68 /* Set the maximum and minimum increment with the kernel */
69 HalpCurrentTimeIncrement
= Increment
;
70 KeSetTimeIncrement(Increment
, HalpRolloverTable
[0].HighPart
);
72 /* Disable interrupts */
73 Flags
= __readeflags();
76 /* Program the PIT for binary mode */
77 TimerControl
.BcdMode
= FALSE
;
80 * Program the PIT to generate a normal rate wave (Mode 3) on channel 0.
81 * Channel 0 is used for the IRQ0 clock interval timer, and channel
82 * 1 is used for DRAM refresh.
84 * Mode 2 gives much better accuracy than Mode 3.
86 TimerControl
.OperatingMode
= PitOperatingMode2
;
87 TimerControl
.Channel
= PitChannel0
;
89 /* Set the access mode that we'll use to program the reload value */
90 TimerControl
.AccessMode
= PitAccessModeLowHigh
;
92 /* Now write the programming bits */
93 __outbyte(TIMER_CONTROL_PORT
, TimerControl
.Bits
);
95 /* Next we write the reload value for channel 0 */
96 __outbyte(TIMER_CHANNEL0_DATA_PORT
, RollOver
& 0xFF);
97 __outbyte(TIMER_CHANNEL0_DATA_PORT
, RollOver
>> 8);
99 /* Restore interrupts if they were previously enabled */
100 __writeeflags(Flags
);
102 /* Save rollover and return */
103 HalpCurrentRollOver
= RollOver
;
110 HalpClockInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
115 KiEnterInterruptTrap(TrapFrame
);
117 /* Start the interrupt */
118 if (HalBeginSystemInterrupt(CLOCK2_LEVEL
, PRIMARY_VECTOR_BASE
, &Irql
))
120 /* Update the performance counter */
121 HalpPerfCounter
.QuadPart
+= HalpCurrentRollOver
;
122 HalpPerfCounterCutoff
= KiEnableTimerWatchdog
;
124 /* Check if someone changed the time rate */
125 if (HalpClockSetMSRate
)
127 /* Not yet supported */
132 /* Update the system time -- the kernel will exit this trap */
133 KeUpdateSystemTime(TrapFrame
, HalpCurrentTimeIncrement
, Irql
);
136 /* Spurious, just end the interrupt */
137 KiEoiHelper(TrapFrame
);
142 HalpProfileInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
147 KiEnterInterruptTrap(TrapFrame
);
149 /* Start the interrupt */
150 if (HalBeginSystemInterrupt(PROFILE_LEVEL
, PRIMARY_VECTOR_BASE
+ 8, &Irql
))
152 /* Profiling isn't yet enabled */
157 /* Spurious, just end the interrupt */
158 KiEoiHelper(TrapFrame
);
164 /* PUBLIC FUNCTIONS ***********************************************************/
171 HalCalibratePerformanceCounter(IN
volatile PLONG Count
,
172 IN ULONGLONG NewCount
)
176 /* Disable interrupts */
177 Flags
= __readeflags();
180 /* Do a decrement for this CPU */
181 _InterlockedDecrement(Count
);
183 /* Wait for other CPUs */
186 /* Restore interrupts if they were previously enabled */
187 __writeeflags(Flags
);
195 HalSetTimeIncrement(IN ULONG Increment
)
197 /* Round increment to ms */
200 /* Normalize between our minimum (1 ms) and maximum (variable) setting */
201 if (Increment
> HalpLargestClockMS
) Increment
= HalpLargestClockMS
;
202 if (Increment
<= 0) Increment
= 1;
204 /* Set the rate and tell HAL we want to change it */
205 HalpNextMSRate
= Increment
;
206 HalpClockSetMSRate
= TRUE
;
208 /* Return the increment */
209 return HalpRolloverTable
[Increment
- 1].HighPart
;