Struct vm_superio::serial::Serial
source · pub struct Serial<T: Trigger, EV: SerialEvents, W: Write> { /* private fields */ }
Expand description
The serial console emulation is done by emulating a serial COM port.
Each serial COM port (COM1-4) has an associated Port I/O address base and
12 registers mapped into 8 consecutive Port I/O locations (with the first
one being the base).
This structure emulates the registers that make sense for UART 16550 (and below)
and helps in the interaction between the driver and device by using a
Trigger
object for notifications. It also writes the
guest’s output to an out
Write object.
§Example
struct EventFdTrigger(EventFd);
impl Trigger for EventFdTrigger {
type E = Error;
fn trigger(&self) -> Result<()> {
self.write(1)
}
}
impl Deref for EventFdTrigger {
type Target = EventFd;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl EventFdTrigger {
pub fn new(flag: i32) -> Self {
EventFdTrigger(EventFd::new(flag).unwrap())
}
pub fn try_clone(&self) -> Self {
EventFdTrigger((**self).try_clone().unwrap())
}
}
let intr_evt = EventFdTrigger::new(libc::EFD_NONBLOCK);
let mut serial = Serial::new(intr_evt.try_clone(), Vec::new());
// std::io::Sink can be used if user is not interested in guest's output.
let serial_with_sink = Serial::new(intr_evt, sink());
// Write 0x01 to THR register.
serial.write(0, 0x01).unwrap();
// Read from RBR register.
let value = serial.read(0);
// Send more bytes to the guest in one shot.
let input = &[b'a', b'b', b'c'];
// Before enqueuing bytes we first check if there is enough free space
// in the FIFO.
if serial.fifo_capacity() >= input.len() {
serial.enqueue_raw_bytes(input).unwrap();
}
Implementations§
source§impl<T: Trigger, W: Write> Serial<T, NoEvents, W>
impl<T: Trigger, W: Write> Serial<T, NoEvents, W>
sourcepub fn new(trigger: T, out: W) -> Serial<T, NoEvents, W>
pub fn new(trigger: T, out: W) -> Serial<T, NoEvents, W>
Creates a new Serial
instance which writes the guest’s output to
out
and uses trigger
object to notify the driver about new
events.
§Arguments
trigger
- The Trigger object that will be used to notify the driver about events.out
- An object for writing guest’s output to. In case the output is not of interest, std::io::Sink can be used here.
§Example
You can see an example of how to use this function in the
Example
section from Serial
.
source§impl<T: Trigger, EV: SerialEvents, W: Write> Serial<T, EV, W>
impl<T: Trigger, EV: SerialEvents, W: Write> Serial<T, EV, W>
sourcepub fn from_state(
state: &SerialState,
trigger: T,
serial_evts: EV,
out: W
) -> Result<Self, Error<T::E>>
pub fn from_state( state: &SerialState, trigger: T, serial_evts: EV, out: W ) -> Result<Self, Error<T::E>>
Creates a new Serial
instance from a given state
, which writes the guest’s output to
out
, uses trigger
object to notify the driver about new
events, and invokes the serial_evts
implementation of SerialEvents
during operation.
For creating the instance from a default state, with_events
method
can be used.
§Arguments
state
- A reference to the state from which theSerial
is constructed.trigger
- TheTrigger
object that will be used to notify the driver about events.serial_evts
- TheSerialEvents
implementation used to track the occurrence of significant events in the serial operation logic.out
- An object for writing guest’s output to. In case the output is not of interest, std::io::Sink can be used here.
sourcepub fn with_events(trigger: T, serial_evts: EV, out: W) -> Self
pub fn with_events(trigger: T, serial_evts: EV, out: W) -> Self
Creates a new Serial
instance from the default state, which writes the guest’s output to
out
, uses trigger
object to notify the driver about new
events, and invokes the serial_evts
implementation of SerialEvents
during operation.
§Arguments
trigger
- TheTrigger
object that will be used to notify the driver about events.serial_evts
- TheSerialEvents
implementation used to track the occurrence of significant events in the serial operation logic.out
- An object for writing guest’s output to. In case the output is not of interest, std::io::Sink can be used here.
sourcepub fn state(&self) -> SerialState
pub fn state(&self) -> SerialState
Returns the state of the Serial.
sourcepub fn writer(&self) -> &W
pub fn writer(&self) -> &W
Gets a reference to the output Write object
const DATA_OFFSET: u8 = 0;
let output = Vec::new();
let mut serial = Serial::new(DummyTrigger, output);
serial.write(DATA_OFFSET, 0x66).unwrap();
assert_eq!(serial.writer().first().copied(), Some(0x66));
sourcepub fn writer_mut(&mut self) -> &mut W
pub fn writer_mut(&mut self) -> &mut W
Gets a mutable reference to the output Write object
const DATA_OFFSET: u8 = 0;
let output = Vec::new();
let mut serial = Serial::new(DummyTrigger, output);
serial.write(DATA_OFFSET, 0x66).unwrap();
serial.writer_mut().clear();
assert_eq!(serial.writer().first(), None);
sourcepub fn into_writer(self) -> W
pub fn into_writer(self) -> W
Consumes the device and retrieves the inner writer. This can be useful when restoring a copy of the device.
const DATA_OFFSET: u8 = 0;
// Create a device with some state
let output = Vec::new();
let mut serial = Serial::new(DummyTrigger, output);
serial.write(DATA_OFFSET, 0x66).unwrap();
// Save the state
let state = serial.state();
let output = serial.into_writer();
// Restore the device
let restored_serial = Serial::from_state(&state, DummyTrigger, NoEvents, output).unwrap();
assert_eq!(restored_serial.writer().first().copied(), Some(0x66));
sourcepub fn interrupt_evt(&self) -> &T
pub fn interrupt_evt(&self) -> &T
Provides a reference to the interrupt event object.
sourcepub fn write(&mut self, offset: u8, value: u8) -> Result<(), Error<T::E>>
pub fn write(&mut self, offset: u8, value: u8) -> Result<(), Error<T::E>>
Handles a write request from the driver at offset
offset from the
base Port I/O address.
§Arguments
offset
- The offset that will be added to the base PIO address for writing to a specific register.value
- The byte that should be written.
§Example
You can see an example of how to use this function in the
Example
section from Serial
.
sourcepub fn read(&mut self, offset: u8) -> u8
pub fn read(&mut self, offset: u8) -> u8
Handles a read request from the driver at offset
offset from the
base Port I/O address.
Returns the read value.
§Arguments
offset
- The offset that will be added to the base PIO address for reading from a specific register.
§Example
You can see an example of how to use this function in the
Example
section from Serial
.
sourcepub fn fifo_capacity(&self) -> usize
pub fn fifo_capacity(&self) -> usize
Returns how much space is still available in the FIFO.
§Example
You can see an example of how to use this function in the
Example
section from Serial
.
sourcepub fn enqueue_raw_bytes(&mut self, input: &[u8]) -> Result<usize, Error<T::E>>
pub fn enqueue_raw_bytes(&mut self, input: &[u8]) -> Result<usize, Error<T::E>>
Helps in sending more bytes to the guest in one shot, by storing
input
bytes in UART buffer and letting the driver know there is
some pending data to be read by setting RDA bit and its corresponding
interrupt when not already triggered.
§Arguments
input
- The data to be sent to the guest.
§Returns
The function returns the number of bytes it was able to write to the fifo,
or FullFifo
error when the fifo is full. Users can use
fifo_capacity
before calling this function
to check the available space.
§Example
You can see an example of how to use this function in the
Example
section from Serial
.