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 after 0c11c2b5
captured a broken intermediate edit. Completes the _REG wiring begun in
c3a27717 (which delivered the acpid-side call).
This commit is contained in:
Red Bear OS
2026-07-24 10:01:12 +09:00
parent c3a2771780
commit 3ba37444a0
+69
View File
@@ -241,10 +241,79 @@ where
handlers.insert(space, handler); 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(&region.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 /// 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`, /// operation region handlers registered. Specifically, it will call relevant `_STA`, `_INI`,
/// and `_REG` methods. /// and `_REG` methods.
pub fn initialize_namespace(&self) { 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`, * 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, * which indicates if the device is present and functional. If this method does not exist,
* we assume the device should be initialized. * we assume the device should be initialized.