]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fundamental: Introduce EDID header parsing
authoranonymix007 <48598263+anonymix007@users.noreply.github.com>
Mon, 31 Mar 2025 17:38:24 +0000 (20:38 +0300)
committeranonymix007 <48598263+anonymix007@users.noreply.github.com>
Wed, 7 May 2025 15:10:51 +0000 (18:10 +0300)
src/fundamental/edid-fundamental.c [new file with mode: 0644]
src/fundamental/edid-fundamental.h [new file with mode: 0644]
src/fundamental/meson.build

diff --git a/src/fundamental/edid-fundamental.c b/src/fundamental/edid-fundamental.c
new file mode 100644 (file)
index 0000000..9657d96
--- /dev/null
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "edid-fundamental.h"
+#include "efivars-fundamental.h"
+
+#define EDID_FIXED_HEADER_PATTERN "\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+assert_cc(sizeof_field(EdidHeader, pattern) == sizeof(EDID_FIXED_HEADER_PATTERN));
+
+int edid_parse_blob(const void *blob, size_t blob_size, EdidHeader *ret_header) {
+        assert(ret_header);
+
+        /* EDID size is at least 128 as per the specification */
+        if (blob_size < 128)
+                return -EINVAL;
+
+        const EdidHeader *edid_header = ASSERT_PTR(blob);
+        if (memcmp(edid_header->pattern, EDID_FIXED_HEADER_PATTERN, sizeof(EDID_FIXED_HEADER_PATTERN)) != 0)
+                return -EINVAL;
+
+        *ret_header = (EdidHeader) {
+                .pattern = EDID_FIXED_HEADER_PATTERN,
+                .manufacturer_id = be16toh(edid_header->manufacturer_id),
+                .manufacturer_product_code = le16toh(edid_header->manufacturer_product_code),
+                .serial_number = le32toh(edid_header->serial_number),
+                .week_of_manufacture = edid_header->week_of_manufacture,
+                .year_of_manufacture = edid_header->year_of_manufacture,
+                .edid_version = edid_header->edid_version,
+                .edid_revision = edid_header->edid_revision,
+        };
+        return 0;
+}
+
+int edid_get_panel_id(const EdidHeader *edid_header, char16_t ret_panel[static 8]) {
+        assert(edid_header);
+        assert(ret_panel);
+
+        for (size_t i = 0; i < 3; i++) {
+                uint8_t letter = (edid_header->manufacturer_id >> (5 * i)) & 0b11111;
+                if (letter > 0b11010)
+                        return -EINVAL;
+                ret_panel[2 - i] = letter + 'A' - 1;
+        }
+        ret_panel[3] = LOWERCASE_HEXDIGITS[(edid_header->manufacturer_product_code >> 12) & 0x0F];
+        ret_panel[4] = LOWERCASE_HEXDIGITS[(edid_header->manufacturer_product_code >>  8) & 0x0F];
+        ret_panel[5] = LOWERCASE_HEXDIGITS[(edid_header->manufacturer_product_code >>  4) & 0x0F];
+        ret_panel[6] = LOWERCASE_HEXDIGITS[(edid_header->manufacturer_product_code >>  0) & 0x0F];
+        ret_panel[7] = L'\0';
+        return 0;
+}
diff --git a/src/fundamental/edid-fundamental.h b/src/fundamental/edid-fundamental.h
new file mode 100644 (file)
index 0000000..5247378
--- /dev/null
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#if SD_BOOT
+#  include "efi-string.h"
+#  include "util.h"
+#else
+#  include <endian.h>
+#  include <stddef.h>
+#  include <stdint.h>
+#  include <uchar.h>
+#endif
+
+#include "string-util-fundamental.h"
+
+/* EDID structure, version 1.4 */
+typedef struct EdidHeader {
+        uint8_t pattern[8];                   /* fixed pattern */
+        uint16_t manufacturer_id;             /* big-endian 3-letter code */
+        uint16_t manufacturer_product_code;   /* little-endian */
+        uint32_t serial_number;               /* little-endian */
+        uint8_t week_of_manufacture;          /* week or model year flag (0xFF) */
+        uint8_t year_of_manufacture;          /* year or model if flag is set (0 is 1990) */
+        uint8_t edid_version;                 /* 0x01 for 1.3 and 1.4 */
+        uint8_t edid_revision;                /* 0x03 for 1.3, 0x04 for 1.4 */
+} _packed_ EdidHeader;
+
+int edid_parse_blob(const void *blob, size_t blob_size, EdidHeader *ret_header);
+int edid_get_panel_id(const EdidHeader *edid_header, char16_t ret_panel[static 8]);
index 7b72372e8382d57e557004e680eddd3c50683f44..5536be6e4c4ad6dfdfc270eecfd81253404c5b3f 100644 (file)
@@ -5,6 +5,7 @@ fundamental_include = include_directories('.')
 fundamental_sources = files(
         'bootspec-fundamental.c',
         'chid-fundamental.c',
+        'edid-fundamental.c',
         'efivars-fundamental.c',
         'iovec-util-fundamental.h',
         'sha1-fundamental.c',