summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/x86/isa/clock.c25
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
OpenPOWER on IntegriCloud