Verified Commit d2eba737 authored by Allie Sargente's avatar Allie Sargente 😑

Made the PIT driver less of a headache

Works in Qemu now (PIT shouldn't crash the system)
Also messed a bit with serial, should behave properly now
Signed-off-by: Allie Sargente's avatarAllison Sargente <[email protected]>
parent 4ba6ecb9
No preview for this file type
No preview for this file type
No preview for this file type
......@@ -10,9 +10,9 @@
#include <sys/hal.h>
#include <sys/timekeeping.h>
#include <stdio.h>
// 36.157 KHz, 99 ticks per correction, 2 tick correction.
// 27 Microseconds per tick, 3 ticks per correction, 2 uS correction.
static const uint32_t PIT_config[] = { 36157, 99, 2, 27, 3, 2 };
// Desired Frequency, us per tick, fractional nanoseconds leftover
static const uint32_t PIT_config[] = { 36157, 27, 657 };
static int timekeeping(struct regs *regs, void *p)
{
......@@ -20,24 +20,12 @@ static int timekeeping(struct regs *regs, void *p)
uint64_t ts = get_timestamp();
timekeeping_state_t *state = (timekeeping_state_t*)p;
state->ticks += 1;
state->correction_count += 1;
state->us_correction_count++;
if(state->us_correction_count >= state->us_correction_rate) {
ts += state->us_correction_factor;
state->us_correction_count = 0;
}
if (state->correction_count >= state->correction_rate) {
// Add ticks that we missed from the rounding error
state->ticks += state->correction_factor;
// Factor into the system clock
ts += (state->us_per_tick * state->correction_factor);
state->correction_count = 0;
state->ns_count += state->ns_per_tick;
if(state->ns_count >= 1000) { // Did we hit a microsecond?
ts += state->ns_count / 1000;
state->ns_count %= 1000;
}
// The PIT is set to around 27 microseconds
// Add Microseconds to the clock.
ts += state->us_per_tick;
set_timestamp(ts);
return 0;
......@@ -51,17 +39,15 @@ static int PIT_init()
timekeeping_state_t state;
int interrupt_state;
state.frequency = PIT_config[0];
state.correction_rate = PIT_config[1];
state.correction_factor = PIT_config[2];
state.us_per_tick = PIT_config[3];
state.us_correction_factor = PIT_config[4];
state.us_correction_rate = PIT_config[5];
state.tick_per_us = 0;
state.ticks = 0;
state.correction_count = 0;
state.us_correction_count = 0;
// Nearest integer frequency of the PIT
state.frequency = PIT_config[0];
// Calculated Microseconds per tick (from real frequency)
state.us_per_tick = PIT_config[1];
// Calculated Nanoseconds per tick (3 Significant Figures, only the ns part)
state.ns_per_tick = PIT_config[2];
state.ns_count = 0;
// Re-init the timestamp.
set_timestamp(0);
init_byte = PIT_CHANNEL_0 | PIT_LHBYTE | PIT_MODE_2 | PIT_BIN_MODE;
......@@ -72,6 +58,8 @@ static int PIT_init()
interrupt_state = get_interrupt_state();
disable_interrupts();
// Atomic Section
write_register(PIT_DATA_PORT, PIT_CMD, init_byte);
write_register(PIT_DATA_PORT, PIT_DATA_0, low);
write_register(PIT_DATA_PORT, PIT_DATA_0, high);
......@@ -79,6 +67,7 @@ static int PIT_init()
register_interrupt_handler(32, &timekeeping, (void*)&state);
set_interrupt_state(interrupt_state);
return 0;
}
......
......@@ -81,7 +81,13 @@ static int open(console_t *obj)
buf = (status->data_bits);
buf += (status->parity);
buf += (status->stop_bits);
// flush the serial buffer a bit
read_register(base, UART_INTEN);
read_register(base, UART_INTEN);
read_register(base, UART_INTEN);
read_register(base, UART_INTEN);
// Disable interrupts from the device
write_register(base, UART_INTEN, 0);
// Enable Divisor Latch Access Bit (DLAB), to set the baud rate
write_register(base, UART_LCR, UART_DLAB);
......@@ -108,7 +114,13 @@ static int open(console_t *obj)
static uint8_t is_connected(int base) {
uint8_t iir;
uint8_t msr;
/**
// TODO: Detect if we're in QEMU via CPUID or ACPI tables
// Qemu will hang if we try to detect
if (base == bases[0]) {
return 1; // Not sure what QEMU emulates...
}
*/
// First off, check Modem Status, make sure a chip exists at that address
msr = read_register(base, UART_MSR);
if(!(msr & (UART_DATA_SET_READY | UART_CLEAR_TO_SEND))) {
......@@ -194,7 +206,8 @@ static int register_serial()
// TODO: Scan for bases instead of assuming
// TODO: don't set like this, check kernel line from multiboot
// TODO: allow for more than 4 (right now that's limit from hardcoding)
for(i = 0; i < 4; i++) {
// TODO: can only use 2 unless we distunguish in IRQ which is which
for(i = 0; i < 2; i++) {
if(!is_connected(bases[i])) {
continue; // no serial port here, go to next one
}
......@@ -210,9 +223,8 @@ static int register_serial()
consoles[i].write = &write;
consoles[i].flush = NULL;
consoles[i].data = (void*)&states[i];
(void)register_console(&consoles[i]);
(void)register_interrupt_handler(irqs[i], &serial_interrupt_handler,
register_console(&consoles[i]);
register_interrupt_handler(irqs[i], &serial_interrupt_handler,
(void*)&states[i]);
}
return 0;
......
......@@ -3,6 +3,8 @@
#include <stdint.h>
#define IRQ(n) (n+32)
typedef struct {
int reg;
uint8_t cmd;
......
......@@ -12,10 +12,10 @@
#define UART_BASE_COM3 0x3e8
#define UART_BASE_COM4 0x2e8
#define UART_IRQ_COM1 36
#define UART_IRQ_COM2 35
#define UART_IRQ_COM3 36
#define UART_IRQ_COM4 35
#define UART_IRQ_COM1 IRQ(4)
#define UART_IRQ_COM2 IRQ(3)
#define UART_IRQ_COM3 IRQ(4)
#define UART_IRQ_COM4 IRQ(3)
// UART REGISTERS
......
......@@ -18,19 +18,15 @@ typedef struct callback_state
} callback_state_t;
// Struct for a timekeeping device
typedef struct timekeeping_state
{
uint32_t frequency; // Frequency of clock
uint64_t ticks; // Simple number of ticks
uint32_t tick_per_us; // Set to 0 if tick > 1 microsecond
uint32_t us_per_tick; // Set to 0 if tick < 1 microsecond
uint32_t us_correction_factor; // How much to correct
uint32_t us_correction_rate; // How often to apply correction
uint32_t us_correction_count; // Count for correction
uint32_t correction_rate; // How often to apply correction
uint32_t correction_factor; // How much to correct
uint32_t correction_count; // Count for correction
uint32_t frequency; // Frequency of clock
uint64_t ticks; // Simple number of ticks
uint32_t us_per_tick; // Microseconds per tick (rounded)
uint32_t ns_per_tick; // Remainder from microsecond round (3 places)
uint32_t ns_count; // Count of ns, so we can add it to timestamp
} timekeeping_state_t;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment