Files
FoundryOS/lib/lib_serial/src/lib.rs
T
2025-02-20 22:59:24 +00:00

158 lines
3.8 KiB
Rust

#![no_std]
use core::{fmt, sync::atomic::{AtomicUsize, Ordering}};
use spin::Mutex;
use lazy_static::lazy_static;
mod io;
use io::*;
use x86_64::instructions::interrupts;
static PORT: u16 = 0x3f8;
static mut BUFFER: [u8; 256] = [0; 256];
static BUFFER_LEN: AtomicUsize = AtomicUsize::new(0);
lazy_static!{
static ref READER: Mutex<Option<Reader>> = Mutex::new(None);
static ref WRITER: Mutex<Option<Writer>> = Mutex::new(None);
}
struct Reader;
struct Writer;
impl fmt::Write for Writer {
fn write_str(&mut self, s: &str) -> fmt::Result {
for c in s.chars() {
self.write_byte(c as u8);
}
Ok(())
}
}
impl Writer {
unsafe fn write_success(&self) -> bool {
inb(PORT + 5) & 0x20 != 0
}
pub fn write_byte(&self, data: u8) { unsafe {
while !self.write_success() {};
outb(PORT + 0, data);
}}
}
pub fn init() -> Result<(), &'static str> {
if let Err(e) = test() {
return Err(e);
}
if READER.lock().is_none() {
*READER.lock() = Some(Reader);
}
if WRITER.lock().is_none() {
*WRITER.lock() = Some(Writer);
}
Ok(())
}
pub fn test() -> Result<(), &'static str> {
unsafe {
outb(PORT + 1, 0x00); // Disable all interrupts
outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud
outb(PORT + 1, 0x00); // (hi byte)
outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit
outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-bytethreshold
outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip
outb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte)
if inb(PORT + 0) != 0xAE {
return Err("serial test failed")
}
outb(PORT + 4, 0x0F);
}
Ok(())
}
impl Reader {
pub fn read_str_to_buffer(&mut self) { unsafe {
while !self.read_ready() {};
BUFFER_LEN.store(0, Ordering::SeqCst);
while BUFFER_LEN.load(Ordering::SeqCst) < 256 {
let c = self.read();
BUFFER[BUFFER_LEN.load(Ordering::SeqCst)] = c;
if c as char == '\r' {
break;
}
BUFFER_LEN.fetch_add(1, Ordering::SeqCst);
}
serial_println!("returning")
}}
unsafe fn read_ready(&self) -> bool {
inb(PORT + 5) & 1 != 0
}
pub fn read(&self) -> u8 { unsafe {
while !self.read_ready() {};
return inb(PORT + 0);
}}
}
pub fn _serial_write(args: fmt::Arguments) {
use core::fmt::Write;
interrupts::without_interrupts(|| {
if let Some(writer) = WRITER.lock().as_mut() {
writer.write_fmt(args).unwrap();
}
})
}
#[macro_export]
macro_rules! serial_println {
() => ($crate::serial_print!("\n"));
($($arg:tt)*) => ($crate::serial_print!("{}\n", format_args!($($arg)*)));
}
#[macro_export]
macro_rules! serial_print {
($($arg:tt)*) => ($crate::_serial_write(format_args!($($arg)*)));
}
pub fn serial_read() -> &'static str {
serial_println!("getting value!");
interrupts::without_interrupts(|| {
if let Some(reader) = READER.lock().as_mut() {
serial_println!("stuff happnin.");
reader.read_str_to_buffer();
} else {
serial_println!("failed to get writer");
}
});
serial_println!("eee");
let i = BUFFER_LEN.load(Ordering::SeqCst);
return unsafe {
if i != 0 {
core::str::from_utf8(&BUFFER[..i - 1]).unwrap()
} else {
serial_println!("empty string");
""
}
}
}