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.3 2002/09/08 10:22:25 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 ***************************************************************/
35 #include <ddk/ntddk.h>
38 #include <internal/debug.h>
40 /* GLOBALS ******************************************************************/
42 static unsigned int delay_count
= 1;
45 #define FREQ (1000/MILLISEC)
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 */
54 #define TMR_SC0 0 /* Select channel 0 */
55 #define TMR_SC1 0x40 /* Select channel 1 */
56 #define TMR_SC2 0x80 /* Select channel 2 */
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 */
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 */
69 #define TMR_BCD 1 /* BCD mode */
71 #define TMR_LATCH 0 /* Latch command */
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 */
80 static BOOLEAN UdelayCalibrated
= FALSE
;
82 /* FUNCTIONS **************************************************************/
84 void init_pit(float h
, unsigned char channel
)
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));
101 __KeStallExecutionProcessor(ULONG Loops
)
103 register unsigned int i
;
104 for (i
=0; i
<Loops
;i
++);
107 VOID STDCALL
KeStallExecutionProcessor(ULONG Microseconds
)
109 __KeStallExecutionProcessor((delay_count
*Microseconds
)/1000);
113 #define CLOCK_TICK_RATE (1193182)
114 #define LATCH (CLOCK_TICK_RATE / HZ)
116 static ULONG
Read8254Timer(VOID
)
120 WRITE_PORT_UCHAR((PUCHAR
)0x43, 0x00);
121 Count
= READ_PORT_UCHAR((PUCHAR
)0x40);
122 Count
|= READ_PORT_UCHAR((PUCHAR
)0x40) << 8;
127 static VOID
WaitFor8254Wraparound(VOID
)
129 ULONG CurCount
, PrevCount
= ~0;
132 CurCount
= Read8254Timer();
135 PrevCount
= CurCount
;
136 CurCount
= Read8254Timer();
137 Delta
= CurCount
- PrevCount
;
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.
145 } while (Delta
< 300);
148 VOID
HalpCalibrateStallExecution(VOID
)
154 if (UdelayCalibrated
)
157 UdelayCalibrated
= TRUE
;
159 DbgPrint("Calibrating delay loop... [");
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 */
166 /* Stage 1: Coarse calibration */
168 WaitFor8254Wraparound();
173 delay_count
<<= 1; /* Next delay count to try */
175 WaitFor8254Wraparound();
177 __KeStallExecutionProcessor(delay_count
); /* Do the delay */
179 CurCount
= Read8254Timer();
180 } while (CurCount
> LATCH
/ 2);
182 delay_count
>>= 1; /* Get bottom value for delay */
184 /* Stage 2: Fine calibration */
185 DbgPrint("delay_count: %d", delay_count
);
187 calib_bit
= delay_count
; /* Which bit are we going to test */
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 */
193 delay_count
|= calib_bit
; /* Set the bit in delay_count */
195 WaitFor8254Wraparound();
197 __KeStallExecutionProcessor(delay_count
); /* Do the delay */
199 CurCount
= Read8254Timer();
200 if (CurCount
<= LATCH
/ 2) /* If a tick has passed, turn the */
201 delay_count
&= ~calib_bit
; /* calibrated bit back off */
204 /* We're finished: Do the finishing touches */
206 delay_count
/= (MILLISEC
/ 2); /* Calculate delay_count for 1ms */
209 DbgPrint("delay_count: %d\n", delay_count
);
210 DbgPrint("CPU speed: %d\n", delay_count
/250);
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
++)
216 KeStallExecutionProcessor(50);
218 DbgPrint("finished\n");