From ec7c6eff3c10565a57ba2b2c14b3f224d9216b76 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Sun, 10 Apr 2022 16:17:57 +0200 Subject: kernel/i386: rewrite the serial driver to wait for IRQ proper multiprocess support! --- src/kernel/arch/i386/driver/serial.c | 45 +++++++++++++++++++++++------------ src/kernel/arch/i386/driver/serial.h | 6 +++-- src/kernel/arch/i386/interrupts/isr.c | 2 ++ 3 files changed, 36 insertions(+), 17 deletions(-) (limited to 'src/kernel/arch/i386') diff --git a/src/kernel/arch/i386/driver/serial.c b/src/kernel/arch/i386/driver/serial.c index 14bb8fd..56a2f62 100644 --- a/src/kernel/arch/i386/driver/serial.c +++ b/src/kernel/arch/i386/driver/serial.c @@ -2,10 +2,17 @@ #include #include #include +#include #include + +#define BACKLOG_CAPACITY 64 +static volatile uint8_t backlog[BACKLOG_CAPACITY] = {}; +static volatile size_t backlog_size = 0; + static const int COM1 = 0x3f8; + static void serial_selftest(void) { char b = 0x69; port_out8(COM1 + 4, 0b00011110); // enable loopback mode @@ -29,29 +36,37 @@ void serial_init(void) { port_out8(COM1 + 4, 0b00001111); // enable everything in the MCR } -static void serial_putchar(char c) { - while ((port_in8(COM1 + 5) & 0x20) == 0); // wait for THRE - port_out8(COM1, c); + +bool serial_ready(void) { + return backlog_size > 0; } -bool serial_poll_read(char *c) { - if ((port_in8(COM1 + 5) & 0x01) == 0) // needs DR - return false; - *c = port_in8(COM1); - return true; +void serial_irq(void) { + if (backlog_size >= BACKLOG_CAPACITY) return; + backlog[backlog_size++] = port_in8(COM1); } size_t serial_read(char *buf, size_t len) { - irq_interrupt_flag(true); - for (size_t i = 0; i < len; i++) { - while (!serial_poll_read(&buf[i])) - asm("hlt" ::: "memory"); - } - irq_interrupt_flag(false); - // TODO root driver assumes no partial reads + // copied from ps2, maybe could be made into a shared function? TODO FIFO lib + if (backlog_size <= len) + len = backlog_size; + backlog_size -= len; /* guaranteed to never be < 0 */ + memcpy(buf, (void*)backlog, len); + + /* move rest of buffer back on partial reads */ + // TODO assumes that memcpy()ing into an overlapping buffer is fine, outside spec + if (backlog_size > 0) + memcpy((void*)backlog, (void*)backlog + len, backlog_size); + return len; } + +static void serial_putchar(char c) { + while ((port_in8(COM1 + 5) & 0x20) == 0); // wait for THRE + port_out8(COM1, c); +} + void serial_write(const char *buf, size_t len) { for (size_t i = 0; i < len; i++) serial_putchar(buf[i]); diff --git a/src/kernel/arch/i386/driver/serial.h b/src/kernel/arch/i386/driver/serial.h index be738d1..c2b93ce 100644 --- a/src/kernel/arch/i386/driver/serial.h +++ b/src/kernel/arch/i386/driver/serial.h @@ -3,7 +3,9 @@ #include void serial_init(void); + +bool serial_ready(void); +void serial_irq(void); size_t serial_read(char *buf, size_t len); -void serial_write(const char *buf, size_t len); -bool serial_poll_read(char *c); +void serial_write(const char *buf, size_t len); diff --git a/src/kernel/arch/i386/interrupts/isr.c b/src/kernel/arch/i386/interrupts/isr.c index e3bb6d6..5bba43d 100644 --- a/src/kernel/arch/i386/interrupts/isr.c +++ b/src/kernel/arch/i386/interrupts/isr.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -25,6 +26,7 @@ void isr_stage3(int interrupt) { return; case 0x24: // COM1 irq + serial_irq(); irq_eoi(1); return; -- cgit v1.2.3