smbioslib/structs/types/
onboard_devices_extended_information.rs

1use super::system_slot::{BusNumber, DeviceFunctionNumber, SegmentGroupNumber};
2use crate::core::{strings::*, UndefinedStruct};
3use crate::{OnBoardDeviceType, SMBiosStruct};
4use serde::{ser::SerializeStruct, Serialize, Serializer};
5use std::fmt;
6
7/// # Onboard Devices Extended Information (Type 41)
8///
9/// The information in this structure defines the attributes of devices that are onboard (soldered onto) a
10/// system element, usually the baseboard.
11///
12/// In general, an entry in this table implies that the BIOS has some level of control over the enablement of
13/// the associated device for use by the system.
14///
15/// To describe multi-function devices, use one type 41 structure per function, and one type 14 (Group
16/// Association) structure referencing all the function handles.
17///
18/// NOTE: This structure replaces Onboard Device Information (Type 10) starting with version 2.6 of this specification.
19/// BIOS providers can choose to implement both types to allow existing SMBIOS browsers to properly display
20/// the system’s onboard devices information.
21///
22/// Compliant with:
23/// DMTF SMBIOS Reference Specification 3.5.0 (DSP0134)
24/// Document Date: 2021-09-15
25pub struct SMBiosOnboardDevicesExtendedInformation<'a> {
26    parts: &'a UndefinedStruct,
27}
28
29impl<'a> SMBiosStruct<'a> for SMBiosOnboardDevicesExtendedInformation<'a> {
30    const STRUCT_TYPE: u8 = 41u8;
31
32    fn new(parts: &'a UndefinedStruct) -> Self {
33        Self { parts }
34    }
35
36    fn parts(&self) -> &'a UndefinedStruct {
37        self.parts
38    }
39}
40
41impl<'a> SMBiosOnboardDevicesExtendedInformation<'a> {
42    /// The onboard device reference designation
43    pub fn reference_designation(&self) -> SMBiosString {
44        self.parts.get_field_string(0x4)
45    }
46
47    /// Device type bit field and enum
48    pub fn device_type(&self) -> Option<OnBoardDeviceType> {
49        self.parts
50            .get_field_byte(0x5)
51            .map(|raw| OnBoardDeviceType::from(raw))
52    }
53
54    /// Device type instance
55    pub fn device_type_instance(&self) -> Option<u8> {
56        self.parts.get_field_byte(0x6)
57    }
58
59    /// Segment group number
60    pub fn segment_group_number(&self) -> Option<SegmentGroupNumber> {
61        self.parts
62            .get_field_word(0x7)
63            .map(|raw| SegmentGroupNumber::from(raw))
64    }
65
66    /// Bus number
67    pub fn bus_number(&self) -> Option<BusNumber> {
68        self.parts
69            .get_field_byte(0x9)
70            .map(|raw| BusNumber::from(raw))
71    }
72
73    /// Device/Function number
74    pub fn device_function_number(&self) -> Option<DeviceFunctionNumber> {
75        self.parts
76            .get_field_byte(0xA)
77            .map(|raw| DeviceFunctionNumber::from(raw))
78    }
79}
80
81impl fmt::Debug for SMBiosOnboardDevicesExtendedInformation<'_> {
82    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
83        fmt.debug_struct(std::any::type_name::<
84            SMBiosOnboardDevicesExtendedInformation<'_>,
85        >())
86        .field("header", &self.parts.header)
87        .field("reference_designation", &self.reference_designation())
88        .field("device_type", &self.device_type())
89        .field("device_type_instance", &self.device_type_instance())
90        .field("segment_group_number", &self.segment_group_number())
91        .field("bus_number", &self.bus_number())
92        .field("device_function_number", &self.device_function_number())
93        .finish()
94    }
95}
96
97impl Serialize for SMBiosOnboardDevicesExtendedInformation<'_> {
98    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
99    where
100        S: Serializer,
101    {
102        let mut state =
103            serializer.serialize_struct("SMBiosOnboardDevicesExtendedInformation", 7)?;
104        state.serialize_field("header", &self.parts.header)?;
105        state.serialize_field("reference_designation", &self.reference_designation())?;
106        state.serialize_field("device_type", &self.device_type())?;
107        state.serialize_field("device_type_instance", &self.device_type_instance())?;
108        state.serialize_field("segment_group_number", &self.segment_group_number())?;
109        state.serialize_field("bus_number", &self.bus_number())?;
110        state.serialize_field("device_function_number", &self.device_function_number())?;
111        state.end()
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118    use crate::{DeviceStatus, SMBiosStruct, TypeOfDevice, UndefinedStruct};
119
120    #[test]
121    fn unit_test() {
122        let struct_type41 = vec![
123            0x29, 0x0B, 0x3B, 0x00, 0x01, 0x85, 0x01, 0x00, 0x00, 0x00, 0xFE, 0x69, 0x32, 0x31,
124            0x39, 0x00, 0x00,
125        ];
126
127        let parts = UndefinedStruct::new(&struct_type41);
128        let test_struct = SMBiosOnboardDevicesExtendedInformation::new(&parts);
129
130        assert_eq!(
131            test_struct.reference_designation().to_string(),
132            "i219".to_string()
133        );
134        let device_type = test_struct.device_type().unwrap();
135        assert_eq!(device_type.type_of_device(), TypeOfDevice::Ethernet);
136        assert_eq!(device_type.status(), DeviceStatus::Enabled);
137        assert_eq!(test_struct.device_type_instance(), Some(1));
138        match test_struct.segment_group_number().unwrap() {
139            SegmentGroupNumber::SingleSegment => (),
140            SegmentGroupNumber::NotApplicable => panic!("expected SingleSegment"),
141            SegmentGroupNumber::Number(_) => panic!("expected SingleSegment"),
142        }
143        match test_struct.bus_number().unwrap() {
144            BusNumber::Number(number) => assert_eq!(number, 0),
145            BusNumber::NotApplicable => panic!("expected Number"),
146        }
147
148        // At offset 0x0A is the value 0xFE which is the device/function value.
149        // The 8 bits are 0b11111 (0n31) and 0b110 (0n6)
150        match test_struct.device_function_number().unwrap() {
151            DeviceFunctionNumber::Number { device, function } => {
152                assert_eq!(device, 31);
153                assert_eq!(function, 6);
154            }
155            _ => panic!("expected device and function values"),
156        }
157    }
158}