diff --git a/kernel/include/kernel/Serial.h b/kernel/include/kernel/Serial.h index bcbdf9516b..2b1afe8b8c 100644 --- a/kernel/include/kernel/Serial.h +++ b/kernel/include/kernel/Serial.h @@ -1,11 +1,28 @@ #pragma once -namespace Serial +#include + +namespace Kernel { - void initialize(); - bool is_initialized(); + class Serial + { + public: + static void initialize(); + static bool has_devices(); + static void putchar_any(char); - void putchar(char); + void putchar(char); + + private: + static bool port_has_device(uint16_t); + + bool is_transmit_empty() const; + + bool is_valid() const { return m_port != 0; } + + private: + uint16_t m_port { 0 }; + }; } \ No newline at end of file diff --git a/kernel/kernel/Debug.cpp b/kernel/kernel/Debug.cpp index b3de7521d7..a965db645c 100644 --- a/kernel/kernel/Debug.cpp +++ b/kernel/kernel/Debug.cpp @@ -60,8 +60,8 @@ namespace Debug void putchar(char ch) { - if (Serial::is_initialized()) - return Serial::putchar(ch); + if (Kernel::Serial::has_devices()) + return Kernel::Serial::putchar_any(ch); if (Kernel::TTY::is_initialized()) return Kernel::TTY::putchar_current(ch); } diff --git a/kernel/kernel/Serial.cpp b/kernel/kernel/Serial.cpp index 663b5b4639..87491202d4 100644 --- a/kernel/kernel/Serial.cpp +++ b/kernel/kernel/Serial.cpp @@ -1,49 +1,76 @@ -#include +#include #include +#include #define COM1_PORT 0x3f8 -namespace Serial +namespace Kernel { - static bool s_initialized = false; + static constexpr uint16_t s_serial_ports[] = { 0x3F8, 0x2F8, 0x3E8, 0x2E8, 0x5F8, 0x4F8, 0x5E8, 0x4E8 }; + static BAN::Array s_serial_devices; + static bool s_has_devices { false }; - void initialize() + void Serial::initialize() { - IO::outb(COM1_PORT + 1, 0x00); // Disable all interrupts - IO::outb(COM1_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) - IO::outb(COM1_PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud - IO::outb(COM1_PORT + 1, 0x00); // (hi byte) - IO::outb(COM1_PORT + 3, 0x03); // 8 bits, no parity, one stop bit - IO::outb(COM1_PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold - IO::outb(COM1_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set - IO::outb(COM1_PORT + 4, 0x1E); // Set in loopback mode, test the serial chip - IO::outb(COM1_PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) + int count = 0; + for (size_t i = 0; i < s_serial_devices.size(); i++) + { + if (port_has_device(s_serial_ports[i])) + { + s_serial_devices[i].m_port = s_serial_ports[i]; + count++; + } + } + s_has_devices = !!count; + dprintln("Initialized {} serial devices", count); + } + + bool Serial::port_has_device(uint16_t port) + { + IO::outb(port + 1, 0x00); // Disable all interrupts + IO::outb(port + 3, 0x80); // Enable DLAB (set baud rate divisor) + IO::outb(port + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud + IO::outb(port + 1, 0x00); // (hi byte) + IO::outb(port + 3, 0x03); // 8 bits, no parity, one stop bit + IO::outb(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold + IO::outb(port + 4, 0x0B); // IRQs enabled, RTS/DSR set + IO::outb(port + 4, 0x1E); // Set in loopback mode, test the serial chip + IO::outb(port + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) // Check if serial is faulty (i.e: not same byte as sent) if(IO::inb(COM1_PORT + 0) != 0xAE) - return; + return false; // If serial is not faulty set it in normal operation mode // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) - IO::outb(COM1_PORT + 4, 0x0F); - s_initialized = true; + IO::outb(port + 4, 0x0F); + + return true; } - bool is_initialized() + bool Serial::has_devices() { - return s_initialized; + return s_has_devices; } - static int is_transmit_empty() { - return IO::inb(COM1_PORT + 5) & 0x20; + bool Serial::is_transmit_empty() const + { + return !(IO::inb(m_port + 5) & 0x20); } - void putchar(char c) + void Serial::putchar(char c) { - ASSERT(s_initialized); - while (is_transmit_empty() == 0); - IO::outb(COM1_PORT, c); + while (is_transmit_empty()) + continue; + IO::outb(m_port, c); + } + + void Serial::putchar_any(char c) + { + for (auto& device : s_serial_devices) + if (device.is_valid()) + device.putchar(c); } } \ No newline at end of file