1use crate::{
2 address::{GenericAddress, RawGenericAddress},
3 AcpiResult,
4 AcpiTable,
5 SdtHeader,
6 Signature,
7};
8use core::{
9 num::{NonZeroU32, NonZeroU8},
10 ptr,
11 slice,
12 str::{self, Utf8Error},
13};
14
15#[repr(C, packed)]
24#[derive(Debug)]
25pub struct Spcr {
26 pub header: SdtHeader,
27 interface_type: u8,
28 _reserved: [u8; 3],
29 base_address: RawGenericAddress,
30 interrupt_type: u8,
31 irq: u8,
32 global_system_interrupt: u32,
33 configured_baud_rate: u8,
35 pub parity: u8,
36 pub stop_bits: u8,
37 flow_control: u8,
38 terminal_type: u8,
39 pub language: u8,
41 pci_device_id: u16,
42 pci_vendor_id: u16,
43 pci_bus_number: u8,
44 pci_device_number: u8,
45 pci_function_number: u8,
46 pub pci_flags: u32,
47 pub pci_segment: u8,
50 uart_clock_freq: u32,
51 precise_baud_rate: u32,
52 namespace_string_length: u16,
53 namespace_string_offset: u16,
54}
55
56unsafe impl AcpiTable for Spcr {
57 const SIGNATURE: Signature = Signature::SPCR;
58
59 fn header(&self) -> &SdtHeader {
60 &self.header
61 }
62}
63
64impl Spcr {
65 pub fn interface_type(&self) -> SpcrInterfaceType {
67 SpcrInterfaceType::from(self.interface_type)
68 }
69
70 pub fn base_address(&self) -> Option<AcpiResult<GenericAddress>> {
73 (!self.base_address.is_empty()).then(|| GenericAddress::from_raw(self.base_address))
74 }
75
76 fn configured_baud_rate(&self) -> Option<NonZeroU32> {
77 match self.configured_baud_rate {
78 3 => unsafe { Some(NonZeroU32::new_unchecked(9600)) },
79 4 => unsafe { Some(NonZeroU32::new_unchecked(19200)) },
80 6 => unsafe { Some(NonZeroU32::new_unchecked(57600)) },
81 7 => unsafe { Some(NonZeroU32::new_unchecked(115200)) },
82 _ => None,
83 }
84 }
85
86 pub fn baud_rate(&self) -> Option<NonZeroU32> {
88 NonZeroU32::new(self.precise_baud_rate).or_else(|| self.configured_baud_rate())
89 }
90
91 pub fn flow_control(&self) -> SpcrFlowControl {
93 SpcrFlowControl::from_bits_truncate(self.flow_control)
94 }
95
96 pub fn interrupt_type(&self) -> SpcrInterruptType {
98 SpcrInterruptType::from_bits_truncate(self.interrupt_type)
99 }
100
101 pub fn irq(&self) -> Option<u8> {
104 self.interrupt_type().contains(SpcrInterruptType::DUAL_8259).then_some(self.irq)
105 }
106
107 pub fn global_system_interrupt(&self) -> Option<u32> {
111 if self.interrupt_type().difference(SpcrInterruptType::DUAL_8259).is_empty() {
112 return None;
113 }
114 Some(self.global_system_interrupt)
115 }
116
117 pub fn terminal_type(&self) -> SpcrTerminalType {
119 SpcrTerminalType::from_bits_truncate(self.terminal_type)
120 }
121
122 pub fn pci_device_id(&self) -> Option<u16> {
124 (self.pci_device_id != 0xffff).then_some(self.pci_device_id)
125 }
126
127 pub fn pci_vendor_id(&self) -> Option<u16> {
129 (self.pci_vendor_id != 0xffff).then_some(self.pci_vendor_id)
130 }
131
132 pub fn pci_bus_number(&self) -> Option<NonZeroU8> {
134 NonZeroU8::new(self.pci_bus_number)
135 }
136
137 pub fn pci_device_number(&self) -> Option<NonZeroU8> {
139 NonZeroU8::new(self.pci_device_number)
140 }
141
142 pub fn pci_function_number(&self) -> Option<NonZeroU8> {
144 NonZeroU8::new(self.pci_function_number)
145 }
146
147 pub const fn uart_clock_frequency(&self) -> Option<NonZeroU32> {
149 if self.header.revision <= 2 {
150 return None;
151 }
152 NonZeroU32::new(self.uart_clock_freq)
153 }
154
155 pub fn namespace_string(&self) -> Result<&str, Utf8Error> {
160 let start = ptr::from_ref(self).cast::<u8>();
161 let bytes = unsafe {
162 let str_start = start.add(self.namespace_string_offset as usize);
163 slice::from_raw_parts(str_start, self.namespace_string_length as usize)
164 };
165 str::from_utf8(bytes)
166 }
167}
168
169bitflags::bitflags! {
170 #[derive(Clone, Copy, Debug)]
172 pub struct SpcrInterruptType: u8 {
173 const DUAL_8259 = 1 << 0;
175 const IO_APIC = 1 << 1;
177 const IO_SAPIC = 1 << 2;
179 const ARMH_GIC = 1 << 3;
181 const RISCV_PLIC = 1 << 4;
183 }
184}
185
186bitflags::bitflags! {
187 #[derive(Clone, Copy, Debug)]
189 pub struct SpcrTerminalType: u8 {
190 const VT1000 = 1 << 0;
191 const EXTENDED_VT1000 = 1 << 1;
192 const VT_UTF8 = 1 << 2;
193 const ANSI = 1 << 3;
194 }
195}
196
197bitflags::bitflags! {
198 #[derive(Clone, Copy, Debug)]
200 pub struct SpcrFlowControl: u8 {
201 const DCD = 1 << 0;
203 const RTS_CTS = 1 << 1;
205 const XON_XOFF = 1 << 2;
207 }
208}
209
210#[repr(u8)]
211#[derive(Clone, Copy, Debug)]
212pub enum SpcrInterfaceType {
213 Full16550,
215 Full16450,
217 MAX311xE,
219 ArmPL011,
221 MSM8x60,
223 Nvidia16550,
225 TiOmap,
227 APM88xxxx,
229 Msm8974,
231 Sam5250,
233 IntelUSIF,
235 Imx6,
237 ArmSBSAGeneric32bit,
239 ArmSBSAGeneric,
241 ArmDCC,
243 Bcm2835,
245 Sdm845_18432,
247 Generic16550,
249 Sdm845_7372,
251 IntelLPSS,
253 RiscVSbi,
255 Unknown(u8),
257}
258
259impl From<u8> for SpcrInterfaceType {
260 fn from(val: u8) -> Self {
261 match val {
262 0x00 => Self::Full16550,
263 0x01 => Self::Full16450,
264 0x02 => Self::MAX311xE,
265 0x03 => Self::ArmPL011,
266 0x04 => Self::MSM8x60,
267 0x05 => Self::Nvidia16550,
268 0x06 => Self::TiOmap,
269 0x08 => Self::APM88xxxx,
270 0x09 => Self::Msm8974,
271 0x0A => Self::Sam5250,
272 0x0B => Self::IntelUSIF,
273 0x0C => Self::Imx6,
274 0x0D => Self::ArmSBSAGeneric32bit,
275 0x0E => Self::ArmSBSAGeneric,
276 0x0F => Self::ArmDCC,
277 0x10 => Self::Bcm2835,
278 0x11 => Self::Sdm845_18432,
279 0x12 => Self::Generic16550,
280 0x13 => Self::Sdm845_7372,
281 0x14 => Self::IntelLPSS,
282 0x15 => Self::RiscVSbi,
283 _ => Self::Unknown(val),
284 }
285 }
286}