~emersion/drmdb

7eee002028feb90543070634623c62b791903366 — Simon Ser 2 years ago b5a9821
cmd/drmdump: split tree structure
2 files changed, 191 insertions(+), 182 deletions(-)

M cmd/drmdump/main.go
A drmtree/drmtree.go
M cmd/drmdump/main.go => cmd/drmdump/main.go +47 -182
@@ 10,28 10,10 @@ import (
	"syscall"

	"git.sr.ht/~emersion/drmdb/treefmt"
	"git.sr.ht/~emersion/drmdb/drmtree"
	"git.sr.ht/~emersion/go-drm"
)

type DriverVersion struct {
	Major int32  `json:"major"`
	Minor int32  `json:"minor"`
	Patch int32  `json:"patch"`
	Date  string `json:"date"`
}

func (ver *DriverVersion) String() string {
	return fmt.Sprintf("%v.%v.%v (%v)", ver.Major, ver.Minor, ver.Patch, ver.Date)
}

type Driver struct {
	Name       string             `json:"name"`
	Desc       string             `json:"desc"`
	Version    DriverVersion      `json:"version"`
	Caps       map[string]*uint64 `json:"caps"`
	ClientCaps map[string]bool    `json:"client_caps"`
}

var capNames = map[drm.Cap]string{
	drm.CapDumbBuffer:          "DUMB_BUFFER",
	drm.CapVblankHighCRTC:      "VBLANK_HIGH_CRTC",


@@ 56,7 38,7 @@ var clientCapNames = map[drm.ClientCap]string{
	drm.ClientCapWritebackConnectors: "WRITEBACK_CONNECTORS",
}

func driver(n *drm.Node) (*Driver, error) {
func driver(n *drm.Node) (*drmtree.Driver, error) {
	v, err := n.Version()
	if err != nil {
		return nil, fmt.Errorf("cannot get version: %v", err)


@@ 85,10 67,10 @@ func driver(n *drm.Node) (*Driver, error) {
		clientCaps[s] = ok
	}

	return &Driver{
	return &drmtree.Driver{
		Name: v.Name,
		Desc: v.Desc,
		Version: DriverVersion{
		Version: drmtree.DriverVersion{
			Major: v.Major,
			Minor: v.Minor,
			Patch: v.Patch,


@@ 99,7 81,7 @@ func driver(n *drm.Node) (*Driver, error) {
	}, nil
}

func printDriver(tf treefmt.Formatter, drv *Driver) {
func printDriver(tf treefmt.Formatter, drv *drmtree.Driver) {
	tf.Printf("Driver: %v (%v) version %v", drv.Name, drv.Desc, &drv.Version)
	tfc := tf.NewChild()



@@ 127,19 109,7 @@ func printDriver(tf treefmt.Formatter, drv *Driver) {
	}
}

type DevicePCI struct {
	Vendor    uint32 `json:"vendor"`
	Device    uint32 `json:"device"`
	SubVendor uint32 `json:"subsystem_vendor"`
	SubDevice uint32 `json:"subsystem_device"`
}

type Device struct {
	BusType    drm.BusType `json:"bus_type"`
	DeviceData interface{} `json:"device_data,omitempty"`
}

func device(n *drm.Node) (*Device, error) {
func device(n *drm.Node) (*drmtree.Device, error) {
	dev, err := n.GetDevice()
	if err != nil {
		return nil, fmt.Errorf("failed to get device: %v", err)


@@ 147,9 117,9 @@ func device(n *drm.Node) (*Device, error) {

	switch dev := dev.(type) {
	case *drm.PCIDevice:
		return &Device{
		return &drmtree.Device{
			BusType: dev.BusType(),
			DeviceData: &DevicePCI{
			DeviceData: &drmtree.DevicePCI{
				Vendor:    dev.Vendor,
				Device:    dev.Device,
				SubVendor: dev.SubVendor,


@@ 157,14 127,14 @@ func device(n *drm.Node) (*Device, error) {
			},
		}, nil
	default:
		return &Device{BusType: dev.BusType()}, nil
		return &drmtree.Device{BusType: dev.BusType()}, nil
	}
}

func printDevice(tf treefmt.Formatter, dev *Device) {
func printDevice(tf treefmt.Formatter, dev *drmtree.Device) {
	switch dev.BusType {
	case drm.BusPCI:
		pci := dev.DeviceData.(*DevicePCI)
		pci := dev.DeviceData.(*drmtree.DevicePCI)
		tf.Printf("Device: %v %04X:%04X", dev.BusType, pci.Vendor, pci.Device)
	default:
		tf.Printf("Device: %v", dev.BusType)


@@ 187,33 157,10 @@ func bitfieldString(v uint32) string {
	return s
}

type Mode struct {
	Clock      uint32 `json:"clock"`
	HDisplay   uint16 `json:"hdisplay"`
	HSyncStart uint16 `json:"hsync_start"`
	HSyncEnd   uint16 `json:"hsync_end"`
	HTotal     uint16 `json:"htotal"`
	HSkew      uint16 `json:"hskew"`
	VDisplay   uint16 `json:"vdisplay"`
	VSyncStart uint16 `json:"vsync_total"`
	VSyncEnd   uint16 `json:"vsync_end"`
	VTotal     uint16 `json:"vtotal"`
	VScan      uint16 `json:"vscan"`
	VRefresh   uint32 `json:"vrefresh"`
	Flags      uint32 `json:"flags"`
	Type       uint32 `json:"type"`
	Name       string `json:"name"`
}

func (mode *Mode) String() string {
	// TODO: refresh and flags
	return mode.Name
}

func modeList(modes []drm.ModeModeInfo) []Mode {
	l := make([]Mode, len(modes))
func modeList(modes []drm.ModeModeInfo) []drmtree.Mode {
	l := make([]drmtree.Mode, len(modes))
	for i, m := range modes {
		l[i] = Mode(m)
		l[i] = drmtree.Mode(m)
	}
	return l
}


@@ 222,11 169,6 @@ func parseFixedPoint16(v interface{}) (interface{}, error) {
	return v.(uint64) >> 16, nil
}

type PlaneInFormatsModifier struct {
	Modifier drm.Modifier `json:"modifier"`
	Formats  []drm.Format `json:"formats"`
}

func parseInFormats(v interface{}) (interface{}, error) {
	b := v.([]byte)
	set, err := drm.ParseFormatModifierSet(b)


@@ 234,9 176,9 @@ func parseInFormats(v interface{}) (interface{}, error) {
		return nil, err
	}
	m := set.Map()
	l := make([]PlaneInFormatsModifier, 0, len(m))
	l := make([]drmtree.PlaneInFormatsModifier, 0, len(m))
	for mod, fmts := range m {
		l = append(l, PlaneInFormatsModifier{
		l = append(l, drmtree.PlaneInFormatsModifier{
			Modifier: mod,
			Formats:  fmts,
		})


@@ 250,7 192,7 @@ func parseModeID(v interface{}) (interface{}, error) {
	if err != nil {
		return nil, err
	}
	return (*Mode)(mode), nil
	return (*drmtree.Mode)(mode), nil
}

func parseWritebackPixelFormats(v interface{}) (interface{}, error) {


@@ 282,41 224,13 @@ var propertyParsers = map[string]struct {
	"PATH":                    {drm.ObjectConnector, drm.PropertyBlob, parsePath},
}

type PropertySpecEnum struct {
	Name  string `json:"name"`
	Value uint64 `json:"value"`
}

type PropertySpecRange struct {
	Min uint64 `json:"min"`
	Max uint64 `json:"max`
}

type PropertySpecSignedRange struct {
	Min int64 `json:"min"`
	Max int64 `json:"max`
}

type Property struct {
	ID        drm.PropertyID   `json:"id"`
	Type      drm.PropertyType `json:"type"`
	Immutable bool             `json:"immutable"`
	Atomic    bool             `json:"atomic"`
	Spec      interface{}      `json:"spec"`
	RawValue  uint64           `json:"raw_value"`
	// Value interpreted with the property type
	Value interface{} `json:"value"`
	// Value interpreted with the property name, optional
	Data interface{} `json:"data"`
}

func properties(n *drm.Node, id drm.AnyID) (map[string]Property, error) {
func properties(n *drm.Node, id drm.AnyID) (map[string]drmtree.Property, error) {
	props, err := n.ModeObjectGetProperties(id)
	if err != nil {
		return nil, fmt.Errorf("failed to get properties for object %v: %v", id, err)
	}

	m := make(map[string]Property, len(props))
	m := make(map[string]drmtree.Property, len(props))
	for propID, propValue := range props {
		prop, err := n.ModeGetProperty(propID)
		if err != nil {


@@ 327,19 241,19 @@ func properties(n *drm.Node, id drm.AnyID) (map[string]Property, error) {
		switch prop.Type() {
		case drm.PropertyRange:
			min, max, _ := prop.Range()
			spec = &PropertySpecRange{Min: min, Max: max}
			spec = &drmtree.PropertySpecRange{Min: min, Max: max}
		case drm.PropertyEnum, drm.PropertyBitmask:
			enums, _ := prop.Enums()
			l := make([]PropertySpecEnum, len(enums))
			l := make([]drmtree.PropertySpecEnum, len(enums))
			for i, e := range enums {
				l[i] = PropertySpecEnum(e)
				l[i] = drmtree.PropertySpecEnum(e)
			}
			spec = l
		case drm.PropertyObject:
			spec, _ = prop.ObjectType()
		case drm.PropertySignedRange:
			min, max, _ := prop.SignedRange()
			spec = &PropertySpecSignedRange{Min: min, Max: max}
			spec = &drmtree.PropertySpecSignedRange{Min: min, Max: max}
		}

		var val interface{}


@@ 378,7 292,7 @@ func properties(n *drm.Node, id drm.AnyID) (map[string]Property, error) {
			}
		}

		m[prop.Name] = Property{
		m[prop.Name] = drmtree.Property{
			ID:        prop.ID,
			Type:      prop.Type(),
			Immutable: prop.Immutable(),


@@ 393,7 307,7 @@ func properties(n *drm.Node, id drm.AnyID) (map[string]Property, error) {
	return m, nil
}

func printProperties(tf treefmt.Formatter, props map[string]Property) {
func printProperties(tf treefmt.Formatter, props map[string]drmtree.Property) {
	for name, prop := range props {
		// TODO: immutable, atomic
		// TODO: type-specific property data


@@ 405,20 319,8 @@ func printProperties(tf treefmt.Formatter, props map[string]Property) {
	}
}

type Connector struct {
	ID         drm.ConnectorID     `json:"id"`
	Type       drm.ConnectorType   `json:"type"`
	Status     drm.ConnectorStatus `json:"status"`
	PhyWidth   uint32              `json:"phy_width"`
	PhyHeight  uint32              `json:"phy_height"`
	Subpixel   drm.Subpixel        `json:"subpixel"`
	Encoders   []drm.EncoderID     `json:"encoders"`
	Modes      []Mode              `json:"modes"`
	Properties map[string]Property `json:"properties"`
}

func connectors(n *drm.Node, card *drm.ModeCard) ([]Connector, error) {
	l := make([]Connector, len(card.Connectors))
func connectors(n *drm.Node, card *drm.ModeCard) ([]drmtree.Connector, error) {
	l := make([]drmtree.Connector, len(card.Connectors))
	for i, id := range card.Connectors {
		conn, err := n.ModeGetConnector(id)
		if err != nil {


@@ 430,7 332,7 @@ func connectors(n *drm.Node, card *drm.ModeCard) ([]Connector, error) {
			return nil, fmt.Errorf("failed to get connector properties: %v", err)
		}

		l[i] = Connector{
		l[i] = drmtree.Connector{
			ID:         conn.ID,
			Type:       conn.Type,
			Status:     conn.Status,


@@ 457,13 359,13 @@ func encoderIDsString(encs []drm.EncoderID) string {
	return s
}

func printModes(tf treefmt.Formatter, modes []Mode) {
func printModes(tf treefmt.Formatter, modes []drmtree.Mode) {
	for _, mode := range modes {
		tf.Printf("%v", &mode)
	}
}

func printConnectors(tf treefmt.Formatter, conns []Connector) {
func printConnectors(tf treefmt.Formatter, conns []drmtree.Connector) {
	for i, conn := range conns {
		tf.Printf("Connector %v", i)
		tfc := tf.NewChild()


@@ 485,28 387,20 @@ func printConnectors(tf treefmt.Formatter, conns []Connector) {
	}
}

type Encoder struct {
	ID             drm.EncoderID   `json:"id"`
	Type           drm.EncoderType `json:"type"`
	CRTC           drm.CRTCID      `json:"crtc"`
	PossibleCRTCs  uint32          `json:"possible_crtcs"`
	PossibleClones uint32          `json:"possible_clones"`
}

func encoders(n *drm.Node, card *drm.ModeCard) ([]Encoder, error) {
	l := make([]Encoder, len(card.Encoders))
func encoders(n *drm.Node, card *drm.ModeCard) ([]drmtree.Encoder, error) {
	l := make([]drmtree.Encoder, len(card.Encoders))
	for i, id := range card.Encoders {
		enc, err := n.ModeGetEncoder(id)
		if err != nil {
			return nil, fmt.Errorf("failed to get encoder: %v", err)
		}

		l[i] = Encoder(*enc)
		l[i] = drmtree.Encoder(*enc)
	}
	return l, nil
}

func printEncoders(tf treefmt.Formatter, encs []Encoder) {
func printEncoders(tf treefmt.Formatter, encs []drmtree.Encoder) {
	for i, enc := range encs {
		tf.Printf("Encoder %v", i)
		tfc := tf.NewChild()


@@ 518,18 412,8 @@ func printEncoders(tf treefmt.Formatter, encs []Encoder) {
	}
}

type CRTC struct {
	ID         drm.CRTCID          `json:"id"`
	FB         drm.FBID            `json:"fb"`
	X          uint32              `json:"x"`
	Y          uint32              `json:"y"`
	GammaSize  uint32              `json:"gamma_size"`
	Mode       *Mode               `json:"mode"`
	Properties map[string]Property `json:"properties"`
}

func crtcs(n *drm.Node, card *drm.ModeCard) ([]CRTC, error) {
	l := make([]CRTC, len(card.CRTCs))
func crtcs(n *drm.Node, card *drm.ModeCard) ([]drmtree.CRTC, error) {
	l := make([]drmtree.CRTC, len(card.CRTCs))
	for i, id := range card.CRTCs {
		crtc, err := n.ModeGetCRTC(id)
		if err != nil {


@@ 541,20 425,20 @@ func crtcs(n *drm.Node, card *drm.ModeCard) ([]CRTC, error) {
			return nil, fmt.Errorf("failed to get CRTC properties: %v", err)
		}

		l[i] = CRTC{
		l[i] = drmtree.CRTC{
			ID:         crtc.ID,
			FB:         crtc.FB,
			X:          crtc.X,
			Y:          crtc.Y,
			GammaSize:  crtc.GammaSize,
			Mode:       (*Mode)(crtc.Mode),
			Mode:       (*drmtree.Mode)(crtc.Mode),
			Properties: props,
		}
	}
	return l, nil
}

func printCRTCs(tf treefmt.Formatter, crtcs []CRTC) {
func printCRTCs(tf treefmt.Formatter, crtcs []drmtree.CRTC) {
	for i, crtc := range crtcs {
		tf.Printf("CRTC %v", i)
		tfc := tf.NewChild()


@@ 573,23 457,13 @@ func printCRTCs(tf treefmt.Formatter, crtcs []CRTC) {
	}
}

type Plane struct {
	ID            drm.PlaneID         `json:"id"`
	CRTC          drm.CRTCID          `json:"crtc"`
	FB            drm.FBID            `json:"fb"`
	PossibleCRTCs uint32              `json:"possible_crtcs"`
	GammaSize     uint32              `json:"gamma_size"`
	Formats       []drm.Format        `json:"formats"`
	Properties    map[string]Property `json:"properties"`
}

func planes(n *drm.Node) ([]Plane, error) {
func planes(n *drm.Node) ([]drmtree.Plane, error) {
	planes, err := n.ModeGetPlaneResources()
	if err != nil {
		log.Fatal(err)
	}

	l := make([]Plane, len(planes))
	l := make([]drmtree.Plane, len(planes))
	for i, id := range planes {
		plane, err := n.ModeGetPlane(id)
		if err != nil {


@@ 601,7 475,7 @@ func planes(n *drm.Node) ([]Plane, error) {
			return nil, fmt.Errorf("failed to get plane properties: %v", err)
		}

		l[i] = Plane{
		l[i] = drmtree.Plane{
			ID:            plane.ID,
			CRTC:          plane.CRTC,
			FB:            plane.FB,


@@ 621,7 495,7 @@ func printFormats(tf treefmt.Formatter, formats []drm.Format) {
	}
}

func printPlanes(tf treefmt.Formatter, planes []Plane) {
func printPlanes(tf treefmt.Formatter, planes []drmtree.Plane) {
	for i, plane := range planes {
		tf.Printf("Plane %v", i)
		tfc := tf.NewChild()


@@ 642,16 516,7 @@ func printPlanes(tf treefmt.Formatter, planes []Plane) {
	}
}

type Node struct {
	Driver     *Driver     `json:"driver"`
	Device     *Device     `json:"device"`
	Connectors []Connector `json:"connectors"`
	Encoders   []Encoder   `json:"encoders"`
	CRTCs      []CRTC      `json:"crtcs"`
	Planes     []Plane     `json:"planes"`
}

func node(nodePath string) (*Node, error) {
func node(nodePath string) (*drmtree.Node, error) {
	f, err := os.Open(nodePath)
	if err != nil {
		return nil, fmt.Errorf("failed to open DRM node: %v", err)


@@ 695,7 560,7 @@ func node(nodePath string) (*Node, error) {
		return nil, err
	}

	return &Node{
	return &drmtree.Node{
		Driver:     drv,
		Device:     dev,
		Connectors: conns,


@@ 705,7 570,7 @@ func node(nodePath string) (*Node, error) {
	}, nil
}

func printNode(tf treefmt.Formatter, path string, n *Node) {
func printNode(tf treefmt.Formatter, path string, n *drmtree.Node) {
	tf.Printf("Node: %s", path)
	tfc := tf.NewChild()



@@ 737,7 602,7 @@ func main() {
		log.Fatalf("Failed to list DRM nodes: %v", err)
	}

	nodes := make(map[string]*Node)
	nodes := make(map[string]*drmtree.Node)
	for _, p := range paths {
		n, err := node(p)
		if err != nil {

A drmtree/drmtree.go => drmtree/drmtree.go +144 -0
@@ 0,0 1,144 @@
// Package drmtree exposes DRM data as a tree structure.
package drmtree

import (
	"fmt"

	"git.sr.ht/~emersion/go-drm"
)

type DriverVersion struct {
	Major int32  `json:"major"`
	Minor int32  `json:"minor"`
	Patch int32  `json:"patch"`
	Date  string `json:"date"`
}

func (ver *DriverVersion) String() string {
	return fmt.Sprintf("%v.%v.%v (%v)", ver.Major, ver.Minor, ver.Patch, ver.Date)
}

type Driver struct {
	Name       string             `json:"name"`
	Desc       string             `json:"desc"`
	Version    DriverVersion      `json:"version"`
	Caps       map[string]*uint64 `json:"caps"`
	ClientCaps map[string]bool    `json:"client_caps"`
}

type DevicePCI struct {
	Vendor    uint32 `json:"vendor"`
	Device    uint32 `json:"device"`
	SubVendor uint32 `json:"subsystem_vendor"`
	SubDevice uint32 `json:"subsystem_device"`
}

type Device struct {
	BusType    drm.BusType `json:"bus_type"`
	DeviceData interface{} `json:"device_data,omitempty"`
}

type Mode struct {
	Clock      uint32 `json:"clock"`
	HDisplay   uint16 `json:"hdisplay"`
	HSyncStart uint16 `json:"hsync_start"`
	HSyncEnd   uint16 `json:"hsync_end"`
	HTotal     uint16 `json:"htotal"`
	HSkew      uint16 `json:"hskew"`
	VDisplay   uint16 `json:"vdisplay"`
	VSyncStart uint16 `json:"vsync_total"`
	VSyncEnd   uint16 `json:"vsync_end"`
	VTotal     uint16 `json:"vtotal"`
	VScan      uint16 `json:"vscan"`
	VRefresh   uint32 `json:"vrefresh"`
	Flags      uint32 `json:"flags"`
	Type       uint32 `json:"type"`
	Name       string `json:"name"`
}

func (mode *Mode) String() string {
	// TODO: refresh and flags
	return mode.Name
}

type PlaneInFormatsModifier struct {
	Modifier drm.Modifier `json:"modifier"`
	Formats  []drm.Format `json:"formats"`
}

type PropertySpecEnum struct {
	Name  string `json:"name"`
	Value uint64 `json:"value"`
}

type PropertySpecRange struct {
	Min uint64 `json:"min"`
	Max uint64 `json:"max`
}

type PropertySpecSignedRange struct {
	Min int64 `json:"min"`
	Max int64 `json:"max`
}

type Property struct {
	ID        drm.PropertyID   `json:"id"`
	Type      drm.PropertyType `json:"type"`
	Immutable bool             `json:"immutable"`
	Atomic    bool             `json:"atomic"`
	Spec      interface{}      `json:"spec"`
	RawValue  uint64           `json:"raw_value"`
	// Value interpreted with the property type
	Value interface{} `json:"value"`
	// Value interpreted with the property name, optional
	Data interface{} `json:"data"`
}

type Connector struct {
	ID         drm.ConnectorID     `json:"id"`
	Type       drm.ConnectorType   `json:"type"`
	Status     drm.ConnectorStatus `json:"status"`
	PhyWidth   uint32              `json:"phy_width"`
	PhyHeight  uint32              `json:"phy_height"`
	Subpixel   drm.Subpixel        `json:"subpixel"`
	Encoders   []drm.EncoderID     `json:"encoders"`
	Modes      []Mode              `json:"modes"`
	Properties map[string]Property `json:"properties"`
}

type Encoder struct {
	ID             drm.EncoderID   `json:"id"`
	Type           drm.EncoderType `json:"type"`
	CRTC           drm.CRTCID      `json:"crtc"`
	PossibleCRTCs  uint32          `json:"possible_crtcs"`
	PossibleClones uint32          `json:"possible_clones"`
}

type CRTC struct {
	ID         drm.CRTCID          `json:"id"`
	FB         drm.FBID            `json:"fb"`
	X          uint32              `json:"x"`
	Y          uint32              `json:"y"`
	GammaSize  uint32              `json:"gamma_size"`
	Mode       *Mode               `json:"mode"`
	Properties map[string]Property `json:"properties"`
}

type Plane struct {
	ID            drm.PlaneID         `json:"id"`
	CRTC          drm.CRTCID          `json:"crtc"`
	FB            drm.FBID            `json:"fb"`
	PossibleCRTCs uint32              `json:"possible_crtcs"`
	GammaSize     uint32              `json:"gamma_size"`
	Formats       []drm.Format        `json:"formats"`
	Properties    map[string]Property `json:"properties"`
}

type Node struct {
	Driver     *Driver     `json:"driver"`
	Device     *Device     `json:"device"`
	Connectors []Connector `json:"connectors"`
	Encoders   []Encoder   `json:"encoders"`
	CRTCs      []CRTC      `json:"crtcs"`
	Planes     []Plane     `json:"planes"`
}