libdisplay-info/di-edid-decode/main.c

185 lines
4.1 KiB
C
Raw Normal View History

#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;
}