Add beginning basic serial driver
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
#include "console.h"
|
||||
#include "io.h"
|
||||
#include "serial.h"
|
||||
|
||||
const char digits[] = "0123456789abcdef";
|
||||
console g_console;
|
||||
@@ -212,25 +212,28 @@ console_get_screen_out(const font &f, const screen &s, void *scratch, size_t len
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
serial_ready()
|
||||
{
|
||||
return (inb(COM1 + 5) & 0x20) != 0;
|
||||
}
|
||||
|
||||
static void
|
||||
serial_write(char c) {
|
||||
while (!serial_ready());
|
||||
outb(COM1, c);
|
||||
}
|
||||
|
||||
|
||||
console::console() :
|
||||
m_screen(nullptr)
|
||||
m_screen(nullptr),
|
||||
m_serial(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
console::console(serial_port *serial) :
|
||||
m_screen(nullptr),
|
||||
m_serial(serial)
|
||||
{
|
||||
if (m_serial) {
|
||||
const char *fgseq = "\x1b[2J";
|
||||
while (*fgseq)
|
||||
serial_write(*fgseq++);
|
||||
m_serial->write(*fgseq++);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
console::echo()
|
||||
{
|
||||
putc(m_serial->read());
|
||||
}
|
||||
|
||||
void
|
||||
@@ -239,32 +242,40 @@ console::set_color(uint8_t fg, uint8_t bg)
|
||||
if (m_screen)
|
||||
m_screen->set_color(fg, bg);
|
||||
|
||||
if (m_serial) {
|
||||
const char *fgseq = "\x1b[38;5;";
|
||||
while (*fgseq)
|
||||
serial_write(*fgseq++);
|
||||
if (fg >= 100) serial_write('0' + (fg/100));
|
||||
if (fg >= 10) serial_write('0' + (fg/10) % 10);
|
||||
serial_write('0' + fg % 10);
|
||||
serial_write('m');
|
||||
m_serial->write(*fgseq++);
|
||||
if (fg >= 100) m_serial->write('0' + (fg/100));
|
||||
if (fg >= 10) m_serial->write('0' + (fg/10) % 10);
|
||||
m_serial->write('0' + fg % 10);
|
||||
m_serial->write('m');
|
||||
|
||||
const char *bgseq = "\x1b[48;5;";
|
||||
while (*bgseq)
|
||||
serial_write(*bgseq++);
|
||||
if (bg >= 100) serial_write('0' + (bg/100));
|
||||
if (bg >= 10) serial_write('0' + (bg/10) % 10);
|
||||
serial_write('0' + bg % 10);
|
||||
serial_write('m');
|
||||
m_serial->write(*bgseq++);
|
||||
if (bg >= 100) m_serial->write('0' + (bg/100));
|
||||
if (bg >= 10) m_serial->write('0' + (bg/10) % 10);
|
||||
m_serial->write('0' + bg % 10);
|
||||
m_serial->write('m');
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
console::puts(const char *message)
|
||||
{
|
||||
while (message && *message) {
|
||||
char c = *message++;
|
||||
while (message && *message)
|
||||
putc(*message++);
|
||||
}
|
||||
|
||||
void
|
||||
console::putc(char c)
|
||||
{
|
||||
if (m_screen) m_screen->putc(c);
|
||||
|
||||
serial_write(c);
|
||||
if (c == '\n') serial_write('\r');
|
||||
if (m_serial) {
|
||||
m_serial->write(c);
|
||||
if (c == '\r') m_serial->write('\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,14 +6,17 @@
|
||||
#include "screen.h"
|
||||
|
||||
class console_out_screen;
|
||||
class serial_port;
|
||||
|
||||
class console
|
||||
{
|
||||
public:
|
||||
console();
|
||||
console(serial_port *serial);
|
||||
|
||||
void set_color(uint8_t fg = 7, uint8_t bg = 0);
|
||||
|
||||
void putc(char c);
|
||||
void puts(const char *message);
|
||||
void vprintf(const char *fmt, va_list args);
|
||||
|
||||
@@ -33,10 +36,13 @@ public:
|
||||
|
||||
void set_screen(console_out_screen *out) { m_screen = out; }
|
||||
|
||||
void echo();
|
||||
|
||||
static console * get();
|
||||
|
||||
private:
|
||||
console_out_screen *m_screen;
|
||||
serial_port *m_serial;
|
||||
};
|
||||
|
||||
extern console g_console;
|
||||
|
||||
@@ -130,7 +130,7 @@ set_idt_entry(uint8_t i, uint64_t addr, uint16_t selector, uint8_t flags)
|
||||
g_idt_table[i].reserved = 0;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
disable_legacy_pic()
|
||||
{
|
||||
|
||||
@@ -154,6 +154,13 @@ disable_legacy_pic()
|
||||
outb(PIC2+1, 0x02); io_wait();
|
||||
}
|
||||
|
||||
static void
|
||||
enable_serial_interrupts()
|
||||
{
|
||||
uint8_t ier = inb(COM1+1);
|
||||
outb(COM1+1, ier | 0x1);
|
||||
}
|
||||
|
||||
void
|
||||
interrupts_init()
|
||||
{
|
||||
@@ -186,6 +193,7 @@ interrupts_init()
|
||||
|
||||
idt_write();
|
||||
disable_legacy_pic();
|
||||
enable_serial_interrupts();
|
||||
|
||||
log::info(logs::interrupt, "Interrupts enabled.");
|
||||
}
|
||||
@@ -288,6 +296,11 @@ irq_handler(registers regs)
|
||||
cons->set_color();
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// TODO: move this to a real serial driver
|
||||
cons->echo();
|
||||
break;
|
||||
|
||||
default:
|
||||
cons->set_color(11);
|
||||
cons->printf("\nReceived IRQ interrupt: %d (vec %d)\n",
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
#include "device_manager.h"
|
||||
#include "font.h"
|
||||
#include "interrupts.h"
|
||||
#include "io.h"
|
||||
#include "kernel_data.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "memory_pages.h"
|
||||
#include "screen.h"
|
||||
#include "serial.h"
|
||||
|
||||
extern "C" {
|
||||
void do_the_set_registers(popcorn_data *header);
|
||||
@@ -41,7 +43,9 @@ load_console(const popcorn_data *header)
|
||||
void
|
||||
kernel_main(popcorn_data *header)
|
||||
{
|
||||
console *cons = new (&g_console) console();
|
||||
serial_port *com1 = new (&g_com1) serial_port(COM1);
|
||||
console *cons = new (&g_console) console(com1);
|
||||
|
||||
cons->set_color(0x21, 0x00);
|
||||
cons->puts("Popcorn OS ");
|
||||
cons->set_color(0x08, 0x00);
|
||||
|
||||
31
src/kernel/serial.cpp
Normal file
31
src/kernel/serial.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "io.h"
|
||||
#include "serial.h"
|
||||
|
||||
serial_port g_com1;
|
||||
|
||||
|
||||
serial_port::serial_port() :
|
||||
m_port(0)
|
||||
{
|
||||
}
|
||||
|
||||
serial_port::serial_port(uint16_t port) :
|
||||
m_port(port)
|
||||
{
|
||||
}
|
||||
|
||||
bool serial_port::read_ready() { return (inb(m_port + 5) & 0x01) != 0; }
|
||||
bool serial_port::write_ready() { return (inb(m_port + 5) & 0x20) != 0; }
|
||||
|
||||
char
|
||||
serial_port::read() {
|
||||
while (!read_ready());
|
||||
return inb(m_port);
|
||||
}
|
||||
|
||||
void
|
||||
serial_port::write(char c) {
|
||||
while (!write_ready());
|
||||
outb(m_port, c);
|
||||
}
|
||||
|
||||
25
src/kernel/serial.h
Normal file
25
src/kernel/serial.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
/// \file serial.h
|
||||
/// Declarations related to serial ports.
|
||||
#include <stdint.h>
|
||||
|
||||
class serial_port
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
/// \arg port The IO address of the serial port
|
||||
serial_port(uint16_t port);
|
||||
|
||||
serial_port();
|
||||
|
||||
void write(char c);
|
||||
char read();
|
||||
|
||||
private:
|
||||
uint16_t m_port;
|
||||
|
||||
bool read_ready();
|
||||
bool write_ready();
|
||||
};
|
||||
|
||||
extern serial_port g_com1;
|
||||
Reference in New Issue
Block a user