~emersion/drmdb

drmdb/walk.go -rw-r--r-- 2.1 KiB View raw
31ca651fSimon Ser drmtree: handle USB devices 21 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package drmdb

import (
	"sort"

	"git.sr.ht/~emersion/drmdb/database"
	"git.sr.ht/~emersion/drmdb/drmtree"
	"git.sr.ht/~emersion/go-drm"
	"github.com/mcuadros/go-version"
)

func walkProps(props drmtree.PropertyMap, obj drm.AnyID, f func(drm.AnyID, string, *drmtree.Property) error) error {
	for name, prop := range props {
		if err := f(obj, name, &prop); err != nil {
			return err
		}
	}
	return nil
}

func walkNodeProps(n *drmtree.Node, f func(drm.AnyID, string, *drmtree.Property) error) error {
	for _, conn := range n.Connectors {
		if err := walkProps(conn.Properties, conn.ID, f); err != nil {
			return err
		}
	}
	for _, crtc := range n.CRTCs {
		if err := walkProps(crtc.Properties, crtc.ID, f); err != nil {
			return err
		}
	}
	for _, plane := range n.Planes {
		if err := walkProps(plane.Properties, plane.ID, f); err != nil {
			return err
		}
	}
	return nil
}

func driverLess(a *drmtree.Driver, b *drmtree.Driver) bool {
	if a.Version.Less(&b.Version) {
		return true
	}
	// Linux is the upstream
	if b.Kernel.SysName == "Linux" && a.Kernel.SysName != "Linux" {
		return true
	}
	return version.Compare(a.Kernel.Release, b.Kernel.Release, "<")
}

type walkLatestField int

const (
	walkLatestDriver walkLatestField = iota
	walkLatestDevice
)

func walkLatest(f walkLatestField, fn func(k string, n *drmtree.Node) error) error {
	type node struct {
		k string
		n *drmtree.Node
	}

	latest := make(map[string]node)
	err := database.Walk(func(k string, n *drmtree.Node) error {
		var latestKey string
		switch f {
		case walkLatestDriver:
			latestKey = n.Driver.Name
		case walkLatestDevice:
			latestKey = n.Device.BusID()
		}
		if latestKey == "" {
			return nil
		}

		other, ok := latest[latestKey]
		if ok && driverLess(n.Driver, other.n.Driver) {
			return nil
		}
		latest[latestKey] = node{k, n}
		return nil
	})
	if err != nil {
		return err
	}

	keys := make([]string, 0, len(latest))
	for k := range latest {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	for _, k := range keys {
		n := latest[k]
		if err := fn(n.k, n.n); err != nil {
			return err
		}
	}
	return nil
}