use std::collections::VecDeque;
use std::error::Error as StdError;
use std::fmt;
use std::io::{self, Write};
use std::result::Result;
use std::sync::Arc;
use crate::Trigger;
const DATA_OFFSET: u8 = 0;
const IER_OFFSET: u8 = 1;
const IIR_OFFSET: u8 = 2;
const LCR_OFFSET: u8 = 3;
const MCR_OFFSET: u8 = 4;
const LSR_OFFSET: u8 = 5;
const MSR_OFFSET: u8 = 6;
const SCR_OFFSET: u8 = 7;
const DLAB_LOW_OFFSET: u8 = 0;
const DLAB_HIGH_OFFSET: u8 = 1;
const FIFO_SIZE: usize = 0x40;
const IER_RDA_BIT: u8 = 0b0000_0001;
const IER_THR_EMPTY_BIT: u8 = 0b0000_0010;
const IER_UART_VALID_BITS: u8 = 0b0000_1111;
const IIR_FIFO_BITS: u8 = 0b1100_0000;
const IIR_NONE_BIT: u8 = 0b0000_0001;
const IIR_THR_EMPTY_BIT: u8 = 0b0000_0010;
const IIR_RDA_BIT: u8 = 0b0000_0100;
const LCR_DLAB_BIT: u8 = 0b1000_0000;
const LSR_DATA_READY_BIT: u8 = 0b0000_0001;
const LSR_EMPTY_THR_BIT: u8 = 0b0010_0000;
const LSR_IDLE_BIT: u8 = 0b0100_0000;
const MCR_DTR_BIT: u8 = 0b0000_0001;
const MCR_RTS_BIT: u8 = 0b0000_0010;
const MCR_OUT1_BIT: u8 = 0b0000_0100;
const MCR_OUT2_BIT: u8 = 0b0000_1000;
const MCR_LOOP_BIT: u8 = 0b0001_0000;
const MSR_CTS_BIT: u8 = 0b0001_0000;
const MSR_DSR_BIT: u8 = 0b0010_0000;
const MSR_RI_BIT: u8 = 0b0100_0000;
const MSR_DCD_BIT: u8 = 0b1000_0000;
const DEFAULT_BAUD_DIVISOR_HIGH: u8 = 0x00;
const DEFAULT_BAUD_DIVISOR_LOW: u8 = 0x0C;
const DEFAULT_INTERRUPT_ENABLE: u8 = 0x00;
const DEFAULT_INTERRUPT_IDENTIFICATION: u8 = IIR_NONE_BIT;
const DEFAULT_LINE_STATUS: u8 = LSR_EMPTY_THR_BIT | LSR_IDLE_BIT;
const DEFAULT_LINE_CONTROL: u8 = 0b0000_0011;
const DEFAULT_MODEM_CONTROL: u8 = MCR_OUT2_BIT;
const DEFAULT_MODEM_STATUS: u8 = MSR_DSR_BIT | MSR_CTS_BIT | MSR_DCD_BIT;
const DEFAULT_SCRATCH: u8 = 0x00;
pub trait SerialEvents {
fn buffer_read(&self);
fn out_byte(&self);
fn tx_lost_byte(&self);
fn in_buffer_empty(&self);
}
#[derive(Debug, Clone, Copy)]
pub struct NoEvents;
impl SerialEvents for NoEvents {
fn buffer_read(&self) {}
fn out_byte(&self) {}
fn tx_lost_byte(&self) {}
fn in_buffer_empty(&self) {}
}
impl<EV: SerialEvents> SerialEvents for Arc<EV> {
fn buffer_read(&self) {
self.as_ref().buffer_read();
}
fn out_byte(&self) {
self.as_ref().out_byte();
}
fn tx_lost_byte(&self) {
self.as_ref().tx_lost_byte();
}
fn in_buffer_empty(&self) {
self.as_ref().in_buffer_empty();
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SerialState {
pub baud_divisor_low: u8,
pub baud_divisor_high: u8,
pub interrupt_enable: u8,
pub interrupt_identification: u8,
pub line_control: u8,
pub line_status: u8,
pub modem_control: u8,
pub modem_status: u8,
pub scratch: u8,
pub in_buffer: Vec<u8>,
}
impl Default for SerialState {
fn default() -> Self {
SerialState {
baud_divisor_low: DEFAULT_BAUD_DIVISOR_LOW,
baud_divisor_high: DEFAULT_BAUD_DIVISOR_HIGH,
interrupt_enable: DEFAULT_INTERRUPT_ENABLE,
interrupt_identification: DEFAULT_INTERRUPT_IDENTIFICATION,
line_control: DEFAULT_LINE_CONTROL,
line_status: DEFAULT_LINE_STATUS,
modem_control: DEFAULT_MODEM_CONTROL,
modem_status: DEFAULT_MODEM_STATUS,
scratch: DEFAULT_SCRATCH,
in_buffer: Vec::new(),
}
}
}
#[derive(Debug)]
pub struct Serial<T: Trigger, EV: SerialEvents, W: Write> {
baud_divisor_low: u8,
baud_divisor_high: u8,
interrupt_enable: u8,
interrupt_identification: u8,
line_control: u8,
line_status: u8,
modem_control: u8,
modem_status: u8,
scratch: u8,
in_buffer: VecDeque<u8>,
interrupt_evt: T,
events: EV,
out: W,
}
#[derive(Debug)]
pub enum Error<E> {
Trigger(E),
IOError(io::Error),
FullFifo,
}
impl<E: fmt::Display> fmt::Display for Error<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::Trigger(e) => write!(f, "Failed to trigger interrupt: {e}"),
Error::IOError(e) => write!(f, "Couldn't write/flush to the given destination: {e}"),
Error::FullFifo => write!(f, "No space left in FIFO"),
}
}
}
impl<E: StdError> StdError for Error<E> {}
impl<T: Trigger, W: Write> Serial<T, NoEvents, W> {
pub fn new(trigger: T, out: W) -> Serial<T, NoEvents, W> {
Self::with_events(trigger, NoEvents, out)
}
}
impl<T: Trigger, EV: SerialEvents, W: Write> Serial<T, EV, W> {
pub fn from_state(
state: &SerialState,
trigger: T,
serial_evts: EV,
out: W,
) -> Result<Self, Error<T::E>> {
if state.in_buffer.len() > FIFO_SIZE {
return Err(Error::FullFifo);
}
let mut serial = Serial {
baud_divisor_low: state.baud_divisor_low,
baud_divisor_high: state.baud_divisor_high,
interrupt_enable: state.interrupt_enable,
interrupt_identification: state.interrupt_identification,
line_control: state.line_control,
line_status: state.line_status,
modem_control: state.modem_control,
modem_status: state.modem_status,
scratch: state.scratch,
in_buffer: VecDeque::from(state.in_buffer.clone()),
interrupt_evt: trigger,
events: serial_evts,
out,
};
if serial.is_thr_interrupt_enabled() && serial.is_thr_interrupt_set() {
serial.trigger_interrupt().map_err(Error::Trigger)?;
}
if serial.is_rda_interrupt_enabled() && serial.is_rda_interrupt_set() {
serial.trigger_interrupt().map_err(Error::Trigger)?;
}
Ok(serial)
}
pub fn with_events(trigger: T, serial_evts: EV, out: W) -> Self {
Self::from_state(&SerialState::default(), trigger, serial_evts, out).unwrap()
}
pub fn state(&self) -> SerialState {
SerialState {
baud_divisor_low: self.baud_divisor_low,
baud_divisor_high: self.baud_divisor_high,
interrupt_enable: self.interrupt_enable,
interrupt_identification: self.interrupt_identification,
line_control: self.line_control,
line_status: self.line_status,
modem_control: self.modem_control,
modem_status: self.modem_status,
scratch: self.scratch,
in_buffer: Vec::from(self.in_buffer.clone()),
}
}
pub fn writer(&self) -> &W {
&self.out
}
pub fn writer_mut(&mut self) -> &mut W {
&mut self.out
}
pub fn into_writer(self) -> W {
self.out
}
pub fn interrupt_evt(&self) -> &T {
&self.interrupt_evt
}
pub fn events(&self) -> &EV {
&self.events
}
fn is_dlab_set(&self) -> bool {
(self.line_control & LCR_DLAB_BIT) != 0
}
fn is_rda_interrupt_enabled(&self) -> bool {
(self.interrupt_enable & IER_RDA_BIT) != 0
}
fn is_thr_interrupt_enabled(&self) -> bool {
(self.interrupt_enable & IER_THR_EMPTY_BIT) != 0
}
fn is_rda_interrupt_set(&self) -> bool {
(self.interrupt_identification & IIR_RDA_BIT) != 0
}
fn is_thr_interrupt_set(&self) -> bool {
(self.interrupt_identification & IIR_THR_EMPTY_BIT) != 0
}
fn is_in_loop_mode(&self) -> bool {
(self.modem_control & MCR_LOOP_BIT) != 0
}
fn trigger_interrupt(&mut self) -> Result<(), T::E> {
self.interrupt_evt.trigger()
}
fn set_lsr_rda_bit(&mut self) {
self.line_status |= LSR_DATA_READY_BIT
}
fn clear_lsr_rda_bit(&mut self) {
self.line_status &= !LSR_DATA_READY_BIT
}
fn add_interrupt(&mut self, interrupt_bits: u8) {
self.interrupt_identification &= !IIR_NONE_BIT;
self.interrupt_identification |= interrupt_bits;
}
fn del_interrupt(&mut self, interrupt_bits: u8) {
self.interrupt_identification &= !interrupt_bits;
if self.interrupt_identification == 0x00 {
self.interrupt_identification = IIR_NONE_BIT;
}
}
fn thr_empty_interrupt(&mut self) -> Result<(), T::E> {
if self.is_thr_interrupt_enabled() {
if self.interrupt_identification & IIR_THR_EMPTY_BIT == 0 {
self.add_interrupt(IIR_THR_EMPTY_BIT);
self.trigger_interrupt()?
}
}
Ok(())
}
fn received_data_interrupt(&mut self) -> Result<(), T::E> {
if self.is_rda_interrupt_enabled() {
if self.interrupt_identification & IIR_RDA_BIT == 0 {
self.add_interrupt(IIR_RDA_BIT);
self.trigger_interrupt()?
}
}
Ok(())
}
fn reset_iir(&mut self) {
self.interrupt_identification = DEFAULT_INTERRUPT_IDENTIFICATION
}
pub fn write(&mut self, offset: u8, value: u8) -> Result<(), Error<T::E>> {
match offset {
DLAB_LOW_OFFSET if self.is_dlab_set() => self.baud_divisor_low = value,
DLAB_HIGH_OFFSET if self.is_dlab_set() => self.baud_divisor_high = value,
DATA_OFFSET => {
if self.is_in_loop_mode() {
if self.in_buffer.len() < FIFO_SIZE {
self.in_buffer.push_back(value);
self.set_lsr_rda_bit();
self.received_data_interrupt().map_err(Error::Trigger)?;
}
} else {
let res = self
.out
.write_all(&[value])
.map_err(Error::IOError)
.and_then(|_| self.out.flush().map_err(Error::IOError))
.map(|_| self.events.out_byte())
.inspect_err(|_| {
self.events.tx_lost_byte();
});
self.thr_empty_interrupt().map_err(Error::Trigger)?;
return res;
}
}
IER_OFFSET => self.interrupt_enable = value & IER_UART_VALID_BITS,
LCR_OFFSET => self.line_control = value,
MCR_OFFSET => self.modem_control = value,
SCR_OFFSET => self.scratch = value,
_ => {}
}
Ok(())
}
pub fn read(&mut self, offset: u8) -> u8 {
match offset {
DLAB_LOW_OFFSET if self.is_dlab_set() => self.baud_divisor_low,
DLAB_HIGH_OFFSET if self.is_dlab_set() => self.baud_divisor_high,
DATA_OFFSET => {
self.del_interrupt(IIR_RDA_BIT);
let byte = self.in_buffer.pop_front().unwrap_or_default();
if self.in_buffer.is_empty() {
self.clear_lsr_rda_bit();
self.events.in_buffer_empty();
}
self.events.buffer_read();
byte
}
IER_OFFSET => self.interrupt_enable,
IIR_OFFSET => {
let iir = self.interrupt_identification | IIR_FIFO_BITS;
self.reset_iir();
iir
}
LCR_OFFSET => self.line_control,
MCR_OFFSET => self.modem_control,
LSR_OFFSET => self.line_status,
MSR_OFFSET => {
if self.is_in_loop_mode() {
let mut msr =
self.modem_status & !(MSR_DSR_BIT | MSR_CTS_BIT | MSR_RI_BIT | MSR_DCD_BIT);
if (self.modem_control & MCR_DTR_BIT) != 0 {
msr |= MSR_DSR_BIT;
}
if (self.modem_control & MCR_RTS_BIT) != 0 {
msr |= MSR_CTS_BIT;
}
if (self.modem_control & MCR_OUT1_BIT) != 0 {
msr |= MSR_RI_BIT;
}
if (self.modem_control & MCR_OUT2_BIT) != 0 {
msr |= MSR_DCD_BIT;
}
msr
} else {
self.modem_status
}
}
SCR_OFFSET => self.scratch,
_ => 0,
}
}
#[inline]
pub fn fifo_capacity(&self) -> usize {
FIFO_SIZE - self.in_buffer.len()
}
pub fn enqueue_raw_bytes(&mut self, input: &[u8]) -> Result<usize, Error<T::E>> {
let mut write_count = 0;
if !self.is_in_loop_mode() {
if input.is_empty() {
return Ok(0);
}
if self.fifo_capacity() == 0 {
return Err(Error::FullFifo);
}
write_count = std::cmp::min(self.fifo_capacity(), input.len());
self.in_buffer.extend(&input[0..write_count]);
self.set_lsr_rda_bit();
self.received_data_interrupt().map_err(Error::Trigger)?;
}
Ok(write_count)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::{sink, Result};
use std::sync::atomic::AtomicU64;
use std::sync::Arc;
use vmm_sys_util::eventfd::EventFd;
use vmm_sys_util::metric::Metric;
const RAW_INPUT_BUF: [u8; 3] = [b'a', b'b', b'c'];
impl Trigger for EventFd {
type E = io::Error;
fn trigger(&self) -> Result<()> {
self.write(1)
}
}
struct ExampleSerialEvents {
read_count: AtomicU64,
out_byte_count: AtomicU64,
tx_lost_byte_count: AtomicU64,
buffer_ready_event: EventFd,
}
impl ExampleSerialEvents {
fn new() -> Self {
ExampleSerialEvents {
read_count: AtomicU64::new(0),
out_byte_count: AtomicU64::new(0),
tx_lost_byte_count: AtomicU64::new(0),
buffer_ready_event: EventFd::new(libc::EFD_NONBLOCK).unwrap(),
}
}
}
impl SerialEvents for ExampleSerialEvents {
fn buffer_read(&self) {
self.read_count.inc();
}
fn out_byte(&self) {
self.out_byte_count.inc();
}
fn tx_lost_byte(&self) {
self.tx_lost_byte_count.inc();
}
fn in_buffer_empty(&self) {
self.buffer_ready_event.write(1).unwrap();
}
}
#[test]
fn test_serial_output() {
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let mut serial = Serial::new(intr_evt, Vec::new());
RAW_INPUT_BUF
.iter()
.for_each(|&c| serial.write(DATA_OFFSET, c).unwrap());
assert_eq!(serial.writer().as_slice(), &RAW_INPUT_BUF);
}
#[test]
fn test_serial_raw_input() {
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let mut serial = Serial::new(intr_evt.try_clone().unwrap(), sink());
serial.write(IER_OFFSET, IER_RDA_BIT).unwrap();
serial.enqueue_raw_bytes(&[]).unwrap();
assert_eq!(
intr_evt.read().unwrap_err().kind(),
io::ErrorKind::WouldBlock
);
let mut lsr = serial.read(LSR_OFFSET);
assert_eq!(lsr & LSR_DATA_READY_BIT, 0);
serial.enqueue_raw_bytes(&RAW_INPUT_BUF).unwrap();
assert_eq!(intr_evt.read().unwrap(), 1);
lsr = serial.read(LSR_OFFSET);
assert_ne!(lsr & LSR_DATA_READY_BIT, 0);
RAW_INPUT_BUF.iter().for_each(|&c| {
lsr = serial.read(LSR_OFFSET);
assert_ne!(lsr & LSR_DATA_READY_BIT, 0);
assert_eq!(serial.read(DATA_OFFSET), c);
assert_eq!(
serial.interrupt_identification,
DEFAULT_INTERRUPT_IDENTIFICATION
);
});
lsr = serial.read(LSR_OFFSET);
assert_eq!(lsr & LSR_DATA_READY_BIT, 0);
}
#[test]
fn test_serial_thr() {
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let mut serial = Serial::new(intr_evt.try_clone().unwrap(), sink());
serial.write(IER_OFFSET, IER_THR_EMPTY_BIT).unwrap();
assert_eq!(
serial.interrupt_enable,
IER_THR_EMPTY_BIT & IER_UART_VALID_BITS
);
serial.write(DATA_OFFSET, b'a').unwrap();
assert_eq!(intr_evt.read().unwrap(), 1);
let ier = serial.read(IER_OFFSET);
assert_eq!(ier & IER_UART_VALID_BITS, IER_THR_EMPTY_BIT);
let iir = serial.read(IIR_OFFSET);
assert_ne!(iir & IIR_THR_EMPTY_BIT, 0);
assert_eq!(iir, IIR_THR_EMPTY_BIT | IIR_FIFO_BITS);
assert_eq!(
serial.interrupt_identification,
DEFAULT_INTERRUPT_IDENTIFICATION
);
}
#[test]
fn test_serial_loop_mode() {
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let mut serial = Serial::new(intr_evt.try_clone().unwrap(), sink());
serial.write(MCR_OFFSET, MCR_LOOP_BIT).unwrap();
serial.write(IER_OFFSET, IER_RDA_BIT).unwrap();
for value in 0..FIFO_SIZE as u8 {
serial.write(DATA_OFFSET, value).unwrap();
assert_eq!(intr_evt.read().unwrap(), 1);
assert_eq!(serial.in_buffer.len(), 1);
assert_eq!(serial.read(DATA_OFFSET), value);
}
assert_eq!(serial.line_status & LSR_DATA_READY_BIT, 0);
for value in 0..FIFO_SIZE as u8 {
serial.write(DATA_OFFSET, value).unwrap();
}
assert_eq!(intr_evt.read().unwrap(), 1);
assert_eq!(serial.in_buffer.len(), FIFO_SIZE);
for value in 0..FIFO_SIZE as u8 {
assert_ne!(serial.line_status & LSR_DATA_READY_BIT, 0);
assert_eq!(serial.read(DATA_OFFSET), value);
}
assert_eq!(serial.line_status & LSR_DATA_READY_BIT, 0);
}
#[test]
fn test_serial_dlab() {
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let mut serial = Serial::new(intr_evt, sink());
serial.write(LCR_OFFSET, LCR_DLAB_BIT).unwrap();
serial.write(DLAB_HIGH_OFFSET, 0x12).unwrap();
assert_eq!(serial.read(DLAB_LOW_OFFSET), DEFAULT_BAUD_DIVISOR_LOW);
assert_eq!(serial.read(DLAB_HIGH_OFFSET), 0x12);
serial.write(DLAB_LOW_OFFSET, 0x34).unwrap();
assert_eq!(serial.read(DLAB_LOW_OFFSET), 0x34);
assert_eq!(serial.read(DLAB_HIGH_OFFSET), 0x12);
serial.write(LCR_OFFSET, 0x00).unwrap();
assert_ne!(serial.read(DLAB_LOW_OFFSET), 0x12);
assert_ne!(serial.read(DLAB_HIGH_OFFSET), 0x34);
}
#[test]
fn test_basic_register_accesses() {
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let mut serial = Serial::new(intr_evt, sink());
let basic_register_accesses = [LCR_OFFSET, MCR_OFFSET, SCR_OFFSET];
for offset in basic_register_accesses.iter() {
serial.write(*offset, 0x12).unwrap();
assert_eq!(serial.read(*offset), 0x12);
}
}
#[test]
fn test_invalid_access() {
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let mut serial = Serial::new(intr_evt, sink());
serial.write(SCR_OFFSET + 1, 5).unwrap();
assert_eq!(serial.read(SCR_OFFSET + 1), 0);
}
#[test]
fn test_serial_msr() {
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let mut serial = Serial::new(intr_evt, sink());
assert_eq!(serial.read(MSR_OFFSET), DEFAULT_MODEM_STATUS);
serial.write(MCR_OFFSET, MCR_LOOP_BIT).unwrap();
assert_ne!(serial.read(MSR_OFFSET), DEFAULT_MODEM_STATUS);
assert_eq!(serial.read(MSR_OFFSET), 0x00);
serial
.write(MCR_OFFSET, DEFAULT_MODEM_CONTROL | MCR_LOOP_BIT)
.unwrap();
assert_eq!(serial.read(MSR_OFFSET), MSR_DCD_BIT);
serial
.write(MCR_OFFSET, MCR_OUT1_BIT | MCR_LOOP_BIT)
.unwrap();
assert_eq!(serial.read(MSR_OFFSET), MSR_RI_BIT);
serial
.write(MCR_OFFSET, MCR_LOOP_BIT | MCR_DTR_BIT | MCR_RTS_BIT)
.unwrap();
assert_eq!(serial.read(MSR_OFFSET), MSR_DSR_BIT | MSR_CTS_BIT);
}
#[test]
fn test_fifo_max_size() {
let event_fd = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let mut serial = Serial::new(event_fd, sink());
let too_many_bytes = vec![1u8; FIFO_SIZE + 1];
let written_bytes = serial.enqueue_raw_bytes(&too_many_bytes).unwrap();
assert_eq!(written_bytes, FIFO_SIZE);
assert_eq!(serial.in_buffer.len(), FIFO_SIZE);
let written_bytes = serial.enqueue_raw_bytes(&[]).unwrap();
assert_eq!(written_bytes, 0);
assert_eq!(serial.in_buffer.len(), FIFO_SIZE);
let one_byte_input = [1u8];
match serial.enqueue_raw_bytes(&one_byte_input) {
Err(Error::FullFifo) => (),
_ => unreachable!(),
}
let _ = serial.read(DATA_OFFSET);
let written_bytes = serial.enqueue_raw_bytes(&too_many_bytes[..2]).unwrap();
assert_eq!(written_bytes, 1);
assert_eq!(serial.in_buffer.len(), FIFO_SIZE);
}
#[test]
fn test_serial_events() {
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let events_ = Arc::new(ExampleSerialEvents::new());
let mut oneslot_buf = [0u8; 1];
let mut serial = Serial::with_events(intr_evt, events_, oneslot_buf.as_mut());
assert_eq!(
serial.events.buffer_ready_event.read().unwrap_err().kind(),
io::ErrorKind::WouldBlock
);
assert_eq!(serial.events.read_count.count(), 0);
assert_eq!(serial.events.out_byte_count.count(), 0);
assert_eq!(serial.events.tx_lost_byte_count.count(), 0);
serial.read(DATA_OFFSET);
assert_eq!(serial.events.read_count.count(), 1);
assert_eq!(serial.events.buffer_ready_event.read().unwrap(), 1);
serial.write(DATA_OFFSET, 1).unwrap();
assert_eq!(serial.events.out_byte_count.count(), 1);
assert_eq!(serial.events.tx_lost_byte_count.count(), 0);
serial.write(DATA_OFFSET, 1).unwrap_err();
assert_eq!(serial.events.tx_lost_byte_count.count(), 1);
assert_eq!(serial.events.read_count.count(), 1);
assert_eq!(serial.events.out_byte_count.count(), 1);
assert_eq!(serial.events.tx_lost_byte_count.count(), 1);
serial.read(DATA_OFFSET);
assert_eq!(serial.events.read_count.count(), 2);
assert_eq!(serial.events.buffer_ready_event.read().unwrap(), 1);
let _res = serial.enqueue_raw_bytes(&[1, 2]);
serial.read(DATA_OFFSET);
assert_eq!(
serial.events.buffer_ready_event.read().unwrap_err().kind(),
io::ErrorKind::WouldBlock
);
}
#[test]
fn test_out_descrp_full_thre_sent() {
let mut nospace_buf = [0u8; 0];
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let mut serial = Serial::new(intr_evt, nospace_buf.as_mut());
serial.write(IER_OFFSET, IER_THR_EMPTY_BIT).unwrap();
let res = serial.write(DATA_OFFSET, 5);
let iir = serial.read(IIR_OFFSET);
assert!(
matches!(res.unwrap_err(), Error::IOError(io_err) if io_err.kind() == io::ErrorKind::WriteZero
)
);
assert_eq!(iir & IIR_THR_EMPTY_BIT, IIR_THR_EMPTY_BIT);
}
#[test]
fn test_serial_state_default() {
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let serial = Serial::new(intr_evt, Vec::new());
assert_eq!(serial.state(), SerialState::default());
}
#[test]
fn test_from_state_with_too_many_bytes() {
let mut state = SerialState::default();
let too_many_bytes = vec![1u8; 128];
state.in_buffer.extend(too_many_bytes);
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let serial = Serial::from_state(&state, intr_evt, NoEvents, sink());
assert!(matches!(serial, Err(Error::FullFifo)));
}
#[test]
fn test_from_state_with_pending_thre_interrupt() {
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let mut serial = Serial::new(intr_evt.try_clone().unwrap(), sink());
serial.write(IER_OFFSET, IER_THR_EMPTY_BIT).unwrap();
serial.write(DATA_OFFSET, b'a').unwrap();
assert_eq!(intr_evt.read().unwrap(), 1);
let state = serial.state();
let mut serial_after_restore =
Serial::from_state(&state, intr_evt.try_clone().unwrap(), NoEvents, sink()).unwrap();
let ier = serial_after_restore.read(IER_OFFSET);
assert_eq!(ier & IER_UART_VALID_BITS, IER_THR_EMPTY_BIT);
let iir = serial_after_restore.read(IIR_OFFSET);
assert_ne!(iir & IIR_THR_EMPTY_BIT, 0);
assert_eq!(intr_evt.read().unwrap(), 1);
}
#[test]
fn test_from_state_with_pending_rda_interrupt() {
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let mut serial = Serial::new(intr_evt.try_clone().unwrap(), sink());
serial.write(IER_OFFSET, IER_RDA_BIT).unwrap();
serial.enqueue_raw_bytes(&RAW_INPUT_BUF).unwrap();
assert_eq!(intr_evt.read().unwrap(), 1);
let state = serial.state();
let mut serial_after_restore =
Serial::from_state(&state, intr_evt.try_clone().unwrap(), NoEvents, sink()).unwrap();
let ier = serial_after_restore.read(IER_OFFSET);
assert_eq!(ier & IER_UART_VALID_BITS, IER_RDA_BIT);
let iir = serial_after_restore.read(IIR_OFFSET);
assert_ne!(iir & IIR_RDA_BIT, 0);
assert_eq!(intr_evt.read().unwrap(), 1);
}
}