blob: de52944de0ae2d5eb8feea09f468ea3321adda73 [file] [log] [blame]
//! Abstraction over byte stream devices, also known as serial I/O devices.
use crate::proto::unsafe_protocol;
use crate::{Result, StatusExt};
use core::fmt::Write;
use uefi_raw::protocol::console::serial::SerialIoProtocol;
pub use uefi_raw::protocol::console::serial::{
ControlBits, Parity, SerialIoMode as IoMode, StopBits,
};
/// Provides access to a serial I/O device.
///
/// This can include standard UART devices, serial ports over a USB interface,
/// or any other character-based communication device.
///
/// Since UEFI drivers are implemented through polling, if you fail to regularly
/// check for input/output, some data might be lost.
#[derive(Debug)]
#[repr(transparent)]
#[unsafe_protocol(SerialIoProtocol::GUID)]
pub struct Serial(SerialIoProtocol);
impl Serial {
/// Reset the device.
pub fn reset(&mut self) -> Result {
unsafe { (self.0.reset)(&mut self.0) }.to_result()
}
/// Returns the current I/O mode.
#[must_use]
pub const fn io_mode(&self) -> &IoMode {
unsafe { &*self.0.mode }
}
/// Sets the device's new attributes.
///
/// The given `IoMode` will become the device's new `IoMode`,
/// with some exceptions:
///
/// - `control_mask` is ignored, since it's a read-only field;
///
/// - values set to `0` / `Default` will be filled with the device's
/// default parameters
///
/// - if either `baud_rate` or `receive_fifo_depth` is less than
/// the device's minimum, an error will be returned;
/// this value will be rounded down to the nearest value supported by the device;
pub fn set_attributes(&mut self, mode: &IoMode) -> Result {
unsafe {
(self.0.set_attributes)(
&mut self.0,
mode.baud_rate,
mode.receive_fifo_depth,
mode.timeout,
mode.parity,
mode.data_bits as u8,
mode.stop_bits,
)
}
.to_result()
}
/// Retrieve the device's current control bits.
pub fn get_control_bits(&self) -> Result<ControlBits> {
let mut bits = ControlBits::empty();
unsafe { (self.0.get_control_bits)(&self.0, &mut bits) }.to_result_with_val(|| bits)
}
/// Sets the device's new control bits.
///
/// Not all bits can be modified with this function. A mask of the allowed
/// bits is stored in the [`ControlBits::SETTABLE`] constant.
pub fn set_control_bits(&mut self, bits: ControlBits) -> Result {
unsafe { (self.0.set_control_bits)(&mut self.0, bits) }.to_result()
}
/// Reads data from this device.
///
/// This operation will block until the buffer has been filled with data or
/// an error occurs. In the latter case, the error will indicate how many
/// bytes were actually read from the device.
pub fn read(&mut self, data: &mut [u8]) -> Result<(), usize> {
let mut buffer_size = data.len();
unsafe { (self.0.read)(&mut self.0, &mut buffer_size, data.as_mut_ptr()) }.to_result_with(
|| debug_assert_eq!(buffer_size, data.len()),
|_| buffer_size,
)
}
/// Writes data to this device.
///
/// This operation will block until the data has been fully written or an
/// error occurs. In the latter case, the error will indicate how many bytes
/// were actually written to the device.
pub fn write(&mut self, data: &[u8]) -> Result<(), usize> {
let mut buffer_size = data.len();
unsafe { (self.0.write)(&mut self.0, &mut buffer_size, data.as_ptr()) }.to_result_with(
|| debug_assert_eq!(buffer_size, data.len()),
|_| buffer_size,
)
}
}
impl Write for Serial {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
self.write(s.as_bytes()).map_err(|_| core::fmt::Error)
}
}