diff options
-rw-r--r-- | sys/x86/isa/clock.c | 25 |
1 files changed, 21 insertions, 4 deletions
diff --git a/sys/x86/isa/clock.c b/sys/x86/isa/clock.c index a74c11f..42cc448 100644 --- a/sys/x86/isa/clock.c +++ b/sys/x86/isa/clock.c @@ -125,6 +125,8 @@ struct attimer_softc { static struct attimer_softc *attimer_sc = NULL; static int timer0_period = -2; +static int timer0_mode = 0xffff; +static int timer0_last = 0xffff; /* Values for timerX_state: */ #define RELEASED 0 @@ -404,7 +406,7 @@ DELAY(int n) static void set_i8254_freq(int mode, uint32_t period) { - int new_count; + int new_count, new_mode; mtx_lock_spin(&clock_lock); if (mode == MODE_STOP) { @@ -423,21 +425,34 @@ set_i8254_freq(int mode, uint32_t period) timer0_period = (mode == MODE_PERIODIC) ? new_count : -1; switch (mode) { case MODE_STOP: - outb(TIMER_MODE, TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT); + new_mode = TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT; + outb(TIMER_MODE, new_mode); outb(TIMER_CNTR0, 0); outb(TIMER_CNTR0, 0); break; case MODE_PERIODIC: - outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); + new_mode = TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT; + outb(TIMER_MODE, new_mode); outb(TIMER_CNTR0, new_count & 0xff); outb(TIMER_CNTR0, new_count >> 8); break; case MODE_ONESHOT: - outb(TIMER_MODE, TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT); + if (new_count < 256 && timer0_last < 256) { + new_mode = TIMER_SEL0 | TIMER_INTTC | TIMER_LSB; + if (new_mode != timer0_mode) + outb(TIMER_MODE, new_mode); + outb(TIMER_CNTR0, new_count & 0xff); + break; + } + new_mode = TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT; + if (new_mode != timer0_mode) + outb(TIMER_MODE, new_mode); outb(TIMER_CNTR0, new_count & 0xff); outb(TIMER_CNTR0, new_count >> 8); break; } + timer0_mode = new_mode; + timer0_last = new_count; out: mtx_unlock_spin(&clock_lock); } @@ -447,6 +462,8 @@ i8254_restore(void) { timer0_period = -2; + timer0_mode = 0xffff; + timer0_last = 0xffff; if (attimer_sc != NULL) set_i8254_freq(attimer_sc->mode, attimer_sc->period); else |