Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions crates/vm-superio/src/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::Trigger;
const DATA_OFFSET: u8 = 0;
const IER_OFFSET: u8 = 1;
const IIR_OFFSET: u8 = 2;
const FCR_OFFSET: u8 = 2;
const LCR_OFFSET: u8 = 3;
const MCR_OFFSET: u8 = 4;
const LSR_OFFSET: u8 = 5;
Expand Down Expand Up @@ -81,6 +82,9 @@ const MSR_RI_BIT: u8 = 0b0100_0000;
// Data Carrier Detect.
const MSR_DCD_BIT: u8 = 0b1000_0000;

const FCR_FIFO_RESET_RX: u8 = 0b0000_0010;
const FCR_FIFO_RESET_TX: u8 = 0b0000_0100;

// The following values can be used to set the baud rate to 9600 bps.
const DEFAULT_BAUD_DIVISOR_HIGH: u8 = 0x00;
const DEFAULT_BAUD_DIVISOR_LOW: u8 = 0x0C;
Expand Down Expand Up @@ -542,6 +546,13 @@ impl<T: Trigger, EV: SerialEvents, W: Write> Serial<T, EV, W> {
}
// We want to enable only the interrupts that are available for 16550A (and below).
IER_OFFSET => self.interrupt_enable = value & IER_UART_VALID_BITS,
FCR_OFFSET => {
if value & FCR_FIFO_RESET_RX != 0 || value & FCR_FIFO_RESET_TX != 0 {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused by this. Resetting the RX buffer isn't the same thing as resetting the TX buffer.

self.in_buffer.clear();
self.clear_lsr_rda_bit();
self.events.in_buffer_empty();
}
}
LCR_OFFSET => self.line_control = value,
MCR_OFFSET => self.modem_control = value,
SCR_OFFSET => self.scratch = value,
Expand Down Expand Up @@ -1117,4 +1128,38 @@ mod tests {
// Verify the serial raised an interrupt again.
assert_eq!(intr_evt.read().unwrap(), 1);
}

fn fifo_rest_rx_tx_from_fifo_control_register(value: u8) {
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let mut serial = Serial::new(intr_evt.try_clone().unwrap(), sink());

// Enqueue a non-empty slice.
serial.enqueue_raw_bytes(&RAW_INPUT_BUF).unwrap();

// Always verify that data ready bit in LSR is cleared off.
let lsr = serial.read(LSR_OFFSET);
assert_eq!(lsr & LSR_DATA_READY_BIT, 1);

// Verify that size of the current buffer is equal to RAW_INPUT_BUF.
assert_eq!(serial.in_buffer.len(), RAW_INPUT_BUF.len());

serial.write(FCR_OFFSET, value).unwrap();

// Verify that size of the current buffer is equal to 0 after setting 0x2 into FCR.
assert_eq!(serial.in_buffer.len(), 0);

// Always verify that data ready bit in LSR is cleared off.
let lsr = serial.read(LSR_OFFSET);
assert_eq!(lsr & LSR_DATA_READY_BIT, 0);
}

#[test]
fn test_fifo_reset_rx_from_fifo_control_register() {
fifo_rest_rx_tx_from_fifo_control_register(FCR_FIFO_RESET_RX);
}

#[test]
fn test_fifo_reset_tx_from_fifo_control_register() {
fifo_rest_rx_tx_from_fifo_control_register(FCR_FIFO_RESET_TX);
}
}