Skip to content

Commit cedfeb4

Browse files
authored
Merge pull request #34 from mkroening/try
feat: add `try_send_raw` and `try_receive`
2 parents b706c76 + b7c1012 commit cedfeb4

File tree

4 files changed

+89
-44
lines changed

4 files changed

+89
-44
lines changed

Changelog.md

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

3+
- Add `try_send_raw` and `try_receive` ([#34](https://github.com/rust-osdev/uart_16550/pull/34))
34
- Update bitflags dependency to version 2 ([#33](https://github.com/rust-osdev/uart_16550/pull/33))
45

56
# 0.3.0 – 2023-08-04

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
}
@@ -106,3 +111,14 @@ bitflags! {
106111
// 6 and 7 unknown
107112
}
108113
}
114+
115+
/// The `WouldBlockError` error indicates that the serial device was not ready immediately.
116+
#[non_exhaustive]
117+
#[derive(Clone, PartialEq, Eq, Debug)]
118+
pub struct WouldBlockError;
119+
120+
impl fmt::Display for WouldBlockError {
121+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122+
f.write_str("serial device not ready")
123+
}
124+
}

src/mmio.rs

Lines changed: 38 additions & 20 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)]
@@ -76,31 +76,49 @@ impl MmioSerialPort {
7676

7777
/// Sends a byte on the serial port.
7878
pub fn send(&mut self, data: u8) {
79-
let self_data = self.data.load(Ordering::Relaxed);
80-
unsafe {
81-
match data {
82-
8 | 0x7F => {
83-
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
84-
self_data.write(8);
85-
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
86-
self_data.write(b' ');
87-
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
88-
self_data.write(8)
89-
}
90-
_ => {
91-
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
92-
self_data.write(data);
93-
}
79+
match data {
80+
8 | 0x7F => {
81+
self.send_raw(8);
82+
self.send_raw(b' ');
83+
self.send_raw(8);
84+
}
85+
data => {
86+
self.send_raw(data);
9487
}
9588
}
9689
}
9790

91+
/// Sends a raw byte on the serial port, intended for binary data.
92+
pub fn send_raw(&mut self, data: u8) {
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)
106+
}
107+
}
108+
98109
/// Receives a byte on the serial port.
99110
pub fn receive(&mut self) -> u8 {
100-
let self_data = self.data.load(Ordering::Relaxed);
101-
unsafe {
102-
wait_for!(self.line_sts().contains(LineStsFlags::INPUT_FULL));
103-
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)
104122
}
105123
}
106124
}

src/port.rs

Lines changed: 31 additions & 21 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"))))]
@@ -101,37 +101,47 @@ impl SerialPort {
101101

102102
/// Sends a byte on the serial port.
103103
pub fn send(&mut self, data: u8) {
104-
unsafe {
105-
match data {
106-
8 | 0x7F => {
107-
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
108-
x86::io::outb(self.port_data(), 8);
109-
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
110-
x86::io::outb(self.port_data(), b' ');
111-
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
112-
x86::io::outb(self.port_data(), 8);
113-
}
114-
_ => {
115-
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
116-
x86::io::outb(self.port_data(), data);
117-
}
104+
match data {
105+
8 | 0x7F => {
106+
self.send_raw(8);
107+
self.send_raw(b' ');
108+
self.send_raw(8);
109+
}
110+
data => {
111+
self.send_raw(data);
118112
}
119113
}
120114
}
121115

122116
/// Sends a raw byte on the serial port, intended for binary data.
123117
pub fn send_raw(&mut self, data: u8) {
124-
unsafe {
125-
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
126-
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)
127130
}
128131
}
129132

130133
/// Receives a byte on the serial port.
131134
pub fn receive(&mut self) -> u8 {
132-
unsafe {
133-
wait_for!(self.line_sts().contains(LineStsFlags::INPUT_FULL));
134-
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)
135145
}
136146
}
137147
}

0 commit comments

Comments
 (0)