+}
+
+static void
+pit_setup(void)
+{
+ // timer0: binary count, 16bit count, mode 2
+ outb(PM_SEL_TIMER0|PM_ACCESS_WORD|PM_MODE2|PM_CNT_BINARY, PORT_PIT_MODE);
+ // maximum count of 0000H = 18.2Hz
+ outb(0x0, PORT_PIT_COUNTER0);
+ outb(0x0, PORT_PIT_COUNTER0);
+}
+
+static void
+init_rtc(void)
+{
+ outb_cmos(0x26, CMOS_STATUS_A); // 32,768Khz src, 976.5625us updates
+ u8 regB = inb_cmos(CMOS_STATUS_B);
+ outb_cmos((regB & RTC_B_DSE) | RTC_B_24HR, CMOS_STATUS_B);
+ inb_cmos(CMOS_STATUS_C);
+ inb_cmos(CMOS_STATUS_D);
+}
+
+static u32
+bcd2bin(u8 val)
+{
+ return (val & 0xf) + ((val >> 4) * 10);
+}
+
+void
+timer_setup(void)
+{
+ dprintf(3, "init timer\n");
+#if 1
+ calibrate_tsc();
+#endif
+ dprintf(3, "init timer: 01\n");
+ pit_setup();
+ dprintf(3, "init timer: 02\n");
+
+ init_rtc();
+ dprintf(3, "init timer: 03\n");
+ rtc_updating();
+ dprintf(3, "init timer: 04\n");
+ u32 seconds = bcd2bin(inb_cmos(CMOS_RTC_SECONDS));
+ dprintf(3, "init timer: 05\n");
+ u32 minutes = bcd2bin(inb_cmos(CMOS_RTC_MINUTES));
+ dprintf(3, "init timer: 06\n");
+ u32 hours = bcd2bin(inb_cmos(CMOS_RTC_HOURS));
+ dprintf(3, "init timer: 07\n");
+ u32 ticks = (hours * 60 + minutes) * 60 + seconds;
+ dprintf(3, "init timer: 08\n");
+ ticks = ((u64)ticks * PIT_TICK_RATE) / PIT_TICK_INTERVAL;
+ dprintf(3, "init timer: 09\n");
+ SET_BDA(timer_counter, ticks);
+ dprintf(3, "init timer: 10\n");
+
+ enable_hwirq(0, FUNC16(entry_08));
+ dprintf(3, "init timer: 11\n");
+ enable_hwirq(8, FUNC16(entry_70));
+ dprintf(3, "init timer: 12\n");
+}
+
+
+/****************************************************************
+ * Standard clock functions
+ ****************************************************************/
+
+#define TICKS_PER_DAY (u32)((u64)60*60*24*PIT_TICK_RATE / PIT_TICK_INTERVAL)
+
+// Calculate the timer value at 'count' number of full timer ticks in
+// the future.
+u32
+calc_future_timer_ticks(u32 count)
+{
+ return (GET_BDA(timer_counter) + count + 1) % TICKS_PER_DAY;
+}
+
+// Return the timer value that is 'msecs' time in the future.
+u32
+calc_future_timer(u32 msecs)
+{
+ if (!msecs)
+ return GET_BDA(timer_counter);
+ u32 kticks = DIV_ROUND_UP((u64)msecs * PIT_TICK_RATE, PIT_TICK_INTERVAL);
+ u32 ticks = DIV_ROUND_UP(kticks, 1000);
+ return calc_future_timer_ticks(ticks);
+}
+
+// Check if the given timer value has passed.
+int
+check_timer(u32 end)
+{
+ return (((GET_BDA(timer_counter) + TICKS_PER_DAY - end) % TICKS_PER_DAY)
+ < (TICKS_PER_DAY/2));