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
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.
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.
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,
23 /* $Id: udelay.c,v 1.2 2002/09/07 15:12:10 chorns Exp $
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)
33 /* INCLUDES ***************************************************************/
38 #include <internal/debug.h>
41 /* GLOBALS ******************************************************************/
43 static unsigned int delay_count
= 1;
46 #define FREQ (1000/MILLISEC)
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 */
55 #define TMR_SC0 0 /* Select channel 0 */
56 #define TMR_SC1 0x40 /* Select channel 1 */
57 #define TMR_SC2 0x80 /* Select channel 2 */
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 */
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 */
70 #define TMR_BCD 1 /* BCD mode */
72 #define TMR_LATCH 0 /* Latch command */
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 */
81 static BOOLEAN UdelayCalibrated
= FALSE
;
83 /* FUNCTIONS **************************************************************/
85 void init_pit(float h
, unsigned char channel
)
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));
102 __KeStallExecutionProcessor(ULONG Loops
)
104 register unsigned int i
;
105 for (i
=0; i
<Loops
;i
++);
108 VOID STDCALL
KeStallExecutionProcessor(ULONG Microseconds
)
110 __KeStallExecutionProcessor((delay_count
*Microseconds
)/1000);
114 #define CLOCK_TICK_RATE (1193182)
115 #define LATCH (CLOCK_TICK_RATE / HZ)
117 static ULONG
Read8254Timer(VOID
)
121 WRITE_PORT_UCHAR((PUCHAR
)0x43, 0x00);
122 Count
= READ_PORT_UCHAR((PUCHAR
)0x40);
123 Count
|= READ_PORT_UCHAR((PUCHAR
)0x40) << 8;
128 static VOID
WaitFor8254Wraparound(VOID
)
130 ULONG CurCount
, PrevCount
= ~0;
133 CurCount
= Read8254Timer();
136 PrevCount
= CurCount
;
137 CurCount
= Read8254Timer();
138 Delta
= CurCount
- PrevCount
;
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.
146 } while (Delta
< 300);
149 VOID
HalpCalibrateStallExecution(VOID
)
155 if (UdelayCalibrated
)
158 UdelayCalibrated
= TRUE
;
160 DbgPrint("Calibrating delay loop... [");
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 */
167 /* Stage 1: Coarse calibration */
169 WaitFor8254Wraparound();
174 delay_count
<<= 1; /* Next delay count to try */
176 WaitFor8254Wraparound();
178 __KeStallExecutionProcessor(delay_count
); /* Do the delay */
180 CurCount
= Read8254Timer();
181 } while (CurCount
> LATCH
/ 2);
183 delay_count
>>= 1; /* Get bottom value for delay */
185 /* Stage 2: Fine calibration */
186 DbgPrint("delay_count: %d", delay_count
);
188 calib_bit
= delay_count
; /* Which bit are we going to test */
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 */
194 delay_count
|= calib_bit
; /* Set the bit in delay_count */
196 WaitFor8254Wraparound();
198 __KeStallExecutionProcessor(delay_count
); /* Do the delay */
200 CurCount
= Read8254Timer();
201 if (CurCount
<= LATCH
/ 2) /* If a tick has passed, turn the */
202 delay_count
&= ~calib_bit
; /* calibrated bit back off */
205 /* We're finished: Do the finishing touches */
207 delay_count
/= (MILLISEC
/ 2); /* Calculate delay_count for 1ms */
210 DbgPrint("delay_count: %d\n", delay_count
);
211 DbgPrint("CPU speed: %d\n", delay_count
/250);
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
++)
217 KeStallExecutionProcessor(50);
219 DbgPrint("finished\n");