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