...

Source file src/edge-infra.dev/pkg/lib/kernel/drm/drm.go

Documentation: edge-infra.dev/pkg/lib/kernel/drm

     1  package drm
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path"
     7  	"regexp"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"edge-infra.dev/pkg/sds/lib/edid"
    12  )
    13  
    14  const DRMPath = "/sys/class/drm"
    15  
    16  const (
    17  	SubSystem        = "drm"
    18  	cardPrefix       = "card"
    19  	edidFileName     = "edid"
    20  	connectorPattern = "^card[0-9](-[A-Za-z0-9]+)+$"
    21  )
    22  
    23  // Connector represents a connector in /sys/class/drm,
    24  // e.g. "card0-HDMI-A-1" or "card1-DP-2".
    25  type Connector struct {
    26  	card int
    27  	port string
    28  	edid *edid.EDID
    29  }
    30  
    31  // The full connector name, e.g. "card0-HDMI-A-1".
    32  func (connector Connector) String() string {
    33  	return fmt.Sprintf("%s%d-%s", cardPrefix, connector.card, connector.port)
    34  }
    35  
    36  // The connector's card, e.g. "card0".
    37  func (connector Connector) Card() string {
    38  	return fmt.Sprintf("%s%d", cardPrefix, connector.card)
    39  }
    40  
    41  // The connector's card number.
    42  func (connector Connector) CardNum() int {
    43  	return connector.card
    44  }
    45  
    46  // The connector's port, e.g. "HDMI-A-1".
    47  func (connector Connector) Port() string {
    48  	return connector.port
    49  }
    50  
    51  // The path to the connector, e.g. "/sys/class/drm/card0-HDMI-A-1".
    52  func (connector Connector) Path() string {
    53  	return path.Join(DRMPath, connector.String())
    54  }
    55  
    56  // The connector's EDID.
    57  func (connector Connector) EDID() *edid.EDID {
    58  	return connector.edid
    59  }
    60  
    61  // Override the connector's EDID.
    62  func (connector *Connector) WithEDID(edid *edid.EDID) {
    63  	connector.edid = edid
    64  }
    65  
    66  func NewConnector(name string) (*Connector, error) {
    67  	cardName, port, err := SplitConnectorName(name)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  
    72  	// we can ignore the error check as we already validated name
    73  	card, err := strconv.Atoi(strings.TrimPrefix(cardName, cardPrefix))
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	connector := &Connector{
    79  		card: card,
    80  		port: port,
    81  	}
    82  
    83  	// add EDID if it is present
    84  	edid, err := edid.NewFromFile(path.Join(connector.Path(), edidFileName))
    85  	if err == nil {
    86  		connector.edid = edid
    87  	}
    88  
    89  	return connector, nil
    90  }
    91  
    92  // Splits connector into card and port,
    93  // e.g. "card0-HDMI-A-1" becomes "card0" and "HDMI-A-1".
    94  func SplitConnectorName(name string) (card, port string, err error) {
    95  	if err := ValidateConnectorName(name); err != nil {
    96  		return "", "", err
    97  	}
    98  	card, port, _ = strings.Cut(name, "-")
    99  	return card, port, nil
   100  }
   101  
   102  // Checks connector name is of format "card<%d>-<port>",
   103  // i.e. matches the pattern ^card[0-9](-[A-Za-z0-9]+)+$
   104  func ValidateConnectorName(name string) error {
   105  	re, err := regexp.Compile(connectorPattern)
   106  	if err != nil {
   107  		return err
   108  	}
   109  
   110  	if match := re.MatchString(name); !match {
   111  		return fmt.Errorf("%s is not a valid connector name", name)
   112  	}
   113  
   114  	return nil
   115  }
   116  
   117  // Returns a list of all connectors in /sys/class/drm.
   118  func Connectors() ([]Connector, error) {
   119  	files, err := os.ReadDir(DRMPath)
   120  	if err != nil {
   121  		return nil, fmt.Errorf("failed to read directory %s: %w", DRMPath, err)
   122  	}
   123  
   124  	connectors := []Connector{}
   125  	for _, file := range files {
   126  		connector, err := NewConnector(file.Name())
   127  		if err == nil {
   128  			connectors = append(connectors, *connector)
   129  		}
   130  	}
   131  
   132  	return connectors, nil
   133  }
   134  

View as plain text