68 lines
1.6 KiB
Rust
68 lines
1.6 KiB
Rust
use core::arch::asm;
|
|
use core::fmt::Write;
|
|
use crate::mem::allocator::Locked;
|
|
|
|
pub struct SerialPort(u16);
|
|
|
|
impl SerialPort {
|
|
pub const COM1: u16 = 0x3F8;
|
|
|
|
pub unsafe fn init() -> Self {
|
|
let port = Self::COM1;
|
|
unsafe {
|
|
outb(port + 1, 0x00);
|
|
outb(port + 3, 0x80);
|
|
outb(port + 0, 0x03);
|
|
outb(port + 1, 0x00);
|
|
outb(port + 3, 0x03);
|
|
outb(port + 2, 0xC7);
|
|
outb(port + 4, 0x0B);
|
|
}
|
|
SerialPort(port)
|
|
}
|
|
|
|
fn is_transmit_empty(&self) -> bool {
|
|
unsafe { (inb(self.0 + 5) & 0x20) != 0 }
|
|
}
|
|
|
|
pub fn send(&self, data: u8) {
|
|
while !self.is_transmit_empty() {}
|
|
unsafe { outb(self.0, data); }
|
|
}
|
|
}
|
|
|
|
impl core::fmt::Write for SerialPort {
|
|
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
|
for byte in s.bytes() { self.send(byte); }
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
static SERIAL_PORT: Locked<Option<SerialPort>> = Locked::new(None);
|
|
|
|
pub fn init_global() {
|
|
let mut guard = SERIAL_PORT.lock();
|
|
*guard = Some(unsafe { SerialPort::init() });
|
|
}
|
|
|
|
pub fn write_global(args: core::fmt::Arguments) {
|
|
let mut guard = SERIAL_PORT.lock();
|
|
if let Some(ref mut sp) = *guard {
|
|
let _ = sp.write_fmt(args);
|
|
}
|
|
}
|
|
|
|
unsafe fn outb(port: u16, val: u8) {
|
|
unsafe {
|
|
asm!("out dx, al", in("dx") port, in("al") val, options(nomem, nostack, preserves_flags));
|
|
}
|
|
}
|
|
|
|
unsafe fn inb(port: u16) -> u8 {
|
|
let res: u8;
|
|
unsafe {
|
|
asm!("in al, dx", out("al") res, in("dx") port, options(nomem, nostack, preserves_flags));
|
|
}
|
|
res
|
|
}
|