/* Copyright (C) 2015-2019 The University of Notre Dame This software is distributed under the GNU General Public License. See the file LICENSE for details. */ #include "interrupt.h" #include "clock.h" #include "ioports.h" #include "process.h" // Minimum PIT frequency is 18.2Hz. #define CLICKS_PER_SECOND 20 #define CLICKS_MILLITIME 1/CLICKS_PER_SECOND #define TIMER0 0x40 #define TIMER_MODE 0x43 #define SQUARE_WAVE 0x36 #define TIMER_FREQ 1193182 #define TIMER_COUNT (((unsigned)TIMER_FREQ)/CLICKS_PER_SECOND) static uint32_t clicks = 0; static uint32_t seconds = 0; static struct list queue = { 0, 0 }; static unsigned long read_pit_counter(void) { unsigned long count = 0; // Disable interrupts // cli(); // al = channel in bits 6 and 7, remaining bits clear outb(0b0000000,TIMER_MODE); count = inb(TIMER0); // Low byte count |= inb(TIMER0)<<8; // High byte return count; } static void clock_interrupt(int i, int code) { clicks++; process_wakeup_all(&queue); if(clicks >= CLICKS_PER_SECOND) { clicks = 0; seconds++; process_preempt(); } } clock_t clock_read() { clock_t result; result.seconds = seconds; result.millis = 1000 * clicks / CLICKS_PER_SECOND; return result; } clock_t clock_diff(clock_t start, clock_t stop) { clock_t result; if(stop.millis < start.millis) { stop.millis += 1000; stop.seconds -= 1; } result.seconds = stop.seconds - start.seconds; result.millis = stop.millis - start.millis; return result; } void clock_wait(uint32_t millis) { clock_t start, elapsed; uint32_t total; start = clock_read(); do { process_wait(&queue); elapsed = clock_diff(start, clock_read()); total = elapsed.millis + elapsed.seconds * 1000; } while(total < millis); } #ifdef KERNEL_CLOCK_EXT #include "kernel_clock_ext.c" #endif void clock_init() { outb(SQUARE_WAVE, TIMER_MODE); outb((TIMER_COUNT & 0xff), TIMER0); outb((TIMER_COUNT >> 8) & 0xff, TIMER0); interrupt_register(32, clock_interrupt); interrupt_enable(32); #ifdef KERNEL_CLOCK_EXT CLOCKINITMESSAGE #else printf("clock: ticking %d %% %d\n",read_pit_counter(),TIMER_COUNT); #endif }