Kernel: You can now read serial output from the /dev/ttyS*
This commit is contained in:
parent
33c81f00b7
commit
4a0652684c
|
@ -43,6 +43,8 @@ namespace Kernel
|
||||||
virtual uint32_t height() const override;
|
virtual uint32_t height() const override;
|
||||||
virtual void putchar(uint8_t) override;
|
virtual void putchar(uint8_t) override;
|
||||||
|
|
||||||
|
virtual void update() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SerialTTY(Serial);
|
SerialTTY(Serial);
|
||||||
bool initialize();
|
bool initialize();
|
||||||
|
|
|
@ -29,6 +29,7 @@ namespace Kernel
|
||||||
|
|
||||||
static void initialize_devices();
|
static void initialize_devices();
|
||||||
void on_key_event(Input::KeyEvent);
|
void on_key_event(Input::KeyEvent);
|
||||||
|
void handle_input(const uint8_t* ch);
|
||||||
|
|
||||||
virtual bool is_tty() const override { return true; }
|
virtual bool is_tty() const override { return true; }
|
||||||
|
|
||||||
|
@ -50,7 +51,7 @@ namespace Kernel
|
||||||
void do_backspace();
|
void do_backspace();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
mutable Kernel::SpinLock m_lock;
|
mutable Kernel::RecursiveSpinLock m_lock;
|
||||||
|
|
||||||
TerminalDriver::Color m_foreground { TerminalColor::BRIGHT_WHITE };
|
TerminalDriver::Color m_foreground { TerminalColor::BRIGHT_WHITE };
|
||||||
TerminalDriver::Color m_background { TerminalColor::BLACK };
|
TerminalDriver::Color m_background { TerminalColor::BLACK };
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#include <BAN/Array.h>
|
#include <BAN/Array.h>
|
||||||
|
#include <BAN/CircularQueue.h>
|
||||||
|
#include <kernel/CriticalScope.h>
|
||||||
#include <kernel/FS/DevFS/FileSystem.h>
|
#include <kernel/FS/DevFS/FileSystem.h>
|
||||||
#include <kernel/IDT.h>
|
#include <kernel/IDT.h>
|
||||||
#include <kernel/InterruptController.h>
|
#include <kernel/InterruptController.h>
|
||||||
|
@ -24,6 +26,11 @@
|
||||||
#define PARITY_MARK (0b101 << 3)
|
#define PARITY_MARK (0b101 << 3)
|
||||||
#define PARITY_SPACE (0b111 << 3)
|
#define PARITY_SPACE (0b111 << 3)
|
||||||
|
|
||||||
|
#define COM1_PORT 0x3F8
|
||||||
|
#define COM2_PORT 0x2F8
|
||||||
|
#define COM1_IRQ 4
|
||||||
|
#define COM2_IRQ 3
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -31,20 +38,35 @@ namespace Kernel
|
||||||
static BAN::Array<Serial, sizeof(s_serial_ports) / sizeof(*s_serial_ports)> s_serial_drivers;
|
static BAN::Array<Serial, sizeof(s_serial_ports) / sizeof(*s_serial_ports)> s_serial_drivers;
|
||||||
static bool s_has_devices { false };
|
static bool s_has_devices { false };
|
||||||
|
|
||||||
|
static BAN::CircularQueue<uint8_t, 128> s_com1_input;
|
||||||
|
static BAN::CircularQueue<uint8_t, 128> s_com2_input;
|
||||||
|
static BAN::RefPtr<SerialTTY> s_com1;
|
||||||
|
static BAN::RefPtr<SerialTTY> s_com2;
|
||||||
|
|
||||||
static void irq3_handler()
|
static void irq3_handler()
|
||||||
{
|
{
|
||||||
if (!s_serial_drivers[1].is_valid())
|
if (!s_serial_drivers[1].is_valid())
|
||||||
return;
|
return;
|
||||||
uint8_t ch = IO::inb(s_serial_drivers[1].port());
|
uint8_t ch = IO::inb(COM2_PORT);
|
||||||
Debug::putchar(ch);
|
if (s_com2_input.full())
|
||||||
|
{
|
||||||
|
dwarnln("COM2 buffer full");
|
||||||
|
s_com2_input.pop();
|
||||||
|
}
|
||||||
|
s_com2_input.push(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void irq4_handler()
|
static void irq4_handler()
|
||||||
{
|
{
|
||||||
if (!s_serial_drivers[0].is_valid())
|
if (!s_serial_drivers[0].is_valid())
|
||||||
return;
|
return;
|
||||||
uint8_t ch = IO::inb(s_serial_drivers[0].port());
|
uint8_t ch = IO::inb(COM1_PORT);
|
||||||
Debug::putchar(ch);
|
if (s_com1_input.full())
|
||||||
|
{
|
||||||
|
dwarnln("COM1 buffer full");
|
||||||
|
s_com1_input.pop();
|
||||||
|
}
|
||||||
|
s_com1_input.push(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
static dev_t next_rdev()
|
static dev_t next_rdev()
|
||||||
|
@ -71,7 +93,8 @@ namespace Kernel
|
||||||
s_has_devices = !!count;
|
s_has_devices = !!count;
|
||||||
|
|
||||||
for (auto& driver : s_serial_drivers)
|
for (auto& driver : s_serial_drivers)
|
||||||
dprintln("{}x{} serial device at 0x{H}", driver.width(), driver.height(), driver.port());
|
if (driver.is_valid())
|
||||||
|
dprintln("{}x{} serial device at 0x{H}", driver.width(), driver.height(), driver.port());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Serial::initialize_devices()
|
void Serial::initialize_devices()
|
||||||
|
@ -192,17 +215,17 @@ namespace Kernel
|
||||||
ASSERT(tty);
|
ASSERT(tty);
|
||||||
|
|
||||||
// Enable interrupts for COM1 and COM2
|
// Enable interrupts for COM1 and COM2
|
||||||
if (serial.port() == s_serial_ports[0])
|
if (serial.port() == COM1_PORT)
|
||||||
{
|
{
|
||||||
IO::outb(serial.port() + 1, 1);
|
IO::outb(COM1_PORT + 1, 1);
|
||||||
InterruptController::get().enable_irq(4);
|
InterruptController::get().enable_irq(COM1_IRQ);
|
||||||
IDT::register_irq_handler(4, irq4_handler);
|
IDT::register_irq_handler(COM1_IRQ, irq4_handler);
|
||||||
}
|
}
|
||||||
else if (serial.port() == s_serial_ports[1])
|
else if (serial.port() == COM2_PORT)
|
||||||
{
|
{
|
||||||
IO::outb(serial.port() + 1, 1);
|
IO::outb(COM2_PORT + 1, 1);
|
||||||
InterruptController::get().enable_irq(3);
|
InterruptController::get().enable_irq(COM2_IRQ);
|
||||||
IDT::register_irq_handler(3, irq3_handler);
|
IDT::register_irq_handler(COM2_IRQ, irq3_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(minor(tty->rdev()) < 10);
|
ASSERT(minor(tty->rdev()) < 10);
|
||||||
|
@ -210,9 +233,46 @@ namespace Kernel
|
||||||
|
|
||||||
auto ref_ptr = BAN::RefPtr<SerialTTY>::adopt(tty);
|
auto ref_ptr = BAN::RefPtr<SerialTTY>::adopt(tty);
|
||||||
DevFileSystem::get().add_device(name, ref_ptr);
|
DevFileSystem::get().add_device(name, ref_ptr);
|
||||||
|
if (serial.port() == COM1_PORT)
|
||||||
|
s_com1 = ref_ptr;
|
||||||
|
if (serial.port() == COM2_PORT)
|
||||||
|
s_com2 = ref_ptr;
|
||||||
return ref_ptr;
|
return ref_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SerialTTY::update()
|
||||||
|
{
|
||||||
|
if (m_serial.port() != COM1_PORT && m_serial.port() != COM2_PORT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto update_com =
|
||||||
|
[&](auto& device, auto& input_queue)
|
||||||
|
{
|
||||||
|
if (input_queue.empty())
|
||||||
|
return;
|
||||||
|
uint8_t buffer[128];
|
||||||
|
uint8_t* ptr = buffer;
|
||||||
|
while (!input_queue.empty())
|
||||||
|
{
|
||||||
|
*ptr = input_queue.front();
|
||||||
|
if (*ptr == '\r')
|
||||||
|
*ptr = '\n';
|
||||||
|
if (*ptr == 127)
|
||||||
|
*ptr++ = '\b', *ptr++ = ' ', *ptr = '\b';
|
||||||
|
input_queue.pop();
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
*ptr = '\0';
|
||||||
|
device->handle_input(buffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
CriticalScope _;
|
||||||
|
if (m_serial.port() == COM1_PORT)
|
||||||
|
update_com(s_com1, s_com1_input);
|
||||||
|
if (m_serial.port() == COM2_PORT)
|
||||||
|
update_com(s_com2, s_com2_input);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t SerialTTY::width() const
|
uint32_t SerialTTY::width() const
|
||||||
{
|
{
|
||||||
return m_serial.width();
|
return m_serial.width();
|
||||||
|
|
|
@ -132,11 +132,16 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t* ansi = (const uint8_t*)ansi_c_str;
|
handle_input((const uint8_t*)ansi_c_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TTY::handle_input(const uint8_t* ansi)
|
||||||
|
{
|
||||||
|
LockGuard _(m_lock);
|
||||||
|
|
||||||
bool eof = ansi && (
|
bool eof = ansi && (
|
||||||
ansi[0] == '\x04' || // ^D
|
ansi[0] == '\x04' || // ^D
|
||||||
ansi[0] == '\n' // \n
|
ansi[0] == '\n' // \n
|
||||||
);
|
);
|
||||||
|
|
||||||
if (ansi && m_termios.canonical)
|
if (ansi && m_termios.canonical)
|
||||||
|
|
Loading…
Reference in New Issue