123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- /* vim: tabstop=4 shiftwidth=4 noexpandtab
- * This file is part of ToaruOS and is released under the terms
- * of the NCSA / University of Illinois License - see LICENSE.md
- * Copyright (C) 2011-2018 K. Lange
- *
- * Programmable Interrupt Timer
- */
- #include <kernel/system.h>
- #include <kernel/logging.h>
- #include <kernel/process.h>
- #define PIT_A 0x40
- #define PIT_B 0x41
- #define PIT_C 0x42
- #define PIT_CONTROL 0x43
- #define PIT_MASK 0xFF
- #define PIT_SCALE 1193180
- #define PIT_SET 0x34
- #define TIMER_IRQ 0
- #define SUBTICKS_PER_TICK 1000
- #define RESYNC_TIME 1
- /*
- * Set the phase (in hertz) for the Programmable
- * Interrupt Timer (PIT).
- */
- void
- timer_phase(
- int hz
- ) {
- int divisor = PIT_SCALE / hz;
- outportb(PIT_CONTROL, PIT_SET);
- outportb(PIT_A, divisor & PIT_MASK);
- outportb(PIT_A, (divisor >> 8) & PIT_MASK);
- }
- /*
- * Internal timer counters
- */
- unsigned long timer_ticks = 0;
- unsigned long timer_subticks = 0;
- signed long timer_drift = 0;
- signed long _timer_drift = 0;
- static int behind = 0;
- /*
- * IRQ handler for when the timer fires
- */
- int timer_handler(struct regs *r) {
- if (++timer_subticks == SUBTICKS_PER_TICK || (behind && ++timer_subticks == SUBTICKS_PER_TICK)) {
- timer_ticks++;
- timer_subticks = 0;
- if (timer_ticks % RESYNC_TIME == 0) {
- uint32_t new_time = read_cmos();
- _timer_drift = new_time - boot_time - timer_ticks;
- if (_timer_drift > 0) behind = 1;
- else behind = 0;
- }
- }
- irq_ack(TIMER_IRQ);
- wakeup_sleepers(timer_ticks, timer_subticks);
- switch_task(1);
- return 1;
- }
- void relative_time(unsigned long seconds, unsigned long subseconds, unsigned long * out_seconds, unsigned long * out_subseconds) {
- if (subseconds + timer_subticks > SUBTICKS_PER_TICK) {
- *out_seconds = timer_ticks + seconds + 1;
- *out_subseconds = (subseconds + timer_subticks) - SUBTICKS_PER_TICK;
- } else {
- *out_seconds = timer_ticks + seconds;
- *out_subseconds = timer_subticks + subseconds;
- }
- }
- /*
- * Device installer for the PIT
- */
- void timer_install(void) {
- debug_print(NOTICE,"Initializing interval timer");
- boot_time = read_cmos();
- irq_install_handler(TIMER_IRQ, timer_handler, "pit timer");
- timer_phase(SUBTICKS_PER_TICK); /* 100Hz */
- }
|