1 #include <assert.h>
2 #include <inttypes.h>
3 #include <math.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <getopt.h>
7
8 #include <libdisplay-info/displayid.h>
9 #include <libdisplay-info/edid.h>
10 #include <libdisplay-info/info.h>
11
12 #include "di-edid-decode.h"
13
14 struct uncommon_features uncommon_features = {0};
15
16 static const struct option long_options[] = {
17 { "help", no_argument, 0, 'h' },
18 { 0, 0, 0, 0 }
19 };
20
usage(void)21 static void usage(void)
22 {
23 fprintf(stderr, "Usage: di-edid-decode <options> [in]\n"
24 " [in]: EDID file to parse. Read from standard input (stdin),\n"
25 " if none given.\n"
26 "Example : di-edid-decode /sys/class/drm/card0-DP-2/edid \n"
27 "\nOptions:\n"
28 "-h, --help display the help message\n");
29 }
30
31 static const char *
ext_tag_name(enum di_edid_ext_tag tag)32 ext_tag_name(enum di_edid_ext_tag tag)
33 {
34 switch (tag) {
35 case DI_EDID_EXT_CEA:
36 return "CTA-861 Extension Block";
37 case DI_EDID_EXT_VTB:
38 return "Video Timing Extension Block";
39 case DI_EDID_EXT_DI:
40 return "Display Information Extension Block";
41 case DI_EDID_EXT_LS:
42 return "Localized String Extension Block";
43 case DI_EDID_EXT_DPVL:
44 return "Digital Packet Video Link Extension";
45 case DI_EDID_EXT_BLOCK_MAP:
46 return "Block Map Extension Block";
47 case DI_EDID_EXT_VENDOR:
48 return "Manufacturer-Specific Extension Block";
49 case DI_EDID_EXT_DISPLAYID:
50 return "DisplayID Extension Block";
51 }
52 abort();
53 }
54
55 static void
print_ext(const struct di_edid_ext * ext,size_t ext_index)56 print_ext(const struct di_edid_ext *ext, size_t ext_index)
57 {
58 const char *tag_name;
59
60 tag_name = ext_tag_name(di_edid_ext_get_tag(ext));
61 printf("\n----------------\n\n");
62 printf("Block %zu, %s:\n", ext_index + 1, tag_name);
63
64 switch (di_edid_ext_get_tag(ext)) {
65 case DI_EDID_EXT_CEA:
66 print_cta(di_edid_ext_get_cta(ext));
67 break;
68 case DI_EDID_EXT_DISPLAYID:
69 print_displayid(di_edid_ext_get_displayid(ext));
70 break;
71 default:
72 break; /* Ignore */
73 }
74 }
75
76 static size_t
edid_checksum_index(size_t block_index)77 edid_checksum_index(size_t block_index)
78 {
79 return 128 * (block_index + 1) - 1;
80 }
81
82 int
main(int argc,char * argv[])83 main(int argc, char *argv[])
84 {
85 FILE *in;
86 static uint8_t raw[32 * 1024];
87 size_t size = 0;
88 const struct di_edid *edid;
89 struct di_info *info;
90 const struct di_edid_ext *const *exts;
91 const char *failure_msg;
92 size_t i;
93 int opt;
94
95 in = stdin;
96 while (1) {
97 int option_index = 0;
98 opt = getopt_long(argc, argv, "h", long_options, &option_index);
99 if (opt == -1)
100 break;
101
102 switch (opt) {
103 case 'h':
104 usage();
105 return -1;
106 default:
107 usage();
108 return -1;
109 }
110 }
111
112 if (argc > 1) {
113 in = fopen(argv[1], "r");
114 if (!in) {
115 perror("failed to open input file");
116 return 1;
117 }
118 }
119
120 while (!feof(in)) {
121 size += fread(&raw[size], 1, sizeof(raw) - size, in);
122 if (ferror(in)) {
123 perror("fread failed");
124 return 1;
125 } else if (size >= sizeof(raw)) {
126 fprintf(stderr, "input too large\n");
127 return 1;
128 }
129 }
130
131 fclose(in);
132
133 info = di_info_parse_edid(raw, size);
134 if (!info) {
135 perror("di_edid_parse failed");
136 return 1;
137 }
138
139 edid = di_info_get_edid(info);
140 print_edid(edid);
141
142 exts = di_edid_get_extensions(edid);
143
144 for (i = 0; exts[i] != NULL; i++);
145 if (i > 0) {
146 printf(" Extension blocks: %zu\n", i);
147 }
148
149 printf("Checksum: 0x%02hhx\n", raw[edid_checksum_index(0)]);
150
151 for (i = 0; exts[i] != NULL; i++) {
152 print_ext(exts[i], i);
153 printf("Checksum: 0x%02hhx\n", raw[edid_checksum_index(i + 1)]);
154 }
155
156 printf("\n----------------\n\n");
157
158 failure_msg = di_info_get_failure_msg(info);
159 if (failure_msg) {
160 printf("Failures:\n\n%s", failure_msg);
161 printf("EDID conformity: FAIL\n");
162 } else {
163 printf("EDID conformity: PASS\n");
164 }
165
166 if (uncommon_features.color_point_descriptor) {
167 fprintf(stderr, "The EDID blob contains an uncommon Color "
168 "Point Descriptor. Please share the EDID blob "
169 "with upstream!\n");
170 }
171 if (uncommon_features.color_management_data) {
172 fprintf(stderr, "The EDID blob contains an uncommon Color "
173 "Management Data Descriptor. Please share the "
174 "EDID blob with upstream!\n");
175 }
176 if (uncommon_features.cta_transfer_characteristics) {
177 fprintf(stderr, "The EDID blob contains an uncommon CTA VESA "
178 "Display Transfer Characteristic data block. "
179 "Please share the EDID blob with upstream!\n");
180 }
181
182 di_info_destroy(info);
183 return failure_msg ? 254 : 0;
184 }
185