1 | //! Abstraction over byte stream devices, also known as serial I/O devices. |
2 | |
3 | use core::fmt::Write; |
4 | |
5 | use crate::proto::unsafe_protocol ; |
6 | use crate::{Result, Status}; |
7 | use bitflags::bitflags; |
8 | |
9 | /// Provides access to a serial I/O device. |
10 | /// |
11 | /// This can include standard UART devices, serial ports over a USB interface, |
12 | /// or any other character-based communication device. |
13 | /// |
14 | /// Since UEFI drivers are implemented through polling, if you fail to regularly |
15 | /// check for input/output, some data might be lost. |
16 | #[repr (C)] |
17 | #[unsafe_protocol ("bb25cf6f-f1d4-11d2-9a0c-0090273fc1fd" )] |
18 | pub struct Serial { |
19 | // Revision of this protocol, only 1.0 is currently defined. |
20 | // Future versions will be backwards compatible. |
21 | revision: u32, |
22 | reset: extern "efiapi" fn(&mut Serial) -> Status, |
23 | set_attributes: extern "efiapi" fn( |
24 | &Serial, |
25 | baud_rate: u64, |
26 | receive_fifo_depth: u32, |
27 | timeout: u32, |
28 | parity: Parity, |
29 | data_bits: u8, |
30 | stop_bits_type: StopBits, |
31 | ) -> Status, |
32 | set_control_bits: extern "efiapi" fn(&mut Serial, ControlBits) -> Status, |
33 | get_control_bits: extern "efiapi" fn(&Serial, &mut ControlBits) -> Status, |
34 | write: unsafe extern "efiapi" fn(&mut Serial, &mut usize, *const u8) -> Status, |
35 | read: unsafe extern "efiapi" fn(&mut Serial, &mut usize, *mut u8) -> Status, |
36 | io_mode: *const IoMode, |
37 | } |
38 | |
39 | impl Serial { |
40 | /// Reset the device. |
41 | pub fn reset(&mut self) -> Result { |
42 | (self.reset)(self).into() |
43 | } |
44 | |
45 | /// Returns the current I/O mode. |
46 | #[must_use ] |
47 | pub const fn io_mode(&self) -> &IoMode { |
48 | unsafe { &*self.io_mode } |
49 | } |
50 | |
51 | /// Sets the device's new attributes. |
52 | /// |
53 | /// The given `IoMode` will become the device's new `IoMode`, |
54 | /// with some exceptions: |
55 | /// |
56 | /// - `control_mask` is ignored, since it's a read-only field; |
57 | /// |
58 | /// - values set to `0` / `Default` will be filled with the device's |
59 | /// default parameters |
60 | /// |
61 | /// - if either `baud_rate` or `receive_fifo_depth` is less than |
62 | /// the device's minimum, an error will be returned; |
63 | /// this value will be rounded down to the nearest value supported by the device; |
64 | pub fn set_attributes(&mut self, mode: &IoMode) -> Result { |
65 | (self.set_attributes)( |
66 | self, |
67 | mode.baud_rate, |
68 | mode.receive_fifo_depth, |
69 | mode.timeout, |
70 | mode.parity, |
71 | mode.data_bits as u8, |
72 | mode.stop_bits, |
73 | ) |
74 | .into() |
75 | } |
76 | |
77 | /// Retrieve the device's current control bits. |
78 | pub fn get_control_bits(&self) -> Result<ControlBits> { |
79 | let mut bits = ControlBits::empty(); |
80 | (self.get_control_bits)(self, &mut bits).into_with_val(|| bits) |
81 | } |
82 | |
83 | /// Sets the device's new control bits. |
84 | /// |
85 | /// Not all bits can be modified with this function. A mask of the allowed |
86 | /// bits is stored in the [`ControlBits::SETTABLE`] constant. |
87 | pub fn set_control_bits(&mut self, bits: ControlBits) -> Result { |
88 | (self.set_control_bits)(self, bits).into() |
89 | } |
90 | |
91 | /// Reads data from this device. |
92 | /// |
93 | /// This operation will block until the buffer has been filled with data or |
94 | /// an error occurs. In the latter case, the error will indicate how many |
95 | /// bytes were actually read from the device. |
96 | pub fn read(&mut self, data: &mut [u8]) -> Result<(), usize> { |
97 | let mut buffer_size = data.len(); |
98 | unsafe { (self.read)(self, &mut buffer_size, data.as_mut_ptr()) }.into_with( |
99 | || debug_assert_eq!(buffer_size, data.len()), |
100 | |_| buffer_size, |
101 | ) |
102 | } |
103 | |
104 | /// Writes data to this device. |
105 | /// |
106 | /// This operation will block until the data has been fully written or an |
107 | /// error occurs. In the latter case, the error will indicate how many bytes |
108 | /// were actually written to the device. |
109 | pub fn write(&mut self, data: &[u8]) -> Result<(), usize> { |
110 | let mut buffer_size = data.len(); |
111 | unsafe { (self.write)(self, &mut buffer_size, data.as_ptr()) }.into_with( |
112 | || debug_assert_eq!(buffer_size, data.len()), |
113 | |_| buffer_size, |
114 | ) |
115 | } |
116 | } |
117 | |
118 | impl Write for Serial { |
119 | fn write_str(&mut self, s: &str) -> core::fmt::Result { |
120 | self.write(s.as_bytes()).map_err(|_| core::fmt::Error) |
121 | } |
122 | } |
123 | |
124 | /// Structure representing the device's current parameters. |
125 | /// |
126 | /// The default values for all UART-like devices is: |
127 | /// - 115,200 baud |
128 | /// - 1 byte receive FIFO |
129 | /// - 1'000'000 microsecond timeout |
130 | /// - no parity |
131 | /// - 8 data bits |
132 | /// - 1 stop bit |
133 | /// |
134 | /// The software is responsible for flow control. |
135 | #[derive (Debug, Copy, Clone)] |
136 | #[repr (C)] |
137 | pub struct IoMode { |
138 | /// Bitmask of the control bits that this device supports. |
139 | pub control_mask: ControlBits, |
140 | /// If applicable, the number of microseconds to wait before assuming an |
141 | /// operation timed out. |
142 | pub timeout: u32, |
143 | /// Device's baud rate, or 0 if unknown. |
144 | pub baud_rate: u64, |
145 | /// Size in character's of the device's buffer. |
146 | pub receive_fifo_depth: u32, |
147 | /// Number of data bits in each character. |
148 | pub data_bits: u32, |
149 | /// If applicable, the parity that is computed or checked for each character. |
150 | pub parity: Parity, |
151 | /// If applicable, the number of stop bits per character. |
152 | pub stop_bits: StopBits, |
153 | } |
154 | |
155 | bitflags! { |
156 | /// The control bits of a device. These are defined in the [RS-232] standard. |
157 | /// |
158 | /// [RS-232]: https://en.wikipedia.org/wiki/RS-232 |
159 | pub struct ControlBits: u32 { |
160 | /// Clear to send |
161 | const CLEAR_TO_SEND = 0x10; |
162 | /// Data set ready |
163 | const DATA_SET_READY = 0x20; |
164 | /// Indicates that a phone line is ringing |
165 | const RING_INDICATE = 0x40; |
166 | /// Indicates the connection is still connected |
167 | const CARRIER_DETECT = 0x80; |
168 | /// The input buffer is empty |
169 | const INPUT_BUFFER_EMPTY = 0x100; |
170 | /// The output buffer is empty |
171 | const OUTPUT_BUFFER_EMPTY = 0x200; |
172 | |
173 | /// Terminal is ready for communications |
174 | const DATA_TERMINAL_READY = 0x1; |
175 | /// Request the device to send data |
176 | const REQUEST_TO_SEND = 0x2; |
177 | /// Enable hardware loop-back |
178 | const HARDWARE_LOOPBACK_ENABLE = 0x1000; |
179 | /// Enable software loop-back |
180 | const SOFTWARE_LOOPBACK_ENABLE = 0x2000; |
181 | /// Allow the hardware to handle flow control |
182 | const HARDWARE_FLOW_CONTROL_ENABLE = 0x4000; |
183 | |
184 | /// Bitmask of the control bits that can be set. |
185 | /// |
186 | /// Up to date as of UEFI 2.7 / Serial protocol v1 |
187 | const SETTABLE = |
188 | ControlBits::DATA_TERMINAL_READY.bits |
189 | | ControlBits::REQUEST_TO_SEND.bits |
190 | | ControlBits::HARDWARE_LOOPBACK_ENABLE.bits |
191 | | ControlBits::SOFTWARE_LOOPBACK_ENABLE.bits |
192 | | ControlBits::HARDWARE_FLOW_CONTROL_ENABLE.bits; |
193 | } |
194 | } |
195 | |
196 | /// The parity of the device. |
197 | #[derive (Debug, Copy, Clone, Eq, PartialEq)] |
198 | #[repr (u32)] |
199 | pub enum Parity { |
200 | /// Device default |
201 | Default = 0, |
202 | /// No parity |
203 | None, |
204 | /// Even parity |
205 | Even, |
206 | /// Odd parity |
207 | Odd, |
208 | /// Mark parity |
209 | Mark, |
210 | /// Space parity |
211 | Space, |
212 | // SAFETY: The serial protocol is very old, and new parity modes are very |
213 | // unlikely to be added at this point in time. Therefore, modeling |
214 | // this C enum as a Rust enum seems safe. |
215 | } |
216 | |
217 | /// Number of stop bits per character. |
218 | #[derive (Debug, Copy, Clone, Eq, PartialEq)] |
219 | #[repr (u32)] |
220 | pub enum StopBits { |
221 | /// Device default |
222 | Default = 0, |
223 | /// 1 stop bit |
224 | One, |
225 | /// 1.5 stop bits |
226 | OneFive, |
227 | /// 2 stop bits |
228 | Two, |
229 | // SAFETY: The serial protocol is very old, and new stop bit modes are very |
230 | // unlikely to be added at this point in time. Therefore, modeling |
231 | // this C enum as a Rust enum seems safe. |
232 | } |
233 | |