smbioslib/structs/types/
on_board_device_information.rs

1use crate::core::{strings::*, Header, UndefinedStruct};
2use crate::SMBiosStruct;
3use serde::{ser::SerializeSeq, ser::SerializeStruct, Serialize, Serializer};
4use std::fmt;
5
6/// # On Board Devices Information (Type 10, Obsolete)
7///
8///  The information in this structure defines the attributes of devices that are onboard
9/// (soldered onto) a system element, usually the baseboard. In general, an entry in this table implies that the
10/// BIOS has some level of control over the enabling of the associated device for use by the system.
11///
12/// NOTE This structure is obsolete starting with version 2.6 of this specification; the [super::SMBiosOnboardDevicesExtendedInformation]
13/// (Type 41) structure should be used instead. BIOS providers can choose to implement
14/// both types to allow existing SMBIOS browsers to properly display the system’s onboard devices information.
15///
16/// Compliant with:
17/// DMTF SMBIOS Reference Specification 3.5.0 (DSP0134)
18/// Document Date: 2021-09-15
19pub struct SMBiosOnBoardDeviceInformation<'a> {
20    parts: &'a UndefinedStruct,
21}
22
23impl<'a> SMBiosStruct<'a> for SMBiosOnBoardDeviceInformation<'a> {
24    const STRUCT_TYPE: u8 = 10u8;
25
26    fn new(parts: &'a UndefinedStruct) -> Self {
27        Self { parts }
28    }
29
30    fn parts(&self) -> &'a UndefinedStruct {
31        self.parts
32    }
33}
34
35impl<'a> SMBiosOnBoardDeviceInformation<'a> {
36    /// The number of [OnBoardDevice] entries
37    pub fn number_of_devices(&self) -> usize {
38        let struct_length = self.parts().header.length() as usize;
39
40        (struct_length - Header::SIZE) / OnBoardDevice::SIZE
41    }
42
43    /// Iterates over the [OnBoardDevice] entries
44    pub fn onboard_device_iterator(&'a self) -> OnBoardDeviceIterator<'a> {
45        OnBoardDeviceIterator::new(self)
46    }
47}
48
49impl fmt::Debug for SMBiosOnBoardDeviceInformation<'_> {
50    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
51        fmt.debug_struct(std::any::type_name::<SMBiosOnBoardDeviceInformation<'_>>())
52            .field("header", &self.parts.header)
53            .field("number_of_devices", &self.number_of_devices())
54            .field("onboard_device_iterator", &self.onboard_device_iterator())
55            .finish()
56    }
57}
58
59impl Serialize for SMBiosOnBoardDeviceInformation<'_> {
60    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
61    where
62        S: Serializer,
63    {
64        let mut state = serializer.serialize_struct("SMBiosOnBoardDeviceInformation", 3)?;
65        state.serialize_field("header", &self.parts.header)?;
66        state.serialize_field("number_of_devices", &self.number_of_devices())?;
67        state.serialize_field("onboard_device_iterator", &self.onboard_device_iterator())?;
68        state.end()
69    }
70}
71
72/// # On Board Device entry within [SMBiosOnBoardDeviceInformation]
73pub struct OnBoardDevice<'a> {
74    onboard_device_information: &'a SMBiosOnBoardDeviceInformation<'a>,
75    entry_offset: usize,
76}
77
78impl<'a> OnBoardDevice<'a> {
79    /// Size in bytes for this structure
80    ///
81    /// This structure is composed of:
82    /// _device_type_ (byte) at offset 0,
83    /// and _description_ (byte) at offset 1
84    /// for a total size of two bytes.
85    const SIZE: usize = 2;
86
87    fn new(
88        onboard_device_information: &'a SMBiosOnBoardDeviceInformation<'a>,
89        entry_offset: usize,
90    ) -> Self {
91        Self {
92            onboard_device_information,
93            entry_offset,
94        }
95    }
96
97    /// Device type
98    pub fn device_type(&self) -> Option<OnBoardDeviceType> {
99        self.onboard_device_information
100            .parts()
101            .get_field_byte(self.entry_offset)
102            .map(|raw| OnBoardDeviceType::from(raw))
103    }
104
105    /// Device description
106    pub fn description(&self) -> SMBiosString {
107        self.onboard_device_information
108            .parts()
109            .get_field_string(self.entry_offset + 1)
110    }
111}
112
113impl fmt::Debug for OnBoardDevice<'_> {
114    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
115        fmt.debug_struct(std::any::type_name::<OnBoardDevice<'_>>())
116            .field("device_type", &self.device_type())
117            .field("description", &self.description())
118            .finish()
119    }
120}
121
122impl Serialize for OnBoardDevice<'_> {
123    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
124    where
125        S: Serializer,
126    {
127        let mut state = serializer.serialize_struct("OnBoardDevice", 2)?;
128        state.serialize_field("device_type", &self.device_type())?;
129        state.serialize_field("description", &self.description())?;
130        state.end()
131    }
132}
133
134/// # On Board Device Type
135pub struct OnBoardDeviceType {
136    /// Raw value
137    pub raw: u8,
138}
139
140impl OnBoardDeviceType {
141    /// One of the onboard device types
142    pub fn type_of_device(&self) -> TypeOfDevice {
143        let result = self.raw & 0x7F;
144        match result {
145            0x01 => TypeOfDevice::Other,
146            0x02 => TypeOfDevice::Unknown,
147            0x03 => TypeOfDevice::Video,
148            0x04 => TypeOfDevice::ScsiController,
149            0x05 => TypeOfDevice::Ethernet,
150            0x06 => TypeOfDevice::TokenRing,
151            0x07 => TypeOfDevice::Sound,
152            0x08 => TypeOfDevice::PataController,
153            0x09 => TypeOfDevice::SataController,
154            0x0A => TypeOfDevice::SasController,
155            0x0B => TypeOfDevice::WirelessLan,
156            0x0C => TypeOfDevice::Bluetooth,
157            0x0D => TypeOfDevice::Wwan,
158            0x0E => TypeOfDevice::Emmc,
159            0x0F => TypeOfDevice::NvmeController,
160            0x10 => TypeOfDevice::UfsController,
161            _ => TypeOfDevice::None,
162        }
163    }
164
165    /// Enabled/disabled device status
166    pub fn status(&self) -> DeviceStatus {
167        if self.raw & 0x80 == 0x80 {
168            DeviceStatus::Enabled
169        } else {
170            DeviceStatus::Disabled
171        }
172    }
173}
174
175impl From<u8> for OnBoardDeviceType {
176    fn from(raw: u8) -> Self {
177        OnBoardDeviceType { raw }
178    }
179}
180
181impl fmt::Debug for OnBoardDeviceType {
182    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
183        fmt.debug_struct(std::any::type_name::<OnBoardDevice<'_>>())
184            .field("raw", &self.raw)
185            .field("type_of_device", &self.type_of_device())
186            .field("status", &self.status())
187            .finish()
188    }
189}
190
191impl Serialize for OnBoardDeviceType {
192    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
193    where
194        S: Serializer,
195    {
196        let mut state = serializer.serialize_struct("OnBoardDeviceType", 3)?;
197        state.serialize_field("raw", &self.raw)?;
198        state.serialize_field("type_of_device", &self.type_of_device())?;
199        state.serialize_field("status", &self.status())?;
200        state.end()
201    }
202}
203
204/// # Onboard Device Types
205#[derive(Serialize, Debug, PartialEq, Eq)]
206pub enum TypeOfDevice {
207    /// Other
208    Other,
209    /// Unknown
210    Unknown,
211    /// Video
212    Video,
213    /// SCSI Controller
214    ScsiController,
215    /// Ethernet
216    Ethernet,
217    /// Token Ring
218    TokenRing,
219    /// Sound
220    Sound,
221    /// PATA Controller
222    PataController,
223    /// SATA Controller
224    SataController,
225    /// SAS Controller
226    SasController,
227    /// Wireless LAN
228    WirelessLan,
229    /// Bluetooth
230    Bluetooth,
231    /// WWAN
232    Wwan,
233    /// eMMC (embedded Milti-Media Controller)
234    Emmc,
235    /// NVMe Controller
236    NvmeController,
237    /// UFS Controller
238    UfsController,
239    /// A value unknown to this standard, check the raw value
240    None,
241}
242
243/// # Enabled/Disabled Device Status
244#[derive(Serialize, Debug, PartialEq, Eq)]
245pub enum DeviceStatus {
246    /// Device is enabled
247    Enabled,
248    /// Device is disabled
249    Disabled,
250}
251
252/// # On-board Device Itereator for [OnBoardDevice]s contained within [SMBiosOnBoardDeviceInformation]
253pub struct OnBoardDeviceIterator<'a> {
254    data: &'a SMBiosOnBoardDeviceInformation<'a>,
255    current_index: usize,
256    current_entry: usize,
257    number_of_entries: usize,
258}
259
260impl<'a> OnBoardDeviceIterator<'a> {
261    const DEVICES_OFFSET: usize = 4usize;
262
263    fn new(data: &'a SMBiosOnBoardDeviceInformation<'a>) -> Self {
264        OnBoardDeviceIterator {
265            data: data,
266            current_index: Self::DEVICES_OFFSET,
267            current_entry: 0,
268            number_of_entries: data.number_of_devices(),
269        }
270    }
271
272    fn reset(&mut self) {
273        self.current_index = Self::DEVICES_OFFSET;
274        self.current_entry = 0;
275    }
276}
277
278impl<'a> IntoIterator for &'a OnBoardDeviceIterator<'a> {
279    type Item = OnBoardDevice<'a>;
280    type IntoIter = OnBoardDeviceIterator<'a>;
281
282    fn into_iter(self) -> Self::IntoIter {
283        OnBoardDeviceIterator {
284            data: self.data,
285            current_index: OnBoardDeviceIterator::DEVICES_OFFSET,
286            current_entry: 0,
287            number_of_entries: self.data.number_of_devices(),
288        }
289    }
290}
291
292impl<'a> Iterator for OnBoardDeviceIterator<'a> {
293    type Item = OnBoardDevice<'a>;
294
295    fn next(&mut self) -> Option<Self::Item> {
296        if self.current_entry == self.number_of_entries {
297            self.reset();
298            return None;
299        }
300
301        let next_index = self.current_index + OnBoardDevice::SIZE;
302        match self
303            .data
304            .parts()
305            .get_field_data(self.current_index, next_index)
306        {
307            Some(_) => {
308                let result = OnBoardDevice::new(self.data, self.current_index);
309                self.current_index = next_index;
310                self.current_entry = self.current_entry + 1;
311                Some(result)
312            }
313            None => {
314                self.reset();
315                None
316            }
317        }
318    }
319}
320
321impl<'a> fmt::Debug for OnBoardDeviceIterator<'a> {
322    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
323        fmt.debug_list().entries(self.into_iter()).finish()
324    }
325}
326
327impl<'a> Serialize for OnBoardDeviceIterator<'a> {
328    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
329    where
330        S: Serializer,
331    {
332        let devices: Vec<OnBoardDevice<'_>> = self.into_iter().collect();
333        let mut seq = serializer.serialize_seq(Some(devices.len()))?;
334        for e in devices {
335            seq.serialize_element(&e)?;
336        }
337        seq.end()
338    }
339}
340
341#[cfg(test)]
342mod tests {
343    use super::*;
344
345    #[test]
346    fn unit_test() {
347        let struct_type10 = vec![
348            0x0A, 0x06, 0x21, 0x00, 0x83, 0x01, 0x20, 0x20, 0x20, 0x54, 0x6F, 0x20, 0x42, 0x65,
349            0x20, 0x46, 0x69, 0x6C, 0x6C, 0x65, 0x64, 0x20, 0x42, 0x79, 0x20, 0x4F, 0x2E, 0x45,
350            0x2E, 0x4D, 0x2E, 0x00, 0x00,
351        ];
352
353        let parts = UndefinedStruct::new(&struct_type10);
354        let test_struct = SMBiosOnBoardDeviceInformation::new(&parts);
355
356        println!("{:?}", test_struct);
357
358        assert_eq!(test_struct.number_of_devices(), 1);
359
360        let mut iterator = test_struct.onboard_device_iterator().into_iter();
361
362        let item = iterator.next().unwrap();
363
364        assert_eq!(
365            item.description().to_string(),
366            "   To Be Filled By O.E.M.".to_string()
367        );
368
369        let device_type = item.device_type().unwrap();
370        assert_eq!(device_type.type_of_device(), TypeOfDevice::Video);
371        assert_eq!(device_type.status(), DeviceStatus::Enabled);
372
373        assert!(iterator.next().is_none());
374    }
375}