[HAL]
[reactos.git] / reactos / 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 INIT_FUNCTION
48 HalpInitializeClock(VOID)
49 {
50 PKPRCB Prcb = KeGetCurrentPrcb();
51 ULONG Increment;
52 USHORT RollOver;
53 ULONG_PTR Flags;
54 TIMER_CONTROL_PORT_REGISTER TimerControl;
55
56 /* Check the CPU Type */
57 if (Prcb->CpuType <= 4)
58 {
59 /* 486's or equal can't go higher then 10ms */
60 HalpLargestClockMS = 10;
61 HalpNextMSRate = 9;
62 }
63
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;
67
68 /* Set the maximum and minimum increment with the kernel */
69 HalpCurrentTimeIncrement = Increment;
70 KeSetTimeIncrement(Increment, HalpRolloverTable[0].HighPart);
71
72 /* Disable interrupts */
73 Flags = __readeflags();
74 _disable();
75
76 /* Program the PIT for binary mode */
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 /* Set the access mode that we'll use to program the reload value */
90 TimerControl.AccessMode = PitAccessModeLowHigh;
91
92 /* Now write the programming bits */
93 __outbyte(TIMER_CONTROL_PORT, TimerControl.Bits);
94
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);
98
99 /* Restore interrupts if they were previously enabled */
100 __writeeflags(Flags);
101
102 /* Save rollover and return */
103 HalpCurrentRollOver = RollOver;
104 }
105
106 #ifdef _M_IX86
107 #ifndef _MINIHAL_
108 VOID
109 FASTCALL
110 HalpClockInterruptHandler(IN PKTRAP_FRAME TrapFrame)
111 {
112 KIRQL Irql;
113
114 /* Enter trap */
115 KiEnterInterruptTrap(TrapFrame);
116
117 /* Start the interrupt */
118 if (HalBeginSystemInterrupt(CLOCK2_LEVEL, PRIMARY_VECTOR_BASE, &Irql))
119 {
120 /* Update the performance counter */
121 HalpPerfCounter.QuadPart += HalpCurrentRollOver;
122 HalpPerfCounterCutoff = KiEnableTimerWatchdog;
123
124 /* Check if someone changed the time rate */
125 if (HalpClockSetMSRate)
126 {
127 /* Not yet supported */
128 UNIMPLEMENTED;
129 ASSERT(FALSE);
130 }
131
132 /* Update the system time -- the kernel will exit this trap */
133 KeUpdateSystemTime(TrapFrame, HalpCurrentTimeIncrement, Irql);
134 }
135
136 /* Spurious, just end the interrupt */
137 KiEoiHelper(TrapFrame);
138 }
139
140 VOID
141 FASTCALL
142 HalpProfileInterruptHandler(IN PKTRAP_FRAME TrapFrame)
143 {
144 KIRQL Irql;
145
146 /* Enter trap */
147 KiEnterInterruptTrap(TrapFrame);
148
149 /* Start the interrupt */
150 if (HalBeginSystemInterrupt(PROFILE_LEVEL, PRIMARY_VECTOR_BASE + 8, &Irql))
151 {
152 /* Profiling isn't yet enabled */
153 UNIMPLEMENTED;
154 ASSERT(FALSE);
155 }
156
157 /* Spurious, just end the interrupt */
158 KiEoiHelper(TrapFrame);
159 }
160 #endif
161
162 #endif
163
164 /* PUBLIC FUNCTIONS ***********************************************************/
165
166 /*
167 * @implemented
168 */
169 VOID
170 NTAPI
171 HalCalibratePerformanceCounter(IN volatile PLONG Count,
172 IN ULONGLONG NewCount)
173 {
174 ULONG_PTR Flags;
175
176 /* Disable interrupts */
177 Flags = __readeflags();
178 _disable();
179
180 /* Do a decrement for this CPU */
181 _InterlockedDecrement(Count);
182
183 /* Wait for other CPUs */
184 while (*Count);
185
186 /* Restore interrupts if they were previously enabled */
187 __writeeflags(Flags);
188 }
189
190 /*
191 * @implemented
192 */
193 ULONG
194 NTAPI
195 HalSetTimeIncrement(IN ULONG Increment)
196 {
197 /* Round increment to ms */
198 Increment /= 10000;
199
200 /* Normalize between our minimum (1 ms) and maximum (variable) setting */
201 if (Increment > HalpLargestClockMS) Increment = HalpLargestClockMS;
202 if (Increment <= 0) Increment = 1;
203
204 /* Set the rate and tell HAL we want to change it */
205 HalpNextMSRate = Increment;
206 HalpClockSetMSRate = TRUE;
207
208 /* Return the increment */
209 return HalpRolloverTable[Increment - 1].HighPart;
210 }
211
212 /* EOF */