use std::ptr::NonNull; use anyhow::{bail, Result}; pub const SUPPORTED_PCI_IDS: &[(u16, u16)] = &[ (0x8086, 0x7eb8), (0x8086, 0x7eb9), (0x8086, 0x7ebd), (0x8086, 0x7ebe), (0x8086, 0xa8b8), (0x8086, 0xa8b9), ]; pub const REG_CONTROL: usize = 0x0000; pub const REG_STATUS: usize = 0x0004; pub const REG_MODE: usize = 0x0010; pub const REG_SUBIP_OPCODE: usize = 0x0800; pub const REG_SUBIP_ADDRESS: usize = 0x0804; pub const REG_SUBIP_LENGTH: usize = 0x0808; pub const REG_SUBIP_DOORBELL: usize = 0x080C; pub const REG_SUBIP_DATA: usize = 0x0810; #[derive(Clone, Copy)] pub struct ThcController { base: NonNull, len: usize, } impl ThcController { pub fn new(base: *mut u8, len: usize) -> Result { let Some(base) = NonNull::new(base) else { bail!("THC BAR mapping returned null base pointer"); }; Ok(Self { base, len }) } pub fn initialize_quicki2c_mode(&self) { self.write32(REG_MODE, 0x1); self.write32(REG_CONTROL, 0x1); } pub fn status(&self) -> u32 { self.read32(REG_STATUS) } pub fn program_subip_transaction(&self, opcode: u32, address: u16, len: usize) { self.write32(REG_SUBIP_OPCODE, opcode); self.write32(REG_SUBIP_ADDRESS, u32::from(address)); self.write32(REG_SUBIP_LENGTH, len as u32); self.write32(REG_SUBIP_DOORBELL, 1); } pub fn write_subip_data(&self, offset: usize, value: u32) { self.write32(REG_SUBIP_DATA + offset, value); } pub fn read_subip_data(&self, offset: usize) -> u32 { self.read32(REG_SUBIP_DATA + offset) } fn read32(&self, offset: usize) -> u32 { if offset + 4 > self.len { return 0; } let ptr = unsafe { self.base.as_ptr().add(offset).cast::() }; unsafe { ptr.read_volatile() } } fn write32(&self, offset: usize, value: u32) { if offset + 4 > self.len { return; } let ptr = unsafe { self.base.as_ptr().add(offset).cast::() }; unsafe { ptr.write_volatile(value) }; } }