59 lines
1.7 KiB
C
59 lines
1.7 KiB
C
// SPDX-License-Identifier: ISC
|
|
|
|
#include <zinnia/console.h>
|
|
#include <zinnia/init.h>
|
|
#include <zinnia/initgraph.h>
|
|
#include <arch/cpu.h>
|
|
#include <stdint.h>
|
|
#include <x86_64/asm.h>
|
|
|
|
constexpr uint16_t COM1_BASE = 0x3F8;
|
|
|
|
static bool is_ready() {
|
|
return asm_inb(COM1_BASE + 5) & 0x20;
|
|
}
|
|
|
|
static void serial_write(struct console* con, const char* buf, size_t count) {
|
|
for (size_t i = 0; i < count; i++) {
|
|
while (!is_ready())
|
|
arch_cpu_pause();
|
|
|
|
asm_outb(COM1_BASE, buf[i]);
|
|
}
|
|
}
|
|
|
|
bool serial_setup(struct console* con) {
|
|
asm_outb(COM1_BASE + 1, 0x00); // Disable interrupts
|
|
asm_outb(COM1_BASE + 3, 0x80); // Enable DLAB (set baud rate divisor)
|
|
asm_outb(COM1_BASE, 0x01); // Set divisor low byte (115200 baud if 1)
|
|
asm_outb(COM1_BASE + 1, 0x00); // Set divisor high byte
|
|
asm_outb(COM1_BASE + 3, 0x03); // 8 bits, no parity, one stop bit (8n1)
|
|
asm_outb(COM1_BASE + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
|
|
asm_outb(COM1_BASE + 4, 0x0B); // IRQs enabled, RTS/DSR set
|
|
|
|
asm_outb(COM1_BASE + 4, 0x1E); // Set to loopback mode.
|
|
asm_outb(COM1_BASE, 0xAE); // Send a test byte.
|
|
|
|
// If we don't get the same value back, this serial port doesn't work.
|
|
if (asm_inb(COM1_BASE) != 0xAE) {
|
|
return false;
|
|
}
|
|
|
|
asm_outb(COM1_BASE + 4, 0x0F); // Disable loopback mode.
|
|
|
|
return true;
|
|
}
|
|
|
|
static struct console serial_con = {
|
|
.name = "com1",
|
|
.write = serial_write,
|
|
.init = serial_setup,
|
|
};
|
|
|
|
[[__init]]
|
|
static void serial_init(struct boot_info*) {
|
|
console_register(&serial_con);
|
|
}
|
|
INIT_TASK(serial_stage, "arch.x86_64.serial", serial_init);
|
|
INIT_ENTAILS(serial_stage, console_stage);
|