use super::{check_signature, ACPISDTHeader}; use core::mem; use io::{Io, Pio}; static mut DSDT: DSDT = DSDT { valid: false, dsdt: None, s5_ptr: 0, slp_typ_a: 0, slp_typ_b: 0, }; struct DSDT { valid: bool, dsdt: Option<&'static ACPISDTHeader>, s5_ptr: u32, slp_typ_a: u16, slp_typ_b: u16, } impl DSDT { fn init(&mut self, addr: u32) -> Result<(), &'static str> { self.dsdt = Some(unsafe { &(*(addr as *const ACPISDTHeader)) }); self.s5_ptr = self.find_s5(addr)?; self.parse_s5(); self.valid = true; Ok(()) } fn find_s5(&self, addr: u32) -> Result { let dsdt_start = addr + mem::size_of::() as u32; let dsdt_end = dsdt_start + self.dsdt.unwrap().length; for addr in dsdt_start..dsdt_end { if check_signature(addr, "_S5_") { if (check_signature(addr - 1, "\x08") || check_signature(addr - 2, "\x08\\")) && check_signature(addr + 4, "\x12") { return Ok(addr); } } } Err("Can not find S5 section in DSDT") } fn parse_s5(&mut self) { let ptr = self.s5_ptr + 5; let ptr = ((unsafe { *(ptr as *const u8) } & 0xC0) >> 6) + 2; let ptr = if unsafe { *(ptr as *const u8) } == 0x0A { ptr + 1 } else { ptr }; // Skip bytePrefix self.slp_typ_a = (unsafe { *(ptr as *const u8) } as u16) << 10; let ptr = ptr + 1; let ptr = if unsafe { *(ptr as *const u8) } == 0x0A { ptr + 1 } else { ptr }; // Skip bytePrefix self.slp_typ_b = (unsafe { *(ptr as *const u8) } as u16) << 10; } } fn is_init() -> Result<(), &'static str> { match unsafe { DSDT.valid } { true => Ok(()), false => match unsafe { DSDT.dsdt } { Some(_) => Err("Differentiated System Description Pointer (DSDP) is not valid"), None => Err("Differentiated System Description Pointer (DSDP) is not initialized"), }, } } /// ## Initialize Differentiated System Description Table (DSDT) /// input param addr is contain in FADT pub fn init(addr: u32) -> Result<(), &'static str> { if ACPISDTHeader::valid(addr, "DSDT") { return unsafe { DSDT.init(addr) }; } return Err("Can not find Differentiated System Description Table (DSDT)."); } /// NOT COMPATIBLE WITH VIRTUALBOX /// Send shutdown signal /// outw(PM1a_CNT_BLK, SLP_TYPx | SLP_EN) pub fn shutdown(pm1_cnt: [u16; 2]) -> Result<(), &'static str> { is_init()?; let slp_typ = unsafe { DSDT.slp_typ_a } | (1 << 13); let mut pin: Pio = Pio::new(pm1_cnt[0]); pin.write(slp_typ); if pm1_cnt[1] != 0 { let slp_typ = unsafe { DSDT.slp_typ_b } | (1 << 13); let mut pin: Pio = Pio::new(pm1_cnt[1]); pin.write(slp_typ); // cpuio::outw(pm1_cnt[1], slp_typ); } Ok(()) }