Skip to content

Commit 8805500

Browse files
authored
feature: check for full buffer before transmitting
1 parent c562f41 commit 8805500

File tree

2 files changed

+37
-11
lines changed

2 files changed

+37
-11
lines changed

uart8250/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ This crate provides a struct with many methods to operate an 8250 UART.
1111
mod registers;
1212
mod uart;
1313

14-
pub use uart::{ChipFifoInfo, InterruptType, MmioUart8250, Parity};
14+
pub use uart::{ChipFifoInfo, InterruptType, MmioUart8250, Parity, TransmitError};

uart8250/src/uart.rs

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use bitflags::bitflags;
2-
#[cfg(feature = "fmt")]
3-
use core::fmt;
2+
use core::fmt::{self, Display, Formatter};
43

54
use crate::registers::Registers;
65

@@ -93,6 +92,21 @@ pub enum Parity {
9392
Space,
9493
}
9594

95+
/// An error encountered which trying to transmit data.
96+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
97+
pub enum TransmitError {
98+
/// The transmit buffer is full, try again later.
99+
BufferFull,
100+
}
101+
102+
impl Display for TransmitError {
103+
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
104+
f.write_str(match self {
105+
Self::BufferFull => "UART buffer full",
106+
})
107+
}
108+
}
109+
96110
/// # MMIO version of an 8250 UART.
97111
///
98112
/// **Note** This is only tested on the NS16550 compatible UART used in QEMU 5.0 virt machine of RISC-V.
@@ -156,10 +170,13 @@ impl<'a> MmioUart8250<'a> {
156170
}
157171

158172
/// Writes a byte to the UART.
159-
///
160-
/// TODO: This currently ignores errors.
161-
pub fn write_byte(&self, byte: u8) {
162-
self.write_thr(byte);
173+
pub fn write_byte(&self, byte: u8) -> Result<(), TransmitError> {
174+
if self.is_transmitter_holding_register_empty() {
175+
self.write_thr(byte);
176+
Ok(())
177+
} else {
178+
Err(TransmitError::BufferFull)
179+
}
163180
}
164181

165182
/// write THR (offset + 0)
@@ -545,12 +562,14 @@ impl<'a> MmioUart8250<'a> {
545562
self.lsr().contains(LSR::RFE)
546563
}
547564

548-
/// get whether data holding registers are empty
565+
/// Gets whether data holding registers are empty, i.e. the UART has finished transmitting all
566+
/// the data it has been given.
549567
pub fn is_data_holding_registers_empty(&self) -> bool {
550568
self.lsr().contains(LSR::DHRE)
551569
}
552570

553-
/// get whether transmitter holding register is empty
571+
/// Gets whether transmitter holding register is empty, i.e. the UART is ready to be given more
572+
/// data to transmit.
554573
pub fn is_transmitter_holding_register_empty(&self) -> bool {
555574
self.lsr().contains(LSR::THRE)
556575
}
@@ -652,7 +671,8 @@ impl<'a> MmioUart8250<'a> {
652671
impl<'a> fmt::Write for MmioUart8250<'a> {
653672
fn write_str(&mut self, s: &str) -> fmt::Result {
654673
for c in s.as_bytes() {
655-
self.write_byte(*c);
674+
// If buffer is full, keep retrying.
675+
while self.write_byte(*c) == Err(TransmitError::BufferFull) {}
656676
}
657677
Ok(())
658678
}
@@ -684,8 +704,14 @@ mod tests {
684704
let mut fake_registers: [u8; 8] = [0; 8];
685705
let uart = unsafe { MmioUart8250::new(&mut fake_registers as *mut u8 as usize) };
686706

687-
uart.write_byte(0x42);
707+
// Pretend that the transmit buffer is full.
708+
fake_registers[5] = 0;
709+
assert_eq!(uart.write_byte(0x42), Err(TransmitError::BufferFull));
710+
assert_eq!(fake_registers[0], 0);
688711

712+
// Pretend that the transmit buffer is available.
713+
fake_registers[5] = 0b0010_0000;
714+
assert_eq!(uart.write_byte(0x42), Ok(()));
689715
assert_eq!(fake_registers[0], 0x42);
690716
}
691717

0 commit comments

Comments
 (0)