Add drivers/pit.c by 3Hren.

This commit is contained in:
Alexander Myltsev 2023-01-25 14:56:38 +04:00
parent 703ddafc34
commit c84d214daa
4 changed files with 92 additions and 1 deletions

View File

@ -76,7 +76,7 @@ image.bin: mbr.bin fs.img
kernel.bin: kernel.o console.o drivers/vga.o drivers/keyboard.o \
drivers/ata.o cpu/vectors.o cpu/idt.o cpu/gdt.o drivers/uart.o \
fs/fs.o lib/mem.o lib/string.o proc.o cpu/swtch.o
fs/fs.o lib/mem.o lib/string.o proc.o cpu/swtch.o drivers/pit.o
$(LD) $(LDFLAGS) $(LDKERNELFLAGS) -o $@ -Ttext 0x1000 $^
%.o: %.c

76
drivers/pit.c Normal file
View File

@ -0,0 +1,76 @@
#include "pit.h"
#include "port.h"
#include "../cpu/isr.h"
enum {
PIT_CRYSTAL_HZ = 1193182,
CLOCK_PRECISION_HZ = 100,
PIT_PROGRAM_REG = PIT_CRYSTAL_HZ / CLOCK_PRECISION_HZ,
PIT_SELECT_CHANNEL0 = 0x0,
PIT_SELECT_CHANNEL1 = 0x1,
PIT_SELECT_CHANNEL2 = 0x2,
PIT_SELECT_CHANNEL_RB = 0x3,
PIT_ACCESS_MODE_LATCH_COUNT_VALUE_COMMAND = 0x0,
PIT_ACCESS_MODE_LOBYTE_ONLY = 0x1,
PIT_ACCESS_MODE_HIBYTE_ONLY = 0x2,
PIT_ACCESS_MODE_LOHIBYTE = 0x3,
PIT_MODE_INTERRUPT_ON_TERMINAL_COUNT = 0x0,
PIT_MODE_HW_ONESHOT = 0x1,
PIT_MODE_RATE_GENERATOR = 0x2,
PIT_MODES_SQUARE_WAVE_GENERATOR = 0x3,
PIT_MODES_SW_TRIGGERRED_STROBE = 0x4,
PIT_MODES_HW_TRIGGERRED_STROBE = 0x5,
};
static timer_callback callbacks[100];
static int registered_callbacks = 0;
void add_timer_callback(timer_callback tc) {
callbacks[registered_callbacks++] = tc;
}
static void timer_interrupt_handler(registers_t *r) {
for (int i = 0; i < registered_callbacks; ++i) {
callbacks[i]();
}
}
struct pit_command_t {
unsigned char bcd : 1;
unsigned char operating_mode : 3;
unsigned char access_mode : 2;
unsigned char select_channel : 2;
} __attribute__((packed));
static void dec_sleep_counter(void);
void init_pit() {
struct pit_command_t cmd = {
.select_channel = PIT_SELECT_CHANNEL0,
.access_mode = PIT_ACCESS_MODE_LOHIBYTE,
.operating_mode = PIT_MODES_SQUARE_WAVE_GENERATOR,
.bcd = 0,
};
port_byte_out(0x43, *(unsigned char *)(&cmd));
port_byte_out(0x40, PIT_PROGRAM_REG & 0xff);
port_byte_out(0x40, (PIT_PROGRAM_REG & 0xff00) >> 8);
register_interrupt_handler(IRQ0, timer_interrupt_handler);
add_timer_callback(dec_sleep_counter);
}
static int sleep_counter = 0;
static void dec_sleep_counter(void) {
sleep_counter--;
}
void msleep(int ms) {
sleep_counter = ms / 10;
while (sleep_counter > 0) {
asm("hlt");
}
}

8
drivers/pit.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
typedef void (*timer_callback)(void);
void init_pit(void);
void add_timer_callback(timer_callback tc);
void msleep(int ms);

View File

@ -7,6 +7,7 @@ asm(".asciz \"kernel start\\n\"");
#include "drivers/vga.h"
#include "drivers/ata.h"
#include "drivers/misc.h"
#include "drivers/pit.h"
#include "drivers/uart.h"
#include "fs/fs.h"
#include "lib/string.h"
@ -16,6 +17,7 @@ asm(".asciz \"kernel start\\n\"");
void _start() {
load_gdt();
init_keyboard();
init_pit();
uartinit();
load_idt();
sti();
@ -35,6 +37,11 @@ void _start() {
if (kbd_buf_size > 0 && kbd_buf[kbd_buf_size-1] == '\n') {
if (!strncmp("halt\n", kbd_buf, kbd_buf_size)) {
qemu_shutdown();
} else if (!strncmp("work\n", kbd_buf, kbd_buf_size)) {
for (int i = 0; i < 5; ++i) {
msleep(1000);
printk(".");
}
} else if (!strncmp("run ", kbd_buf, 4)) {
kbd_buf[kbd_buf_size-1] = '\0';
const char* cmd = kbd_buf + 4;