feature: Add basic EDID reading, writing, and patching capabilities
This commit is contained in:
parent
d0a4d26082
commit
183d2606dc
12 changed files with 431 additions and 5 deletions
102
edidpatcher/edidpatcher.go
Normal file
102
edidpatcher/edidpatcher.go
Normal file
|
@ -0,0 +1,102 @@
|
|||
package edidpatcher
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Calculates a checksum for a given EDID block (base EDID, extension blocks, etc.)
|
||||
func CalculateEDIDChecksum(edidBlock []byte) byte {
|
||||
sum := 0
|
||||
|
||||
for _, value := range edidBlock[:len(edidBlock)-1] {
|
||||
sum += int(value)
|
||||
}
|
||||
|
||||
return byte((-sum) & 0xFF)
|
||||
}
|
||||
|
||||
var MSFTPayloadSize = byte(22 + 4)
|
||||
|
||||
// Patch a given EDID to be a "specialized display", allowing for the display to be used by third-party window-managers/compositors/applications directly.
|
||||
func PatchEDIDToBeSpecialized(edid []byte) ([]byte, error) {
|
||||
newEDID := make([]byte, len(edid))
|
||||
copy(newEDID, edid)
|
||||
|
||||
isAnEnhancedEDID := len(newEDID) > 128
|
||||
|
||||
foundExtensionBase := 0
|
||||
extensionBaseExists := false
|
||||
|
||||
// Find an appropriate extension base
|
||||
if isAnEnhancedEDID {
|
||||
for currentExtensionPosition := 128; currentExtensionPosition < len(newEDID); currentExtensionPosition += 128 {
|
||||
if newEDID[currentExtensionPosition] != 0x02 {
|
||||
continue
|
||||
}
|
||||
|
||||
if newEDID[currentExtensionPosition+1] != 0x03 {
|
||||
log.Warn("Incompatible version detected for ANSI CTA data section in EDID")
|
||||
}
|
||||
|
||||
foundExtensionBase = currentExtensionPosition
|
||||
extensionBaseExists = true
|
||||
}
|
||||
|
||||
if foundExtensionBase == 0 {
|
||||
foundExtensionBase = len(newEDID)
|
||||
newEDID = append(newEDID, make([]byte, 128)...)
|
||||
}
|
||||
} else {
|
||||
foundExtensionBase = 128
|
||||
newEDID = append(newEDID, make([]byte, 128)...)
|
||||
}
|
||||
|
||||
newEDID[foundExtensionBase+2] = MSFTPayloadSize
|
||||
|
||||
if !extensionBaseExists {
|
||||
// Add another extension to the original EDID
|
||||
if newEDID[126] == 255 {
|
||||
return nil, fmt.Errorf("EDID extension block limit reached, but we need to add another extension")
|
||||
}
|
||||
|
||||
newEDID[126] += 1
|
||||
newEDID[127] = CalculateEDIDChecksum(newEDID[:128])
|
||||
|
||||
newEDID[foundExtensionBase] = 0x02
|
||||
newEDID[foundExtensionBase+1] = 0x03
|
||||
newEDID[foundExtensionBase+3] = 0x00
|
||||
} else {
|
||||
if newEDID[foundExtensionBase+2] != MSFTPayloadSize && newEDID[foundExtensionBase+2] != 0 {
|
||||
currentBase := newEDID[foundExtensionBase+2]
|
||||
|
||||
copy(newEDID[foundExtensionBase+4:foundExtensionBase+int(currentBase)-1], make([]byte, int(currentBase)-1))
|
||||
copy(newEDID[foundExtensionBase+int(MSFTPayloadSize):foundExtensionBase+127], newEDID[foundExtensionBase+int(currentBase):foundExtensionBase+127])
|
||||
}
|
||||
}
|
||||
|
||||
generatedUUID := uuid.New()
|
||||
uuidBytes, err := generatedUUID.MarshalBinary()
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal UUID: %w", err)
|
||||
}
|
||||
|
||||
// Implemented using https://learn.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension
|
||||
// VST & Length
|
||||
newEDID[foundExtensionBase+4] = 0x3<<5 | 0x15 // 0x3: vendor specific tag; 0x15: length
|
||||
// Assigned IEEE OUI
|
||||
newEDID[foundExtensionBase+5] = 0x5C
|
||||
newEDID[foundExtensionBase+6] = 0x12
|
||||
newEDID[foundExtensionBase+7] = 0xCA
|
||||
// Actual data
|
||||
newEDID[foundExtensionBase+8] = 0x2 // Using version 0x2 for better compatibility
|
||||
newEDID[foundExtensionBase+9] = 0x7 // Using VR tag for better compatibility even though it probably doesn't matter
|
||||
copy(newEDID[foundExtensionBase+10:foundExtensionBase+10+16], uuidBytes)
|
||||
|
||||
newEDID[foundExtensionBase+127] = CalculateEDIDChecksum(newEDID[foundExtensionBase : foundExtensionBase+127])
|
||||
|
||||
return newEDID, nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue