Use free Windows DDK and compile with latest MinGW releases.
[reactos.git] / reactos / hal / halx86 / udelay.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2000 David Welch <welch@cwcom.net>
4 * Copyright (C) 1999 Gareth Owen <gaz@athene.co.uk>, Ramon von Handel
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 *
7 * This software is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this software; see the file COPYING. If not, write
19 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
20 * MA 02139, USA.
21 *
22 */
23 /* $Id: udelay.c,v 1.2 2002/09/07 15:12:10 chorns Exp $
24 *
25 * PROJECT: ReactOS kernel
26 * FILE: ntoskrnl/hal/x86/udelay.c
27 * PURPOSE: Busy waiting
28 * PROGRAMMER: David Welch (david.welch@seh.ox.ac.uk)
29 * UPDATE HISTORY:
30 * 06/11/99 Created
31 */
32
33 /* INCLUDES ***************************************************************/
34
35 #include <hal.h>
36
37 #define NDEBUG
38 #include <internal/debug.h>
39
40
41 /* GLOBALS ******************************************************************/
42
43 static unsigned int delay_count = 1;
44
45 #define MILLISEC (10)
46 #define FREQ (1000/MILLISEC)
47
48 #define PRECISION (8)
49
50 #define TMR_CTRL 0x43 /* I/O for control */
51 #define TMR_CNT0 0x40 /* I/O for counter 0 */
52 #define TMR_CNT1 0x41 /* I/O for counter 1 */
53 #define TMR_CNT2 0x42 /* I/O for counter 2 */
54
55 #define TMR_SC0 0 /* Select channel 0 */
56 #define TMR_SC1 0x40 /* Select channel 1 */
57 #define TMR_SC2 0x80 /* Select channel 2 */
58
59 #define TMR_LOW 0x10 /* RW low byte only */
60 #define TMR_HIGH 0x20 /* RW high byte only */
61 #define TMR_BOTH 0x30 /* RW both bytes */
62
63 #define TMR_MD0 0 /* Mode 0 */
64 #define TMR_MD1 0x2 /* Mode 1 */
65 #define TMR_MD2 0x4 /* Mode 2 */
66 #define TMR_MD3 0x6 /* Mode 3 */
67 #define TMR_MD4 0x8 /* Mode 4 */
68 #define TMR_MD5 0xA /* Mode 5 */
69
70 #define TMR_BCD 1 /* BCD mode */
71
72 #define TMR_LATCH 0 /* Latch command */
73
74 #define TMR_READ 0xF0 /* Read command */
75 #define TMR_CNT 0x20 /* CNT bit (Active low, subtract it) */
76 #define TMR_STAT 0x10 /* Status bit (Active low, subtract it) */
77 #define TMR_CH2 0x8 /* Channel 2 bit */
78 #define TMR_CH1 0x4 /* Channel 1 bit */
79 #define TMR_CH0 0x2 /* Channel 0 bit */
80
81 static BOOLEAN UdelayCalibrated = FALSE;
82
83 /* FUNCTIONS **************************************************************/
84
85 void init_pit(float h, unsigned char channel)
86 {
87 unsigned int temp=0;
88
89 temp = 1193180/h;
90
91 // WRITE_PORT_UCHAR((PUCHAR)TMR_CTRL,
92 // (channel*0x40) + TMR_BOTH + TMR_MD3);
93 WRITE_PORT_UCHAR((PUCHAR)TMR_CTRL,
94 (channel*0x40) + TMR_BOTH + TMR_MD2);
95 WRITE_PORT_UCHAR((PUCHAR)(0x40+channel),
96 (unsigned char) temp);
97 WRITE_PORT_UCHAR((PUCHAR)(0x40+channel),
98 (unsigned char) (temp>>8));
99 }
100
101 VOID STDCALL
102 __KeStallExecutionProcessor(ULONG Loops)
103 {
104 register unsigned int i;
105 for (i=0; i<Loops;i++);
106 }
107
108 VOID STDCALL KeStallExecutionProcessor(ULONG Microseconds)
109 {
110 __KeStallExecutionProcessor((delay_count*Microseconds)/1000);
111 }
112
113 #define HZ (100)
114 #define CLOCK_TICK_RATE (1193182)
115 #define LATCH (CLOCK_TICK_RATE / HZ)
116
117 static ULONG Read8254Timer(VOID)
118 {
119 ULONG Count;
120
121 WRITE_PORT_UCHAR((PUCHAR)0x43, 0x00);
122 Count = READ_PORT_UCHAR((PUCHAR)0x40);
123 Count |= READ_PORT_UCHAR((PUCHAR)0x40) << 8;
124 return Count;
125 }
126
127
128 static VOID WaitFor8254Wraparound(VOID)
129 {
130 ULONG CurCount, PrevCount = ~0;
131 LONG Delta;
132
133 CurCount = Read8254Timer();
134
135 do {
136 PrevCount = CurCount;
137 CurCount = Read8254Timer();
138 Delta = CurCount - PrevCount;
139
140 /*
141 * This limit for delta seems arbitrary, but it isn't, it's
142 * slightly above the level of error a buggy Mercury/Neptune
143 * chipset timer can cause.
144 */
145
146 } while (Delta < 300);
147 }
148
149 VOID HalpCalibrateStallExecution(VOID)
150 {
151 ULONG i;
152 ULONG calib_bit;
153 ULONG CurCount;
154
155 if (UdelayCalibrated)
156 return;
157
158 UdelayCalibrated = TRUE;
159
160 DbgPrint("Calibrating delay loop... [");
161
162 /* Initialise timer interrupt with MILLISECOND ms interval */
163 WRITE_PORT_UCHAR((PUCHAR)0x43, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
164 WRITE_PORT_UCHAR((PUCHAR)0x40, LATCH & 0xff); /* LSB */
165 WRITE_PORT_UCHAR((PUCHAR)0x40, LATCH >> 8); /* MSB */
166
167 /* Stage 1: Coarse calibration */
168
169 WaitFor8254Wraparound();
170
171 delay_count = 1;
172
173 do {
174 delay_count <<= 1; /* Next delay count to try */
175
176 WaitFor8254Wraparound();
177
178 __KeStallExecutionProcessor(delay_count); /* Do the delay */
179
180 CurCount = Read8254Timer();
181 } while (CurCount > LATCH / 2);
182
183 delay_count >>= 1; /* Get bottom value for delay */
184
185 /* Stage 2: Fine calibration */
186 DbgPrint("delay_count: %d", delay_count);
187
188 calib_bit = delay_count; /* Which bit are we going to test */
189
190 for(i=0;i<PRECISION;i++) {
191 calib_bit >>= 1; /* Next bit to calibrate */
192 if(!calib_bit) break; /* If we have done all bits, stop */
193
194 delay_count |= calib_bit; /* Set the bit in delay_count */
195
196 WaitFor8254Wraparound();
197
198 __KeStallExecutionProcessor(delay_count); /* Do the delay */
199
200 CurCount = Read8254Timer();
201 if (CurCount <= LATCH / 2) /* If a tick has passed, turn the */
202 delay_count &= ~calib_bit; /* calibrated bit back off */
203 }
204
205 /* We're finished: Do the finishing touches */
206
207 delay_count /= (MILLISEC / 2); /* Calculate delay_count for 1ms */
208
209 DbgPrint("]\n");
210 DbgPrint("delay_count: %d\n", delay_count);
211 DbgPrint("CPU speed: %d\n", delay_count/250);
212 #if 0
213 DbgPrint("About to start delay loop test\n");
214 DbgPrint("Waiting for five minutes...");
215 for (i = 0; i < (5*60*1000*20); i++)
216 {
217 KeStallExecutionProcessor(50);
218 }
219 DbgPrint("finished\n");
220 for(;;);
221 #endif
222 }
223
224 /* EOF */