Sync with trunk head (r48786)
[reactos.git] / hal / halx86 / generic / timer.c
1 /*
2 * PROJECT: ReactOS HAL
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)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <hal.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS *******************************************************************/
16
17 ULONG HalpPerfCounterCutoff;
18 BOOLEAN HalpClockSetMSRate;
19 ULONG HalpCurrentTimeIncrement;
20 ULONG HalpCurrentRollOver;
21 ULONG HalpNextMSRate = 14;
22 ULONG HalpLargestClockMS = 15;
23
24 LARGE_INTEGER HalpRolloverTable[15] =
25 {
26 {{1197, 10032}},
27 {{2394, 20064}},
28 {{3591, 30096}},
29 {{4767, 39952}},
30 {{5964, 49984}},
31 {{7161, 60016}},
32 {{8358, 70048}},
33 {{9555, 80080}},
34 {{10731, 89936}},
35 {{11949, 100144}},
36 {{13125, 110000}},
37 {{14322, 120032}},
38 {{15519, 130064}},
39 {{16695, 139920}},
40 {{17892, 149952}}
41 };
42
43 /* PRIVATE FUNCTIONS *********************************************************/
44
45 VOID
46 NTAPI
47 HalpInitializeClock(VOID)
48 {
49 PKPRCB Prcb = KeGetCurrentPrcb();
50 ULONG Increment;
51 USHORT RollOver;
52 ULONG_PTR Flags;
53 TIMER_CONTROL_PORT_REGISTER TimerControl;
54
55 /* Check the CPU Type */
56 if (Prcb->CpuType <= 4)
57 {
58 /* 486's or equal can't go higher then 10ms */
59 HalpLargestClockMS = 10;
60 HalpNextMSRate = 9;
61 }
62
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;
66
67 /* Set the maximum and minimum increment with the kernel */
68 HalpCurrentTimeIncrement = Increment;
69 KeSetTimeIncrement(Increment, HalpRolloverTable[0].HighPart);
70
71 /* Disable interrupts */
72 Flags = __readeflags();
73 _disable();
74
75 /* Program the PIT for binary mode */
76 TimerControl.BcdMode = FALSE;
77
78 /*
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.
82 *
83 * Mode 2 gives much better accuracy than Mode 3.
84 */
85 TimerControl.OperatingMode = PitOperatingMode2;
86 TimerControl.Channel = PitChannel0;
87
88 /* Set the access mode that we'll use to program the reload value */
89 TimerControl.AccessMode = PitAccessModeLowHigh;
90
91 /* Now write the programming bits */
92 __outbyte(TIMER_CONTROL_PORT, TimerControl.Bits);
93
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);
97
98 /* Restore interrupts if they were previously enabled */
99 __writeeflags(Flags);
100
101 /* Save rollover and return */
102 HalpCurrentRollOver = RollOver;
103 }
104
105 #ifdef _M_IX86
106 #ifndef _MINIHAL_
107 VOID
108 FASTCALL
109 HalpClockInterruptHandler(IN PKTRAP_FRAME TrapFrame)
110 {
111 KIRQL Irql;
112
113 /* Enter trap */
114 KiEnterInterruptTrap(TrapFrame);
115
116 /* Start the interrupt */
117 if (HalBeginSystemInterrupt(CLOCK2_LEVEL, PRIMARY_VECTOR_BASE, &Irql))
118 {
119 /* Update the performance counter */
120 HalpPerfCounter.QuadPart += HalpCurrentRollOver;
121 HalpPerfCounterCutoff = KiEnableTimerWatchdog;
122
123 /* Check if someone changed the time rate */
124 if (HalpClockSetMSRate)
125 {
126 /* Not yet supported */
127 UNIMPLEMENTED;
128 while (TRUE);
129 }
130
131 /* Update the system time -- the kernel will exit this trap */
132 KeUpdateSystemTime(TrapFrame, HalpCurrentTimeIncrement, Irql);
133 }
134
135 /* Spurious, just end the interrupt */
136 KiEoiHelper(TrapFrame);
137 }
138
139 VOID
140 FASTCALL
141 HalpProfileInterruptHandler(IN PKTRAP_FRAME TrapFrame)
142 {
143 KIRQL Irql;
144
145 /* Enter trap */
146 KiEnterInterruptTrap(TrapFrame);
147
148 /* Start the interrupt */
149 if (HalBeginSystemInterrupt(PROFILE_LEVEL, PRIMARY_VECTOR_BASE + 8, &Irql))
150 {
151 /* Profiling isn't yet enabled */
152 UNIMPLEMENTED;
153 while (TRUE);
154 }
155
156 /* Spurious, just end the interrupt */
157 KiEoiHelper(TrapFrame);
158 }
159 #endif
160
161 #endif
162
163 /* PUBLIC FUNCTIONS ***********************************************************/
164
165 /*
166 * @implemented
167 */
168 VOID
169 NTAPI
170 HalCalibratePerformanceCounter(IN volatile PLONG Count,
171 IN ULONGLONG NewCount)
172 {
173 ULONG_PTR Flags;
174
175 /* Disable interrupts */
176 Flags = __readeflags();
177 _disable();
178
179 /* Do a decrement for this CPU */
180 _InterlockedDecrement(Count);
181
182 /* Wait for other CPUs */
183 while (*Count);
184
185 /* Restore interrupts if they were previously enabled */
186 __writeeflags(Flags);
187 }
188
189 /*
190 * @implemented
191 */
192 ULONG
193 NTAPI
194 HalSetTimeIncrement(IN ULONG Increment)
195 {
196 /* Round increment to ms */
197 Increment /= 10000;
198
199 /* Normalize between our minimum (1 ms) and maximum (variable) setting */
200 if (Increment > HalpLargestClockMS) Increment = HalpLargestClockMS;
201 if (Increment <= 0) Increment = 1;
202
203 /* Set the rate and tell HAL we want to change it */
204 HalpNextMSRate = Increment;
205 HalpClockSetMSRate = TRUE;
206
207 /* Return the increment */
208 return HalpRolloverTable[Increment - 1].HighPart;
209 }
210
211 /* EOF */