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}