use core::mem::{size_of, MaybeUninit};
use core::ptr;
use crate::bindings::atom_common_table_header;
pub use crate::bindings::ppt::{
smu_v11_0_0_ppt::{smu_11_0_powerplay_table, PPTable_t as PPTable_smu_11_0_t},
smu_v11_0_7_ppt::{smu_11_0_7_powerplay_table, PPTable_t as PPTable_smu_11_0_7_t, PPTable_beige_goby_t},
smu_v13_0_0_ppt::{smu_13_0_0_powerplay_table, PPTable_t as PPTable_smu_13_0_0_t},
smu_v13_0_7_ppt::{smu_13_0_7_powerplay_table, PPTable_t as PPTable_smu_13_0_7_t},
};
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum PPTableDecodeError {
SmallerThanHeader,
SmallerThanStructureSizeInHeader,
}
#[derive(Debug, Clone)]
pub enum PPTable {
V11_0_0(smu_11_0_powerplay_table),
V11_0_7(smu_11_0_7_powerplay_table),
V13_0_0(smu_13_0_0_powerplay_table),
V13_0_7(smu_13_0_7_powerplay_table),
Unknown(atom_common_table_header),
Invalid,
}
impl PPTable {
fn get_header(bytes: &[u8]) -> Option<atom_common_table_header> {
const HEADER_SIZE: usize = size_of::<atom_common_table_header>();
let bin = bytes.get(0..HEADER_SIZE)?;
unsafe {
let mut h = MaybeUninit::<atom_common_table_header>::zeroed();
ptr::copy_nonoverlapping(
bin.as_ptr(),
h.as_mut_ptr() as *mut u8,
HEADER_SIZE,
);
Some(h.assume_init())
}
}
fn check_length(header: &atom_common_table_header, len: usize) -> bool {
header.structuresize as usize <= len
}
pub fn decode(bytes: &[u8]) -> Result<Self, PPTableDecodeError> {
let Some(header) = Self::get_header(bytes) else { return Err(PPTableDecodeError::SmallerThanHeader) };
if !Self::check_length(&header, bytes.len()) {
return Err(PPTableDecodeError::SmallerThanStructureSizeInHeader);
}
let ppt = match header.format_revision {
12 | 14 => Self::V11_0_0(Self::to_pptable(bytes)),
15 | 16 | 18 | 19 => Self::V11_0_7(Self::to_pptable(bytes)),
20 => Self::V13_0_0(Self::to_pptable(bytes)),
_ => Self::Unknown(header),
};
Ok(ppt)
}
pub fn decode_with_smu_version(bytes: &[u8], smu_ver: (u8, u8, u8)) -> Result<Self, PPTableDecodeError> {
let Some(header) = Self::get_header(bytes) else { return Err(PPTableDecodeError::SmallerThanHeader) };
if !Self::check_length(&header, bytes.len()) {
return Err(PPTableDecodeError::SmallerThanStructureSizeInHeader);
}
let ppt = match smu_ver {
(11, 0, 0) |
(11, 0, 5) |
(11, 0, 9)
=> Self::V11_0_0(Self::to_pptable(bytes)),
(11, 0, 7) |
(11, 0, 11) |
(11, 0, 12) |
(11, 0, 13)
=> Self::V11_0_7(Self::to_pptable(bytes)),
(13, 0, 0) |
(13, 0, 10) => Self::V13_0_0(Self::to_pptable(bytes)),
(13, 0, 7) => Self::V13_0_7(Self::to_pptable(bytes)),
_ => Self::Unknown(header),
};
Ok(ppt)
}
fn to_pptable<T>(bytes: &[u8]) -> T {
unsafe {
let mut t = MaybeUninit::<T>::zeroed();
ptr::copy_nonoverlapping(
bytes.as_ptr(),
t.as_mut_ptr() as *mut u8,
size_of::<T>(),
);
t.assume_init()
}
}
pub fn is_valid(&self) -> bool {
match self {
Self::Unknown(_) |
Self::Invalid => false,
_ => true,
}
}
}