Newer
Older
honey-os / src / userland / pit / main.c
#define ALLOC_MAIN
#include <hlib.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

#include "../hlib/include/syscalls.h"

uint32_t systemTime = 0;
ListElement *sleepNotifications = NULL;
uint32_t serviceId;
bool initialized = false;

void interruptHandler() {
    systemTime++;
    if (listRemoveValue(&sleepNotifications, PTR(systemTime))) {
        fireEvent(syscall(SYS_GET_EVENT, serviceId, systemTime, 0, 0), 0);
    }
}

void doSleep(uint32_t millis) {
    uint32_t targetTime = systemTime + millis / 10;
    listAdd(&sleepNotifications, PTR(targetTime));
    uint32_t event = syscall(SYS_GET_EVENT, serviceId, targetTime, 0, 0);
    if (!event) {
        event = syscall(SYS_CREATE_EVENT, targetTime, 0, 0, 0);
    }
    await(serviceId, event);
    // TODO: remove unused event
}

int32_t main() {
    if (!initialized) {
        initialized = true;
        serviceId = getServiceId();
        createFunction("sleep", (void *)doSleep);
        uint32_t service = getService("pic");
        uint32_t event = getEvent(service, "irq0");
        subscribeEvent(service, event, interruptHandler);
        uint32_t hz = 100;
        int divisor = PIT_SCALE / hz;
        ioOut(PIT_CONTROL, CMD_BINARY | CMD_MODE3 | CMD_RW_BOTH | CMD_COUNTER0,
              1);
        ioOut(PIT_A, (uint8_t)divisor, 1);
        ioOut(PIT_A, (uint8_t)(divisor >> 8), 1);
        printf("timer handler installed\n");
    } else {
        printf("current uptime: %i.%is\n", systemTime / 100, systemTime % 100);
        printf("waiting one second to demonstrate sleeping\n");
        doSleep(1000);
    }
}