uefi/proto/console/
serial.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! Abstraction over byte stream devices, also known as serial I/O devices.
4
5use crate::proto::unsafe_protocol;
6use crate::{Result, StatusExt};
7use core::fmt::Write;
8use uefi_raw::protocol::console::serial::SerialIoProtocol;
9
10pub use uefi_raw::protocol::console::serial::{
11    ControlBits, Parity, SerialIoMode as IoMode, StopBits,
12};
13
14/// Provides access to a serial I/O device.
15///
16/// This can include standard UART devices, serial ports over a USB interface,
17/// or any other character-based communication device.
18///
19/// Since UEFI drivers are implemented through polling, if you fail to regularly
20/// check for input/output, some data might be lost.
21#[derive(Debug)]
22#[repr(transparent)]
23#[unsafe_protocol(SerialIoProtocol::GUID)]
24pub struct Serial(SerialIoProtocol);
25
26impl Serial {
27    /// Reset the device.
28    pub fn reset(&mut self) -> Result {
29        unsafe { (self.0.reset)(&mut self.0) }.to_result()
30    }
31
32    /// Returns the current I/O mode.
33    #[must_use]
34    pub const fn io_mode(&self) -> &IoMode {
35        unsafe { &*self.0.mode }
36    }
37
38    /// Sets the device's new attributes.
39    ///
40    /// The given `IoMode` will become the device's new `IoMode`,
41    /// with some exceptions:
42    ///
43    /// - `control_mask` is ignored, since it's a read-only field;
44    ///
45    /// - values set to `0` / `Default` will be filled with the device's
46    ///   default parameters
47    ///
48    /// - if either `baud_rate` or `receive_fifo_depth` is less than
49    ///   the device's minimum, an error will be returned;
50    ///   this value will be rounded down to the nearest value supported by the device;
51    pub fn set_attributes(&mut self, mode: &IoMode) -> Result {
52        unsafe {
53            (self.0.set_attributes)(
54                &mut self.0,
55                mode.baud_rate,
56                mode.receive_fifo_depth,
57                mode.timeout,
58                mode.parity,
59                mode.data_bits as u8,
60                mode.stop_bits,
61            )
62        }
63        .to_result()
64    }
65
66    /// Retrieve the device's current control bits.
67    pub fn get_control_bits(&self) -> Result<ControlBits> {
68        let mut bits = ControlBits::empty();
69        unsafe { (self.0.get_control_bits)(&self.0, &mut bits) }.to_result_with_val(|| bits)
70    }
71
72    /// Sets the device's new control bits.
73    ///
74    /// Not all bits can be modified with this function. A mask of the allowed
75    /// bits is stored in the [`ControlBits::SETTABLE`] constant.
76    pub fn set_control_bits(&mut self, bits: ControlBits) -> Result {
77        unsafe { (self.0.set_control_bits)(&mut self.0, bits) }.to_result()
78    }
79
80    /// Reads data from this device.
81    ///
82    /// This operation will block until the buffer has been filled with data or
83    /// an error occurs. In the latter case, the error will indicate how many
84    /// bytes were actually read from the device.
85    pub fn read(&mut self, data: &mut [u8]) -> Result<(), usize> {
86        let mut buffer_size = data.len();
87        unsafe { (self.0.read)(&mut self.0, &mut buffer_size, data.as_mut_ptr()) }.to_result_with(
88            || debug_assert_eq!(buffer_size, data.len()),
89            |_| buffer_size,
90        )
91    }
92
93    /// Writes data to this device.
94    ///
95    /// This operation will block until the data has been fully written or an
96    /// error occurs. In the latter case, the error will indicate how many bytes
97    /// were actually written to the device.
98    pub fn write(&mut self, data: &[u8]) -> Result<(), usize> {
99        let mut buffer_size = data.len();
100        unsafe { (self.0.write)(&mut self.0, &mut buffer_size, data.as_ptr()) }.to_result_with(
101            || debug_assert_eq!(buffer_size, data.len()),
102            |_| buffer_size,
103        )
104    }
105}
106
107impl Write for Serial {
108    fn write_str(&mut self, s: &str) -> core::fmt::Result {
109        self.write(s.as_bytes()).map_err(|_| core::fmt::Error)
110    }
111}