mirror of
https://gitlab.freedesktop.org/emersion/libdisplay-info.git
synced 2024-11-16 19:48:30 +01:00
edid: add basic support for display descriptors
Expose an API to list display descriptors. Detailed timing descriptors are not parsed. Signed-off-by: Simon Ser <contact@emersion.fr>
This commit is contained in:
parent
c05fbc875b
commit
2f8f41ea48
6 changed files with 211 additions and 7 deletions
|
@ -4,6 +4,51 @@
|
|||
#include <libdisplay-info/edid.h>
|
||||
#include <libdisplay-info/info.h>
|
||||
|
||||
static const char *
|
||||
display_desc_tag_name(enum di_edid_display_descriptor_tag tag)
|
||||
{
|
||||
static char name[256];
|
||||
switch (tag) {
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_PRODUCT_SERIAL:
|
||||
return "Display Product Serial Number";
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_DATA_STRING:
|
||||
return "Alphanumeric Data String";
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_RANGE_LIMITS:
|
||||
return "Display Range Limits";
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_PRODUCT_NAME:
|
||||
return "Display Product Name";
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_COLOR_POINT:
|
||||
return "Color Point Data";
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_STD_TIMING_IDS:
|
||||
return "Standard Timing Identifications";
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_DCM_DATA:
|
||||
return "Display Color Management Data";
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_CVT_TIMING_CODES:
|
||||
return "CVT 3 Byte Timing Codes";
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_ESTABLISHED_TIMINGS_III:
|
||||
return "Established timings III";
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_DUMMY:
|
||||
return "Dummy Descriptor";
|
||||
default:
|
||||
snprintf(name, sizeof(name), "%s Display Descriptor (0x%02hhx)",
|
||||
tag <= 0x0F ? "Manufacturer-Specified" : "Unknown",
|
||||
tag);
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_display_desc(const struct di_edid_display_descriptor *desc)
|
||||
{
|
||||
enum di_edid_display_descriptor_tag tag;
|
||||
const char *tag_name;
|
||||
|
||||
tag = di_edid_display_descriptor_get_tag(desc);
|
||||
tag_name = display_desc_tag_name(tag);
|
||||
|
||||
printf(" %s:\n", tag_name);
|
||||
}
|
||||
|
||||
static const char *
|
||||
ext_tag_name(enum di_edid_ext_tag tag)
|
||||
{
|
||||
|
@ -51,6 +96,7 @@ main(void)
|
|||
const struct di_edid *edid;
|
||||
struct di_info *info;
|
||||
const struct di_edid_vendor_product *vendor_product;
|
||||
const struct di_edid_display_descriptor *const *display_descs;
|
||||
const struct di_edid_ext *const *exts;
|
||||
size_t i;
|
||||
|
||||
|
@ -87,6 +133,12 @@ main(void)
|
|||
vendor_product->manufacture_year);
|
||||
}
|
||||
|
||||
printf(" Detailed Timing Descriptors:\n");
|
||||
display_descs = di_edid_get_display_descriptors(edid);
|
||||
for (i = 0; display_descs[i] != NULL; i++) {
|
||||
print_display_desc(display_descs[i]);
|
||||
}
|
||||
|
||||
exts = di_edid_get_extensions(edid);
|
||||
|
||||
for (i = 0; exts[i] != NULL; i++);
|
||||
|
|
94
edid.c
94
edid.c
|
@ -9,6 +9,10 @@
|
|||
* The size of an EDID block, defined in section 2.2.
|
||||
*/
|
||||
#define EDID_BLOCK_SIZE 128
|
||||
/**
|
||||
* The size of an EDID byte descriptor, defined in section 3.10.
|
||||
*/
|
||||
#define EDID_BYTE_DESCRIPTOR_SIZE 18
|
||||
|
||||
/**
|
||||
* Fixed EDID header, defined in section 3.1.
|
||||
|
@ -76,6 +80,68 @@ parse_vendor_product(const uint8_t data[static EDID_BLOCK_SIZE],
|
|||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_byte_descriptor(struct di_edid *edid,
|
||||
const uint8_t data[static EDID_BYTE_DESCRIPTOR_SIZE])
|
||||
{
|
||||
struct di_edid_display_descriptor *desc;
|
||||
uint8_t tag;
|
||||
|
||||
if (data[0] || data[1]) {
|
||||
if (edid->display_descriptors_len > 0) {
|
||||
/* A detailed timing descriptor is not allowed after a
|
||||
* display descriptor per note 3 of table 3.20. */
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO: parse detailed timing descriptor */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* TODO: check we got at least one detailed timing descriptor, per note
|
||||
* 4 of table 3.20. */
|
||||
|
||||
desc = calloc(1, sizeof(*desc));
|
||||
if (!desc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tag = data[3];
|
||||
switch (tag) {
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_PRODUCT_SERIAL:
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_DATA_STRING:
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_RANGE_LIMITS:
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_PRODUCT_NAME:
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_COLOR_POINT:
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_STD_TIMING_IDS:
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_DCM_DATA:
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_CVT_TIMING_CODES:
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_ESTABLISHED_TIMINGS_III:
|
||||
case DI_EDID_DISPLAY_DESCRIPTOR_DUMMY:
|
||||
break; /* Ignore */
|
||||
default:
|
||||
free(desc);
|
||||
if (tag <= 0x0F) {
|
||||
/* Manufacturer-specific */
|
||||
errno = ENOTSUP;
|
||||
} else {
|
||||
/* Reserved */
|
||||
if (edid->revision > 4) {
|
||||
errno = ENOTSUP;
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
desc->tag = tag;
|
||||
edid->display_descriptors[edid->display_descriptors_len++] = desc;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_ext(struct di_edid *edid, const uint8_t data[static EDID_BLOCK_SIZE])
|
||||
{
|
||||
|
@ -120,7 +186,7 @@ di_edid_parse(const void *data, size_t size)
|
|||
struct di_edid *edid;
|
||||
int version, revision;
|
||||
size_t exts_len, i;
|
||||
const uint8_t *ext_data;
|
||||
const uint8_t *byte_desc_data, *ext_data;
|
||||
|
||||
if (size < EDID_BLOCK_SIZE ||
|
||||
size > EDID_MAX_BLOCK_COUNT * EDID_BLOCK_SIZE ||
|
||||
|
@ -163,6 +229,16 @@ di_edid_parse(const void *data, size_t size)
|
|||
|
||||
parse_vendor_product(data, &edid->vendor_product);
|
||||
|
||||
for (i = 0; i < EDID_BYTE_DESCRIPTOR_COUNT; i++) {
|
||||
byte_desc_data = (const uint8_t *) data
|
||||
+ 0x36 + i * EDID_BYTE_DESCRIPTOR_SIZE;
|
||||
if (!parse_byte_descriptor(edid, byte_desc_data)
|
||||
&& errno != ENOTSUP) {
|
||||
di_edid_destroy(edid);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < exts_len; i++) {
|
||||
ext_data = (const uint8_t *) data + (i + 1) * EDID_BLOCK_SIZE;
|
||||
if (!parse_ext(edid, ext_data) && errno != ENOTSUP) {
|
||||
|
@ -179,6 +255,10 @@ di_edid_destroy(struct di_edid *edid)
|
|||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < edid->display_descriptors_len; i++) {
|
||||
free(edid->display_descriptors[i]);
|
||||
}
|
||||
|
||||
for (i = 0; edid->exts[i] != NULL; i++) {
|
||||
free(edid->exts[i]);
|
||||
}
|
||||
|
@ -204,6 +284,18 @@ di_edid_get_vendor_product(const struct di_edid *edid)
|
|||
return &edid->vendor_product;
|
||||
}
|
||||
|
||||
const struct di_edid_display_descriptor *const *
|
||||
di_edid_get_display_descriptors(const struct di_edid *edid)
|
||||
{
|
||||
return (const struct di_edid_display_descriptor *const *) &edid->display_descriptors;
|
||||
}
|
||||
|
||||
enum di_edid_display_descriptor_tag
|
||||
di_edid_display_descriptor_get_tag(const struct di_edid_display_descriptor *desc)
|
||||
{
|
||||
return desc->tag;
|
||||
}
|
||||
|
||||
const struct di_edid_ext *const *
|
||||
di_edid_get_extensions(const struct di_edid *edid)
|
||||
{
|
||||
|
|
|
@ -14,15 +14,26 @@
|
|||
* section 2.2.1.
|
||||
*/
|
||||
#define EDID_MAX_BLOCK_COUNT 256
|
||||
/**
|
||||
* The number of EDID byte descriptors, defined in section 3.10.
|
||||
*/
|
||||
#define EDID_BYTE_DESCRIPTOR_COUNT 4
|
||||
|
||||
struct di_edid {
|
||||
struct di_edid_vendor_product vendor_product;
|
||||
int version, revision;
|
||||
/* NULL-terminated */
|
||||
struct di_edid_display_descriptor *display_descriptors[EDID_BYTE_DESCRIPTOR_COUNT + 1];
|
||||
size_t display_descriptors_len;
|
||||
/* NULL-terminated, doesn't include the base block */
|
||||
struct di_edid_ext *exts[EDID_MAX_BLOCK_COUNT];
|
||||
size_t exts_len;
|
||||
};
|
||||
|
||||
struct di_edid_display_descriptor {
|
||||
enum di_edid_display_descriptor_tag tag;
|
||||
};
|
||||
|
||||
struct di_edid_ext {
|
||||
enum di_edid_ext_tag tag;
|
||||
};
|
||||
|
|
|
@ -46,6 +46,51 @@ struct di_edid_vendor_product {
|
|||
const struct di_edid_vendor_product *
|
||||
di_edid_get_vendor_product(const struct di_edid *edid);
|
||||
|
||||
/**
|
||||
* EDID display descriptor tag, defined in section 3.10.3.
|
||||
*/
|
||||
enum di_edid_display_descriptor_tag {
|
||||
/* Display Product Serial Number */
|
||||
DI_EDID_DISPLAY_DESCRIPTOR_PRODUCT_SERIAL = 0xFF,
|
||||
/* Alphanumeric Data String (ASCII) */
|
||||
DI_EDID_DISPLAY_DESCRIPTOR_DATA_STRING = 0xFE,
|
||||
/* Display Range Limits */
|
||||
DI_EDID_DISPLAY_DESCRIPTOR_RANGE_LIMITS = 0xFD,
|
||||
/* Display Product Name */
|
||||
DI_EDID_DISPLAY_DESCRIPTOR_PRODUCT_NAME = 0xFC,
|
||||
/* Color Point Data */
|
||||
DI_EDID_DISPLAY_DESCRIPTOR_COLOR_POINT = 0xFB,
|
||||
/* Standard Timing Identifications */
|
||||
DI_EDID_DISPLAY_DESCRIPTOR_STD_TIMING_IDS = 0xFA,
|
||||
/* Display Color Management (DCM) Data */
|
||||
DI_EDID_DISPLAY_DESCRIPTOR_DCM_DATA = 0xF9,
|
||||
/* CVT 3 Byte Timing Codes */
|
||||
DI_EDID_DISPLAY_DESCRIPTOR_CVT_TIMING_CODES = 0xF8,
|
||||
/* Established Timings III */
|
||||
DI_EDID_DISPLAY_DESCRIPTOR_ESTABLISHED_TIMINGS_III = 0xF7,
|
||||
/* Dummy Descriptor */
|
||||
DI_EDID_DISPLAY_DESCRIPTOR_DUMMY = 0x10,
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a list of EDID display descriptors.
|
||||
*
|
||||
* The returned array is NULL-terminated.
|
||||
*/
|
||||
const struct di_edid_display_descriptor *const *
|
||||
di_edid_get_display_descriptors(const struct di_edid *edid);
|
||||
|
||||
/**
|
||||
* EDID display descriptor.
|
||||
*/
|
||||
struct di_edid_display_descriptor;
|
||||
|
||||
/**
|
||||
* Get the tag of an EDID display descriptor.
|
||||
*/
|
||||
enum di_edid_display_descriptor_tag
|
||||
di_edid_display_descriptor_get_tag(const struct di_edid_display_descriptor *desc);
|
||||
|
||||
/**
|
||||
* Get a list of EDID extensions.
|
||||
*
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
--- ref
|
||||
+++ di
|
||||
@@ -5,39 +5,4 @@
|
||||
@@ -5,39 +5,8 @@
|
||||
Model: 41003
|
||||
Serial Number: 842091859
|
||||
Made in: week 47 of 2008
|
||||
|
@ -31,12 +31,14 @@
|
|||
- DMT 0x23: 1280x1024 60.019740 Hz 5:4 63.981 kHz 108.000000 MHz
|
||||
- DMT 0x33: 1600x1200 60.000000 Hz 4:3 75.000 kHz 162.000000 MHz
|
||||
- DMT 0x15: 1152x864 75.000000 Hz 4:3 67.500 kHz 108.000000 MHz
|
||||
- Detailed Timing Descriptors:
|
||||
Detailed Timing Descriptors:
|
||||
- DTD 1: 1920x1200 59.950171 Hz 8:5 74.038 kHz 154.000000 MHz (519 mm x 320 mm)
|
||||
- Hfront 48 Hsync 32 Hback 80 Hpol P
|
||||
- Vfront 3 Vsync 6 Vback 26 Vpol N
|
||||
- Display Product Serial Number: 'G283H8BI21MS'
|
||||
- Display Product Name: 'DELL 2408WFP'
|
||||
- Display Range Limits:
|
||||
+ Display Product Serial Number:
|
||||
+ Display Product Name:
|
||||
Display Range Limits:
|
||||
- Monitor ranges (Bare Limits): 56-76 Hz V, 30-83 kHz H, max dotclock 170 MHz
|
||||
Checksum: 0x92
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
--- ref
|
||||
+++ di
|
||||
@@ -5,103 +5,10 @@
|
||||
@@ -5,103 +5,14 @@
|
||||
Model: 13847
|
||||
Serial Number: 16843009
|
||||
Made in: week 12 of 2019
|
||||
|
@ -30,14 +30,16 @@
|
|||
- DMT 0x2f: 1440x900 59.887445 Hz 16:10 55.935 kHz 106.500000 MHz
|
||||
- DMT 0x33: 1600x1200 60.000000 Hz 4:3 75.000 kHz 162.000000 MHz
|
||||
- DMT 0x23: 1280x1024 60.019740 Hz 5:4 63.981 kHz 108.000000 MHz
|
||||
- Detailed Timing Descriptors:
|
||||
Detailed Timing Descriptors:
|
||||
- DTD 1: 2560x1440 59.950550 Hz 16:9 88.787 kHz 241.500000 MHz (597 mm x 339 mm)
|
||||
- Hfront 48 Hsync 32 Hback 80 Hpol P
|
||||
- Vfront 3 Vsync 5 Vback 33 Vpol N
|
||||
- Display Range Limits:
|
||||
Display Range Limits:
|
||||
- Monitor ranges (GTF): 46-75 Hz V, 30-112 kHz H, max dotclock 310 MHz
|
||||
- Display Product Name: 'HP 27 QD'
|
||||
- Display Product Serial Number: 'CN49120J6N'
|
||||
+ Display Product Name:
|
||||
+ Display Product Serial Number:
|
||||
Extension blocks: 1
|
||||
Checksum: 0x20
|
||||
|
||||
|
|
Loading…
Reference in a new issue