/*
-pcboot - bootable PC demo/game kernel
-Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
+256boss - bootable launcher for 256b intros
+Copyright (C) 2018-2019 John Tsiombikas <nuclear@member.fsf.org>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "intr.h"
#include "asmops.h"
#include "timer.h"
+#include "panic.h"
#include "config.h"
/* frequency of the oscillator driving the 8254 timer */
#define CMD_MODE_BCD 1
-#define MSEC_TO_TICKS(ms) ((ms) * TICK_FREQ_HZ / 1000)
-
struct timer_event {
int dt; /* remaining ticks delta from the previous event */
+ void (*func)(void);
struct timer_event *next;
};
-/* defined in intr_asm.S */
-void intr_entry_fast_timer(void);
+static void timer_handler(int inum);
static struct timer_event *evlist;
outb((reload_count >> 8) & 0xff, PORT_DATA0);
/* set the timer interrupt handler */
- /*interrupt(IRQ_TO_INTR(0), timer_handler);*/
- /* set low level fast timer interrupt routine directly in the IDT */
- set_intr_entry(IRQ_TO_INTR(0), intr_entry_fast_timer);
+ interrupt(IRQ_TO_INTR(0), timer_handler);
+}
+
+void set_alarm(unsigned long msec, void (*func)(void))
+{
+ int ticks, tsum, iflag;
+ struct timer_event *ev, *node;
+
+ if((ticks = MSEC_TO_TICKS(msec)) <= 0) {
+ return;
+ }
+
+ if(!(ev = malloc(sizeof *ev))) {
+ panic("failed to allocate timer event");
+ return;
+ }
+ ev->func = func;
+
+ iflag = get_intr_flag();
+ disable_intr();
+
+ if(!evlist || ticks < evlist->dt) {
+ /* insert at the begining */
+ ev->next = evlist;
+ evlist = ev;
+
+ ev->dt = ticks;
+ if(ev->next) {
+ ev->next->dt -= ticks;
+ }
+ } else {
+ tsum = evlist->dt;
+ node = evlist;
+
+ while(node->next && ticks > tsum + node->next->dt) {
+ tsum += node->next->dt;
+ node = node->next;
+ }
+
+ ev->next = node->next;
+ node->next = ev;
+
+ /* fix the relative times */
+ ev->dt = ticks - tsum;
+ if(ev->next) {
+ ev->next->dt -= ev->dt;
+ }
+ }
+
+ set_intr_flag(iflag);
+}
+
+void cancel_alarm(void (*func)(void))
+{
+ int iflag;
+ struct timer_event *ev, *node;
+ struct timer_event dummy;
+
+ iflag = get_intr_flag();
+ disable_intr();
+
+ dummy.next = evlist;
+ node = &dummy;
+ while(node->next) {
+ ev = node->next;
+ if(ev->func == func) {
+ /* found it */
+ if(ev->next) {
+ ev->next->dt += ev->dt;
+ }
+ node->next = ev->next;
+ free(ev);
+ break;
+ }
+ node = node->next;
+ }
+
+ set_intr_flag(iflag);
}
-/*
static void timer_handler(int inum)
{
nticks++;
+
+ if(evlist) {
+ evlist->dt--;
+
+ while(evlist && evlist->dt <= 0) {
+ struct timer_event *ev = evlist;
+ evlist = evlist->next;
+
+ ev->func();
+ free(ev);
+ }
+ }
}
-*/