Skip to content

Commit

Permalink
feat: add try_send_raw and try_receive
Browse files Browse the repository at this point in the history
Signed-off-by: Martin Kröning <martin.kroening@eonerc.rwth-aachen.de>
  • Loading branch information
mkroening committed Jul 10, 2024
1 parent 46464e8 commit 87b998c
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 18 deletions.
22 changes: 19 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,17 @@
#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]

use core::fmt;

use bitflags::bitflags;

macro_rules! wait_for {
macro_rules! spin_unwrap {
($cond:expr) => {
while !$cond {
core::hint::spin_loop()
loop {
if let Ok(ok) = $cond {
break ok;
}
core::hint::spin_loop();
}
};
}
Expand Down Expand Up @@ -102,3 +107,14 @@ bitflags! {
// 6 and 7 unknown
}
}

/// The `WouldBlockError` error indicates that the serial device was not ready immediately.
#[non_exhaustive]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct WouldBlockError;

impl fmt::Display for WouldBlockError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("serial device not ready")
}
}
34 changes: 26 additions & 8 deletions src/mmio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use core::{
sync::atomic::{AtomicPtr, Ordering},
};

use crate::LineStsFlags;
use crate::{LineStsFlags, WouldBlockError};

/// A memory-mapped UART.
#[derive(Debug)]
Expand Down Expand Up @@ -90,18 +90,36 @@ impl MmioSerialPort {

/// Sends a raw byte on the serial port, intended for binary data.
pub fn send_raw(&mut self, data: u8) {
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
let self_data = self.data.load(Ordering::Relaxed);
unsafe {
self_data.write(data);
spin_unwrap!(self.try_send_raw(data))
}

/// Tries to send a raw byte on the serial port, intended for binary data.
pub fn try_send_raw(&mut self, data: u8) -> Result<(), WouldBlockError> {
if self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {
let self_data = self.data.load(Ordering::Relaxed);
unsafe {
self_data.write(data);
}
Ok(())
} else {
Err(WouldBlockError)
}
}

/// Receives a byte on the serial port.
pub fn receive(&mut self) -> u8 {
wait_for!(self.line_sts().contains(LineStsFlags::INPUT_FULL));
let self_data = self.data.load(Ordering::Relaxed);
unsafe { self_data.read() }
spin_unwrap!(self.try_receive())
}

/// Tries to receive a byte on the serial port.
pub fn try_receive(&mut self) -> Result<u8, WouldBlockError> {
if self.line_sts().contains(LineStsFlags::INPUT_FULL) {
let self_data = self.data.load(Ordering::Relaxed);
let data = unsafe { self_data.read() };
Ok(data)
} else {
Err(WouldBlockError)
}
}
}

Expand Down
30 changes: 23 additions & 7 deletions src/port.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::fmt;

use crate::LineStsFlags;
use crate::{LineStsFlags, WouldBlockError};

/// A x86 I/O port-mapped UART.
#[cfg_attr(docsrs, doc(cfg(any(target_arch = "x86", target_arch = "x86_64"))))]
Expand Down Expand Up @@ -115,17 +115,33 @@ impl SerialPort {

/// Sends a raw byte on the serial port, intended for binary data.
pub fn send_raw(&mut self, data: u8) {
unsafe {
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
x86::io::outb(self.port_data(), data);
spin_unwrap!(self.try_send_raw(data))
}

/// Tries to send a raw byte on the serial port, intended for binary data.
pub fn try_send_raw(&mut self, data: u8) -> Result<(), WouldBlockError> {
if self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {
unsafe {
x86::io::outb(self.port_data(), data);
}
Ok(())
} else {
Err(WouldBlockError)
}
}

/// Receives a byte on the serial port.
pub fn receive(&mut self) -> u8 {
unsafe {
wait_for!(self.line_sts().contains(LineStsFlags::INPUT_FULL));
x86::io::inb(self.port_data())
spin_unwrap!(self.try_receive())
}

/// Tries to receive a byte on the serial port.
pub fn try_receive(&mut self) -> Result<u8, WouldBlockError> {
if self.line_sts().contains(LineStsFlags::INPUT_FULL) {
let data = unsafe { x86::io::inb(self.port_data()) };
Ok(data)
} else {
Err(WouldBlockError)
}
}
}
Expand Down

0 comments on commit 87b998c

Please sign in to comment.