Deleted Added
full compact
clock.c (2103) clock.c (2112)
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * William Jolitz and Don Ahn.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * William Jolitz and Don Ahn.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
37 * $Id: clock.c,v 1.14 1994/08/15 03:15:18 wollman Exp $
37 * $Id: clock.c,v 1.15 1994/08/18 05:09:21 davidg Exp $
38 */
39
40/*
41 * Primitive clock interrupt routines.
42 */
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/time.h>
46#include <sys/kernel.h>
47#include <machine/segments.h>
48#include <machine/frame.h>
49#include <i386/isa/icu.h>
50#include <i386/isa/isa.h>
51#include <i386/isa/rtc.h>
52#include <i386/isa/timerreg.h>
53#include <machine/cpu.h>
54
55/* X-tals being what they are, it's nice to be able to fudge this one... */
56/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
57#ifndef TIMER_FREQ
58#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
59#endif
60#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
61
38 */
39
40/*
41 * Primitive clock interrupt routines.
42 */
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/time.h>
46#include <sys/kernel.h>
47#include <machine/segments.h>
48#include <machine/frame.h>
49#include <i386/isa/icu.h>
50#include <i386/isa/isa.h>
51#include <i386/isa/rtc.h>
52#include <i386/isa/timerreg.h>
53#include <machine/cpu.h>
54
55/* X-tals being what they are, it's nice to be able to fudge this one... */
56/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
57#ifndef TIMER_FREQ
58#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
59#endif
60#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
61
62void hardclock();
63void statclock();
64static int beeping;
65int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */
66u_int timer0_prescale;
67static char timer0_state = 0, timer2_state = 0;
68static char timer0_reprogram = 0;
69static void (*timer_func)() = hardclock;
70static void (*new_function)();
71static u_int new_rate;
72static u_int hardclock_divisor;
73
74#ifdef I586_CPU
75int pentium_mhz = 0;
76#endif
77
78void
79clkintr(frame)
80 struct clockframe frame;
81{
82#ifdef I586_CPU
83 /*
84 * This resets the CPU cycle counter to zero, to make our
85 * job easier in microtime(). Some fancy ifdefs could speed
86 * this up for Pentium-only kernels.
87 * We want this to be done as close as possible to the actual
88 * timer incrementing in hardclock(), because there is a window
89 * between the two where the value is no longer valid. Experimentation
90 * may reveal a good precompensation to apply in microtime().
91 */
92 if(pentium_mhz) {
93 __asm __volatile("movl $0x10,%%ecx\n"
94 "xorl %%eax,%%eax\n"
95 "movl %%eax,%%edx\n"
96 ".byte 0x0f, 0x30\n"
97 "#%0%1"
98 : "=m"(frame) /* no outputs */
99 : "b"(&frame) /* fake input */
100 : "ax", "cx", "dx");
101 }
102#endif
103 hardclock(&frame);
104}
105
106static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
107
108/*
109 * This routine receives statistical clock interrupts from the RTC.
110 * As explained above, these occur at 128 interrupts per second.
111 * When profiling, we receive interrupts at a rate of 1024 Hz.
112 *
113 * This does not actually add as much overhead as it sounds, because
114 * when the statistical clock is active, the hardclock driver no longer
115 * needs to keep (inaccurate) statistics on its own. This decouples
116 * statistics gathering from scheduling interrupts.
117 *
118 * The RTC chip requires that we read status register C (RTC_INTR)
119 * to acknowledge an interrupt, before it will generate the next one.
120 */
121void
122rtcintr(struct clockframe frame)
123{
124 u_char stat;
125 stat = rtcin(RTC_INTR);
126 if(stat & RTCIR_PERIOD) {
127 statclock(&frame);
128 }
129}
130
131#ifdef DEBUG
132void
133printrtc(void)
134{
135 outb(IO_RTC, RTC_STATUSA);
136 printf("RTC status A = %x", inb(IO_RTC+1));
137 outb(IO_RTC, RTC_STATUSB);
138 printf(", B = %x", inb(IO_RTC+1));
139 outb(IO_RTC, RTC_INTR);
140 printf(", C = %x\n", inb(IO_RTC+1));
141}
142#endif
143
144#if 0
145void
146timerintr(struct clockframe frame)
147{
148 timer_func(&frame);
149 switch (timer0_state) {
150 case 0:
151 break;
152 case 1:
153 if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
154 hardclock(&frame);
155 timer0_prescale = 0;
156 }
157 break;
158 case 2:
159 disable_intr();
160 outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
161 outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256);
162 outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256);
163 enable_intr();
164 timer0_divisor = TIMER_DIV(new_rate);
165 timer0_prescale = 0;
166 timer_func = new_function;
167 timer0_state = 1;
168 break;
169 case 3:
170 if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
171 hardclock(&frame);
172 disable_intr();
173 outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
174 outb(TIMER_CNTR0, TIMER_DIV(hz)%256);
175 outb(TIMER_CNTR0, TIMER_DIV(hz)/256);
176 enable_intr();
177 timer0_divisor = TIMER_DIV(hz);
178 timer0_prescale = 0;
179 timer_func = hardclock;;
180 timer0_state = 0;
181 }
182 break;
183 }
184}
185
186#endif
187
188int
189acquire_timer0(int rate, void (*function)() )
190{
191 if (timer0_state || !function)
192 return -1;
193
194 new_function = function;
195 new_rate = rate;
196 timer0_state = 2;
197 return 0;
198}
199
200
201int
202acquire_timer2(int mode)
203{
204 if (timer2_state)
205 return -1;
206 timer2_state = 1;
207 outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f));
208 return 0;
209}
210
211
212int
213release_timer0()
214{
215 if (!timer0_state)
216 return -1;
217 timer0_state = 3;
218 return 0;
219}
220
221
222int
223release_timer2()
224{
225 if (!timer2_state)
226 return -1;
227 timer2_state = 0;
228 outb(TIMER_MODE, TIMER_SEL2|TIMER_SQWAVE|TIMER_16BIT);
229 return 0;
230}
231
232
233static int
234getit()
235{
236 int high, low;
237
238 disable_intr();
239 /* select timer0 and latch counter value */
240 outb(TIMER_MODE, TIMER_SEL0);
241 low = inb(TIMER_CNTR0);
242 high = inb(TIMER_CNTR0);
243 enable_intr();
244 return ((high << 8) | low);
245}
246
247#ifdef I586_CPU
248static long long cycles_per_sec = 0;
249
250/*
251 * Figure out how fast the cyclecounter runs. This must be run with
252 * clock interrupts disabled, but with the timer/counter programmed
253 * and running.
254 */
255void
256calibrate_cyclecounter(void)
257{
258 volatile long edx, eax, lasteax, lastedx;
259
260 __asm __volatile(".byte 0x0f, 0x31" : "=a"(lasteax), "=d"(lastedx) : );
261 DELAY(1000000);
262 __asm __volatile(".byte 0x0f, 0x31" : "=a"(eax), "=d"(edx) : );
263
264 /*
265 * This assumes that you will never have a clock rate higher
266 * than 4GHz, probably a good assumption.
267 */
268 cycles_per_sec = (long long)edx + eax;
269 cycles_per_sec -= (long long)lastedx + lasteax;
270 pentium_mhz = ((long)cycles_per_sec + 500000) / 1000000; /* round up */
271}
272#endif
273
274/*
275 * Wait "n" microseconds.
276 * Relies on timer 1 counting down from (TIMER_FREQ / hz)
277 * Note: timer had better have been programmed before this is first used!
278 */
279void
280DELAY(int n)
281{
282 int counter_limit, prev_tick, tick, ticks_left, sec, usec;
283
284#ifdef DELAYDEBUG
285 int getit_calls = 1;
286 int n1;
287 static int state = 0;
288
289 if (state == 0) {
290 state = 1;
291 for (n1 = 1; n1 <= 10000000; n1 *= 10)
292 DELAY(n1);
293 state = 2;
294 }
295 if (state == 1)
296 printf("DELAY(%d)...", n);
297#endif
298 /*
299 * Read the counter first, so that the rest of the setup overhead is
300 * counted. Guess the initial overhead is 20 usec (on most systems it
301 * takes about 1.5 usec for each of the i/o's in getit(). The loop
302 * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
303 * multiplications and divisions to scale the count take a while).
304 */
305 prev_tick = getit(0, 0);
306 n -= 20;
307 /*
308 * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point
309 * and without any avoidable overflows.
310 */
311 sec = n / 1000000;
312 usec = n - sec * 1000000;
313 ticks_left = sec * TIMER_FREQ
314 + usec * (TIMER_FREQ / 1000000)
315 + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000
316 + usec * (TIMER_FREQ % 1000) / 1000000;
317
318 while (ticks_left > 0) {
319 tick = getit(0, 0);
320#ifdef DELAYDEBUG
321 ++getit_calls;
322#endif
323 if (tick > prev_tick)
324 ticks_left -= prev_tick - (tick - timer0_divisor);
325 else
326 ticks_left -= prev_tick - tick;
327 prev_tick = tick;
328 }
329#ifdef DELAYDEBUG
330 if (state == 1)
331 printf(" %d calls to getit() at %d usec each\n",
332 getit_calls, (n + 5) / getit_calls);
333#endif
334}
335
336
337static void
338sysbeepstop()
339{
340 outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */
341 release_timer2();
342 beeping = 0;
343}
344
345
346int
347sysbeep(int pitch, int period)
348{
349
350 if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT))
351 return -1;
352 disable_intr();
353 outb(TIMER_CNTR2, pitch);
354 outb(TIMER_CNTR2, (pitch>>8));
355 enable_intr();
356 if (!beeping) {
357 outb(IO_PPI, inb(IO_PPI) | 3); /* enable counter2 output to speaker */
358 beeping = period;
359 timeout(sysbeepstop, 0, period);
360 }
361 return 0;
362}
363
364
365void
366startrtclock()
367{
368 int s;
369
370 /* initialize 8253 clock */
371 outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
372
373 /* Correct rounding will buy us a better precision in timekeeping */
374 outb (IO_TIMER1, TIMER_DIV(hz)%256);
375 outb (IO_TIMER1, TIMER_DIV(hz)/256);
376 timer0_divisor = hardclock_divisor = TIMER_DIV(hz);
377
378 /* initialize brain-dead battery powered clock */
379 outb (IO_RTC, RTC_STATUSA);
380 outb (IO_RTC+1, rtc_statusa);
381 outb (IO_RTC, RTC_STATUSB);
382 outb (IO_RTC+1, RTCSB_24HR);
383
384 outb (IO_RTC, RTC_DIAG);
385 if (s = inb (IO_RTC+1))
386 printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
387}
388
389
390/* convert 2 digit BCD number */
391int
392bcd(int i)
393{
394 return ((i/16)*10 + (i%16));
395}
396
397
398/* convert years to seconds (from 1970) */
399unsigned long
400ytos(int y)
401{
402 int i;
403 unsigned long ret;
404
405 ret = 0;
406 for(i = 1970; i < y; i++) {
407 if (i % 4) ret += 365*24*60*60;
408 else ret += 366*24*60*60;
409 }
410 return ret;
411}
412
413
414/* convert months to seconds */
415unsigned long
416mtos(int m, int leap)
417{
418 int i;
419 unsigned long ret;
420
421 ret = 0;
422 for(i=1; i<m; i++) {
423 switch(i){
424 case 1: case 3: case 5: case 7: case 8: case 10: case 12:
425 ret += 31*24*60*60; break;
426 case 4: case 6: case 9: case 11:
427 ret += 30*24*60*60; break;
428 case 2:
429 if (leap) ret += 29*24*60*60;
430 else ret += 28*24*60*60;
431 }
432 }
433 return ret;
434}
435
436
437/*
438 * Initialize the time of day register, based on the time base which is, e.g.
439 * from a filesystem.
440 */
441void
442inittodr(time_t base)
443{
444 unsigned long sec;
445 int leap, day_week, t, yd;
446 int sa,s;
447
448 /* do we have a realtime clock present? (otherwise we loop below) */
449 sa = rtcin(RTC_STATUSA);
450 if (sa == 0xff || sa == 0) return;
451
452 /* ready for a read? */
453 while ((sa&RTCSA_TUP) == RTCSA_TUP)
454 sa = rtcin(RTC_STATUSA);
455
456 sec = bcd(rtcin(RTC_YEAR)) + 1900;
457 if (sec < 1970)
458 sec += 100;
459
460 leap = !(sec % 4); sec = ytos(sec); /* year */
461 yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec+=yd; /* month */
462 t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec+=t; yd+=t; /* date */
463 day_week = rtcin(RTC_WDAY); /* day */
464 sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */
465 sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */
466 sec += bcd(rtcin(RTC_SEC)); /* seconds */
467 sec += tz.tz_minuteswest * 60;
468 time.tv_sec = sec;
469}
470
471
472#ifdef garbage
473/*
474 * Initialze the time of day register, based on the time base which is, e.g.
475 * from a filesystem.
476 */
477test_inittodr(time_t base)
478{
479
480 outb(IO_RTC,9); /* year */
481 printf("%d ",bcd(inb(IO_RTC+1)));
482 outb(IO_RTC,8); /* month */
483 printf("%d ",bcd(inb(IO_RTC+1)));
484 outb(IO_RTC,7); /* day */
485 printf("%d ",bcd(inb(IO_RTC+1)));
486 outb(IO_RTC,4); /* hour */
487 printf("%d ",bcd(inb(IO_RTC+1)));
488 outb(IO_RTC,2); /* minutes */
489 printf("%d ",bcd(inb(IO_RTC+1)));
490 outb(IO_RTC,0); /* seconds */
491 printf("%d\n",bcd(inb(IO_RTC+1)));
492
493 time.tv_sec = base;
494}
495#endif
496
497/*
498 * Wire clock interrupt in.
499 */
500void
501enablertclock()
502{
503 register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr,
504 HWI_MASK | SWI_MASK, /* unit */ 0);
505 INTREN(IRQ0);
506 register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, rtcintr,
507 SWI_CLOCK_MASK, /* unit */ 0);
508 INTREN(IRQ8);
509 outb(IO_RTC, RTC_STATUSB);
510 outb(IO_RTC+1, RTCSB_PINTR | RTCSB_24HR);
511}
512
513
514/*
515 * Delay for some number of milliseconds.
516 */
517void
518spinwait(int millisecs)
519{
520 DELAY(1000 * millisecs);
521}
522
523void
524cpu_initclocks()
525{
526 stathz = RTC_NOPROFRATE;
527 profhz = RTC_PROFRATE;
528 enablertclock();
529}
530
531void
532setstatclockrate(int newhz)
533{
534 if(newhz == RTC_PROFRATE) {
535 rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF;
536 } else {
537 rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
538 }
539 outb(IO_RTC, RTC_STATUSA);
540 outb(IO_RTC+1, rtc_statusa);
541}
62static int beeping;
63int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */
64u_int timer0_prescale;
65static char timer0_state = 0, timer2_state = 0;
66static char timer0_reprogram = 0;
67static void (*timer_func)() = hardclock;
68static void (*new_function)();
69static u_int new_rate;
70static u_int hardclock_divisor;
71
72#ifdef I586_CPU
73int pentium_mhz = 0;
74#endif
75
76void
77clkintr(frame)
78 struct clockframe frame;
79{
80#ifdef I586_CPU
81 /*
82 * This resets the CPU cycle counter to zero, to make our
83 * job easier in microtime(). Some fancy ifdefs could speed
84 * this up for Pentium-only kernels.
85 * We want this to be done as close as possible to the actual
86 * timer incrementing in hardclock(), because there is a window
87 * between the two where the value is no longer valid. Experimentation
88 * may reveal a good precompensation to apply in microtime().
89 */
90 if(pentium_mhz) {
91 __asm __volatile("movl $0x10,%%ecx\n"
92 "xorl %%eax,%%eax\n"
93 "movl %%eax,%%edx\n"
94 ".byte 0x0f, 0x30\n"
95 "#%0%1"
96 : "=m"(frame) /* no outputs */
97 : "b"(&frame) /* fake input */
98 : "ax", "cx", "dx");
99 }
100#endif
101 hardclock(&frame);
102}
103
104static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
105
106/*
107 * This routine receives statistical clock interrupts from the RTC.
108 * As explained above, these occur at 128 interrupts per second.
109 * When profiling, we receive interrupts at a rate of 1024 Hz.
110 *
111 * This does not actually add as much overhead as it sounds, because
112 * when the statistical clock is active, the hardclock driver no longer
113 * needs to keep (inaccurate) statistics on its own. This decouples
114 * statistics gathering from scheduling interrupts.
115 *
116 * The RTC chip requires that we read status register C (RTC_INTR)
117 * to acknowledge an interrupt, before it will generate the next one.
118 */
119void
120rtcintr(struct clockframe frame)
121{
122 u_char stat;
123 stat = rtcin(RTC_INTR);
124 if(stat & RTCIR_PERIOD) {
125 statclock(&frame);
126 }
127}
128
129#ifdef DEBUG
130void
131printrtc(void)
132{
133 outb(IO_RTC, RTC_STATUSA);
134 printf("RTC status A = %x", inb(IO_RTC+1));
135 outb(IO_RTC, RTC_STATUSB);
136 printf(", B = %x", inb(IO_RTC+1));
137 outb(IO_RTC, RTC_INTR);
138 printf(", C = %x\n", inb(IO_RTC+1));
139}
140#endif
141
142#if 0
143void
144timerintr(struct clockframe frame)
145{
146 timer_func(&frame);
147 switch (timer0_state) {
148 case 0:
149 break;
150 case 1:
151 if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
152 hardclock(&frame);
153 timer0_prescale = 0;
154 }
155 break;
156 case 2:
157 disable_intr();
158 outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
159 outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256);
160 outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256);
161 enable_intr();
162 timer0_divisor = TIMER_DIV(new_rate);
163 timer0_prescale = 0;
164 timer_func = new_function;
165 timer0_state = 1;
166 break;
167 case 3:
168 if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
169 hardclock(&frame);
170 disable_intr();
171 outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
172 outb(TIMER_CNTR0, TIMER_DIV(hz)%256);
173 outb(TIMER_CNTR0, TIMER_DIV(hz)/256);
174 enable_intr();
175 timer0_divisor = TIMER_DIV(hz);
176 timer0_prescale = 0;
177 timer_func = hardclock;;
178 timer0_state = 0;
179 }
180 break;
181 }
182}
183
184#endif
185
186int
187acquire_timer0(int rate, void (*function)() )
188{
189 if (timer0_state || !function)
190 return -1;
191
192 new_function = function;
193 new_rate = rate;
194 timer0_state = 2;
195 return 0;
196}
197
198
199int
200acquire_timer2(int mode)
201{
202 if (timer2_state)
203 return -1;
204 timer2_state = 1;
205 outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f));
206 return 0;
207}
208
209
210int
211release_timer0()
212{
213 if (!timer0_state)
214 return -1;
215 timer0_state = 3;
216 return 0;
217}
218
219
220int
221release_timer2()
222{
223 if (!timer2_state)
224 return -1;
225 timer2_state = 0;
226 outb(TIMER_MODE, TIMER_SEL2|TIMER_SQWAVE|TIMER_16BIT);
227 return 0;
228}
229
230
231static int
232getit()
233{
234 int high, low;
235
236 disable_intr();
237 /* select timer0 and latch counter value */
238 outb(TIMER_MODE, TIMER_SEL0);
239 low = inb(TIMER_CNTR0);
240 high = inb(TIMER_CNTR0);
241 enable_intr();
242 return ((high << 8) | low);
243}
244
245#ifdef I586_CPU
246static long long cycles_per_sec = 0;
247
248/*
249 * Figure out how fast the cyclecounter runs. This must be run with
250 * clock interrupts disabled, but with the timer/counter programmed
251 * and running.
252 */
253void
254calibrate_cyclecounter(void)
255{
256 volatile long edx, eax, lasteax, lastedx;
257
258 __asm __volatile(".byte 0x0f, 0x31" : "=a"(lasteax), "=d"(lastedx) : );
259 DELAY(1000000);
260 __asm __volatile(".byte 0x0f, 0x31" : "=a"(eax), "=d"(edx) : );
261
262 /*
263 * This assumes that you will never have a clock rate higher
264 * than 4GHz, probably a good assumption.
265 */
266 cycles_per_sec = (long long)edx + eax;
267 cycles_per_sec -= (long long)lastedx + lasteax;
268 pentium_mhz = ((long)cycles_per_sec + 500000) / 1000000; /* round up */
269}
270#endif
271
272/*
273 * Wait "n" microseconds.
274 * Relies on timer 1 counting down from (TIMER_FREQ / hz)
275 * Note: timer had better have been programmed before this is first used!
276 */
277void
278DELAY(int n)
279{
280 int counter_limit, prev_tick, tick, ticks_left, sec, usec;
281
282#ifdef DELAYDEBUG
283 int getit_calls = 1;
284 int n1;
285 static int state = 0;
286
287 if (state == 0) {
288 state = 1;
289 for (n1 = 1; n1 <= 10000000; n1 *= 10)
290 DELAY(n1);
291 state = 2;
292 }
293 if (state == 1)
294 printf("DELAY(%d)...", n);
295#endif
296 /*
297 * Read the counter first, so that the rest of the setup overhead is
298 * counted. Guess the initial overhead is 20 usec (on most systems it
299 * takes about 1.5 usec for each of the i/o's in getit(). The loop
300 * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
301 * multiplications and divisions to scale the count take a while).
302 */
303 prev_tick = getit(0, 0);
304 n -= 20;
305 /*
306 * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point
307 * and without any avoidable overflows.
308 */
309 sec = n / 1000000;
310 usec = n - sec * 1000000;
311 ticks_left = sec * TIMER_FREQ
312 + usec * (TIMER_FREQ / 1000000)
313 + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000
314 + usec * (TIMER_FREQ % 1000) / 1000000;
315
316 while (ticks_left > 0) {
317 tick = getit(0, 0);
318#ifdef DELAYDEBUG
319 ++getit_calls;
320#endif
321 if (tick > prev_tick)
322 ticks_left -= prev_tick - (tick - timer0_divisor);
323 else
324 ticks_left -= prev_tick - tick;
325 prev_tick = tick;
326 }
327#ifdef DELAYDEBUG
328 if (state == 1)
329 printf(" %d calls to getit() at %d usec each\n",
330 getit_calls, (n + 5) / getit_calls);
331#endif
332}
333
334
335static void
336sysbeepstop()
337{
338 outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */
339 release_timer2();
340 beeping = 0;
341}
342
343
344int
345sysbeep(int pitch, int period)
346{
347
348 if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT))
349 return -1;
350 disable_intr();
351 outb(TIMER_CNTR2, pitch);
352 outb(TIMER_CNTR2, (pitch>>8));
353 enable_intr();
354 if (!beeping) {
355 outb(IO_PPI, inb(IO_PPI) | 3); /* enable counter2 output to speaker */
356 beeping = period;
357 timeout(sysbeepstop, 0, period);
358 }
359 return 0;
360}
361
362
363void
364startrtclock()
365{
366 int s;
367
368 /* initialize 8253 clock */
369 outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
370
371 /* Correct rounding will buy us a better precision in timekeeping */
372 outb (IO_TIMER1, TIMER_DIV(hz)%256);
373 outb (IO_TIMER1, TIMER_DIV(hz)/256);
374 timer0_divisor = hardclock_divisor = TIMER_DIV(hz);
375
376 /* initialize brain-dead battery powered clock */
377 outb (IO_RTC, RTC_STATUSA);
378 outb (IO_RTC+1, rtc_statusa);
379 outb (IO_RTC, RTC_STATUSB);
380 outb (IO_RTC+1, RTCSB_24HR);
381
382 outb (IO_RTC, RTC_DIAG);
383 if (s = inb (IO_RTC+1))
384 printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
385}
386
387
388/* convert 2 digit BCD number */
389int
390bcd(int i)
391{
392 return ((i/16)*10 + (i%16));
393}
394
395
396/* convert years to seconds (from 1970) */
397unsigned long
398ytos(int y)
399{
400 int i;
401 unsigned long ret;
402
403 ret = 0;
404 for(i = 1970; i < y; i++) {
405 if (i % 4) ret += 365*24*60*60;
406 else ret += 366*24*60*60;
407 }
408 return ret;
409}
410
411
412/* convert months to seconds */
413unsigned long
414mtos(int m, int leap)
415{
416 int i;
417 unsigned long ret;
418
419 ret = 0;
420 for(i=1; i<m; i++) {
421 switch(i){
422 case 1: case 3: case 5: case 7: case 8: case 10: case 12:
423 ret += 31*24*60*60; break;
424 case 4: case 6: case 9: case 11:
425 ret += 30*24*60*60; break;
426 case 2:
427 if (leap) ret += 29*24*60*60;
428 else ret += 28*24*60*60;
429 }
430 }
431 return ret;
432}
433
434
435/*
436 * Initialize the time of day register, based on the time base which is, e.g.
437 * from a filesystem.
438 */
439void
440inittodr(time_t base)
441{
442 unsigned long sec;
443 int leap, day_week, t, yd;
444 int sa,s;
445
446 /* do we have a realtime clock present? (otherwise we loop below) */
447 sa = rtcin(RTC_STATUSA);
448 if (sa == 0xff || sa == 0) return;
449
450 /* ready for a read? */
451 while ((sa&RTCSA_TUP) == RTCSA_TUP)
452 sa = rtcin(RTC_STATUSA);
453
454 sec = bcd(rtcin(RTC_YEAR)) + 1900;
455 if (sec < 1970)
456 sec += 100;
457
458 leap = !(sec % 4); sec = ytos(sec); /* year */
459 yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec+=yd; /* month */
460 t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec+=t; yd+=t; /* date */
461 day_week = rtcin(RTC_WDAY); /* day */
462 sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */
463 sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */
464 sec += bcd(rtcin(RTC_SEC)); /* seconds */
465 sec += tz.tz_minuteswest * 60;
466 time.tv_sec = sec;
467}
468
469
470#ifdef garbage
471/*
472 * Initialze the time of day register, based on the time base which is, e.g.
473 * from a filesystem.
474 */
475test_inittodr(time_t base)
476{
477
478 outb(IO_RTC,9); /* year */
479 printf("%d ",bcd(inb(IO_RTC+1)));
480 outb(IO_RTC,8); /* month */
481 printf("%d ",bcd(inb(IO_RTC+1)));
482 outb(IO_RTC,7); /* day */
483 printf("%d ",bcd(inb(IO_RTC+1)));
484 outb(IO_RTC,4); /* hour */
485 printf("%d ",bcd(inb(IO_RTC+1)));
486 outb(IO_RTC,2); /* minutes */
487 printf("%d ",bcd(inb(IO_RTC+1)));
488 outb(IO_RTC,0); /* seconds */
489 printf("%d\n",bcd(inb(IO_RTC+1)));
490
491 time.tv_sec = base;
492}
493#endif
494
495/*
496 * Wire clock interrupt in.
497 */
498void
499enablertclock()
500{
501 register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr,
502 HWI_MASK | SWI_MASK, /* unit */ 0);
503 INTREN(IRQ0);
504 register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, rtcintr,
505 SWI_CLOCK_MASK, /* unit */ 0);
506 INTREN(IRQ8);
507 outb(IO_RTC, RTC_STATUSB);
508 outb(IO_RTC+1, RTCSB_PINTR | RTCSB_24HR);
509}
510
511
512/*
513 * Delay for some number of milliseconds.
514 */
515void
516spinwait(int millisecs)
517{
518 DELAY(1000 * millisecs);
519}
520
521void
522cpu_initclocks()
523{
524 stathz = RTC_NOPROFRATE;
525 profhz = RTC_PROFRATE;
526 enablertclock();
527}
528
529void
530setstatclockrate(int newhz)
531{
532 if(newhz == RTC_PROFRATE) {
533 rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF;
534 } else {
535 rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
536 }
537 outb(IO_RTC, RTC_STATUSA);
538 outb(IO_RTC+1, rtc_statusa);
539}