Newer
Older
tree-os / src / kernel / drivers / interrupts / timer / timer.c
#include <alloc.h>
#include <interrupts.h>
#include <irqs.h>
#include <ports.h>
#include <stdint.h>
#include <stdio.h>
#include <task.h>

#define PIT_A 0x40
#define PIT_CONTROL 0x43

#define PIT_MASK 0xFF
#define PIT_SCALE 1193180
#define PIT_SET 0x36

#define CMD_BINARY 0x00

#define CMD_MODE0 0x00
#define CMD_MODE1 0x02
#define CMD_MODE2 0x04
#define CMD_MODE3 0x06
#define CMD_MODE4 0x08
#define CMD_MODE5 0x0a

#define CMD_RW_BOTH 0x30

#define CMD_COUNTER0 0x00
#define CMD_COUNTER2 0x80

void sleep(uint16_t millis) {
    int32_t ticksLeft = getCurrentTask()->ticksLeft - millis;
    getCurrentTask()->ticksLeft = millis;
    yield();
    if (ticksLeft > 0) {
        getCurrentTask()->ticksLeft = ticksLeft;
    }
}

void setTimerFrequency(uint32_t hz) {
    int divisor = PIT_SCALE / hz;
    outb(PIT_CONTROL, CMD_BINARY | CMD_MODE3 | CMD_RW_BOTH | CMD_COUNTER0);
    outb(PIT_A, (uint8_t)divisor);
    outb(PIT_A, (uint8_t)(divisor >> 8));
}

uintptr_t timerMillis = 0;

void timerHandler() {
    timerMillis++;
    for (ListElement *current = getAllTasks(); current;
         current = current->next) {
        Task *task = current->data;
        if (task->ticksLeft == -1) {
            continue;
        }
        if (task->ticksLeft == 0) {
            task->ticksLeft = task->timerTicks;
            Message *message = malloc(sizeof(Message));
            message->size = 0;
            message->data = (void *)timerMillis;
            message->type = TIMER_UPDATE;
            listAdd(&task->messages, message);
            schedule(task);
        } else {
            task->ticksLeft--;
        }
    }
}

void setupTimer() {
    setTimerFrequency(1000);
    setIRQHandler(0, &timerHandler);
}