Reverted latest changes.
[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.3 2002/09/08 10:22:25 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 <ddk/ntddk.h>
36
37 #define NDEBUG
38 #include <internal/debug.h>
39
40 /* GLOBALS ******************************************************************/
41
42 static unsigned int delay_count = 1;
43
44 #define MILLISEC (10)
45 #define FREQ (1000/MILLISEC)
46
47 #define PRECISION (8)
48
49 #define TMR_CTRL 0x43 /* I/O for control */
50 #define TMR_CNT0 0x40 /* I/O for counter 0 */
51 #define TMR_CNT1 0x41 /* I/O for counter 1 */
52 #define TMR_CNT2 0x42 /* I/O for counter 2 */
53
54 #define TMR_SC0 0 /* Select channel 0 */
55 #define TMR_SC1 0x40 /* Select channel 1 */
56 #define TMR_SC2 0x80 /* Select channel 2 */
57
58 #define TMR_LOW 0x10 /* RW low byte only */
59 #define TMR_HIGH 0x20 /* RW high byte only */
60 #define TMR_BOTH 0x30 /* RW both bytes */
61
62 #define TMR_MD0 0 /* Mode 0 */
63 #define TMR_MD1 0x2 /* Mode 1 */
64 #define TMR_MD2 0x4 /* Mode 2 */
65 #define TMR_MD3 0x6 /* Mode 3 */
66 #define TMR_MD4 0x8 /* Mode 4 */
67 #define TMR_MD5 0xA /* Mode 5 */
68
69 #define TMR_BCD 1 /* BCD mode */
70
71 #define TMR_LATCH 0 /* Latch command */
72
73 #define TMR_READ 0xF0 /* Read command */
74 #define TMR_CNT 0x20 /* CNT bit (Active low, subtract it) */
75 #define TMR_STAT 0x10 /* Status bit (Active low, subtract it) */
76 #define TMR_CH2 0x8 /* Channel 2 bit */
77 #define TMR_CH1 0x4 /* Channel 1 bit */
78 #define TMR_CH0 0x2 /* Channel 0 bit */
79
80 static BOOLEAN UdelayCalibrated = FALSE;
81
82 /* FUNCTIONS **************************************************************/
83
84 void init_pit(float h, unsigned char channel)
85 {
86 unsigned int temp=0;
87
88 temp = 1193180/h;
89
90 // WRITE_PORT_UCHAR((PUCHAR)TMR_CTRL,
91 // (channel*0x40) + TMR_BOTH + TMR_MD3);
92 WRITE_PORT_UCHAR((PUCHAR)TMR_CTRL,
93 (channel*0x40) + TMR_BOTH + TMR_MD2);
94 WRITE_PORT_UCHAR((PUCHAR)(0x40+channel),
95 (unsigned char) temp);
96 WRITE_PORT_UCHAR((PUCHAR)(0x40+channel),
97 (unsigned char) (temp>>8));
98 }
99
100 VOID STDCALL
101 __KeStallExecutionProcessor(ULONG Loops)
102 {
103 register unsigned int i;
104 for (i=0; i<Loops;i++);
105 }
106
107 VOID STDCALL KeStallExecutionProcessor(ULONG Microseconds)
108 {
109 __KeStallExecutionProcessor((delay_count*Microseconds)/1000);
110 }
111
112 #define HZ (100)
113 #define CLOCK_TICK_RATE (1193182)
114 #define LATCH (CLOCK_TICK_RATE / HZ)
115
116 static ULONG Read8254Timer(VOID)
117 {
118 ULONG Count;
119
120 WRITE_PORT_UCHAR((PUCHAR)0x43, 0x00);
121 Count = READ_PORT_UCHAR((PUCHAR)0x40);
122 Count |= READ_PORT_UCHAR((PUCHAR)0x40) << 8;
123 return Count;
124 }
125
126
127 static VOID WaitFor8254Wraparound(VOID)
128 {
129 ULONG CurCount, PrevCount = ~0;
130 LONG Delta;
131
132 CurCount = Read8254Timer();
133
134 do {
135 PrevCount = CurCount;
136 CurCount = Read8254Timer();
137 Delta = CurCount - PrevCount;
138
139 /*
140 * This limit for delta seems arbitrary, but it isn't, it's
141 * slightly above the level of error a buggy Mercury/Neptune
142 * chipset timer can cause.
143 */
144
145 } while (Delta < 300);
146 }
147
148 VOID HalpCalibrateStallExecution(VOID)
149 {
150 ULONG i;
151 ULONG calib_bit;
152 ULONG CurCount;
153
154 if (UdelayCalibrated)
155 return;
156
157 UdelayCalibrated = TRUE;
158
159 DbgPrint("Calibrating delay loop... [");
160
161 /* Initialise timer interrupt with MILLISECOND ms interval */
162 WRITE_PORT_UCHAR((PUCHAR)0x43, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
163 WRITE_PORT_UCHAR((PUCHAR)0x40, LATCH & 0xff); /* LSB */
164 WRITE_PORT_UCHAR((PUCHAR)0x40, LATCH >> 8); /* MSB */
165
166 /* Stage 1: Coarse calibration */
167
168 WaitFor8254Wraparound();
169
170 delay_count = 1;
171
172 do {
173 delay_count <<= 1; /* Next delay count to try */
174
175 WaitFor8254Wraparound();
176
177 __KeStallExecutionProcessor(delay_count); /* Do the delay */
178
179 CurCount = Read8254Timer();
180 } while (CurCount > LATCH / 2);
181
182 delay_count >>= 1; /* Get bottom value for delay */
183
184 /* Stage 2: Fine calibration */
185 DbgPrint("delay_count: %d", delay_count);
186
187 calib_bit = delay_count; /* Which bit are we going to test */
188
189 for(i=0;i<PRECISION;i++) {
190 calib_bit >>= 1; /* Next bit to calibrate */
191 if(!calib_bit) break; /* If we have done all bits, stop */
192
193 delay_count |= calib_bit; /* Set the bit in delay_count */
194
195 WaitFor8254Wraparound();
196
197 __KeStallExecutionProcessor(delay_count); /* Do the delay */
198
199 CurCount = Read8254Timer();
200 if (CurCount <= LATCH / 2) /* If a tick has passed, turn the */
201 delay_count &= ~calib_bit; /* calibrated bit back off */
202 }
203
204 /* We're finished: Do the finishing touches */
205
206 delay_count /= (MILLISEC / 2); /* Calculate delay_count for 1ms */
207
208 DbgPrint("]\n");
209 DbgPrint("delay_count: %d\n", delay_count);
210 DbgPrint("CPU speed: %d\n", delay_count/250);
211 #if 0
212 DbgPrint("About to start delay loop test\n");
213 DbgPrint("Waiting for five minutes...");
214 for (i = 0; i < (5*60*1000*20); i++)
215 {
216 KeStallExecutionProcessor(50);
217 }
218 DbgPrint("finished\n");
219 for(;;);
220 #endif
221 }
222
223 /* EOF */