acpi-rs: add connect_op_regions() + repair initialize_namespace
Add public connect_op_regions() (ACPICA evrgnini.c): \_SB._REG(space, 1) per installed handler space plus <device>._REG(space, 1) per device holding an OpRegion of that space. initialize_namespace() now delegates to it and its ACPICA-order opening (_INI, _SB._INI) is restored after0c11c2b5captured a broken intermediate edit. Completes the _REG wiring begun inc3a27717(which delivered the acpid-side call).
This commit is contained in:
@@ -241,10 +241,79 @@ where
|
||||
handlers.insert(space, handler);
|
||||
}
|
||||
|
||||
/// `_REG` opregion connect (ACPICA evrgnini.c): `\_SB._REG(space, 1)` per
|
||||
/// installed handler + `<device>._REG(space, 1)` per device holding an
|
||||
/// OpRegion of that space. Firmware gates EC access behind this. Idempotent.
|
||||
pub fn connect_op_regions(&self) {
|
||||
let installed_spaces: Vec<RegionSpace> =
|
||||
self.region_handlers.lock().keys().copied().collect();
|
||||
|
||||
for space in &installed_spaces {
|
||||
let space_id = u8::from(*space) as u64;
|
||||
if let Err(err) = self.evaluate_if_present(
|
||||
AmlName::from_str("\\_SB._REG").unwrap(),
|
||||
vec![Object::Integer(space_id).wrap(), Object::Integer(1).wrap()],
|
||||
) {
|
||||
warn!("\\_SB._REG({:?}, connect) failed: {:?}", space, err);
|
||||
}
|
||||
}
|
||||
|
||||
let mut reg_namespace = self.namespace.lock().clone();
|
||||
let _ = reg_namespace.traverse(|path, level| {
|
||||
match level.kind {
|
||||
NamespaceLevelKind::Device
|
||||
| NamespaceLevelKind::Processor
|
||||
| NamespaceLevelKind::ThermalZone
|
||||
| NamespaceLevelKind::PowerResource => {
|
||||
let mut device_spaces: Vec<RegionSpace> = level
|
||||
.values
|
||||
.values()
|
||||
.filter_map(|(_, obj)| match &**obj {
|
||||
Object::OpRegion(region)
|
||||
if installed_spaces.contains(®ion.space) =>
|
||||
{
|
||||
Some(region.space)
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
device_spaces.sort();
|
||||
device_spaces.dedup();
|
||||
for space in device_spaces {
|
||||
let space_id = u8::from(space) as u64;
|
||||
if let Ok(reg_path) =
|
||||
AmlName::from_str("_REG").unwrap().resolve(path)
|
||||
{
|
||||
let _ = self.evaluate_if_present(
|
||||
reg_path,
|
||||
vec![Object::Integer(space_id).wrap(), Object::Integer(1).wrap()],
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
_ => Ok(true),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Initialize the namespace - this should be called after all tables have been loaded and
|
||||
/// operation region handlers registered. Specifically, it will call relevant `_STA`, `_INI`,
|
||||
/// and `_REG` methods.
|
||||
pub fn initialize_namespace(&self) {
|
||||
/*
|
||||
* This should match the initialization order of ACPICA and uACPI.
|
||||
*/
|
||||
if let Err(err) = self.evaluate_if_present(AmlName::from_str("\\_INI").unwrap(), vec![]) {
|
||||
warn!("Invoking \\_INI failed: {:?}", err);
|
||||
}
|
||||
if let Err(err) = self.evaluate_if_present(AmlName::from_str("\\_SB._INI").unwrap(), vec![]) {
|
||||
warn!("Invoking \\_SB._INI failed: {:?}", err);
|
||||
}
|
||||
|
||||
self.connect_op_regions();
|
||||
|
||||
/*
|
||||
* We can now initialize each device in the namespace. For each device, we evaluate `_STA`,
|
||||
* which indicates if the device is present and functional. If this method does not exist,
|
||||
* we assume the device should be initialized.
|
||||
|
||||
Reference in New Issue
Block a user