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