Deleted Added
full compact
atrtc.c (5722) atrtc.c (7090)
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.29 1994/12/30 12:43:34 bde Exp $
37 * $Id: clock.c,v 1.31 1995/01/19 22:05:27 ats Exp $
38 */
39
40/*
41 * inittodr, settodr and support routines written
42 * by Christoph Robitschko <chmr@edvz.tu-graz.ac.at>
43 *
44 * reintroduced and updated by Chris Stenton <chris@gnome.co.uk> 8/10/94
45 */
46
47/*
48 * Primitive clock interrupt routines.
49 */
50#include <sys/param.h>
51#include <sys/systm.h>
52#include <sys/time.h>
53#include <sys/kernel.h>
54#include <machine/clock.h>
55#include <machine/frame.h>
56#include <i386/isa/icu.h>
57#include <i386/isa/isa.h>
38 */
39
40/*
41 * inittodr, settodr and support routines written
42 * by Christoph Robitschko <chmr@edvz.tu-graz.ac.at>
43 *
44 * reintroduced and updated by Chris Stenton <chris@gnome.co.uk> 8/10/94
45 */
46
47/*
48 * Primitive clock interrupt routines.
49 */
50#include <sys/param.h>
51#include <sys/systm.h>
52#include <sys/time.h>
53#include <sys/kernel.h>
54#include <machine/clock.h>
55#include <machine/frame.h>
56#include <i386/isa/icu.h>
57#include <i386/isa/isa.h>
58#include <i386/isa/isa_device.h>
58#include <i386/isa/rtc.h>
59#include <i386/isa/timerreg.h>
60
61/*
62 * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we
63 * can use a simple formula for leap years.
64 */
65#define LEAPYEAR(y) ((u_int)(y) % 4 == 0)
66#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31)
67
68/* X-tals being what they are, it's nice to be able to fudge this one... */
69#ifndef TIMER_FREQ
70#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
71#endif
72#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
73
74/*
75 * Time in timer cycles that it takes for microtime() to disable interrupts
76 * and latch the count. microtime() currently uses "cli; outb ..." so it
77 * normally takes less than 2 timer cycles. Add a few for cache misses.
78 * Add a few more to allow for latency in bogus calls to microtime() with
79 * interrupts already disabled.
80 */
81#define TIMER0_LATCH_COUNT 20
82
83/*
84 * Minimum maximum count that we are willing to program into timer0.
85 * Must be large enough to guarantee that the timer interrupt handler
86 * returns before the next timer interrupt. Must be larger than
87 * TIMER0_LATCH_COUNT so that we don't have to worry about underflow in
88 * the calculation of timer0_overflow_threshold.
89 */
90#define TIMER0_MIN_MAX_COUNT TIMER_DIV(20000)
91
92int adjkerntz = 0; /* offset from CMOS clock */
93int disable_rtc_set = 0; /* disable resettodr() if != 0 */
94#ifdef I586_CPU
95int pentium_mhz;
96#endif
97u_int stat_imask = SWI_CLOCK_MASK;
98int timer0_max_count;
99u_int timer0_overflow_threshold;
100u_int timer0_prescaler_count;
101
102static int beeping = 0;
103static u_int clk_imask = HWI_MASK | SWI_MASK;
104static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
105static u_int hardclock_max_count;
106/*
107 * XXX new_function and timer_func should not handle clockframes, but
108 * timer_func currently needs to hold hardclock to handle the
109 * timer0_state == 0 case. We should use register_intr()/unregister_intr()
110 * to switch between clkintr() and a slightly different timerintr().
111 * This will require locking when acquiring and releasing timer0 - the
112 * current (nonexistent) locking doesn't seem to be adequate even now.
113 */
114static void (*new_function) __P((struct clockframe *frame));
115static u_int new_rate;
116static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
117static char timer0_state = 0;
118static char timer2_state = 0;
119static void (*timer_func) __P((struct clockframe *frame)) = hardclock;
120
121#if 0
122void
123clkintr(struct clockframe frame)
124{
125 hardclock(&frame);
126}
127#else
128void
129clkintr(struct clockframe frame)
130{
131 timer_func(&frame);
132 switch (timer0_state) {
133 case 0:
134 break;
135 case 1:
136 if ((timer0_prescaler_count += timer0_max_count)
137 >= hardclock_max_count) {
138 hardclock(&frame);
139 timer0_prescaler_count -= hardclock_max_count;
140 }
141 break;
142 case 2:
143 timer0_max_count = TIMER_DIV(new_rate);
144 timer0_overflow_threshold =
145 timer0_max_count - TIMER0_LATCH_COUNT;
146 disable_intr();
147 outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
148 outb(TIMER_CNTR0, timer0_max_count & 0xff);
149 outb(TIMER_CNTR0, timer0_max_count >> 8);
150 enable_intr();
151 timer0_prescaler_count = 0;
152 timer_func = new_function;
153 timer0_state = 1;
154 break;
155 case 3:
156 if ((timer0_prescaler_count += timer0_max_count)
157 >= hardclock_max_count) {
158 hardclock(&frame);
159 timer0_max_count = hardclock_max_count;
160 timer0_overflow_threshold =
161 timer0_max_count - TIMER0_LATCH_COUNT;
162 disable_intr();
163 outb(TIMER_MODE,
164 TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
165 outb(TIMER_CNTR0, timer0_max_count & 0xff);
166 outb(TIMER_CNTR0, timer0_max_count >> 8);
167 enable_intr();
168 /*
169 * See microtime.s for this magic.
170 */
171 time.tv_usec += (27645 *
172 (timer0_prescaler_count - hardclock_max_count))
173 >> 15;
174 if (time.tv_usec >= 1000000)
175 time.tv_usec -= 1000000;
176 timer0_prescaler_count = 0;
177 timer_func = hardclock;;
178 timer0_state = 0;
179 }
180 break;
181 }
182}
183#endif
184
185int
186acquire_timer0(int rate, void (*function) __P((struct clockframe *frame)))
187{
188 if (timer0_state || TIMER_DIV(rate) < TIMER0_MIN_MAX_COUNT ||
189 !function)
190 return -1;
191 new_function = function;
192 new_rate = rate;
193 timer0_state = 2;
194 return 0;
195}
196
197int
198acquire_timer2(int mode)
199{
200 if (timer2_state)
201 return -1;
202 timer2_state = 1;
203 outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f));
204 return 0;
205}
206
207int
208release_timer0()
209{
210 if (!timer0_state)
211 return -1;
212 timer0_state = 3;
213 return 0;
214}
215
216int
217release_timer2()
218{
219 if (!timer2_state)
220 return -1;
221 timer2_state = 0;
222 outb(TIMER_MODE, TIMER_SEL2|TIMER_SQWAVE|TIMER_16BIT);
223 return 0;
224}
225
226/*
227 * This routine receives statistical clock interrupts from the RTC.
228 * As explained above, these occur at 128 interrupts per second.
229 * When profiling, we receive interrupts at a rate of 1024 Hz.
230 *
231 * This does not actually add as much overhead as it sounds, because
232 * when the statistical clock is active, the hardclock driver no longer
233 * needs to keep (inaccurate) statistics on its own. This decouples
234 * statistics gathering from scheduling interrupts.
235 *
236 * The RTC chip requires that we read status register C (RTC_INTR)
237 * to acknowledge an interrupt, before it will generate the next one.
238 */
239void
240rtcintr(struct clockframe frame)
241{
242 u_char stat;
243 stat = rtcin(RTC_INTR);
244 if(stat & RTCIR_PERIOD) {
245 statclock(&frame);
246 }
247}
248
249#ifdef DDB
250static void
251printrtc(void)
252{
253 printf("%02x/%02x/%02x %02x:%02x:%02x, A = %02x, B = %02x, C = %02x\n",
254 rtcin(RTC_YEAR), rtcin(RTC_MONTH), rtcin(RTC_DAY),
255 rtcin(RTC_HRS), rtcin(RTC_MIN), rtcin(RTC_SEC),
256 rtcin(RTC_STATUSA), rtcin(RTC_STATUSB), rtcin(RTC_INTR));
257}
258#endif
259
260static int
261getit()
262{
263 int high, low;
264
265 disable_intr();
266 /* select timer0 and latch counter value */
267 outb(TIMER_MODE, TIMER_SEL0);
268 low = inb(TIMER_CNTR0);
269 high = inb(TIMER_CNTR0);
270 enable_intr();
271 return ((high << 8) | low);
272}
273
274#ifdef I586_CPU
275static long long cycles_per_sec = 0;
276
277/*
278 * Figure out how fast the cyclecounter runs. This must be run with
279 * clock interrupts disabled, but with the timer/counter programmed
280 * and running.
281 */
282void
283calibrate_cyclecounter(void)
284{
285 /*
286 * Don't need volatile; should always use unsigned if 2's
287 * complement arithmetic is desired.
288 */
289 unsigned long long count, last_count;
290
291 __asm __volatile(".byte 0xf,0x31" : "=A" (last_count));
292 DELAY(1000000);
293 __asm __volatile(".byte 0xf,0x31" : "=A" (count));
294 /*
295 * XX lose if the clock rate is not nearly a multiple of 1000000.
296 */
297 pentium_mhz = ((count - last_count) + 500000) / 1000000;
298}
299#endif
300
301/*
302 * Wait "n" microseconds.
303 * Relies on timer 1 counting down from (TIMER_FREQ / hz)
304 * Note: timer had better have been programmed before this is first used!
305 */
306void
307DELAY(int n)
308{
309 int prev_tick, tick, ticks_left, sec, usec;
310
311#ifdef DELAYDEBUG
312 int getit_calls = 1;
313 int n1;
314 static int state = 0;
315
316 if (state == 0) {
317 state = 1;
318 for (n1 = 1; n1 <= 10000000; n1 *= 10)
319 DELAY(n1);
320 state = 2;
321 }
322 if (state == 1)
323 printf("DELAY(%d)...", n);
324#endif
325 /*
326 * Read the counter first, so that the rest of the setup overhead is
327 * counted. Guess the initial overhead is 20 usec (on most systems it
328 * takes about 1.5 usec for each of the i/o's in getit(). The loop
329 * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
330 * multiplications and divisions to scale the count take a while).
331 */
332 prev_tick = getit(0, 0);
333 n -= 20;
334 /*
335 * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point
336 * and without any avoidable overflows.
337 */
338 sec = n / 1000000;
339 usec = n - sec * 1000000;
340 ticks_left = sec * TIMER_FREQ
341 + usec * (TIMER_FREQ / 1000000)
342 + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000
343 + usec * (TIMER_FREQ % 1000) / 1000000;
344
345 while (ticks_left > 0) {
346 tick = getit(0, 0);
347#ifdef DELAYDEBUG
348 ++getit_calls;
349#endif
350 if (tick > prev_tick)
351 ticks_left -= prev_tick - (tick - timer0_max_count);
352 else
353 ticks_left -= prev_tick - tick;
354 prev_tick = tick;
355 }
356#ifdef DELAYDEBUG
357 if (state == 1)
358 printf(" %d calls to getit() at %d usec each\n",
359 getit_calls, (n + 5) / getit_calls);
360#endif
361}
362
363static void
364sysbeepstop(void *chan)
365{
366 outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */
367 release_timer2();
368 beeping = 0;
369}
370
371int
372sysbeep(int pitch, int period)
373{
374
375 if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT))
376 return -1;
377 disable_intr();
378 outb(TIMER_CNTR2, pitch);
379 outb(TIMER_CNTR2, (pitch>>8));
380 enable_intr();
381 if (!beeping) {
382 outb(IO_PPI, inb(IO_PPI) | 3); /* enable counter2 output to speaker */
383 beeping = period;
384 timeout(sysbeepstop, (void *)NULL, period);
385 }
386 return 0;
387}
388
389/*
390 * RTC support routines
391 */
392static int
393bcd2int(int bcd)
394{
395 return(bcd/16 * 10 + bcd%16);
396}
397
398static int
399int2bcd(int dez)
400{
401 return(dez/10 * 16 + dez%10);
402}
403
404static inline void
405writertc(u_char reg, u_char val)
406{
407 outb(IO_RTC, reg);
408 outb(IO_RTC + 1, val);
409}
410
411static int
412readrtc(int port)
413{
414 return(bcd2int(rtcin(port)));
415}
416
417/*
418 * Initialize 8253 timer 0 early so that it can be used in DELAY().
419 * XXX initialization of other timers is unintentionally left blank.
420 */
421void
422startrtclock()
423{
424 timer0_max_count = hardclock_max_count = TIMER_DIV(hz);
425 timer0_overflow_threshold = timer0_max_count - TIMER0_LATCH_COUNT;
426 outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
427 outb(TIMER_CNTR0, timer0_max_count & 0xff);
428 outb(TIMER_CNTR0, timer0_max_count >> 8);
429}
430
431/*
432 * Initialize the time of day register, based on the time base which is, e.g.
433 * from a filesystem.
434 */
435void
436inittodr(time_t base)
437{
438 unsigned long sec, days;
439 int yd;
440 int year, month;
441 int y, m, s;
442
443 s = splclock();
444 time.tv_sec = base;
445 time.tv_usec = 0;
446 splx(s);
447
448 /* Look if we have a RTC present and the time is valid */
449 if (rtcin(RTC_STATUSD) != RTCSD_PWR)
450 goto wrong_time;
451
452 /* wait for time update to complete */
453 /* If RTCSA_TUP is zero, we have at least 244us before next update */
454 while (rtcin(RTC_STATUSA) & RTCSA_TUP);
455
456 days = 0;
457#ifdef USE_RTC_CENTURY
458 year = readrtc(RTC_YEAR) + readrtc(RTC_CENTURY) * 100;
459#else
460 year = readrtc(RTC_YEAR) + 1900;
461 if (year < 1970)
462 year += 100;
463#endif
464 if (year < 1970)
465 goto wrong_time;
466 month = readrtc(RTC_MONTH);
467 for (m = 1; m < month; m++)
468 days += daysinmonth[m-1];
469 if ((month > 2) && LEAPYEAR(year))
470 days ++;
471 days += readrtc(RTC_DAY) - 1;
472 yd = days;
473 for (y = 1970; y < year; y++)
474 days += DAYSPERYEAR + LEAPYEAR(y);
475 sec = ((( days * 24 +
476 readrtc(RTC_HRS)) * 60 +
477 readrtc(RTC_MIN)) * 60 +
478 readrtc(RTC_SEC));
479 /* sec now contains the number of seconds, since Jan 1 1970,
480 in the local time zone */
481
482 sec += tz.tz_minuteswest * 60 + adjkerntz;
483
484 s = splclock();
485 time.tv_sec = sec;
486 splx(s);
487 return;
488
489wrong_time:
490 printf("Invalid time in real time clock.\n");
491 printf("Check and reset the date immediately!\n");
492}
493
494/*
495 * Write system time back to RTC
496 */
497void
498resettodr()
499{
500 unsigned long tm;
501 int y, m, fd, r, s;
502
503 if (disable_rtc_set)
504 return;
505
506 s = splclock();
507 tm = time.tv_sec;
508 splx(s);
509
510 /* Disable RTC updates and interrupts. */
511 writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR);
512
513 /* Calculate local time to put in RTC */
514
515 tm -= tz.tz_minuteswest * 60 + adjkerntz;
516
517 writertc(RTC_SEC, int2bcd(tm%60)); tm /= 60; /* Write back Seconds */
518 writertc(RTC_MIN, int2bcd(tm%60)); tm /= 60; /* Write back Minutes */
519 writertc(RTC_HRS, int2bcd(tm%24)); tm /= 24; /* Write back Hours */
520
521 /* We have now the days since 01-01-1970 in tm */
522 writertc(RTC_WDAY, (tm+4)%7); /* Write back Weekday */
523 for (y=1970;; y++)
524 if ((tm - DAYSPERYEAR - LEAPYEAR(y)) > tm)
525 break;
526 else
527 tm -= DAYSPERYEAR + LEAPYEAR(y);
528
529 /* Now we have the years in y and the day-of-the-year in tm */
530 writertc(RTC_YEAR, int2bcd(y%100)); /* Write back Year */
531#ifdef USE_RTC_CENTURY
532 writertc(RTC_CENTURY, int2bcd(y/100)); /* ... and Century */
533#endif
534 if (LEAPYEAR(y) && (tm >= 31+29))
535 tm--; /* Subtract Feb-29 */
536 for (m=1;; m++)
537 if (tm - daysinmonth[m-1] > tm)
538 break;
539 else
540 tm -= daysinmonth[m-1];
541
542 writertc(RTC_MONTH, int2bcd(m)); /* Write back Month */
543 writertc(RTC_DAY, int2bcd(tm+1)); /* Write back Day */
544
545 /* Reenable RTC updates and interrupts. */
546 writertc(RTC_STATUSB, RTCSB_24HR | RTCSB_PINTR);
547}
548
549/*
550 * Start both clocks running.
551 */
552void
553cpu_initclocks()
554{
555 int diag;
556
557 stathz = RTC_NOPROFRATE;
558 profhz = RTC_PROFRATE;
559
560 /* Finish initializing 8253 timer 0. */
59#include <i386/isa/rtc.h>
60#include <i386/isa/timerreg.h>
61
62/*
63 * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we
64 * can use a simple formula for leap years.
65 */
66#define LEAPYEAR(y) ((u_int)(y) % 4 == 0)
67#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31)
68
69/* X-tals being what they are, it's nice to be able to fudge this one... */
70#ifndef TIMER_FREQ
71#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
72#endif
73#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
74
75/*
76 * Time in timer cycles that it takes for microtime() to disable interrupts
77 * and latch the count. microtime() currently uses "cli; outb ..." so it
78 * normally takes less than 2 timer cycles. Add a few for cache misses.
79 * Add a few more to allow for latency in bogus calls to microtime() with
80 * interrupts already disabled.
81 */
82#define TIMER0_LATCH_COUNT 20
83
84/*
85 * Minimum maximum count that we are willing to program into timer0.
86 * Must be large enough to guarantee that the timer interrupt handler
87 * returns before the next timer interrupt. Must be larger than
88 * TIMER0_LATCH_COUNT so that we don't have to worry about underflow in
89 * the calculation of timer0_overflow_threshold.
90 */
91#define TIMER0_MIN_MAX_COUNT TIMER_DIV(20000)
92
93int adjkerntz = 0; /* offset from CMOS clock */
94int disable_rtc_set = 0; /* disable resettodr() if != 0 */
95#ifdef I586_CPU
96int pentium_mhz;
97#endif
98u_int stat_imask = SWI_CLOCK_MASK;
99int timer0_max_count;
100u_int timer0_overflow_threshold;
101u_int timer0_prescaler_count;
102
103static int beeping = 0;
104static u_int clk_imask = HWI_MASK | SWI_MASK;
105static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
106static u_int hardclock_max_count;
107/*
108 * XXX new_function and timer_func should not handle clockframes, but
109 * timer_func currently needs to hold hardclock to handle the
110 * timer0_state == 0 case. We should use register_intr()/unregister_intr()
111 * to switch between clkintr() and a slightly different timerintr().
112 * This will require locking when acquiring and releasing timer0 - the
113 * current (nonexistent) locking doesn't seem to be adequate even now.
114 */
115static void (*new_function) __P((struct clockframe *frame));
116static u_int new_rate;
117static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
118static char timer0_state = 0;
119static char timer2_state = 0;
120static void (*timer_func) __P((struct clockframe *frame)) = hardclock;
121
122#if 0
123void
124clkintr(struct clockframe frame)
125{
126 hardclock(&frame);
127}
128#else
129void
130clkintr(struct clockframe frame)
131{
132 timer_func(&frame);
133 switch (timer0_state) {
134 case 0:
135 break;
136 case 1:
137 if ((timer0_prescaler_count += timer0_max_count)
138 >= hardclock_max_count) {
139 hardclock(&frame);
140 timer0_prescaler_count -= hardclock_max_count;
141 }
142 break;
143 case 2:
144 timer0_max_count = TIMER_DIV(new_rate);
145 timer0_overflow_threshold =
146 timer0_max_count - TIMER0_LATCH_COUNT;
147 disable_intr();
148 outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
149 outb(TIMER_CNTR0, timer0_max_count & 0xff);
150 outb(TIMER_CNTR0, timer0_max_count >> 8);
151 enable_intr();
152 timer0_prescaler_count = 0;
153 timer_func = new_function;
154 timer0_state = 1;
155 break;
156 case 3:
157 if ((timer0_prescaler_count += timer0_max_count)
158 >= hardclock_max_count) {
159 hardclock(&frame);
160 timer0_max_count = hardclock_max_count;
161 timer0_overflow_threshold =
162 timer0_max_count - TIMER0_LATCH_COUNT;
163 disable_intr();
164 outb(TIMER_MODE,
165 TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
166 outb(TIMER_CNTR0, timer0_max_count & 0xff);
167 outb(TIMER_CNTR0, timer0_max_count >> 8);
168 enable_intr();
169 /*
170 * See microtime.s for this magic.
171 */
172 time.tv_usec += (27645 *
173 (timer0_prescaler_count - hardclock_max_count))
174 >> 15;
175 if (time.tv_usec >= 1000000)
176 time.tv_usec -= 1000000;
177 timer0_prescaler_count = 0;
178 timer_func = hardclock;;
179 timer0_state = 0;
180 }
181 break;
182 }
183}
184#endif
185
186int
187acquire_timer0(int rate, void (*function) __P((struct clockframe *frame)))
188{
189 if (timer0_state || TIMER_DIV(rate) < TIMER0_MIN_MAX_COUNT ||
190 !function)
191 return -1;
192 new_function = function;
193 new_rate = rate;
194 timer0_state = 2;
195 return 0;
196}
197
198int
199acquire_timer2(int mode)
200{
201 if (timer2_state)
202 return -1;
203 timer2_state = 1;
204 outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f));
205 return 0;
206}
207
208int
209release_timer0()
210{
211 if (!timer0_state)
212 return -1;
213 timer0_state = 3;
214 return 0;
215}
216
217int
218release_timer2()
219{
220 if (!timer2_state)
221 return -1;
222 timer2_state = 0;
223 outb(TIMER_MODE, TIMER_SEL2|TIMER_SQWAVE|TIMER_16BIT);
224 return 0;
225}
226
227/*
228 * This routine receives statistical clock interrupts from the RTC.
229 * As explained above, these occur at 128 interrupts per second.
230 * When profiling, we receive interrupts at a rate of 1024 Hz.
231 *
232 * This does not actually add as much overhead as it sounds, because
233 * when the statistical clock is active, the hardclock driver no longer
234 * needs to keep (inaccurate) statistics on its own. This decouples
235 * statistics gathering from scheduling interrupts.
236 *
237 * The RTC chip requires that we read status register C (RTC_INTR)
238 * to acknowledge an interrupt, before it will generate the next one.
239 */
240void
241rtcintr(struct clockframe frame)
242{
243 u_char stat;
244 stat = rtcin(RTC_INTR);
245 if(stat & RTCIR_PERIOD) {
246 statclock(&frame);
247 }
248}
249
250#ifdef DDB
251static void
252printrtc(void)
253{
254 printf("%02x/%02x/%02x %02x:%02x:%02x, A = %02x, B = %02x, C = %02x\n",
255 rtcin(RTC_YEAR), rtcin(RTC_MONTH), rtcin(RTC_DAY),
256 rtcin(RTC_HRS), rtcin(RTC_MIN), rtcin(RTC_SEC),
257 rtcin(RTC_STATUSA), rtcin(RTC_STATUSB), rtcin(RTC_INTR));
258}
259#endif
260
261static int
262getit()
263{
264 int high, low;
265
266 disable_intr();
267 /* select timer0 and latch counter value */
268 outb(TIMER_MODE, TIMER_SEL0);
269 low = inb(TIMER_CNTR0);
270 high = inb(TIMER_CNTR0);
271 enable_intr();
272 return ((high << 8) | low);
273}
274
275#ifdef I586_CPU
276static long long cycles_per_sec = 0;
277
278/*
279 * Figure out how fast the cyclecounter runs. This must be run with
280 * clock interrupts disabled, but with the timer/counter programmed
281 * and running.
282 */
283void
284calibrate_cyclecounter(void)
285{
286 /*
287 * Don't need volatile; should always use unsigned if 2's
288 * complement arithmetic is desired.
289 */
290 unsigned long long count, last_count;
291
292 __asm __volatile(".byte 0xf,0x31" : "=A" (last_count));
293 DELAY(1000000);
294 __asm __volatile(".byte 0xf,0x31" : "=A" (count));
295 /*
296 * XX lose if the clock rate is not nearly a multiple of 1000000.
297 */
298 pentium_mhz = ((count - last_count) + 500000) / 1000000;
299}
300#endif
301
302/*
303 * Wait "n" microseconds.
304 * Relies on timer 1 counting down from (TIMER_FREQ / hz)
305 * Note: timer had better have been programmed before this is first used!
306 */
307void
308DELAY(int n)
309{
310 int prev_tick, tick, ticks_left, sec, usec;
311
312#ifdef DELAYDEBUG
313 int getit_calls = 1;
314 int n1;
315 static int state = 0;
316
317 if (state == 0) {
318 state = 1;
319 for (n1 = 1; n1 <= 10000000; n1 *= 10)
320 DELAY(n1);
321 state = 2;
322 }
323 if (state == 1)
324 printf("DELAY(%d)...", n);
325#endif
326 /*
327 * Read the counter first, so that the rest of the setup overhead is
328 * counted. Guess the initial overhead is 20 usec (on most systems it
329 * takes about 1.5 usec for each of the i/o's in getit(). The loop
330 * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
331 * multiplications and divisions to scale the count take a while).
332 */
333 prev_tick = getit(0, 0);
334 n -= 20;
335 /*
336 * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point
337 * and without any avoidable overflows.
338 */
339 sec = n / 1000000;
340 usec = n - sec * 1000000;
341 ticks_left = sec * TIMER_FREQ
342 + usec * (TIMER_FREQ / 1000000)
343 + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000
344 + usec * (TIMER_FREQ % 1000) / 1000000;
345
346 while (ticks_left > 0) {
347 tick = getit(0, 0);
348#ifdef DELAYDEBUG
349 ++getit_calls;
350#endif
351 if (tick > prev_tick)
352 ticks_left -= prev_tick - (tick - timer0_max_count);
353 else
354 ticks_left -= prev_tick - tick;
355 prev_tick = tick;
356 }
357#ifdef DELAYDEBUG
358 if (state == 1)
359 printf(" %d calls to getit() at %d usec each\n",
360 getit_calls, (n + 5) / getit_calls);
361#endif
362}
363
364static void
365sysbeepstop(void *chan)
366{
367 outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */
368 release_timer2();
369 beeping = 0;
370}
371
372int
373sysbeep(int pitch, int period)
374{
375
376 if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT))
377 return -1;
378 disable_intr();
379 outb(TIMER_CNTR2, pitch);
380 outb(TIMER_CNTR2, (pitch>>8));
381 enable_intr();
382 if (!beeping) {
383 outb(IO_PPI, inb(IO_PPI) | 3); /* enable counter2 output to speaker */
384 beeping = period;
385 timeout(sysbeepstop, (void *)NULL, period);
386 }
387 return 0;
388}
389
390/*
391 * RTC support routines
392 */
393static int
394bcd2int(int bcd)
395{
396 return(bcd/16 * 10 + bcd%16);
397}
398
399static int
400int2bcd(int dez)
401{
402 return(dez/10 * 16 + dez%10);
403}
404
405static inline void
406writertc(u_char reg, u_char val)
407{
408 outb(IO_RTC, reg);
409 outb(IO_RTC + 1, val);
410}
411
412static int
413readrtc(int port)
414{
415 return(bcd2int(rtcin(port)));
416}
417
418/*
419 * Initialize 8253 timer 0 early so that it can be used in DELAY().
420 * XXX initialization of other timers is unintentionally left blank.
421 */
422void
423startrtclock()
424{
425 timer0_max_count = hardclock_max_count = TIMER_DIV(hz);
426 timer0_overflow_threshold = timer0_max_count - TIMER0_LATCH_COUNT;
427 outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
428 outb(TIMER_CNTR0, timer0_max_count & 0xff);
429 outb(TIMER_CNTR0, timer0_max_count >> 8);
430}
431
432/*
433 * Initialize the time of day register, based on the time base which is, e.g.
434 * from a filesystem.
435 */
436void
437inittodr(time_t base)
438{
439 unsigned long sec, days;
440 int yd;
441 int year, month;
442 int y, m, s;
443
444 s = splclock();
445 time.tv_sec = base;
446 time.tv_usec = 0;
447 splx(s);
448
449 /* Look if we have a RTC present and the time is valid */
450 if (rtcin(RTC_STATUSD) != RTCSD_PWR)
451 goto wrong_time;
452
453 /* wait for time update to complete */
454 /* If RTCSA_TUP is zero, we have at least 244us before next update */
455 while (rtcin(RTC_STATUSA) & RTCSA_TUP);
456
457 days = 0;
458#ifdef USE_RTC_CENTURY
459 year = readrtc(RTC_YEAR) + readrtc(RTC_CENTURY) * 100;
460#else
461 year = readrtc(RTC_YEAR) + 1900;
462 if (year < 1970)
463 year += 100;
464#endif
465 if (year < 1970)
466 goto wrong_time;
467 month = readrtc(RTC_MONTH);
468 for (m = 1; m < month; m++)
469 days += daysinmonth[m-1];
470 if ((month > 2) && LEAPYEAR(year))
471 days ++;
472 days += readrtc(RTC_DAY) - 1;
473 yd = days;
474 for (y = 1970; y < year; y++)
475 days += DAYSPERYEAR + LEAPYEAR(y);
476 sec = ((( days * 24 +
477 readrtc(RTC_HRS)) * 60 +
478 readrtc(RTC_MIN)) * 60 +
479 readrtc(RTC_SEC));
480 /* sec now contains the number of seconds, since Jan 1 1970,
481 in the local time zone */
482
483 sec += tz.tz_minuteswest * 60 + adjkerntz;
484
485 s = splclock();
486 time.tv_sec = sec;
487 splx(s);
488 return;
489
490wrong_time:
491 printf("Invalid time in real time clock.\n");
492 printf("Check and reset the date immediately!\n");
493}
494
495/*
496 * Write system time back to RTC
497 */
498void
499resettodr()
500{
501 unsigned long tm;
502 int y, m, fd, r, s;
503
504 if (disable_rtc_set)
505 return;
506
507 s = splclock();
508 tm = time.tv_sec;
509 splx(s);
510
511 /* Disable RTC updates and interrupts. */
512 writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR);
513
514 /* Calculate local time to put in RTC */
515
516 tm -= tz.tz_minuteswest * 60 + adjkerntz;
517
518 writertc(RTC_SEC, int2bcd(tm%60)); tm /= 60; /* Write back Seconds */
519 writertc(RTC_MIN, int2bcd(tm%60)); tm /= 60; /* Write back Minutes */
520 writertc(RTC_HRS, int2bcd(tm%24)); tm /= 24; /* Write back Hours */
521
522 /* We have now the days since 01-01-1970 in tm */
523 writertc(RTC_WDAY, (tm+4)%7); /* Write back Weekday */
524 for (y=1970;; y++)
525 if ((tm - DAYSPERYEAR - LEAPYEAR(y)) > tm)
526 break;
527 else
528 tm -= DAYSPERYEAR + LEAPYEAR(y);
529
530 /* Now we have the years in y and the day-of-the-year in tm */
531 writertc(RTC_YEAR, int2bcd(y%100)); /* Write back Year */
532#ifdef USE_RTC_CENTURY
533 writertc(RTC_CENTURY, int2bcd(y/100)); /* ... and Century */
534#endif
535 if (LEAPYEAR(y) && (tm >= 31+29))
536 tm--; /* Subtract Feb-29 */
537 for (m=1;; m++)
538 if (tm - daysinmonth[m-1] > tm)
539 break;
540 else
541 tm -= daysinmonth[m-1];
542
543 writertc(RTC_MONTH, int2bcd(m)); /* Write back Month */
544 writertc(RTC_DAY, int2bcd(tm+1)); /* Write back Day */
545
546 /* Reenable RTC updates and interrupts. */
547 writertc(RTC_STATUSB, RTCSB_24HR | RTCSB_PINTR);
548}
549
550/*
551 * Start both clocks running.
552 */
553void
554cpu_initclocks()
555{
556 int diag;
557
558 stathz = RTC_NOPROFRATE;
559 profhz = RTC_PROFRATE;
560
561 /* Finish initializing 8253 timer 0. */
561 register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr,
562 &clk_imask, /* unit */ 0);
562 register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0,
563 /* XXX */ (inthand2_t *)clkintr, &clk_imask,
564 /* unit */ 0);
563 INTREN(IRQ0);
564
565 /* Initialize RTC. */
566 writertc(RTC_STATUSA, rtc_statusa);
567 writertc(RTC_STATUSB, RTCSB_24HR);
568 diag = rtcin(RTC_DIAG);
569 if (diag != 0)
570 printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS);
565 INTREN(IRQ0);
566
567 /* Initialize RTC. */
568 writertc(RTC_STATUSA, rtc_statusa);
569 writertc(RTC_STATUSB, RTCSB_24HR);
570 diag = rtcin(RTC_DIAG);
571 if (diag != 0)
572 printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS);
571 register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, rtcintr,
572 &stat_imask, /* unit */ 0);
573 register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0,
574 /* XXX */ (inthand2_t *)rtcintr, &stat_imask,
575 /* unit */ 0);
573 INTREN(IRQ8);
574 writertc(RTC_STATUSB, RTCSB_24HR | RTCSB_PINTR);
575}
576
577void
578setstatclockrate(int newhz)
579{
580 if (newhz == RTC_PROFRATE)
581 rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF;
582 else
583 rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
584 writertc(RTC_STATUSA, rtc_statusa);
585}
576 INTREN(IRQ8);
577 writertc(RTC_STATUSB, RTCSB_24HR | RTCSB_PINTR);
578}
579
580void
581setstatclockrate(int newhz)
582{
583 if (newhz == RTC_PROFRATE)
584 rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF;
585 else
586 rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
587 writertc(RTC_STATUSA, rtc_statusa);
588}