diff options
author | sos <sos@FreeBSD.org> | 1994-04-21 14:19:16 +0000 |
---|---|---|
committer | sos <sos@FreeBSD.org> | 1994-04-21 14:19:16 +0000 |
commit | a02f0d6fd90a09bffab0ab3bc8609c6629d5f74f (patch) | |
tree | 848715f0e7022e104b3b63549bbc52219d18d60a /sys/amd64/isa | |
parent | f850d82cc53bae4545f03c2f302eb2926b73df02 (diff) | |
download | FreeBSD-src-a02f0d6fd90a09bffab0ab3bc8609c6629d5f74f.zip FreeBSD-src-a02f0d6fd90a09bffab0ab3bc8609c6629d5f74f.tar.gz |
New support for sharing the timers
acquire_timer / release_timer
Pulled in timer related functions from isa.c
Diffstat (limited to 'sys/amd64/isa')
-rw-r--r-- | sys/amd64/isa/clock.c | 231 |
1 files changed, 208 insertions, 23 deletions
diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c index 2c70507..511edca 100644 --- a/sys/amd64/isa/clock.c +++ b/sys/amd64/isa/clock.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.5 1993/12/19 00:50:30 wollman Exp $ + * $Id: clock.c,v 1.6 1994/02/06 22:48:13 davidg 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,9 +56,193 @@ #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 void findcpuspeed(void); +static char timer0_in_use = 0, timer2_in_use = 0; +static int timer0_rate = 100; /* XXX should be hz */ +static void (*timer_func)() = hardclock; +static unsigned int prescale = 0; +static unsigned int hardclock_prescale; +static int beeping; +unsigned int delaycount; /* calibrated loop variable (1 millisecond) */ + + +void +timerintr(struct intrframe frame) +{ + timer_func(frame); + if (timer0_in_use) + if (prescale++ >= hardclock_prescale) { + hardclock(frame); + prescale = 0; + } +} + + +int +acquire_timer0(int rate, void (*function)() ) +{ + if (timer0_in_use) /* XXX || (rate < 20000 && rate % hz)) */ + return -1; + timer0_in_use = 1; + timer0_rate = rate; + prescale = 0; + hardclock_prescale = rate/hz; + outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); + outb(TIMER_CNTR0, TIMER_DIV(rate)%256); + outb(TIMER_CNTR0, TIMER_DIV(rate)/256); + if (function) + timer_func = function; + return 0; +} + + +int +acquire_timer2(int mode) +{ + if (timer2_in_use) + return -1; + timer2_in_use = 1; + outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f)); + return 0; +} + + +int +release_timer0() +{ + if (!timer0_in_use) + return -1; + timer0_in_use = 0; + timer0_rate = hz; + outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); + outb(TIMER_CNTR0, TIMER_DIV(hz)%256); + outb(TIMER_CNTR0, TIMER_DIV(hz)/256); + timer_func = hardclock; + return 0; +} + + +int +release_timer2() +{ + if (!timer2_in_use) + return -1; + timer2_in_use = 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; + + counter_limit = TIMER_FREQ/timer0_rate; + while (ticks_left > 0) { + tick = getit(0, 0); +#ifdef DELAYDEBUG + ++getit_calls; +#endif + if (tick > prev_tick) + ticks_left -= prev_tick - (tick - counter_limit); + 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() /* SOS XXX dummy is not needed */ +{ + 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; + outb(TIMER_CNTR2, pitch); + outb(TIMER_CNTR2, (pitch>>8)); + if (!beeping) { + outb(IO_PPI, inb(IO_PPI) | 3); /* enable counter2 output to speaker */ + beeping = period; + timeout(sysbeepstop, 0, period); + } + return 0; +} + + void startrtclock() { @@ -69,8 +254,9 @@ startrtclock() 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_rate = hz; /* initialize brain-dead battery powered clock */ outb (IO_RTC, RTC_STATUSA); @@ -83,7 +269,6 @@ 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 @@ -93,7 +278,7 @@ findcpuspeed() unsigned int remainder; /* Put counter in count down mode */ - outb(IO_TIMER1+3, 0x34); + outb(TIMER_MODE, TIMER_16BIT|TIMER_RATEGEN); outb(IO_TIMER1, 0xff); outb(IO_TIMER1, 0xff); delaycount = FIRST_GUESS; @@ -111,16 +296,15 @@ findcpuspeed() /* 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 +317,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 +346,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 +363,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 */ + 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 +401,7 @@ test_inittodr(base) } #endif + /* * Restart the clock. */ @@ -227,12 +410,14 @@ resettodr() { } + /* * Wire clock interrupt in. */ #define V(s) __CONCAT(V, s) extern void V(clk)(); + void enablertclock() { @@ -240,12 +425,12 @@ enablertclock() INTREN(IRQ0); } + /* * Delay for some number of milliseconds. */ void -spinwait(millisecs) - int millisecs; +spinwait(int millisecs) { DELAY(1000 * millisecs); } |