diff options
author | svn2git <svn2git@FreeBSD.org> | 1994-07-01 08:00:00 +0000 |
---|---|---|
committer | svn2git <svn2git@FreeBSD.org> | 1994-07-01 08:00:00 +0000 |
commit | 5e0e9b99dc3fc0ecd49d929db0d57c784b66f481 (patch) | |
tree | e779b5a6edddbb949b7990751b12d6f25304ba86 /sys/i386/isa/clock.c | |
parent | a16f65c7d117419bd266c28a1901ef129a337569 (diff) |
Diffstat (limited to 'sys/i386/isa/clock.c')
-rw-r--r-- | sys/i386/isa/clock.c | 279 |
1 files changed, 229 insertions, 50 deletions
diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c index cd87b28b90e6..5832801d24ae 100644 --- a/sys/i386/isa/clock.c +++ b/sys/i386/isa/clock.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.6 1994/02/06 22:48:13 davidg Exp $ + * $Id: clock.c,v 1.9 1994/05/02 09:41:24 sos Exp $ */ /* @@ -45,6 +45,7 @@ #include "time.h" #include "kernel.h" #include "machine/segments.h" +#include "machine/frame.h" #include "i386/isa/icu.h" #include "i386/isa/isa.h" #include "i386/isa/rtc.h" @@ -55,22 +56,225 @@ #ifndef TIMER_FREQ #define TIMER_FREQ 1193182 /* XXX - should be in isa.h */ #endif +#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x)) + +void hardclock(); +static int beeping; +int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */ +u_int timer0_prescale; +static char timer0_state = 0, timer2_state = 0; +static char timer0_reprogram = 0; +static void (*timer_func)() = hardclock; +static void (*new_function)(); +static u_int new_rate; +static u_int hardclock_divisor; + + +void +timerintr(struct intrframe frame) +{ + timer_func(frame); + switch (timer0_state) { + case 0: + break; + case 1: + if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) { + hardclock(frame); + timer0_prescale = 0; + } + break; + case 2: + disable_intr(); + outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); + outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256); + outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256); + enable_intr(); + timer0_divisor = TIMER_DIV(new_rate); + timer0_prescale = 0; + timer_func = new_function; + timer0_state = 1; + break; + case 3: + if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) { + hardclock(frame); + disable_intr(); + outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); + outb(TIMER_CNTR0, TIMER_DIV(hz)%256); + outb(TIMER_CNTR0, TIMER_DIV(hz)/256); + enable_intr(); + timer0_divisor = TIMER_DIV(hz); + timer0_prescale = 0; + timer_func = hardclock;; + timer0_state = 0; + } + break; + } +} + + +int +acquire_timer0(int rate, void (*function)() ) +{ + if (timer0_state || !function) + return -1; + + new_function = function; + new_rate = rate; + timer0_state = 2; + return 0; +} + + +int +acquire_timer2(int mode) +{ + if (timer2_state) + return -1; + timer2_state = 1; + outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f)); + return 0; +} + + +int +release_timer0() +{ + if (!timer0_state) + return -1; + timer0_state = 3; + return 0; +} + + +int +release_timer2() +{ + if (!timer2_state) + return -1; + timer2_state = 0; + outb(TIMER_MODE, TIMER_SEL2|TIMER_SQWAVE|TIMER_16BIT); + return 0; +} + + +static int +getit() +{ + int high, low; + + disable_intr(); + /* select timer0 and latch counter value */ + outb(TIMER_MODE, TIMER_SEL0); + low = inb(TIMER_CNTR0); + high = inb(TIMER_CNTR0); + enable_intr(); + return ((high << 8) | low); +} + + +/* + * Wait "n" microseconds. + * Relies on timer 1 counting down from (TIMER_FREQ / hz) + * Note: timer had better have been programmed before this is first used! + */ +void +DELAY(int n) +{ + int counter_limit, prev_tick, tick, ticks_left, sec, usec; + +#ifdef DELAYDEBUG + int getit_calls = 1; + int n1; + static int state = 0; + + if (state == 0) { + state = 1; + for (n1 = 1; n1 <= 10000000; n1 *= 10) + DELAY(n1); + state = 2; + } + if (state == 1) + printf("DELAY(%d)...", n); +#endif + /* + * Read the counter first, so that the rest of the setup overhead is + * counted. Guess the initial overhead is 20 usec (on most systems it + * takes about 1.5 usec for each of the i/o's in getit(). The loop + * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The + * multiplications and divisions to scale the count take a while). + */ + prev_tick = getit(0, 0); + n -= 20; + /* + * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point + * and without any avoidable overflows. + */ + sec = n / 1000000; + usec = n - sec * 1000000; + ticks_left = sec * TIMER_FREQ + + usec * (TIMER_FREQ / 1000000) + + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000 + + usec * (TIMER_FREQ % 1000) / 1000000; + + while (ticks_left > 0) { + tick = getit(0, 0); +#ifdef DELAYDEBUG + ++getit_calls; +#endif + if (tick > prev_tick) + ticks_left -= prev_tick - (tick - timer0_divisor); + else + ticks_left -= prev_tick - tick; + prev_tick = tick; + } +#ifdef DELAYDEBUG + if (state == 1) + printf(" %d calls to getit() at %d usec each\n", + getit_calls, (n + 5) / getit_calls); +#endif +} + + +static void +sysbeepstop() +{ + outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */ + release_timer2(); + beeping = 0; +} + + +int +sysbeep(int pitch, int period) +{ + + if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT)) + return -1; + disable_intr(); + outb(TIMER_CNTR2, pitch); + outb(TIMER_CNTR2, (pitch>>8)); + enable_intr(); + if (!beeping) { + outb(IO_PPI, inb(IO_PPI) | 3); /* enable counter2 output to speaker */ + beeping = period; + timeout(sysbeepstop, 0, period); + } + return 0; +} -static void findcpuspeed(void); void startrtclock() { int s; - findcpuspeed(); /* use the clock (while it's free) - to find the cpu speed */ /* initialize 8253 clock */ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); /* Correct rounding will buy us a better precision in timekeeping */ - outb (IO_TIMER1, (TIMER_FREQ+hz/2)/hz); - outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256); + outb (IO_TIMER1, TIMER_DIV(hz)%256); + outb (IO_TIMER1, TIMER_DIV(hz)/256); + timer0_divisor = hardclock_divisor = TIMER_DIV(hz); /* initialize brain-dead battery powered clock */ outb (IO_RTC, RTC_STATUSA); @@ -83,44 +287,18 @@ startrtclock() printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); } -unsigned int delaycount; /* calibrated loop variable (1 millisecond) */ - -#define FIRST_GUESS 0x2000 -static void -findcpuspeed() -{ - unsigned char low; - unsigned int remainder; - - /* Put counter in count down mode */ - outb(IO_TIMER1+3, 0x34); - outb(IO_TIMER1, 0xff); - outb(IO_TIMER1, 0xff); - delaycount = FIRST_GUESS; - spinwait(1); - /* Read the value left in the counter */ - low = inb(IO_TIMER1); /* least siginifcant */ - remainder = inb(IO_TIMER1); /* most significant */ - remainder = (remainder<<8) + low ; - /* Formula for delaycount is : - * (loopcount * timer clock speed)/ (counter ticks * 1000) - */ - delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder); -} - /* convert 2 digit BCD number */ int -bcd(i) - int i; +bcd(int i) { return ((i/16)*10 + (i%16)); } + /* convert years to seconds (from 1970) */ unsigned long -ytos(y) -int y; +ytos(int y) { int i; unsigned long ret; @@ -133,16 +311,16 @@ int y; return ret; } + /* convert months to seconds */ unsigned long -mtos(m,leap) -int m,leap; +mtos(int m, int leap) { int i; unsigned long ret; ret = 0; - for(i=1;i<m;i++) { + for(i=1; i<m; i++) { switch(i){ case 1: case 3: case 5: case 7: case 8: case 10: case 12: ret += 31*24*60*60; break; @@ -162,11 +340,10 @@ int m,leap; * from a filesystem. */ void -inittodr(base) - time_t base; +inittodr(time_t base) { unsigned long sec; - int leap,day_week,t,yd; + int leap, day_week, t, yd; int sa,s; /* do we have a realtime clock present? (otherwise we loop below) */ @@ -180,26 +357,25 @@ inittodr(base) sec = bcd(rtcin(RTC_YEAR)) + 1900; if (sec < 1970) sec += 100; - leap = !(sec % 4); sec = ytos(sec); /* year */ - yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd; /* month */ - t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date */ + + leap = !(sec % 4); sec = ytos(sec); /* year */ + yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec+=yd; /* month */ + t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec+=t; yd+=t; /* date */ day_week = rtcin(RTC_WDAY); /* day */ sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */ sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */ sec += bcd(rtcin(RTC_SEC)); /* seconds */ - sec += tz.tz_minuteswest * 60; - time.tv_sec = sec; } + #ifdef garbage /* * Initialze the time of day register, based on the time base which is, e.g. * from a filesystem. */ -test_inittodr(base) - time_t base; +test_inittodr(time_t base) { outb(IO_RTC,9); /* year */ @@ -219,6 +395,7 @@ test_inittodr(base) } #endif + /* * Restart the clock. */ @@ -227,12 +404,14 @@ resettodr() { } + /* * Wire clock interrupt in. */ #define V(s) __CONCAT(V, s) extern void V(clk)(); + void enablertclock() { @@ -240,12 +419,12 @@ enablertclock() INTREN(IRQ0); } + /* * Delay for some number of milliseconds. */ void -spinwait(millisecs) - int millisecs; +spinwait(int millisecs) { DELAY(1000 * millisecs); } |