mirror of
https://gitlab.freedesktop.org/emersion/libdisplay-info.git
synced 2024-12-26 21:59:15 +01:00
185 lines
4.1 KiB
C
185 lines
4.1 KiB
C
|
#include <assert.h>
|
||
|
#include <inttypes.h>
|
||
|
#include <math.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <getopt.h>
|
||
|
|
||
|
#include <libdisplay-info/displayid.h>
|
||
|
#include <libdisplay-info/edid.h>
|
||
|
#include <libdisplay-info/info.h>
|
||
|
|
||
|
#include "di-edid-decode.h"
|
||
|
|
||
|
struct uncommon_features uncommon_features = {0};
|
||
|
|
||
|
static const struct option long_options[] = {
|
||
|
{ "help", no_argument, 0, 'h' },
|
||
|
{ 0, 0, 0, 0 }
|
||
|
};
|
||
|
|
||
|
static void usage(void)
|
||
|
{
|
||
|
fprintf(stderr, "Usage: di-edid-decode <options> [in]\n"
|
||
|
" [in]: EDID file to parse. Read from standard input (stdin),\n"
|
||
|
" if none given.\n"
|
||
|
"Example : di-edid-decode /sys/class/drm/card0-DP-2/edid \n"
|
||
|
"\nOptions:\n"
|
||
|
"-h, --help display the help message\n");
|
||
|
}
|
||
|
|
||
|
static const char *
|
||
|
ext_tag_name(enum di_edid_ext_tag tag)
|
||
|
{
|
||
|
switch (tag) {
|
||
|
case DI_EDID_EXT_CEA:
|
||
|
return "CTA-861 Extension Block";
|
||
|
case DI_EDID_EXT_VTB:
|
||
|
return "Video Timing Extension Block";
|
||
|
case DI_EDID_EXT_DI:
|
||
|
return "Display Information Extension Block";
|
||
|
case DI_EDID_EXT_LS:
|
||
|
return "Localized String Extension Block";
|
||
|
case DI_EDID_EXT_DPVL:
|
||
|
return "Digital Packet Video Link Extension";
|
||
|
case DI_EDID_EXT_BLOCK_MAP:
|
||
|
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();
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
print_ext(const struct di_edid_ext *ext, size_t ext_index)
|
||
|
{
|
||
|
const char *tag_name;
|
||
|
|
||
|
tag_name = ext_tag_name(di_edid_ext_get_tag(ext));
|
||
|
printf("\n----------------\n\n");
|
||
|
printf("Block %zu, %s:\n", ext_index + 1, tag_name);
|
||
|
|
||
|
switch (di_edid_ext_get_tag(ext)) {
|
||
|
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 */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static size_t
|
||
|
edid_checksum_index(size_t block_index)
|
||
|
{
|
||
|
return 128 * (block_index + 1) - 1;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
main(int argc, char *argv[])
|
||
|
{
|
||
|
FILE *in;
|
||
|
static uint8_t raw[32 * 1024];
|
||
|
size_t size = 0;
|
||
|
const struct di_edid *edid;
|
||
|
struct di_info *info;
|
||
|
const struct di_edid_ext *const *exts;
|
||
|
const char *failure_msg;
|
||
|
size_t i;
|
||
|
int opt;
|
||
|
|
||
|
in = stdin;
|
||
|
while (1) {
|
||
|
int option_index = 0;
|
||
|
opt = getopt_long(argc, argv, "h", long_options, &option_index);
|
||
|
if (opt == -1)
|
||
|
break;
|
||
|
|
||
|
switch (opt) {
|
||
|
case 'h':
|
||
|
usage();
|
||
|
return -1;
|
||
|
default:
|
||
|
usage();
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (argc > 1) {
|
||
|
in = fopen(argv[1], "r");
|
||
|
if (!in) {
|
||
|
perror("failed to open input file");
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while (!feof(in)) {
|
||
|
size += fread(&raw[size], 1, sizeof(raw) - size, in);
|
||
|
if (ferror(in)) {
|
||
|
perror("fread failed");
|
||
|
return 1;
|
||
|
} else if (size >= sizeof(raw)) {
|
||
|
fprintf(stderr, "input too large\n");
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fclose(in);
|
||
|
|
||
|
info = di_info_parse_edid(raw, size);
|
||
|
if (!info) {
|
||
|
perror("di_edid_parse failed");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
edid = di_info_get_edid(info);
|
||
|
print_edid(edid);
|
||
|
|
||
|
exts = di_edid_get_extensions(edid);
|
||
|
|
||
|
for (i = 0; exts[i] != NULL; i++);
|
||
|
if (i > 0) {
|
||
|
printf(" Extension blocks: %zu\n", i);
|
||
|
}
|
||
|
|
||
|
printf("Checksum: 0x%02hhx\n", raw[edid_checksum_index(0)]);
|
||
|
|
||
|
for (i = 0; exts[i] != NULL; i++) {
|
||
|
print_ext(exts[i], i);
|
||
|
printf("Checksum: 0x%02hhx\n", raw[edid_checksum_index(i + 1)]);
|
||
|
}
|
||
|
|
||
|
printf("\n----------------\n\n");
|
||
|
|
||
|
failure_msg = di_info_get_failure_msg(info);
|
||
|
if (failure_msg) {
|
||
|
printf("Failures:\n\n%s", failure_msg);
|
||
|
printf("EDID conformity: FAIL\n");
|
||
|
} else {
|
||
|
printf("EDID conformity: PASS\n");
|
||
|
}
|
||
|
|
||
|
if (uncommon_features.color_point_descriptor) {
|
||
|
fprintf(stderr, "The EDID blob contains an uncommon Color "
|
||
|
"Point Descriptor. Please share the EDID blob "
|
||
|
"with upstream!\n");
|
||
|
}
|
||
|
if (uncommon_features.color_management_data) {
|
||
|
fprintf(stderr, "The EDID blob contains an uncommon Color "
|
||
|
"Management Data Descriptor. Please share the "
|
||
|
"EDID blob with upstream!\n");
|
||
|
}
|
||
|
if (uncommon_features.cta_transfer_characteristics) {
|
||
|
fprintf(stderr, "The EDID blob contains an uncommon CTA VESA "
|
||
|
"Display Transfer Characteristic data block. "
|
||
|
"Please share the EDID blob with upstream!\n");
|
||
|
}
|
||
|
|
||
|
di_info_destroy(info);
|
||
|
return failure_msg ? 254 : 0;
|
||
|
}
|