Files
opencoreC/kernel/src/drivers/serial.rs
T

84 lines
2.2 KiB
Rust

//! Early Serial Driver (16550 UART on COM1 0x3F8)
use core::fmt::{self, Write};
use core::sync::atomic::{AtomicBool, Ordering};
const COM1: u16 = 0x3F8;
static SERIAL_INITIALIZED: AtomicBool = AtomicBool::new(false);
#[inline]
unsafe fn outb(port: u16, val: u8) {
core::arch::asm!("out dx, al", in("dx") port, in("al") val, options(nomem, nostack, preserves_flags));
}
#[inline]
unsafe fn inb(port: u16) -> u8 {
let mut val: u8;
core::arch::asm!("in al, dx", in("dx") port, out("al") val, options(nomem, nostack, preserves_flags));
val
}
pub struct SerialPort;
impl SerialPort {
pub fn init() {
unsafe {
outb(COM1 + 1, 0x00); // Disable all interrupts
outb(COM1 + 3, 0x80); // Enable DLAB (set baud rate divisor)
outb(COM1 + 0, 0x01); // Set divisor to 1 (lo byte) 115200 baud
outb(COM1 + 1, 0x00); // (hi byte)
outb(COM1 + 3, 0x03); // 8 bits, no parity, one stop bit
outb(COM1 + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
outb(COM1 + 4, 0x0B); // IRQs enabled, RTS/DSR set
}
SERIAL_INITIALIZED.store(true, Ordering::Release);
}
pub fn write_byte(&self, byte: u8) {
unsafe {
// Wait for transmit buffer empty
while (inb(COM1 + 5) & 0x20) == 0 {
core::hint::spin_loop();
}
outb(COM1, byte);
}
}
pub fn write_str(&self, s: &str) {
for b in s.bytes() {
if b == b'\n' {
self.write_byte(b'\r');
}
self.write_byte(b);
}
}
}
impl Write for SerialPort {
fn write_str(&mut self, s: &str) -> fmt::Result {
SerialPort.write_str(s);
Ok(())
}
}
pub fn _kprint(args: fmt::Arguments) {
let mut port = SerialPort;
let _ = port.write_fmt(args);
}
#[macro_export]
macro_rules! kprint {
($($arg:tt)*) => {
$crate::drivers::serial::_kprint(format_args!($($arg)*))
};
}
#[macro_export]
macro_rules! kprintln {
() => ($crate::kprint!("\n"));
($($arg:tt)*) => ({
$crate::kprint!("{}\n", format_args!($($arg)*));
});
}