84 lines
2.2 KiB
Rust
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)*));
|
|
});
|
|
}
|