#include <alarm_struct.h>
#include <proc.h>
#include <printk.h>
#include <asm.h>
#include <config.h>
#include <stddef.h>
#define DIVISOR (1193180 / TIMER_FREQUENCY)
static volatile unsigned long ticks;
static struct alarm_struct *first_alarm;
static void insert_alarm(struct alarm_struct *alarm)
{
struct alarm_struct *alm1, *alm2;
alm1 = NULL;
alm2 = first_alarm;
while (alm2 && alm2->time <= alarm->time)
alm1 = alm2, alm2 = alm2->next;
alarm->previous = alm1;
alarm->next = alm2;
if (alm1)
alm1->next = alarm;
else
first_alarm = alarm;
if (alm2)
alm2->previous = alarm;
alarm->active = 1;
}
static void remove_alarm(struct alarm_struct *alarm)
{
if (alarm->previous)
alarm->previous->next = alarm->next;
else
first_alarm = alarm->next;
if (alarm->next)
alarm->next->previous = alarm->previous;
alarm->active = 0;
}
void timer_init()
{
ticks = 0;
first_alarm = NULL;
outbp(0x34, 0x43);
outb(DIVISOR & 0xff, 0x40);
outb(DIVISOR >> 8, 0x40);
}
void timer_print_info()
{
printk("Timer: Intel 8254 Programmable Interval Timer\n");
printk("Timer frequency set to %dHz.\n", TIMER_FREQUENCY);
}
void do_timer_interrupt(const struct interrupted_instruction_struct *interrupted_instruction)
{
struct alarm_struct *alm;
ticks++;
while (first_alarm && first_alarm->time <= ticks) {
alm = first_alarm;
remove_alarm(alm);
alm->handler(alm);
}
preempt(interrupted_instruction);
}
void alarm_init(struct alarm_struct *alarm, void (*handler)(struct alarm_struct *))
{
alarm->handler = handler;
alarm->active = 0;
}
void alarm_set(struct alarm_struct *alarm, unsigned long milliseconds)
{
int intr;
disable_intr(intr);
if (alarm->active)
remove_alarm(alarm);
alarm->time = ticks + milliseconds * TIMER_FREQUENCY / 1000;
insert_alarm(alarm);
restore_intr(intr);
}
unsigned long alarm_unset(struct alarm_struct *alarm)
{
int intr;
unsigned long left;
disable_intr(intr);
if (alarm->active) {
left = (alarm->time - ticks) * 1000 / TIMER_FREQUENCY;
remove_alarm(alarm);
}
else
left = 0;
restore_intr(intr);
return left;
}