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
38143ab510
commit
7e419ae20e
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