1 // io/timer/i8254.cc -- Intel 8254 and compatible timer driver
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
5 // This software is provided 'as-is', without any express or implied warranty.
6 // In no event will the authors or contributors be held liable for any damages
7 // arising from the use of this software.
9 // Permission is hereby granted to everyone, free of charge, to use, copy,
10 // modify, prepare derivative works of, publish, distribute, perform,
11 // sublicense, and/or sell copies of the Software, provided that the above
12 // copyright notice and disclaimer of warranty be included in all copies or
13 // substantial portions of this software.
15 #include <kern/time.h>
17 #include <lowlevel/clock.h>
22 using Time::monotonic_clock;
26 class I8254 : public HWTimer {
33 u16 ret = ll_in_8(0x40);
34 ret |= (u16)ll_in_8(0x40) << 8;
44 } while (val < 0x8000);
48 } while (val > 0x8000);
65 s64 start_tick = ll_getclock();
68 s64 end_tick = ll_getclock();
70 s64 ticks_per_second = (end_tick - start_tick) *
71 (u64)clock_freq / 0x20000;
73 monotonic_clock.calibrate(ticks_per_second);
76 void arm(Time new_expiry)
78 // Interrupts should always be disabled when
81 Lock::AutoSpinLock autolock(lock);
83 // The 8254 is often slow to program, so don't re-program if the
84 // expiry is the same. To accomodate this, the tick timer must
85 // be set to go off often enough that the expiry is never more
86 // than 0xffff 8254 ticks (about 1/18.2 sec) in the future.
88 if (armed && expiry != new_expiry) {
90 monotonic_clock.get_time(&now);
91 Time rel_expiry = new_expiry - now;
96 assert(rel_expiry.seconds <= 0);
98 if (rel_expiry.seconds < 0)
101 // Add one extra tick to make sure we round up rather than
102 // down; otherwise, we'll just end up programming the timer
103 // for one tick and trying again.
105 ticks = rel_expiry.nanos * (u64)clock_freq /
108 assert(ticks <= 0xffff);
115 ll_out_8(0x43, 0x30);
117 ll_out_8(0x40, ticks & 0xff);
118 ll_out_8(0x40, ticks >> 8);