FreeBSD/Linux Kernel Cross Reference
sys/i386/pit.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
4 * Copyright (c) 1991 IBM Corporation
5 * All Rights Reserved.
6 *
7 * Permission to use, copy, modify and distribute this software and its
8 * documentation is hereby granted, provided that both the copyright
9 * notice and this permission notice appear in all copies of the
10 * software, derivative works or modified versions, and any portions
11 * thereof, and that both notices appear in supporting documentation,
12 * and that the name IBM not be used in advertising or publicity
13 * pertaining to distribution of the software without specific, written
14 * prior permission.
15 *
16 * CARNEGIE MELLON AND IBM ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17 * CONDITION. CARNEGIE MELLON AND IBM DISCLAIM ANY LIABILITY OF ANY KIND FOR
18 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19 *
20 * Carnegie Mellon requests users of this software to return to
21 *
22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
23 * School of Computer Science
24 * Carnegie Mellon University
25 * Pittsburgh PA 15213-3890
26 *
27 * any improvements or extensions that they make and grant Carnegie Mellon
28 * the rights to redistribute these changes.
29 */
30
31 /*
32 * HISTORY
33 * $Log: pit.c,v $
34 * Revision 2.11 93/02/04 07:56:56 danner
35 * Make spinwait() and tenmicrosec() [findspeed() & microtime()]
36 * available for everyone. They once were but they were incorrect.
37 * Re-add tenmicrosec for PS2.
38 * [92/02/25 dbg@ibm]
39 *
40 * Revision 2.9 91/10/07 17:25:03 af
41 * tenmicrosec() was all wrong has been expunged, since noone uses
42 * it.
43 * [91/09/04 rvb]
44 *
45 * Revision 2.8 91/06/19 11:55:29 rvb
46 * cputypes.h->platforms.h
47 * [91/06/12 13:45:16 rvb]
48 *
49 * Revision 2.7 91/05/14 16:14:40 mrt
50 * Correcting copyright
51 *
52 * Revision 2.6 91/02/05 17:14:03 mrt
53 * Changed to new Mach copyright
54 * [91/02/01 17:37:14 mrt]
55 *
56 * Revision 2.5 91/01/09 19:25:33 rpd
57 * Fixed clkstart to reset clock interrupt priority, etc.
58 * [91/01/09 rpd]
59 *
60 * Flush dead EXL code.
61 * [90/11/27 11:38:08 rvb]
62 *
63 * Revision 2.3 90/08/27 21:57:57 dbg
64 * Fix Intel Copyright as per B. Davies authorization.
65 * [90/08/14 dbg]
66 * Add Intel copyright.
67 * [90/01/08 rvb]
68 * splall/backall -> splon/sploff
69 * [89/10/20 rvb]
70 *
71 * Revision 2.2 90/05/03 15:36:34 dbg
72 * Converted for pure kernel.
73 * [90/02/20 dbg]
74 *
75 * Revision 2.2 89/09/25 12:32:40 rvb
76 * File was provided by Intel 9/18/89.
77 * [89/09/23 rvb]
78 *
79 */
80
81 /*
82 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
83
84 All Rights Reserved
85
86 Permission to use, copy, modify, and distribute this software and
87 its documentation for any purpose and without fee is hereby
88 granted, provided that the above copyright notice appears in all
89 copies and that both the copyright notice and this permission notice
90 appear in supporting documentation, and that the name of Intel
91 not be used in advertising or publicity pertaining to distribution
92 of the software without specific, written prior permission.
93
94 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
95 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
96 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
97 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
98 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
99 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
100 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
101 */
102
103 #include <platforms.h>
104 #include <kern/time_out.h>
105 #include <i386/ipl.h>
106 #include <i386/pit.h>
107
108 int pitctl_port = PITCTL_PORT; /* For 386/20 Board */
109 int pitctr0_port = PITCTR0_PORT; /* For 386/20 Board */
110 int pitctr1_port = PITCTR1_PORT; /* For 386/20 Board */
111 int pitctr2_port = PITCTR2_PORT; /* For 386/20 Board */
112 /* We want PIT 0 in square wave mode */
113
114 int pit0_mode = PIT_C0|PIT_SQUAREMODE|PIT_READMODE ;
115
116
117 unsigned int delaycount; /* loop count in trying to delay for
118 * 1 millisecond
119 */
120 unsigned long microdata=50; /* loop count for 10 microsecond wait.
121 MUST be initialized for those who
122 insist on calling "tenmicrosec"
123 it before the clock has been
124 initialized.
125 */
126 unsigned int clknumb = CLKNUM; /* interrupt interval for timer 0 */
127
128 #ifdef PS2
129 extern int clock_int_handler();
130
131 #include <sys/types.h>
132 #include <i386ps2/abios.h>
133 static struct generic_request *clock_request_block;
134 static int clock_flags;
135 char cqbuf[200]; /*XXX temporary.. should use kmem_alloc or whatever..*/
136 #endif /* PS2 */
137
138 clkstart()
139 {
140 unsigned int flags;
141 unsigned char byte;
142 int s;
143
144 intpri[0] = SPLHI;
145 form_pic_mask();
146
147 findspeed();
148 microfind();
149 s = sploff(); /* disable interrupts */
150
151 #ifdef PS2
152 abios_clock_start();
153 #endif /* PS2 */
154
155 /* Since we use only timer 0, we program that.
156 * 8254 Manual specifically says you do not need to program
157 * timers you do not use
158 */
159 outb(pitctl_port, pit0_mode);
160 clknumb = CLKNUM/hz;
161 byte = clknumb;
162 outb(pitctr0_port, byte);
163 byte = clknumb>>8;
164 outb(pitctr0_port, byte);
165 splon(s); /* restore interrupt state */
166 }
167
168 #define COUNT 10000 /* should be a multiple of 1000! */
169
170 findspeed()
171 {
172 unsigned int flags;
173 unsigned char byte;
174 unsigned int leftover;
175 int i;
176 int j;
177 int s;
178
179 s = sploff(); /* disable interrupts */
180 /* Put counter in count down mode */
181 #define PIT_COUNTDOWN PIT_READMODE|PIT_NDIVMODE
182 outb(pitctl_port, PIT_COUNTDOWN);
183 /* output a count of -1 to counter 0 */
184 outb(pitctr0_port, 0xff);
185 outb(pitctr0_port, 0xff);
186 delaycount = COUNT;
187 spinwait(1);
188 /* Read the value left in the counter */
189 byte = inb(pitctr0_port); /* least siginifcant */
190 leftover = inb(pitctr0_port); /* most significant */
191 leftover = (leftover<<8) + byte ;
192 /* Formula for delaycount is :
193 * (loopcount * timer clock speed)/ (counter ticks * 1000)
194 * 1000 is for figuring out milliseconds
195 */
196 /* we arrange calculation so that it doesn't overflow */
197 delaycount = ((COUNT/1000) * CLKNUM) / (0xffff-leftover);
198 printf("findspeed: delaycount=%d (tics=%d)\n",
199 delaycount, (0xffff-leftover));
200 splon(s); /* restore interrupt state */
201 }
202
203 #ifdef PS2
204
205 abios_clock_start()
206 {
207 struct generic_request temp_request_block;
208 int rc;
209
210 nmi_enable(); /* has to happen somewhere! */
211 temp_request_block.r_current_req_blck_len = ABIOS_MIN_REQ_SIZE;
212 temp_request_block.r_logical_id = abios_next_LID(SYSTIME_ID,
213 ABIOS_FIRST_LID);
214 temp_request_block.r_unit = 0;
215 temp_request_block.r_function = ABIOS_LOGICAL_PARAMETER;
216 temp_request_block.r_return_code = ABIOS_UNDEFINED;
217
218 abios_common_start(&temp_request_block,0);
219 if (temp_request_block.r_return_code != ABIOS_DONE) {
220 panic("couldn init abios time code!\n");
221 }
222
223 /*
224 * now build the clock request for the hardware system clock
225 */
226 clock_request_block = (struct generic_request *)cqbuf;
227 clock_request_block->r_current_req_blck_len =
228 temp_request_block.r_request_block_length;
229 clock_request_block->r_logical_id = temp_request_block.r_logical_id;
230 clock_request_block->r_unit = 0;
231 clock_request_block->r_function = ABIOS_DEFAULT_INTERRUPT;
232 clock_request_block->r_return_code = ABIOS_UNDEFINED;
233 clock_flags = temp_request_block.r_logical_id_flags;
234 }
235
236 ackrtclock()
237 {
238 if (clock_request_block) {
239 clock_request_block->r_return_code = ABIOS_UNDEFINED;
240 abios_common_interrupt(clock_request_block,clock_flags);
241 }
242 }
243 #endif /* PS2 */
244
245
246 spinwait(millis)
247 int millis; /* number of milliseconds to delay */
248 {
249 int i, j;
250
251 for (i=0;i<millis;i++)
252 for (j=0;j<delaycount;j++)
253 ;
254 }
255
256 #define MICROCOUNT 1000 /* keep small to prevent overflow */
257 microfind()
258 {
259 unsigned int flags;
260 unsigned char byte;
261 unsigned short leftover;
262 int s;
263
264
265 s = sploff(); /* disable interrupts */
266
267 /* Put counter in count down mode */
268 outb(pitctl_port, PIT_COUNTDOWN);
269 /* output a count of -1 to counter 0 */
270 outb(pitctr0_port, 0xff);
271 outb(pitctr0_port, 0xff);
272 microdata=MICROCOUNT;
273 tenmicrosec();
274 /* Read the value left in the counter */
275 byte = inb(pitctr0_port); /* least siginifcant */
276 leftover = inb(pitctr0_port); /* most significant */
277 leftover = (leftover<<8) + byte ;
278 /* Formula for delaycount is :
279 * (loopcount * timer clock speed)/ (counter ticks * 1000)
280 * Note also that 1000 is for figuring out milliseconds
281 */
282 microdata = (MICROCOUNT * CLKNUM) / ((0xffff-leftover)*100000);
283 if (!microdata)
284 microdata++;
285
286 splon(s); /* restore interrupt state */
287 }
Cache object: d425671a4148801e18dba284a6ee9582
|