Skip to content

Commit 2dfeb8a

Browse files
committed
feat: add try_send_raw and try_receive
Signed-off-by: Martin Kröning <[email protected]>
1 parent 46464e8 commit 2dfeb8a

File tree

4 files changed

+70
-18
lines changed

4 files changed

+70
-18
lines changed

Changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Unreleased
22

3+
- Add `try_send_raw` and `try_receive` ([#34](https://github.com/rust-osdev/uart_16550/pull/34))
4+
35
# 0.3.0 – 2023-08-04
46

57
- Internal rewrite of port operations to work on both `x86` and `x86_64` ([#29](https://github.com/rust-osdev/uart_16550/pull/29))

src/lib.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,17 @@
6262
#![warn(missing_docs)]
6363
#![cfg_attr(docsrs, feature(doc_cfg))]
6464

65+
use core::fmt;
66+
6567
use bitflags::bitflags;
6668

67-
macro_rules! wait_for {
69+
macro_rules! retry_until_ok {
6870
($cond:expr) => {
69-
while !$cond {
70-
core::hint::spin_loop()
71+
loop {
72+
if let Ok(ok) = $cond {
73+
break ok;
74+
}
75+
core::hint::spin_loop();
7176
}
7277
};
7378
}
@@ -102,3 +107,14 @@ bitflags! {
102107
// 6 and 7 unknown
103108
}
104109
}
110+
111+
/// The `WouldBlockError` error indicates that the serial device was not ready immediately.
112+
#[non_exhaustive]
113+
#[derive(Clone, PartialEq, Eq, Debug)]
114+
pub struct WouldBlockError;
115+
116+
impl fmt::Display for WouldBlockError {
117+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118+
f.write_str("serial device not ready")
119+
}
120+
}

src/mmio.rs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use core::{
33
sync::atomic::{AtomicPtr, Ordering},
44
};
55

6-
use crate::LineStsFlags;
6+
use crate::{LineStsFlags, WouldBlockError};
77

88
/// A memory-mapped UART.
99
#[derive(Debug)]
@@ -90,18 +90,36 @@ impl MmioSerialPort {
9090

9191
/// Sends a raw byte on the serial port, intended for binary data.
9292
pub fn send_raw(&mut self, data: u8) {
93-
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
94-
let self_data = self.data.load(Ordering::Relaxed);
95-
unsafe {
96-
self_data.write(data);
93+
retry_until_ok!(self.try_send_raw(data))
94+
}
95+
96+
/// Tries to send a raw byte on the serial port, intended for binary data.
97+
pub fn try_send_raw(&mut self, data: u8) -> Result<(), WouldBlockError> {
98+
if self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {
99+
let self_data = self.data.load(Ordering::Relaxed);
100+
unsafe {
101+
self_data.write(data);
102+
}
103+
Ok(())
104+
} else {
105+
Err(WouldBlockError)
97106
}
98107
}
99108

100109
/// Receives a byte on the serial port.
101110
pub fn receive(&mut self) -> u8 {
102-
wait_for!(self.line_sts().contains(LineStsFlags::INPUT_FULL));
103-
let self_data = self.data.load(Ordering::Relaxed);
104-
unsafe { self_data.read() }
111+
retry_until_ok!(self.try_receive())
112+
}
113+
114+
/// Tries to receive a byte on the serial port.
115+
pub fn try_receive(&mut self) -> Result<u8, WouldBlockError> {
116+
if self.line_sts().contains(LineStsFlags::INPUT_FULL) {
117+
let self_data = self.data.load(Ordering::Relaxed);
118+
let data = unsafe { self_data.read() };
119+
Ok(data)
120+
} else {
121+
Err(WouldBlockError)
122+
}
105123
}
106124
}
107125

src/port.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use core::fmt;
22

3-
use crate::LineStsFlags;
3+
use crate::{LineStsFlags, WouldBlockError};
44

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

116116
/// Sends a raw byte on the serial port, intended for binary data.
117117
pub fn send_raw(&mut self, data: u8) {
118-
unsafe {
119-
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
120-
x86::io::outb(self.port_data(), data);
118+
retry_until_ok!(self.try_send_raw(data))
119+
}
120+
121+
/// Tries to send a raw byte on the serial port, intended for binary data.
122+
pub fn try_send_raw(&mut self, data: u8) -> Result<(), WouldBlockError> {
123+
if self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {
124+
unsafe {
125+
x86::io::outb(self.port_data(), data);
126+
}
127+
Ok(())
128+
} else {
129+
Err(WouldBlockError)
121130
}
122131
}
123132

124133
/// Receives a byte on the serial port.
125134
pub fn receive(&mut self) -> u8 {
126-
unsafe {
127-
wait_for!(self.line_sts().contains(LineStsFlags::INPUT_FULL));
128-
x86::io::inb(self.port_data())
135+
retry_until_ok!(self.try_receive())
136+
}
137+
138+
/// Tries to receive a byte on the serial port.
139+
pub fn try_receive(&mut self) -> Result<u8, WouldBlockError> {
140+
if self.line_sts().contains(LineStsFlags::INPUT_FULL) {
141+
let data = unsafe { x86::io::inb(self.port_data()) };
142+
Ok(data)
143+
} else {
144+
Err(WouldBlockError)
129145
}
130146
}
131147
}

0 commit comments

Comments
 (0)