//! 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 { 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) } }