use ieee1212_config_rom::*;
#[derive(Default, Debug, Clone, Copy)]
pub struct Identifier {
pub vendor_id: u32,
pub category: u8,
pub product_id: u16,
pub serial: u32,
}
#[derive(Default, Debug, Clone, Copy)]
pub struct RootData<'a> {
pub vendor_id: u32,
pub vendor_name: &'a str,
pub product_id: u32,
pub product_name: &'a str,
}
#[derive(Default, Debug, Clone, Copy)]
pub struct UnitData<'a> {
pub model_id: u32,
pub model_name: &'a str,
pub specifier_id: u32,
pub version: u32,
}
const VENDOR_ID_MASK: u32 = 0xffffff00;
const VENDOR_ID_SHIFT: usize = 8;
const CATEGORY_MASK: u32 = 0x000000ff;
const CATEGORY_SHIFT: usize = 0;
const PRODUCT_ID_MASK: u32 = 0xffc00000;
const PRODUCT_ID_SHIFT: usize = 22;
const SERIAL_MASK: u32 = 0x003fffff;
const SERIAL_SHIFT: usize = 0;
pub trait DiceConfigRom<'a> {
fn get_identifier(&self) -> Option<Identifier>;
fn get_root_data(&'a self) -> Option<RootData<'a>>;
fn get_unit_data(&'a self) -> Vec<UnitData<'a>>;
}
impl<'a> DiceConfigRom<'a> for ConfigRom<'a> {
fn get_identifier(&self) -> Option<Identifier> {
if self.bus_info.len() < 12 {
None
} else {
let mut quadlet = [0; 4];
quadlet.copy_from_slice(&self.bus_info[8..12]);
let val = u32::from_be_bytes(quadlet);
let vendor_id = (val & VENDOR_ID_MASK) >> VENDOR_ID_SHIFT;
let category = ((val & CATEGORY_MASK) >> CATEGORY_SHIFT) as u8;
quadlet.copy_from_slice(&self.bus_info[12..16]);
let val = u32::from_be_bytes(quadlet);
let product_id = ((val & PRODUCT_ID_MASK) >> PRODUCT_ID_SHIFT) as u16;
let serial = (val & SERIAL_MASK) >> SERIAL_SHIFT;
Some(Identifier {
vendor_id,
category,
product_id,
serial,
})
}
}
fn get_root_data(&'a self) -> Option<RootData<'a>> {
let (vendor_id, vendor_name) = detect_desc_text(&self.root, KeyType::Vendor)?;
let (product_id, product_name) = detect_desc_text(&self.root, KeyType::Model)?;
let data = RootData {
vendor_id,
vendor_name,
product_id,
product_name,
};
Some(data)
}
fn get_unit_data(&'a self) -> Vec<UnitData<'a>> {
self.root
.iter()
.filter_map(|entry| {
let entries = EntryDataAccess::<&[Entry]>::get(entry, KeyType::Unit)?;
let specifier_id = entries
.iter()
.find_map(|entry| EntryDataAccess::<u32>::get(entry, KeyType::SpecifierId))?;
let version = entries
.iter()
.find_map(|entry| EntryDataAccess::<u32>::get(entry, KeyType::Version))?;
let (model_id, model_name) = detect_desc_text(entries, KeyType::Model)?;
let data = UnitData {
model_id,
model_name,
specifier_id,
version,
};
Some(data)
})
.collect()
}
}
fn detect_desc_text<'a>(entries: &'a [Entry], key_type: KeyType) -> Option<(u32, &'a str)> {
let mut peekable = entries.iter().peekable();
while let Some(entry) = peekable.next() {
let result = EntryDataAccess::<u32>::get(entry, key_type).and_then(|value| {
peekable.peek().and_then(|&next| {
EntryDataAccess::<&str>::get(next, KeyType::Descriptor).map(|name| (value, name))
})
});
if result.is_some() {
return result;
}
}
None
}