This is done to help potential dependents reduce download sizes and only download what they need.
101 lines
3.2 KiB
Go
101 lines
3.2 KiB
Go
package edidpatcher
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"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 {
|
|
fmt.Println("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
|
|
}
|