mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
acpi: move entity visitor code to the entity pkg
This commit is contained in:
parent
89882545f2
commit
bd14d52b60
64
src/gopheros/device/acpi/aml/entity/visitor.go
Normal file
64
src/gopheros/device/acpi/aml/entity/visitor.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
// Visitor is a function invoked by the VM for each AML tree entity that matches
|
||||||
|
// a particular type. The return value controls whether the children of this
|
||||||
|
// entity should also be visited.
|
||||||
|
type Visitor func(depth int, obj Entity) (keepRecursing bool)
|
||||||
|
|
||||||
|
// Type defines the type of entity that visitors should inspect.
|
||||||
|
type Type uint8
|
||||||
|
|
||||||
|
// The list of supported Type values. TypeAny works as a wildcard
|
||||||
|
// allowing the visitor to inspect all entities in the AML tree.
|
||||||
|
const (
|
||||||
|
TypeAny Type = iota
|
||||||
|
TypeDevice
|
||||||
|
TypeProcessor
|
||||||
|
TypePowerResource
|
||||||
|
TypeThermalZone
|
||||||
|
TypeMethod
|
||||||
|
TypeMutex
|
||||||
|
TypeEvent
|
||||||
|
TypeField
|
||||||
|
TypeIndexField
|
||||||
|
TypeBankField
|
||||||
|
)
|
||||||
|
|
||||||
|
// Visit descends a scope hierarchy and invokes visitorFn for each entity
|
||||||
|
// that matches entType.
|
||||||
|
func Visit(depth int, ent Entity, entType Type, visitorFn Visitor) bool {
|
||||||
|
op := ent.Opcode()
|
||||||
|
switch {
|
||||||
|
case (entType == TypeAny) ||
|
||||||
|
(entType == TypeDevice && op == OpDevice) ||
|
||||||
|
(entType == TypeProcessor && op == OpProcessor) ||
|
||||||
|
(entType == TypePowerResource && op == OpPowerRes) ||
|
||||||
|
(entType == TypeThermalZone && op == OpThermalZone) ||
|
||||||
|
(entType == TypeMethod && op == OpMethod) ||
|
||||||
|
(entType == TypeMutex && op == OpMutex) ||
|
||||||
|
(entType == TypeEvent && op == OpEvent) ||
|
||||||
|
(entType == TypeField && op == OpField) ||
|
||||||
|
(entType == TypeIndexField && op == OpIndexField) ||
|
||||||
|
(entType == TypeBankField && op == OpBankField):
|
||||||
|
// If the visitor returned false we should not visit the children
|
||||||
|
if !visitorFn(depth, ent) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visit any args that are also entities
|
||||||
|
for _, arg := range ent.Args() {
|
||||||
|
if argEnt, isEnt := arg.(Entity); isEnt && !Visit(depth+1, argEnt, entType, visitorFn) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the entity defines a scope we need to visit the child entities.
|
||||||
|
if container, isContainer := ent.(Container); isContainer {
|
||||||
|
for _, child := range container.Children() {
|
||||||
|
_ = Visit(depth+1, child, entType, visitorFn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
93
src/gopheros/device/acpi/aml/entity/visitor_test.go
Normal file
93
src/gopheros/device/acpi/aml/entity/visitor_test.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestScopeVisit(t *testing.T) {
|
||||||
|
tableHandle := uint8(42)
|
||||||
|
keepRecursing := func(Entity) bool { return true }
|
||||||
|
stopRecursing := func(Entity) bool { return false }
|
||||||
|
|
||||||
|
// Append special entities under IDE0
|
||||||
|
root := NewScope(tableHandle, "IDE0")
|
||||||
|
root.Append(NewDevice(tableHandle, "DEV0"))
|
||||||
|
root.Append(NewProcessor(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewProcessor(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewPowerResource(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewPowerResource(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewPowerResource(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewThermalZone(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewThermalZone(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewThermalZone(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewThermalZone(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewMethod(tableHandle, "MTH0"))
|
||||||
|
root.Append(NewMethod(tableHandle, "MTH1"))
|
||||||
|
root.Append(NewMethod(tableHandle, "MTH2"))
|
||||||
|
root.Append(NewMethod(tableHandle, "MTH3"))
|
||||||
|
root.Append(NewMethod(tableHandle, "MTH4"))
|
||||||
|
root.Append(NewMutex(tableHandle))
|
||||||
|
root.Append(NewMutex(tableHandle))
|
||||||
|
root.Append(NewEvent(tableHandle))
|
||||||
|
root.Append(NewEvent(tableHandle))
|
||||||
|
root.Append(NewEvent(tableHandle))
|
||||||
|
root.Append(NewField(tableHandle))
|
||||||
|
root.Append(NewIndexField(tableHandle))
|
||||||
|
root.Append(NewBankField(tableHandle))
|
||||||
|
root.Append(&Invocation{
|
||||||
|
Generic: Generic{
|
||||||
|
op: OpMethodInvocation,
|
||||||
|
args: []interface{}{
|
||||||
|
NewConst(OpOne, tableHandle, uint64(1)),
|
||||||
|
NewConst(OpDwordPrefix, tableHandle, uint64(2)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
specs := []struct {
|
||||||
|
searchType Type
|
||||||
|
keepRecursingFn func(Entity) bool
|
||||||
|
wantHits int
|
||||||
|
}{
|
||||||
|
{TypeAny, keepRecursing, 27},
|
||||||
|
{TypeAny, stopRecursing, 1},
|
||||||
|
{
|
||||||
|
TypeAny,
|
||||||
|
func(ent Entity) bool {
|
||||||
|
// Stop recursing after visiting the Invocation entity
|
||||||
|
_, isInv := ent.(*Invocation)
|
||||||
|
return !isInv
|
||||||
|
},
|
||||||
|
25,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TypeAny,
|
||||||
|
func(ent Entity) bool {
|
||||||
|
// Stop recursing after visiting the first Const entity
|
||||||
|
_, isConst := ent.(*Const)
|
||||||
|
return !isConst
|
||||||
|
},
|
||||||
|
26,
|
||||||
|
},
|
||||||
|
{TypeDevice, keepRecursing, 1},
|
||||||
|
{TypeProcessor, keepRecursing, 2},
|
||||||
|
{TypePowerResource, keepRecursing, 3},
|
||||||
|
{TypeThermalZone, keepRecursing, 4},
|
||||||
|
{TypeMethod, keepRecursing, 5},
|
||||||
|
{TypeMutex, keepRecursing, 2},
|
||||||
|
{TypeEvent, keepRecursing, 3},
|
||||||
|
{TypeField, keepRecursing, 1},
|
||||||
|
{TypeIndexField, keepRecursing, 1},
|
||||||
|
{TypeBankField, keepRecursing, 1},
|
||||||
|
}
|
||||||
|
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
var hits int
|
||||||
|
Visit(0, root, spec.searchType, func(_ int, obj Entity) bool {
|
||||||
|
hits++
|
||||||
|
return spec.keepRecursingFn(obj)
|
||||||
|
})
|
||||||
|
|
||||||
|
if hits != spec.wantHits {
|
||||||
|
t.Errorf("[spec %d] expected visitor to be called %d times; got %d", specIndex, spec.wantHits, hits)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user