diff --git a/di-edid-decode.c b/di-edid-decode.c index a7a70aa..6adebdb 100644 --- a/di-edid-decode.c +++ b/di-edid-decode.c @@ -7,6 +7,7 @@ #include #include +#include #include static size_t num_detailed_timing_defs = 0; @@ -418,6 +419,8 @@ ext_tag_name(enum di_edid_ext_tag tag) return "Block Map Extension Block"; case DI_EDID_EXT_VENDOR: return "Manufacturer-Specific Extension Block"; + case DI_EDID_EXT_DISPLAYID: + return "DisplayID Extension Block"; } abort(); } @@ -674,6 +677,13 @@ print_cta(const struct di_edid_cta *cta) } } +static void +print_displayid(const struct di_displayid *displayid) +{ + printf(" Version: %d.%d\n", di_displayid_get_version(displayid), + di_displayid_get_revision(displayid)); +} + static void print_ext(const struct di_edid_ext *ext, size_t ext_index) { @@ -687,6 +697,9 @@ print_ext(const struct di_edid_ext *ext, size_t ext_index) case DI_EDID_EXT_CEA: print_cta(di_edid_ext_get_cta(ext)); break; + case DI_EDID_EXT_DISPLAYID: + print_displayid(di_edid_ext_get_displayid(ext)); + break; default: break; /* Ignore */ } diff --git a/displayid.c b/displayid.c new file mode 100644 index 0000000..9a0906e --- /dev/null +++ b/displayid.c @@ -0,0 +1,35 @@ +#include + +#include "bits.h" +#include "displayid.h" + +bool +_di_displayid_parse(struct di_displayid *displayid, const uint8_t *data, + size_t size, struct di_logger *logger) +{ + if (size < 5) { + errno = EINVAL; + return false; + } + + displayid->version = get_bit_range(data[0x00], 7, 4); + displayid->revision = get_bit_range(data[0x00], 3, 0); + if (displayid->version == 0 || displayid->version > 1) { + errno = ENOTSUP; + return false; + } + + return true; +} + +int +di_displayid_get_version(const struct di_displayid *displayid) +{ + return displayid->version; +} + +int +di_displayid_get_revision(const struct di_displayid *displayid) +{ + return displayid->revision; +} diff --git a/edid.c b/edid.c index a40ec48..8e62574 100644 --- a/edid.c +++ b/edid.c @@ -764,6 +764,21 @@ parse_ext(struct di_edid *edid, const uint8_t data[static EDID_BLOCK_SIZE]) case DI_EDID_EXT_VENDOR: /* Supported */ break; + case DI_EDID_EXT_DISPLAYID: + snprintf(section_name, sizeof(section_name), + "Block %zu, DisplayID Extension Block", + edid->exts_len + 1); + logger = (struct di_logger) { + .f = edid->logger->f, + .section = section_name, + }; + + if (!_di_displayid_parse(&ext->displayid, &data[1], + EDID_BLOCK_SIZE - 2, &logger)) { + free(ext); + return false; + } + break; default: /* Unsupported */ free(ext); @@ -1115,3 +1130,12 @@ di_edid_ext_get_cta(const struct di_edid_ext *ext) } return &ext->cta; } + +const struct di_displayid * +di_edid_ext_get_displayid(const struct di_edid_ext *ext) +{ + if (ext->tag != DI_EDID_EXT_DISPLAYID) { + return NULL; + } + return &ext->displayid; +} diff --git a/include/bits.h b/include/bits.h index 309a240..b240127 100644 --- a/include/bits.h +++ b/include/bits.h @@ -5,6 +5,7 @@ * Utility functions to operate on bits. */ +#include #include #include #include diff --git a/include/displayid.h b/include/displayid.h new file mode 100644 index 0000000..1b43167 --- /dev/null +++ b/include/displayid.h @@ -0,0 +1,24 @@ +#ifndef DISPLAYID_H +#define DISPLAYID_H + +/** + * Private header for the low-level DisplayID API. + */ + +#include +#include +#include + +#include + +#include "log.h" + +struct di_displayid { + int version, revision; +}; + +bool +_di_displayid_parse(struct di_displayid *displayid, const uint8_t *data, + size_t size, struct di_logger *logger); + +#endif diff --git a/include/edid.h b/include/edid.h index 26a1ca4..bb2ba5f 100644 --- a/include/edid.h +++ b/include/edid.h @@ -12,6 +12,7 @@ #include #include "cta.h" +#include "displayid.h" /** * The maximum number of EDID blocks (including the base block), defined in @@ -96,6 +97,8 @@ struct di_edid_ext { enum di_edid_ext_tag tag; /* Used for DI_EDID_EXT_CEA */ struct di_edid_cta cta; + /* Used for DI_EDID_EXT_DISPLAYID */ + struct di_displayid displayid; }; /** diff --git a/include/libdisplay-info/displayid.h b/include/libdisplay-info/displayid.h new file mode 100644 index 0000000..90e3428 --- /dev/null +++ b/include/libdisplay-info/displayid.h @@ -0,0 +1,29 @@ +#ifndef DI_DISPLAYID_H +#define DI_DISPLAYID_H + +/** + * libdisplay-info's low-level API for VESA Display Identification Data + * (DisplayID). + * + * The library implements DisplayID version 1.3, available at: + * https://vesa.org/vesa-standards/ + */ + +/** + * DisplayID data structure. + */ +struct di_displayid; + +/** + * Get the DisplayID version. + */ +int +di_displayid_get_version(const struct di_displayid *displayid); + +/** + * Get the DisplayID revision. + */ +int +di_displayid_get_revision(const struct di_displayid *displayid); + +#endif diff --git a/include/libdisplay-info/edid.h b/include/libdisplay-info/edid.h index 6fb890e..2b766eb 100644 --- a/include/libdisplay-info/edid.h +++ b/include/libdisplay-info/edid.h @@ -614,6 +614,9 @@ enum di_edid_ext_tag { DI_EDID_EXT_BLOCK_MAP = 0xF0, /* Extension defined by the display manufacturer */ DI_EDID_EXT_VENDOR = 0xFF, + + /* DisplayID Extension */ + DI_EDID_EXT_DISPLAYID = 0x70, }; /** @@ -638,4 +641,15 @@ struct di_edid_cta; const struct di_edid_cta * di_edid_ext_get_cta(const struct di_edid_ext *ext); +/* See */ +struct di_displayid; + +/** + * Get a DisplayID extension block. + * + * Returns NULL if the extension block tag is not DI_EDID_EXT_DISPLAYID. + */ +const struct di_displayid * +di_edid_ext_get_displayid(const struct di_edid_ext *ext); + #endif diff --git a/meson.build b/meson.build index ba7d8e1..49086f1 100644 --- a/meson.build +++ b/meson.build @@ -36,6 +36,7 @@ di_lib = library( 'display-info', [ 'cta.c', + 'displayid.c', 'dmt-table.c', 'edid.c', 'info.c', diff --git a/test/data/apple-xdr-dp.diff b/test/data/apple-xdr-dp.diff index faac6db..e09b706 100644 --- a/test/data/apple-xdr-dp.diff +++ b/test/data/apple-xdr-dp.diff @@ -1,15 +1,6 @@ --- ref +++ di -@@ -31,7 +31,7 @@ - Hfront 8 Hsync 32 Hback 40 Hpol P - Vfront 43 Vsync 8 Vback 6 Vpol N - Display Product Name: 'ProDisplayXDR' -- Extension blocks: 6 -+ Extension blocks: 1 - Checksum: 0xeb - - ---------------- -@@ -62,171 +62,16 @@ +@@ -62,171 +62,38 @@ DTD 6: 3840x2160 47.951737 Hz 16:9 134.696 kHz 528.010000 MHz (699 mm x 393 mm) Hfront 8 Hsync 32 Hback 40 Hpol P Vfront 59 Vsync 8 Vback 582 Vpol N @@ -18,8 +9,8 @@ ---------------- --Block 2, DisplayID Extension Block: -- Version: 1.2 + Block 2, DisplayID Extension Block: + Version: 1.2 - Extension Count: 0 - Display Product Type: Extension Section - ContainerID Data Block: @@ -60,12 +51,12 @@ - Hfront 8 Hsync 32 Hback 28 Hpol P - Vfront 118 Vsync 8 Vback 6 Vpol N - Checksum: 0x8c --Checksum: 0x90 -- ------------------ -- --Block 3, DisplayID Extension Block: -- Version: 1.2 + Checksum: 0x90 + + ---------------- + + Block 3, DisplayID Extension Block: + Version: 1.2 - Extension Count: 0 - Video Timing Modes Type 1 - Detailed Timings Data Block: - DTD: 2560x2880 59.999451 Hz 0:0 179.578 kHz 481.270000 MHz (aspect undefined, no 3D stereo) @@ -84,12 +75,12 @@ - Hfront 8 Hsync 32 Hback 80 Hpol P - Vfront 850 Vsync 8 Vback 6 Vpol N - Checksum: 0x93 --Checksum: 0x90 -- ------------------ -- --Block 4, DisplayID Extension Block: -- Version: 1.2 + Checksum: 0x90 + + ---------------- + + Block 4, DisplayID Extension Block: + Version: 1.2 - Extension Count: 0 - Video Timing Modes Type 1 - Detailed Timings Data Block: - DTD: 3008x3384 59.999726 Hz 0:0 210.959 kHz 648.910000 MHz (aspect undefined, no 3D stereo) @@ -108,12 +99,12 @@ - Hfront 8 Hsync 32 Hback 28 Hpol P - Vfront 1001 Vsync 8 Vback 6 Vpol N - Checksum: 0x7e --Checksum: 0x90 -- ------------------ -- --Block 5, DisplayID Extension Block: -- Version: 1.2 + Checksum: 0x90 + + ---------------- + + Block 5, DisplayID Extension Block: + Version: 1.2 - Extension Count: 0 - Video Timing Modes Type 1 - Detailed Timings Data Block: - DTD: 5120x2880 59.999614 Hz 16:9 179.579 kHz 933.810000 MHz (aspect 16:9, no 3D stereo) @@ -132,12 +123,12 @@ - Hfront 8 Hsync 32 Hback 40 Hpol P - Vfront 850 Vsync 8 Vback 6 Vpol N - Checksum: 0x0a --Checksum: 0x90 -- ------------------ -- --Block 6, DisplayID Extension Block: -- Version: 1.2 + Checksum: 0x90 + + ---------------- + + Block 6, DisplayID Extension Block: + Version: 1.2 - Extension Count: 0 - Video Timing Modes Type 1 - Detailed Timings Data Block: - DTD: 6016x3384 59.999899 Hz 16:9 210.960 kHz 1286.010000 MHz (aspect 16:9, no 3D stereo, preferred) @@ -156,10 +147,10 @@ - Hfront 8 Hsync 32 Hback 40 Hpol P - Vfront 1001 Vsync 8 Vback 6 Vpol N - Checksum: 0xb4 --Checksum: 0x90 -- ------------------ -- + Checksum: 0x90 + + ---------------- + -Warnings: - -Block 1, CTA-861 Extension Block: @@ -167,8 +158,8 @@ -Block 2, DisplayID Extension Block: - Vendor-Specific Data Block (0x7f) (Apple), OUI 00-10-FA: Expected PNP ID but found OUI. - - Failures: - +-Failures: +- -Block 1, CTA-861 Extension Block: - Required 640x480p60 timings are missing in the established timings and the SVD list (VIC 1). - Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues. @@ -181,10 +172,5 @@ -EDID: - DisplayID: Missing DisplayID Product Identification Data Block. - -+Block 0, Base EDID: -+ Unknown Extension Block. -+ Unknown Extension Block. -+ Unknown Extension Block. -+ Unknown Extension Block. -+ Unknown Extension Block. - EDID conformity: FAIL +-EDID conformity: FAIL ++EDID conformity: PASS