1*193032a3SAndroid Build Coastguard Worker // SPDX-License-Identifier: MIT
2*193032a3SAndroid Build Coastguard Worker /*
3*193032a3SAndroid Build Coastguard Worker * Copyright 2006-2012 Red Hat, Inc.
4*193032a3SAndroid Build Coastguard Worker * Copyright 2018-2020 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5*193032a3SAndroid Build Coastguard Worker *
6*193032a3SAndroid Build Coastguard Worker * Author: Adam Jackson <[email protected]>
7*193032a3SAndroid Build Coastguard Worker * Maintainer: Hans Verkuil <[email protected]>
8*193032a3SAndroid Build Coastguard Worker */
9*193032a3SAndroid Build Coastguard Worker
10*193032a3SAndroid Build Coastguard Worker #include <ctype.h>
11*193032a3SAndroid Build Coastguard Worker #include <fcntl.h>
12*193032a3SAndroid Build Coastguard Worker #include <getopt.h>
13*193032a3SAndroid Build Coastguard Worker #include <math.h>
14*193032a3SAndroid Build Coastguard Worker #include <stdarg.h>
15*193032a3SAndroid Build Coastguard Worker #include <stdio.h>
16*193032a3SAndroid Build Coastguard Worker #include <stdlib.h>
17*193032a3SAndroid Build Coastguard Worker #include <unistd.h>
18*193032a3SAndroid Build Coastguard Worker
19*193032a3SAndroid Build Coastguard Worker #include "edid-decode.h"
20*193032a3SAndroid Build Coastguard Worker
21*193032a3SAndroid Build Coastguard Worker #define STR(x) #x
22*193032a3SAndroid Build Coastguard Worker #define STRING(x) STR(x)
23*193032a3SAndroid Build Coastguard Worker
24*193032a3SAndroid Build Coastguard Worker static edid_state state;
25*193032a3SAndroid Build Coastguard Worker
26*193032a3SAndroid Build Coastguard Worker static unsigned char edid[EDID_PAGE_SIZE * EDID_MAX_BLOCKS];
27*193032a3SAndroid Build Coastguard Worker static bool odd_hex_digits;
28*193032a3SAndroid Build Coastguard Worker
29*193032a3SAndroid Build Coastguard Worker enum output_format {
30*193032a3SAndroid Build Coastguard Worker OUT_FMT_DEFAULT,
31*193032a3SAndroid Build Coastguard Worker OUT_FMT_HEX,
32*193032a3SAndroid Build Coastguard Worker OUT_FMT_RAW,
33*193032a3SAndroid Build Coastguard Worker OUT_FMT_CARRAY,
34*193032a3SAndroid Build Coastguard Worker OUT_FMT_XML,
35*193032a3SAndroid Build Coastguard Worker };
36*193032a3SAndroid Build Coastguard Worker
37*193032a3SAndroid Build Coastguard Worker /*
38*193032a3SAndroid Build Coastguard Worker * Options
39*193032a3SAndroid Build Coastguard Worker * Please keep in alphabetical order of the short option.
40*193032a3SAndroid Build Coastguard Worker * That makes it easier to see which options are still free.
41*193032a3SAndroid Build Coastguard Worker */
42*193032a3SAndroid Build Coastguard Worker enum Option {
43*193032a3SAndroid Build Coastguard Worker OptCheck = 'c',
44*193032a3SAndroid Build Coastguard Worker OptCheckInline = 'C',
45*193032a3SAndroid Build Coastguard Worker OptFBModeTimings = 'F',
46*193032a3SAndroid Build Coastguard Worker OptHelp = 'h',
47*193032a3SAndroid Build Coastguard Worker OptOnlyHexDump = 'H',
48*193032a3SAndroid Build Coastguard Worker OptLongTimings = 'L',
49*193032a3SAndroid Build Coastguard Worker OptNativeTimings = 'n',
50*193032a3SAndroid Build Coastguard Worker OptOutputFormat = 'o',
51*193032a3SAndroid Build Coastguard Worker OptPreferredTimings = 'p',
52*193032a3SAndroid Build Coastguard Worker OptPhysicalAddress = 'P',
53*193032a3SAndroid Build Coastguard Worker OptSkipHexDump = 's',
54*193032a3SAndroid Build Coastguard Worker OptShortTimings = 'S',
55*193032a3SAndroid Build Coastguard Worker OptV4L2Timings = 'V',
56*193032a3SAndroid Build Coastguard Worker OptXModeLineTimings = 'X',
57*193032a3SAndroid Build Coastguard Worker OptSkipSHA = 128,
58*193032a3SAndroid Build Coastguard Worker OptHideSerialNumbers,
59*193032a3SAndroid Build Coastguard Worker OptVersion,
60*193032a3SAndroid Build Coastguard Worker OptSTD,
61*193032a3SAndroid Build Coastguard Worker OptDMT,
62*193032a3SAndroid Build Coastguard Worker OptVIC,
63*193032a3SAndroid Build Coastguard Worker OptHDMIVIC,
64*193032a3SAndroid Build Coastguard Worker OptCVT,
65*193032a3SAndroid Build Coastguard Worker OptGTF,
66*193032a3SAndroid Build Coastguard Worker OptListEstTimings,
67*193032a3SAndroid Build Coastguard Worker OptListDMTs,
68*193032a3SAndroid Build Coastguard Worker OptListVICs,
69*193032a3SAndroid Build Coastguard Worker OptListHDMIVICs,
70*193032a3SAndroid Build Coastguard Worker OptLast = 256
71*193032a3SAndroid Build Coastguard Worker };
72*193032a3SAndroid Build Coastguard Worker
73*193032a3SAndroid Build Coastguard Worker static char options[OptLast];
74*193032a3SAndroid Build Coastguard Worker
75*193032a3SAndroid Build Coastguard Worker static struct option long_options[] = {
76*193032a3SAndroid Build Coastguard Worker { "help", no_argument, 0, OptHelp },
77*193032a3SAndroid Build Coastguard Worker { "output-format", required_argument, 0, OptOutputFormat },
78*193032a3SAndroid Build Coastguard Worker { "native-timings", no_argument, 0, OptNativeTimings },
79*193032a3SAndroid Build Coastguard Worker { "preferred-timings", no_argument, 0, OptPreferredTimings },
80*193032a3SAndroid Build Coastguard Worker { "physical-address", no_argument, 0, OptPhysicalAddress },
81*193032a3SAndroid Build Coastguard Worker { "skip-hex-dump", no_argument, 0, OptSkipHexDump },
82*193032a3SAndroid Build Coastguard Worker { "only-hex-dump", no_argument, 0, OptOnlyHexDump },
83*193032a3SAndroid Build Coastguard Worker { "skip-sha", no_argument, 0, OptSkipSHA },
84*193032a3SAndroid Build Coastguard Worker { "hide-serial-numbers", no_argument, 0, OptHideSerialNumbers },
85*193032a3SAndroid Build Coastguard Worker { "version", no_argument, 0, OptVersion },
86*193032a3SAndroid Build Coastguard Worker { "check-inline", no_argument, 0, OptCheckInline },
87*193032a3SAndroid Build Coastguard Worker { "check", no_argument, 0, OptCheck },
88*193032a3SAndroid Build Coastguard Worker { "short-timings", no_argument, 0, OptShortTimings },
89*193032a3SAndroid Build Coastguard Worker { "long-timings", no_argument, 0, OptLongTimings },
90*193032a3SAndroid Build Coastguard Worker { "xmodeline", no_argument, 0, OptXModeLineTimings },
91*193032a3SAndroid Build Coastguard Worker { "fbmode", no_argument, 0, OptFBModeTimings },
92*193032a3SAndroid Build Coastguard Worker { "v4l2-timings", no_argument, 0, OptV4L2Timings },
93*193032a3SAndroid Build Coastguard Worker { "std", required_argument, 0, OptSTD },
94*193032a3SAndroid Build Coastguard Worker { "dmt", required_argument, 0, OptDMT },
95*193032a3SAndroid Build Coastguard Worker { "vic", required_argument, 0, OptVIC },
96*193032a3SAndroid Build Coastguard Worker { "hdmi-vic", required_argument, 0, OptHDMIVIC },
97*193032a3SAndroid Build Coastguard Worker { "cvt", required_argument, 0, OptCVT },
98*193032a3SAndroid Build Coastguard Worker { "gtf", required_argument, 0, OptGTF },
99*193032a3SAndroid Build Coastguard Worker { "list-established-timings", no_argument, 0, OptListEstTimings },
100*193032a3SAndroid Build Coastguard Worker { "list-dmts", no_argument, 0, OptListDMTs },
101*193032a3SAndroid Build Coastguard Worker { "list-vics", no_argument, 0, OptListVICs },
102*193032a3SAndroid Build Coastguard Worker { "list-hdmi-vics", no_argument, 0, OptListHDMIVICs },
103*193032a3SAndroid Build Coastguard Worker { 0, 0, 0, 0 }
104*193032a3SAndroid Build Coastguard Worker };
105*193032a3SAndroid Build Coastguard Worker
usage(void)106*193032a3SAndroid Build Coastguard Worker static void usage(void)
107*193032a3SAndroid Build Coastguard Worker {
108*193032a3SAndroid Build Coastguard Worker printf("Usage: edid-decode <options> [in [out]]\n"
109*193032a3SAndroid Build Coastguard Worker " [in] EDID file to parse. Read from standard input if none given\n"
110*193032a3SAndroid Build Coastguard Worker " or if the input filename is '-'.\n"
111*193032a3SAndroid Build Coastguard Worker " [out] Output the read EDID to this file. Write to standard output\n"
112*193032a3SAndroid Build Coastguard Worker " if the output filename is '-'.\n"
113*193032a3SAndroid Build Coastguard Worker "\nOptions:\n"
114*193032a3SAndroid Build Coastguard Worker " -o, --output-format <fmt>\n"
115*193032a3SAndroid Build Coastguard Worker " If [out] is specified, then write the EDID in this format\n"
116*193032a3SAndroid Build Coastguard Worker " <fmt> is one of:\n"
117*193032a3SAndroid Build Coastguard Worker " hex: hex numbers in ascii text (default for stdout)\n"
118*193032a3SAndroid Build Coastguard Worker " raw: binary data (default unless writing to stdout)\n"
119*193032a3SAndroid Build Coastguard Worker " carray: c-program struct\n"
120*193032a3SAndroid Build Coastguard Worker " xml: XML data\n"
121*193032a3SAndroid Build Coastguard Worker " -c, --check Check if the EDID conforms to the standards, failures and\n"
122*193032a3SAndroid Build Coastguard Worker " warnings are reported at the end.\n"
123*193032a3SAndroid Build Coastguard Worker " -C, --check-inline Check if the EDID conforms to the standards, failures and\n"
124*193032a3SAndroid Build Coastguard Worker " warnings are reported inline.\n"
125*193032a3SAndroid Build Coastguard Worker " -n, --native-timings Report the native timings.\n"
126*193032a3SAndroid Build Coastguard Worker " -p, --preferred-timings Report the preferred timings.\n"
127*193032a3SAndroid Build Coastguard Worker " -P, --physical-address Only report the CEC physical address.\n"
128*193032a3SAndroid Build Coastguard Worker " -S, --short-timings Report all video timings in a short format.\n"
129*193032a3SAndroid Build Coastguard Worker " -L, --long-timings Report all video timings in a long format.\n"
130*193032a3SAndroid Build Coastguard Worker " -X, --xmodeline Report all long video timings in Xorg.conf format.\n"
131*193032a3SAndroid Build Coastguard Worker " -F, --fbmode Report all long video timings in fb.modes format.\n"
132*193032a3SAndroid Build Coastguard Worker " -V, --v4l2-timings Report all long video timings in v4l2-dv-timings.h format.\n"
133*193032a3SAndroid Build Coastguard Worker " -s, --skip-hex-dump Skip the initial hex dump of the EDID.\n"
134*193032a3SAndroid Build Coastguard Worker " -H, --only-hex-dump Only output the hex dump of the EDID.\n"
135*193032a3SAndroid Build Coastguard Worker " --skip-sha Skip the SHA report.\n"
136*193032a3SAndroid Build Coastguard Worker " --hide-serial-numbers Replace serial numbers with '...'\n"
137*193032a3SAndroid Build Coastguard Worker " --version show the edid-decode version (SHA)\n"
138*193032a3SAndroid Build Coastguard Worker " --std <byte1>,<byte2> Show the standard timing represented by these two bytes.\n"
139*193032a3SAndroid Build Coastguard Worker " --dmt <dmt> Show the timings for the DMT with the given DMT ID.\n"
140*193032a3SAndroid Build Coastguard Worker " --vic <vic> Show the timings for this VIC.\n"
141*193032a3SAndroid Build Coastguard Worker " --hdmi-vic <hdmivic> Show the timings for this HDMI VIC.\n"
142*193032a3SAndroid Build Coastguard Worker " --cvt w=<width>,h=<height>,fps=<fps>[,rb=<rb>][,interlaced][,overscan][,alt][,hblank=<hblank]\n"
143*193032a3SAndroid Build Coastguard Worker " Calculate the CVT timings for the given format.\n"
144*193032a3SAndroid Build Coastguard Worker " <fps> is frames per second for progressive timings,\n"
145*193032a3SAndroid Build Coastguard Worker " or fields per second for interlaced timings.\n"
146*193032a3SAndroid Build Coastguard Worker " <rb> can be 0 (no reduced blanking, default), or\n"
147*193032a3SAndroid Build Coastguard Worker " 1-3 for the reduced blanking version.\n"
148*193032a3SAndroid Build Coastguard Worker " If 'interlaced' is given, then this is an interlaced format.\n"
149*193032a3SAndroid Build Coastguard Worker " If 'overscan' is given, then this is an overscanned format.\n"
150*193032a3SAndroid Build Coastguard Worker " If 'alt' is given and <rb>=2, then report the timings\n"
151*193032a3SAndroid Build Coastguard Worker " optimized for video: 1000 / 1001 * <fps>.\n"
152*193032a3SAndroid Build Coastguard Worker " If 'alt' is given and <rb>=3, then the horizontal blanking\n"
153*193032a3SAndroid Build Coastguard Worker " is 160 instead of 80 pixels.\n"
154*193032a3SAndroid Build Coastguard Worker " If 'hblank' is given and <rb>=3, then the horizontal blanking\n"
155*193032a3SAndroid Build Coastguard Worker " is <hblank> pixels (range of 80-200), overriding 'alt'.\n"
156*193032a3SAndroid Build Coastguard Worker " --gtf w=<width>,h=<height>[,fps=<fps>][,horfreq=<horfreq>][,pixclk=<pixclk>][,interlaced]\n"
157*193032a3SAndroid Build Coastguard Worker " [,overscan][,secondary][,C=<c>][,M=<m>][,K=<k>][,J=<j>]\n"
158*193032a3SAndroid Build Coastguard Worker " Calculate the GTF timings for the given format.\n"
159*193032a3SAndroid Build Coastguard Worker " <fps> is frames per second for progressive timings,\n"
160*193032a3SAndroid Build Coastguard Worker " or fields per second for interlaced timings.\n"
161*193032a3SAndroid Build Coastguard Worker " <horfreq> is the horizontal frequency in kHz.\n"
162*193032a3SAndroid Build Coastguard Worker " <pixclk> is the pixel clock frequency in MHz.\n"
163*193032a3SAndroid Build Coastguard Worker " Only one of fps, horfreq or pixclk must be given.\n"
164*193032a3SAndroid Build Coastguard Worker " If 'interlaced' is given, then this is an interlaced format.\n"
165*193032a3SAndroid Build Coastguard Worker " If 'overscan' is given, then this is an overscanned format.\n"
166*193032a3SAndroid Build Coastguard Worker " If 'secondary' is given, then the secondary GTF is used for\n"
167*193032a3SAndroid Build Coastguard Worker " reduced blanking, where <c>, <m>, <k> and <j> are parameters\n"
168*193032a3SAndroid Build Coastguard Worker " for the secondary curve.\n"
169*193032a3SAndroid Build Coastguard Worker " --list-established-timings List all known Established Timings.\n"
170*193032a3SAndroid Build Coastguard Worker " --list-dmts List all known DMTs.\n"
171*193032a3SAndroid Build Coastguard Worker " --list-vics List all known VICs.\n"
172*193032a3SAndroid Build Coastguard Worker " --list-hdmi-vics List all known HDMI VICs.\n"
173*193032a3SAndroid Build Coastguard Worker " -h, --help Display this help message.\n");
174*193032a3SAndroid Build Coastguard Worker }
175*193032a3SAndroid Build Coastguard Worker
176*193032a3SAndroid Build Coastguard Worker static std::string s_msgs[EDID_MAX_BLOCKS + 1][2];
177*193032a3SAndroid Build Coastguard Worker
msg(bool is_warn,const char * fmt,...)178*193032a3SAndroid Build Coastguard Worker void msg(bool is_warn, const char *fmt, ...)
179*193032a3SAndroid Build Coastguard Worker {
180*193032a3SAndroid Build Coastguard Worker char buf[1024] = "";
181*193032a3SAndroid Build Coastguard Worker va_list ap;
182*193032a3SAndroid Build Coastguard Worker
183*193032a3SAndroid Build Coastguard Worker va_start(ap, fmt);
184*193032a3SAndroid Build Coastguard Worker vsprintf(buf, fmt, ap);
185*193032a3SAndroid Build Coastguard Worker va_end(ap);
186*193032a3SAndroid Build Coastguard Worker
187*193032a3SAndroid Build Coastguard Worker if (is_warn)
188*193032a3SAndroid Build Coastguard Worker state.warnings++;
189*193032a3SAndroid Build Coastguard Worker else
190*193032a3SAndroid Build Coastguard Worker state.failures++;
191*193032a3SAndroid Build Coastguard Worker if (state.data_block.empty())
192*193032a3SAndroid Build Coastguard Worker s_msgs[state.block_nr][is_warn] += std::string(" ") + buf;
193*193032a3SAndroid Build Coastguard Worker else
194*193032a3SAndroid Build Coastguard Worker s_msgs[state.block_nr][is_warn] += " " + state.data_block + ": " + buf;
195*193032a3SAndroid Build Coastguard Worker
196*193032a3SAndroid Build Coastguard Worker if (options[OptCheckInline])
197*193032a3SAndroid Build Coastguard Worker printf("%s: %s", is_warn ? "WARN" : "FAIL", buf);
198*193032a3SAndroid Build Coastguard Worker }
199*193032a3SAndroid Build Coastguard Worker
show_msgs(bool is_warn)200*193032a3SAndroid Build Coastguard Worker static void show_msgs(bool is_warn)
201*193032a3SAndroid Build Coastguard Worker {
202*193032a3SAndroid Build Coastguard Worker printf("\n%s:\n\n", is_warn ? "Warnings" : "Failures");
203*193032a3SAndroid Build Coastguard Worker for (unsigned i = 0; i < state.num_blocks; i++) {
204*193032a3SAndroid Build Coastguard Worker if (s_msgs[i][is_warn].empty())
205*193032a3SAndroid Build Coastguard Worker continue;
206*193032a3SAndroid Build Coastguard Worker printf("Block %u, %s:\n%s",
207*193032a3SAndroid Build Coastguard Worker i, block_name(edid[i * EDID_PAGE_SIZE]).c_str(),
208*193032a3SAndroid Build Coastguard Worker s_msgs[i][is_warn].c_str());
209*193032a3SAndroid Build Coastguard Worker }
210*193032a3SAndroid Build Coastguard Worker if (s_msgs[EDID_MAX_BLOCKS][is_warn].empty())
211*193032a3SAndroid Build Coastguard Worker return;
212*193032a3SAndroid Build Coastguard Worker printf("EDID:\n%s",
213*193032a3SAndroid Build Coastguard Worker s_msgs[EDID_MAX_BLOCKS][is_warn].c_str());
214*193032a3SAndroid Build Coastguard Worker }
215*193032a3SAndroid Build Coastguard Worker
216*193032a3SAndroid Build Coastguard Worker
do_checksum(const char * prefix,const unsigned char * x,size_t len)217*193032a3SAndroid Build Coastguard Worker void do_checksum(const char *prefix, const unsigned char *x, size_t len)
218*193032a3SAndroid Build Coastguard Worker {
219*193032a3SAndroid Build Coastguard Worker unsigned char check = x[len - 1];
220*193032a3SAndroid Build Coastguard Worker unsigned char sum = 0;
221*193032a3SAndroid Build Coastguard Worker unsigned i;
222*193032a3SAndroid Build Coastguard Worker
223*193032a3SAndroid Build Coastguard Worker printf("%sChecksum: 0x%02hhx", prefix, check);
224*193032a3SAndroid Build Coastguard Worker
225*193032a3SAndroid Build Coastguard Worker for (i = 0; i < len-1; i++)
226*193032a3SAndroid Build Coastguard Worker sum += x[i];
227*193032a3SAndroid Build Coastguard Worker
228*193032a3SAndroid Build Coastguard Worker if ((unsigned char)(check + sum) != 0) {
229*193032a3SAndroid Build Coastguard Worker printf(" (should be 0x%02x)\n", -sum & 0xff);
230*193032a3SAndroid Build Coastguard Worker fail("Invalid checksum 0x%02x (should be 0x%02x).\n",
231*193032a3SAndroid Build Coastguard Worker check, -sum & 0xff);
232*193032a3SAndroid Build Coastguard Worker return;
233*193032a3SAndroid Build Coastguard Worker }
234*193032a3SAndroid Build Coastguard Worker printf("\n");
235*193032a3SAndroid Build Coastguard Worker }
236*193032a3SAndroid Build Coastguard Worker
gcd(unsigned a,unsigned b)237*193032a3SAndroid Build Coastguard Worker static unsigned gcd(unsigned a, unsigned b)
238*193032a3SAndroid Build Coastguard Worker {
239*193032a3SAndroid Build Coastguard Worker while (b) {
240*193032a3SAndroid Build Coastguard Worker unsigned t = b;
241*193032a3SAndroid Build Coastguard Worker
242*193032a3SAndroid Build Coastguard Worker b = a % b;
243*193032a3SAndroid Build Coastguard Worker a = t;
244*193032a3SAndroid Build Coastguard Worker }
245*193032a3SAndroid Build Coastguard Worker return a;
246*193032a3SAndroid Build Coastguard Worker }
247*193032a3SAndroid Build Coastguard Worker
calc_ratio(struct timings * t)248*193032a3SAndroid Build Coastguard Worker void calc_ratio(struct timings *t)
249*193032a3SAndroid Build Coastguard Worker {
250*193032a3SAndroid Build Coastguard Worker unsigned d = gcd(t->hact, t->vact);
251*193032a3SAndroid Build Coastguard Worker
252*193032a3SAndroid Build Coastguard Worker if (d == 0) {
253*193032a3SAndroid Build Coastguard Worker t->hratio = t->vratio = 0;
254*193032a3SAndroid Build Coastguard Worker return;
255*193032a3SAndroid Build Coastguard Worker }
256*193032a3SAndroid Build Coastguard Worker t->hratio = t->hact / d;
257*193032a3SAndroid Build Coastguard Worker t->vratio = t->vact / d;
258*193032a3SAndroid Build Coastguard Worker }
259*193032a3SAndroid Build Coastguard Worker
dtd_type(unsigned cnt)260*193032a3SAndroid Build Coastguard Worker std::string edid_state::dtd_type(unsigned cnt)
261*193032a3SAndroid Build Coastguard Worker {
262*193032a3SAndroid Build Coastguard Worker unsigned len = std::to_string(cta.preparsed_total_dtds).length();
263*193032a3SAndroid Build Coastguard Worker char buf[16];
264*193032a3SAndroid Build Coastguard Worker sprintf(buf, "DTD %*u", len, cnt);
265*193032a3SAndroid Build Coastguard Worker return buf;
266*193032a3SAndroid Build Coastguard Worker }
267*193032a3SAndroid Build Coastguard Worker
match_timings(const timings & t1,const timings & t2)268*193032a3SAndroid Build Coastguard Worker bool edid_state::match_timings(const timings &t1, const timings &t2)
269*193032a3SAndroid Build Coastguard Worker {
270*193032a3SAndroid Build Coastguard Worker if (t1.hact != t2.hact ||
271*193032a3SAndroid Build Coastguard Worker t1.vact != t2.vact ||
272*193032a3SAndroid Build Coastguard Worker t1.rb != t2.rb ||
273*193032a3SAndroid Build Coastguard Worker t1.interlaced != t2.interlaced ||
274*193032a3SAndroid Build Coastguard Worker t1.hfp != t2.hfp ||
275*193032a3SAndroid Build Coastguard Worker t1.hbp != t2.hbp ||
276*193032a3SAndroid Build Coastguard Worker t1.hsync != t2.hsync ||
277*193032a3SAndroid Build Coastguard Worker t1.pos_pol_hsync != t2.pos_pol_hsync ||
278*193032a3SAndroid Build Coastguard Worker t1.hratio != t2.hratio ||
279*193032a3SAndroid Build Coastguard Worker t1.vfp != t2.vfp ||
280*193032a3SAndroid Build Coastguard Worker t1.vbp != t2.vbp ||
281*193032a3SAndroid Build Coastguard Worker t1.vsync != t2.vsync ||
282*193032a3SAndroid Build Coastguard Worker t1.pos_pol_vsync != t2.pos_pol_vsync ||
283*193032a3SAndroid Build Coastguard Worker t1.vratio != t2.vratio ||
284*193032a3SAndroid Build Coastguard Worker t1.pixclk_khz != t2.pixclk_khz)
285*193032a3SAndroid Build Coastguard Worker return false;
286*193032a3SAndroid Build Coastguard Worker return true;
287*193032a3SAndroid Build Coastguard Worker }
288*193032a3SAndroid Build Coastguard Worker
or_str(std::string & s,const std::string & flag,unsigned & num_flags)289*193032a3SAndroid Build Coastguard Worker static void or_str(std::string &s, const std::string &flag, unsigned &num_flags)
290*193032a3SAndroid Build Coastguard Worker {
291*193032a3SAndroid Build Coastguard Worker if (!num_flags)
292*193032a3SAndroid Build Coastguard Worker s = flag;
293*193032a3SAndroid Build Coastguard Worker else if (num_flags % 2 == 0)
294*193032a3SAndroid Build Coastguard Worker s = s + " | \\\n\t\t" + flag;
295*193032a3SAndroid Build Coastguard Worker else
296*193032a3SAndroid Build Coastguard Worker s = s + " | " + flag;
297*193032a3SAndroid Build Coastguard Worker num_flags++;
298*193032a3SAndroid Build Coastguard Worker }
299*193032a3SAndroid Build Coastguard Worker
300*193032a3SAndroid Build Coastguard Worker /*
301*193032a3SAndroid Build Coastguard Worker * Return true if the timings are a close, but not identical,
302*193032a3SAndroid Build Coastguard Worker * match. The only differences allowed are polarities and
303*193032a3SAndroid Build Coastguard Worker * porches and syncs, provided the total blanking remains the
304*193032a3SAndroid Build Coastguard Worker * same.
305*193032a3SAndroid Build Coastguard Worker */
timings_close_match(const timings & t1,const timings & t2)306*193032a3SAndroid Build Coastguard Worker bool timings_close_match(const timings &t1, const timings &t2)
307*193032a3SAndroid Build Coastguard Worker {
308*193032a3SAndroid Build Coastguard Worker // We don't want to deal with borders, you're on your own
309*193032a3SAndroid Build Coastguard Worker // if you are using those.
310*193032a3SAndroid Build Coastguard Worker if (t1.hborder || t1.vborder ||
311*193032a3SAndroid Build Coastguard Worker t2.hborder || t2.vborder)
312*193032a3SAndroid Build Coastguard Worker return false;
313*193032a3SAndroid Build Coastguard Worker if (t1.hact != t2.hact || t1.vact != t2.vact ||
314*193032a3SAndroid Build Coastguard Worker t1.interlaced != t2.interlaced ||
315*193032a3SAndroid Build Coastguard Worker t1.pixclk_khz != t2.pixclk_khz ||
316*193032a3SAndroid Build Coastguard Worker t1.hfp + t1.hsync + t1.hbp != t2.hfp + t2.hsync + t2.hbp ||
317*193032a3SAndroid Build Coastguard Worker t1.vfp + t1.vsync + t1.vbp != t2.vfp + t2.vsync + t2.vbp)
318*193032a3SAndroid Build Coastguard Worker return false;
319*193032a3SAndroid Build Coastguard Worker if (t1.hfp == t2.hfp &&
320*193032a3SAndroid Build Coastguard Worker t1.hsync == t2.hsync &&
321*193032a3SAndroid Build Coastguard Worker t1.hbp == t2.hbp &&
322*193032a3SAndroid Build Coastguard Worker t1.pos_pol_hsync == t2.pos_pol_hsync &&
323*193032a3SAndroid Build Coastguard Worker t1.vfp == t2.vfp &&
324*193032a3SAndroid Build Coastguard Worker t1.vsync == t2.vsync &&
325*193032a3SAndroid Build Coastguard Worker t1.vbp == t2.vbp &&
326*193032a3SAndroid Build Coastguard Worker t1.pos_pol_vsync == t2.pos_pol_vsync)
327*193032a3SAndroid Build Coastguard Worker return false;
328*193032a3SAndroid Build Coastguard Worker return true;
329*193032a3SAndroid Build Coastguard Worker }
330*193032a3SAndroid Build Coastguard Worker
print_modeline(unsigned indent,const struct timings * t,double refresh)331*193032a3SAndroid Build Coastguard Worker static void print_modeline(unsigned indent, const struct timings *t, double refresh)
332*193032a3SAndroid Build Coastguard Worker {
333*193032a3SAndroid Build Coastguard Worker unsigned offset = (!t->even_vtotal && t->interlaced) ? 1 : 0;
334*193032a3SAndroid Build Coastguard Worker unsigned hfp = t->hborder + t->hfp;
335*193032a3SAndroid Build Coastguard Worker unsigned hbp = t->hborder + t->hbp;
336*193032a3SAndroid Build Coastguard Worker unsigned vfp = t->vborder + t->vfp;
337*193032a3SAndroid Build Coastguard Worker unsigned vbp = t->vborder + t->vbp;
338*193032a3SAndroid Build Coastguard Worker
339*193032a3SAndroid Build Coastguard Worker printf("%*sModeline \"%ux%u_%.2f%s\" %.3f %u %u %u %u %u %u %u %u %cHSync",
340*193032a3SAndroid Build Coastguard Worker indent, "",
341*193032a3SAndroid Build Coastguard Worker t->hact, t->vact, refresh,
342*193032a3SAndroid Build Coastguard Worker t->interlaced ? "i" : "", t->pixclk_khz / 1000.0,
343*193032a3SAndroid Build Coastguard Worker t->hact, t->hact + hfp, t->hact + hfp + t->hsync,
344*193032a3SAndroid Build Coastguard Worker t->hact + hfp + t->hsync + hbp,
345*193032a3SAndroid Build Coastguard Worker t->vact, t->vact + vfp, t->vact + vfp + t->vsync,
346*193032a3SAndroid Build Coastguard Worker t->vact + vfp + t->vsync + vbp + offset,
347*193032a3SAndroid Build Coastguard Worker t->pos_pol_hsync ? '+' : '-');
348*193032a3SAndroid Build Coastguard Worker if (!t->no_pol_vsync)
349*193032a3SAndroid Build Coastguard Worker printf(" %cVSync", t->pos_pol_vsync ? '+' : '-');
350*193032a3SAndroid Build Coastguard Worker if (t->interlaced)
351*193032a3SAndroid Build Coastguard Worker printf(" Interlace");
352*193032a3SAndroid Build Coastguard Worker printf("\n");
353*193032a3SAndroid Build Coastguard Worker }
354*193032a3SAndroid Build Coastguard Worker
print_fbmode(unsigned indent,const struct timings * t,double refresh,double hor_freq_khz)355*193032a3SAndroid Build Coastguard Worker static void print_fbmode(unsigned indent, const struct timings *t,
356*193032a3SAndroid Build Coastguard Worker double refresh, double hor_freq_khz)
357*193032a3SAndroid Build Coastguard Worker {
358*193032a3SAndroid Build Coastguard Worker printf("%*smode \"%ux%u-%u%s\"\n",
359*193032a3SAndroid Build Coastguard Worker indent, "",
360*193032a3SAndroid Build Coastguard Worker t->hact, t->vact,
361*193032a3SAndroid Build Coastguard Worker (unsigned)(0.5 + (t->interlaced ? refresh / 2.0 : refresh)),
362*193032a3SAndroid Build Coastguard Worker t->interlaced ? "-lace" : "");
363*193032a3SAndroid Build Coastguard Worker printf("%*s# D: %.2f MHz, H: %.3f kHz, V: %.2f Hz\n",
364*193032a3SAndroid Build Coastguard Worker indent + 8, "",
365*193032a3SAndroid Build Coastguard Worker t->pixclk_khz / 1000.0, hor_freq_khz, refresh);
366*193032a3SAndroid Build Coastguard Worker printf("%*sgeometry %u %u %u %u 32\n",
367*193032a3SAndroid Build Coastguard Worker indent + 8, "",
368*193032a3SAndroid Build Coastguard Worker t->hact, t->vact, t->hact, t->vact);
369*193032a3SAndroid Build Coastguard Worker unsigned mult = t->interlaced ? 2 : 1;
370*193032a3SAndroid Build Coastguard Worker unsigned offset = !t->even_vtotal && t->interlaced;
371*193032a3SAndroid Build Coastguard Worker unsigned hfp = t->hborder + t->hfp;
372*193032a3SAndroid Build Coastguard Worker unsigned hbp = t->hborder + t->hbp;
373*193032a3SAndroid Build Coastguard Worker unsigned vfp = t->vborder + t->vfp;
374*193032a3SAndroid Build Coastguard Worker unsigned vbp = t->vborder + t->vbp;
375*193032a3SAndroid Build Coastguard Worker printf("%*stimings %llu %d %d %d %u %u %u\n",
376*193032a3SAndroid Build Coastguard Worker indent + 8, "",
377*193032a3SAndroid Build Coastguard Worker (unsigned long long)(1000000000.0 / (double)(t->pixclk_khz) + 0.5),
378*193032a3SAndroid Build Coastguard Worker hbp, hfp, mult * vbp, mult * vfp + offset, t->hsync, mult * t->vsync);
379*193032a3SAndroid Build Coastguard Worker if (t->interlaced)
380*193032a3SAndroid Build Coastguard Worker printf("%*slaced true\n", indent + 8, "");
381*193032a3SAndroid Build Coastguard Worker if (t->pos_pol_hsync)
382*193032a3SAndroid Build Coastguard Worker printf("%*shsync high\n", indent + 8, "");
383*193032a3SAndroid Build Coastguard Worker if (t->pos_pol_vsync)
384*193032a3SAndroid Build Coastguard Worker printf("%*svsync high\n", indent + 8, "");
385*193032a3SAndroid Build Coastguard Worker printf("%*sendmode\n", indent, "");
386*193032a3SAndroid Build Coastguard Worker }
387*193032a3SAndroid Build Coastguard Worker
print_v4l2_timing(const struct timings * t,double refresh,const char * type)388*193032a3SAndroid Build Coastguard Worker static void print_v4l2_timing(const struct timings *t,
389*193032a3SAndroid Build Coastguard Worker double refresh, const char *type)
390*193032a3SAndroid Build Coastguard Worker {
391*193032a3SAndroid Build Coastguard Worker printf("\t#define V4L2_DV_BT_%uX%u%c%u_%02u { \\\n",
392*193032a3SAndroid Build Coastguard Worker t->hact, t->vact, t->interlaced ? 'I' : 'P',
393*193032a3SAndroid Build Coastguard Worker (unsigned)refresh, (unsigned)(0.5 + 100.0 * (refresh - (unsigned)refresh)));
394*193032a3SAndroid Build Coastguard Worker printf("\t\t.type = V4L2_DV_BT_656_1120, \\\n");
395*193032a3SAndroid Build Coastguard Worker printf("\t\tV4L2_INIT_BT_TIMINGS(%u, %u, %u, ",
396*193032a3SAndroid Build Coastguard Worker t->hact, t->vact, t->interlaced);
397*193032a3SAndroid Build Coastguard Worker if (!t->pos_pol_hsync && !t->pos_pol_vsync)
398*193032a3SAndroid Build Coastguard Worker printf("0, \\\n");
399*193032a3SAndroid Build Coastguard Worker else if (t->pos_pol_hsync && t->pos_pol_vsync)
400*193032a3SAndroid Build Coastguard Worker printf("\\\n\t\t\tV4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \\\n");
401*193032a3SAndroid Build Coastguard Worker else if (t->pos_pol_hsync)
402*193032a3SAndroid Build Coastguard Worker printf("V4L2_DV_HSYNC_POS_POL, \\\n");
403*193032a3SAndroid Build Coastguard Worker else
404*193032a3SAndroid Build Coastguard Worker printf("V4L2_DV_VSYNC_POS_POL, \\\n");
405*193032a3SAndroid Build Coastguard Worker unsigned hfp = t->hborder + t->hfp;
406*193032a3SAndroid Build Coastguard Worker unsigned hbp = t->hborder + t->hbp;
407*193032a3SAndroid Build Coastguard Worker unsigned vfp = t->vborder + t->vfp;
408*193032a3SAndroid Build Coastguard Worker unsigned vbp = t->vborder + t->vbp;
409*193032a3SAndroid Build Coastguard Worker printf("\t\t\t%lluULL, %d, %u, %d, %u, %u, %d, %u, %u, %d, \\\n",
410*193032a3SAndroid Build Coastguard Worker t->pixclk_khz * 1000ULL, hfp, t->hsync, hbp,
411*193032a3SAndroid Build Coastguard Worker vfp, t->vsync, vbp,
412*193032a3SAndroid Build Coastguard Worker t->interlaced ? vfp : 0,
413*193032a3SAndroid Build Coastguard Worker t->interlaced ? t->vsync : 0,
414*193032a3SAndroid Build Coastguard Worker t->interlaced ? vbp + !t->even_vtotal : 0);
415*193032a3SAndroid Build Coastguard Worker
416*193032a3SAndroid Build Coastguard Worker std::string flags;
417*193032a3SAndroid Build Coastguard Worker unsigned num_flags = 0;
418*193032a3SAndroid Build Coastguard Worker unsigned vic = 0;
419*193032a3SAndroid Build Coastguard Worker unsigned hdmi_vic = 0;
420*193032a3SAndroid Build Coastguard Worker const char *std = "0";
421*193032a3SAndroid Build Coastguard Worker
422*193032a3SAndroid Build Coastguard Worker if (t->interlaced && !t->even_vtotal)
423*193032a3SAndroid Build Coastguard Worker or_str(flags, "V4L2_DV_FL_HALF_LINE", num_flags);
424*193032a3SAndroid Build Coastguard Worker if (!memcmp(type, "VIC", 3)) {
425*193032a3SAndroid Build Coastguard Worker or_str(flags, "V4L2_DV_FL_HAS_CEA861_VIC", num_flags);
426*193032a3SAndroid Build Coastguard Worker or_str(flags, "V4L2_DV_FL_IS_CE_VIDEO", num_flags);
427*193032a3SAndroid Build Coastguard Worker vic = strtoul(type + 4, 0, 0);
428*193032a3SAndroid Build Coastguard Worker }
429*193032a3SAndroid Build Coastguard Worker if (!memcmp(type, "HDMI VIC", 8)) {
430*193032a3SAndroid Build Coastguard Worker or_str(flags, "V4L2_DV_FL_HAS_HDMI_VIC", num_flags);
431*193032a3SAndroid Build Coastguard Worker or_str(flags, "V4L2_DV_FL_IS_CE_VIDEO", num_flags);
432*193032a3SAndroid Build Coastguard Worker hdmi_vic = strtoul(type + 9, 0, 0);
433*193032a3SAndroid Build Coastguard Worker vic = hdmi_vic_to_vic(hdmi_vic);
434*193032a3SAndroid Build Coastguard Worker if (vic)
435*193032a3SAndroid Build Coastguard Worker or_str(flags, "V4L2_DV_FL_HAS_CEA861_VIC", num_flags);
436*193032a3SAndroid Build Coastguard Worker }
437*193032a3SAndroid Build Coastguard Worker if (vic && (fmod(refresh, 6)) == 0.0)
438*193032a3SAndroid Build Coastguard Worker or_str(flags, "V4L2_DV_FL_CAN_REDUCE_FPS", num_flags);
439*193032a3SAndroid Build Coastguard Worker if (t->rb)
440*193032a3SAndroid Build Coastguard Worker or_str(flags, "V4L2_DV_FL_REDUCED_BLANKING", num_flags);
441*193032a3SAndroid Build Coastguard Worker if (t->hratio && t->vratio)
442*193032a3SAndroid Build Coastguard Worker or_str(flags, "V4L2_DV_FL_HAS_PICTURE_ASPECT", num_flags);
443*193032a3SAndroid Build Coastguard Worker
444*193032a3SAndroid Build Coastguard Worker if (!memcmp(type, "VIC", 3) || !memcmp(type, "HDMI VIC", 8))
445*193032a3SAndroid Build Coastguard Worker std = "V4L2_DV_BT_STD_CEA861";
446*193032a3SAndroid Build Coastguard Worker else if (!memcmp(type, "DMT", 3))
447*193032a3SAndroid Build Coastguard Worker std = "V4L2_DV_BT_STD_DMT";
448*193032a3SAndroid Build Coastguard Worker else if (!memcmp(type, "CVT", 3))
449*193032a3SAndroid Build Coastguard Worker std = "V4L2_DV_BT_STD_CVT";
450*193032a3SAndroid Build Coastguard Worker else if (!memcmp(type, "GTF", 3))
451*193032a3SAndroid Build Coastguard Worker std = "V4L2_DV_BT_STD_GTF";
452*193032a3SAndroid Build Coastguard Worker printf("\t\t\t%s, \\\n", std);
453*193032a3SAndroid Build Coastguard Worker printf("\t\t\t%s, \\\n", flags.empty() ? "0" : flags.c_str());
454*193032a3SAndroid Build Coastguard Worker printf("\t\t\t{ %u, %u }, %u, %u) \\\n",
455*193032a3SAndroid Build Coastguard Worker t->hratio, t->vratio, vic, hdmi_vic);
456*193032a3SAndroid Build Coastguard Worker printf("\t}\n");
457*193032a3SAndroid Build Coastguard Worker }
458*193032a3SAndroid Build Coastguard Worker
print_detailed_timing(unsigned indent,const struct timings * t)459*193032a3SAndroid Build Coastguard Worker static void print_detailed_timing(unsigned indent, const struct timings *t)
460*193032a3SAndroid Build Coastguard Worker {
461*193032a3SAndroid Build Coastguard Worker printf("%*sHfront %4d Hsync %3u Hback %3d Hpol %s",
462*193032a3SAndroid Build Coastguard Worker indent, "",
463*193032a3SAndroid Build Coastguard Worker t->hfp, t->hsync, t->hbp, t->pos_pol_hsync ? "P" : "N");
464*193032a3SAndroid Build Coastguard Worker if (t->hborder)
465*193032a3SAndroid Build Coastguard Worker printf(" Hborder %u", t->hborder);
466*193032a3SAndroid Build Coastguard Worker printf("\n");
467*193032a3SAndroid Build Coastguard Worker
468*193032a3SAndroid Build Coastguard Worker printf("%*sVfront %4u Vsync %3u Vback %3d",
469*193032a3SAndroid Build Coastguard Worker indent, "", t->vfp, t->vsync, t->vbp);
470*193032a3SAndroid Build Coastguard Worker if (!t->no_pol_vsync)
471*193032a3SAndroid Build Coastguard Worker printf(" Vpol %s", t->pos_pol_vsync ? "P" : "N");
472*193032a3SAndroid Build Coastguard Worker if (t->vborder)
473*193032a3SAndroid Build Coastguard Worker printf(" Vborder %u", t->vborder);
474*193032a3SAndroid Build Coastguard Worker if (t->even_vtotal) {
475*193032a3SAndroid Build Coastguard Worker printf(" Both Fields");
476*193032a3SAndroid Build Coastguard Worker } else if (t->interlaced) {
477*193032a3SAndroid Build Coastguard Worker printf(" Vfront +0.5 Odd Field\n");
478*193032a3SAndroid Build Coastguard Worker printf("%*sVfront %4d Vsync %3u Vback %3d",
479*193032a3SAndroid Build Coastguard Worker indent, "", t->vfp, t->vsync, t->vbp);
480*193032a3SAndroid Build Coastguard Worker if (!t->no_pol_vsync)
481*193032a3SAndroid Build Coastguard Worker printf(" Vpol %s", t->pos_pol_vsync ? "P" : "N");
482*193032a3SAndroid Build Coastguard Worker if (t->vborder)
483*193032a3SAndroid Build Coastguard Worker printf(" Vborder %u", t->vborder);
484*193032a3SAndroid Build Coastguard Worker printf(" Vback +0.5 Even Field");
485*193032a3SAndroid Build Coastguard Worker }
486*193032a3SAndroid Build Coastguard Worker printf("\n");
487*193032a3SAndroid Build Coastguard Worker }
488*193032a3SAndroid Build Coastguard Worker
print_timings(const char * prefix,const struct timings * t,const char * type,const char * flags,bool detailed,bool do_checks)489*193032a3SAndroid Build Coastguard Worker bool edid_state::print_timings(const char *prefix, const struct timings *t,
490*193032a3SAndroid Build Coastguard Worker const char *type, const char *flags,
491*193032a3SAndroid Build Coastguard Worker bool detailed, bool do_checks)
492*193032a3SAndroid Build Coastguard Worker {
493*193032a3SAndroid Build Coastguard Worker if (!t) {
494*193032a3SAndroid Build Coastguard Worker // Should not happen
495*193032a3SAndroid Build Coastguard Worker if (do_checks)
496*193032a3SAndroid Build Coastguard Worker fail("Unknown video timings.\n");
497*193032a3SAndroid Build Coastguard Worker return false;
498*193032a3SAndroid Build Coastguard Worker }
499*193032a3SAndroid Build Coastguard Worker
500*193032a3SAndroid Build Coastguard Worker if (detailed && options[OptShortTimings])
501*193032a3SAndroid Build Coastguard Worker detailed = false;
502*193032a3SAndroid Build Coastguard Worker if (options[OptLongTimings])
503*193032a3SAndroid Build Coastguard Worker detailed = true;
504*193032a3SAndroid Build Coastguard Worker
505*193032a3SAndroid Build Coastguard Worker unsigned vact = t->vact;
506*193032a3SAndroid Build Coastguard Worker unsigned hbl = t->hfp + t->hsync + t->hbp + 2 * t->hborder;
507*193032a3SAndroid Build Coastguard Worker unsigned vbl = t->vfp + t->vsync + t->vbp + 2 * t->vborder;
508*193032a3SAndroid Build Coastguard Worker unsigned htotal = t->hact + hbl;
509*193032a3SAndroid Build Coastguard Worker double hor_freq_khz = htotal ? (double)t->pixclk_khz / htotal : 0;
510*193032a3SAndroid Build Coastguard Worker
511*193032a3SAndroid Build Coastguard Worker if (t->interlaced)
512*193032a3SAndroid Build Coastguard Worker vact /= 2;
513*193032a3SAndroid Build Coastguard Worker
514*193032a3SAndroid Build Coastguard Worker if (t->ycbcr420)
515*193032a3SAndroid Build Coastguard Worker hor_freq_khz /= 2;
516*193032a3SAndroid Build Coastguard Worker
517*193032a3SAndroid Build Coastguard Worker double vtotal = vact + vbl;
518*193032a3SAndroid Build Coastguard Worker
519*193032a3SAndroid Build Coastguard Worker bool ok = true;
520*193032a3SAndroid Build Coastguard Worker
521*193032a3SAndroid Build Coastguard Worker if (!t->hact || !hbl || !t->hfp || !t->hsync ||
522*193032a3SAndroid Build Coastguard Worker !vact || !vbl || (!t->vfp && !t->interlaced && !t->even_vtotal) || !t->vsync) {
523*193032a3SAndroid Build Coastguard Worker if (do_checks)
524*193032a3SAndroid Build Coastguard Worker fail("0 values in the video timing:\n"
525*193032a3SAndroid Build Coastguard Worker " Horizontal Active/Blanking %u/%u\n"
526*193032a3SAndroid Build Coastguard Worker " Horizontal Frontporch/Sync Width %u/%u\n"
527*193032a3SAndroid Build Coastguard Worker " Vertical Active/Blanking %u/%u\n"
528*193032a3SAndroid Build Coastguard Worker " Vertical Frontporch/Sync Width %u/%u\n",
529*193032a3SAndroid Build Coastguard Worker t->hact, hbl, t->hfp, t->hsync, vact, vbl, t->vfp, t->vsync);
530*193032a3SAndroid Build Coastguard Worker ok = false;
531*193032a3SAndroid Build Coastguard Worker }
532*193032a3SAndroid Build Coastguard Worker
533*193032a3SAndroid Build Coastguard Worker if (t->even_vtotal)
534*193032a3SAndroid Build Coastguard Worker vtotal = vact + t->vfp + t->vsync + t->vbp;
535*193032a3SAndroid Build Coastguard Worker else if (t->interlaced)
536*193032a3SAndroid Build Coastguard Worker vtotal = vact + t->vfp + t->vsync + t->vbp + 0.5;
537*193032a3SAndroid Build Coastguard Worker
538*193032a3SAndroid Build Coastguard Worker double refresh = (double)t->pixclk_khz * 1000.0 / (htotal * vtotal);
539*193032a3SAndroid Build Coastguard Worker
540*193032a3SAndroid Build Coastguard Worker std::string s;
541*193032a3SAndroid Build Coastguard Worker unsigned rb = t->rb & ~RB_ALT;
542*193032a3SAndroid Build Coastguard Worker if (rb) {
543*193032a3SAndroid Build Coastguard Worker bool alt = t->rb & RB_ALT;
544*193032a3SAndroid Build Coastguard Worker s = "RB";
545*193032a3SAndroid Build Coastguard Worker if (rb == RB_CVT_V2)
546*193032a3SAndroid Build Coastguard Worker s += std::string("v2") + (alt ? ",video-optimized" : "");
547*193032a3SAndroid Build Coastguard Worker else if (rb == RB_CVT_V3)
548*193032a3SAndroid Build Coastguard Worker s += std::string("v3") + (alt ? ",h-blank-160" : "");
549*193032a3SAndroid Build Coastguard Worker }
550*193032a3SAndroid Build Coastguard Worker add_str(s, flags);
551*193032a3SAndroid Build Coastguard Worker if (t->hsize_mm || t->vsize_mm)
552*193032a3SAndroid Build Coastguard Worker add_str(s, std::to_string(t->hsize_mm) + " mm x " + std::to_string(t->vsize_mm) + " mm");
553*193032a3SAndroid Build Coastguard Worker if (t->hsize_mm > dtd_max_hsize_mm)
554*193032a3SAndroid Build Coastguard Worker dtd_max_hsize_mm = t->hsize_mm;
555*193032a3SAndroid Build Coastguard Worker if (t->vsize_mm > dtd_max_vsize_mm)
556*193032a3SAndroid Build Coastguard Worker dtd_max_vsize_mm = t->vsize_mm;
557*193032a3SAndroid Build Coastguard Worker if (!s.empty())
558*193032a3SAndroid Build Coastguard Worker s = " (" + s + ")";
559*193032a3SAndroid Build Coastguard Worker unsigned pixclk_khz = t->pixclk_khz / (t->ycbcr420 ? 2 : 1);
560*193032a3SAndroid Build Coastguard Worker
561*193032a3SAndroid Build Coastguard Worker char buf[10];
562*193032a3SAndroid Build Coastguard Worker
563*193032a3SAndroid Build Coastguard Worker sprintf(buf, "%u%s", t->vact, t->interlaced ? "i" : "");
564*193032a3SAndroid Build Coastguard Worker printf("%s%s: %5ux%-5s %7.3f Hz %3u:%-3u %7.3f kHz %8.3f MHz%s\n",
565*193032a3SAndroid Build Coastguard Worker prefix, type,
566*193032a3SAndroid Build Coastguard Worker t->hact, buf,
567*193032a3SAndroid Build Coastguard Worker refresh,
568*193032a3SAndroid Build Coastguard Worker t->hratio, t->vratio,
569*193032a3SAndroid Build Coastguard Worker hor_freq_khz,
570*193032a3SAndroid Build Coastguard Worker pixclk_khz / 1000.0,
571*193032a3SAndroid Build Coastguard Worker s.c_str());
572*193032a3SAndroid Build Coastguard Worker
573*193032a3SAndroid Build Coastguard Worker unsigned len = strlen(prefix) + 2;
574*193032a3SAndroid Build Coastguard Worker
575*193032a3SAndroid Build Coastguard Worker if (!t->ycbcr420 && detailed && options[OptXModeLineTimings])
576*193032a3SAndroid Build Coastguard Worker print_modeline(len, t, refresh);
577*193032a3SAndroid Build Coastguard Worker else if (!t->ycbcr420 && detailed && options[OptFBModeTimings])
578*193032a3SAndroid Build Coastguard Worker print_fbmode(len, t, refresh, hor_freq_khz);
579*193032a3SAndroid Build Coastguard Worker else if (!t->ycbcr420 && detailed && options[OptV4L2Timings])
580*193032a3SAndroid Build Coastguard Worker print_v4l2_timing(t, refresh, type);
581*193032a3SAndroid Build Coastguard Worker else if (detailed)
582*193032a3SAndroid Build Coastguard Worker print_detailed_timing(len + strlen(type) + 6, t);
583*193032a3SAndroid Build Coastguard Worker
584*193032a3SAndroid Build Coastguard Worker if (!do_checks)
585*193032a3SAndroid Build Coastguard Worker return ok;
586*193032a3SAndroid Build Coastguard Worker
587*193032a3SAndroid Build Coastguard Worker if (!memcmp(type, "DTD", 3)) {
588*193032a3SAndroid Build Coastguard Worker unsigned vic, dmt;
589*193032a3SAndroid Build Coastguard Worker const timings *vic_t = cta_close_match_to_vic(*t, vic);
590*193032a3SAndroid Build Coastguard Worker
591*193032a3SAndroid Build Coastguard Worker if (vic_t)
592*193032a3SAndroid Build Coastguard Worker warn("DTD is similar but not identical to VIC %u.\n", vic);
593*193032a3SAndroid Build Coastguard Worker
594*193032a3SAndroid Build Coastguard Worker const timings *dmt_t = close_match_to_dmt(*t, dmt);
595*193032a3SAndroid Build Coastguard Worker if (!vic_t && dmt_t)
596*193032a3SAndroid Build Coastguard Worker warn("DTD is similar but not identical to DMT 0x%02x.\n", dmt);
597*193032a3SAndroid Build Coastguard Worker }
598*193032a3SAndroid Build Coastguard Worker
599*193032a3SAndroid Build Coastguard Worker if (refresh) {
600*193032a3SAndroid Build Coastguard Worker min_vert_freq_hz = min(min_vert_freq_hz, refresh);
601*193032a3SAndroid Build Coastguard Worker max_vert_freq_hz = max(max_vert_freq_hz, refresh);
602*193032a3SAndroid Build Coastguard Worker }
603*193032a3SAndroid Build Coastguard Worker if (hor_freq_khz) {
604*193032a3SAndroid Build Coastguard Worker min_hor_freq_hz = min(min_hor_freq_hz, hor_freq_khz * 1000.0);
605*193032a3SAndroid Build Coastguard Worker max_hor_freq_hz = max(max_hor_freq_hz, hor_freq_khz * 1000.0);
606*193032a3SAndroid Build Coastguard Worker max_pixclk_khz = max(max_pixclk_khz, pixclk_khz);
607*193032a3SAndroid Build Coastguard Worker if (t->pos_pol_hsync && !t->pos_pol_vsync && t->vsync == 3)
608*193032a3SAndroid Build Coastguard Worker base.max_pos_neg_hor_freq_khz = hor_freq_khz;
609*193032a3SAndroid Build Coastguard Worker }
610*193032a3SAndroid Build Coastguard Worker
611*193032a3SAndroid Build Coastguard Worker if (t->ycbcr420 && t->pixclk_khz < 590000)
612*193032a3SAndroid Build Coastguard Worker warn_once("Some YCbCr 4:2:0 timings are invalid for HDMI (which requires an RGB timings pixel rate >= 590 MHz).\n");
613*193032a3SAndroid Build Coastguard Worker if (t->hfp <= 0)
614*193032a3SAndroid Build Coastguard Worker fail("0 or negative horizontal front porch.\n");
615*193032a3SAndroid Build Coastguard Worker if (t->hbp <= 0)
616*193032a3SAndroid Build Coastguard Worker fail("0 or negative horizontal back porch.\n");
617*193032a3SAndroid Build Coastguard Worker if (t->vbp <= 0)
618*193032a3SAndroid Build Coastguard Worker fail("0 or negative vertical back porch.\n");
619*193032a3SAndroid Build Coastguard Worker if (!base.max_display_width_mm && !base.max_display_height_mm) {
620*193032a3SAndroid Build Coastguard Worker /* this is valid */
621*193032a3SAndroid Build Coastguard Worker } else if (!t->hsize_mm && !t->vsize_mm) {
622*193032a3SAndroid Build Coastguard Worker /* this is valid */
623*193032a3SAndroid Build Coastguard Worker } else if (t->hsize_mm > base.max_display_width_mm + 9 ||
624*193032a3SAndroid Build Coastguard Worker t->vsize_mm > base.max_display_height_mm + 9) {
625*193032a3SAndroid Build Coastguard Worker fail("Mismatch of image size %ux%u mm vs display size %ux%u mm.\n",
626*193032a3SAndroid Build Coastguard Worker t->hsize_mm, t->vsize_mm, base.max_display_width_mm, base.max_display_height_mm);
627*193032a3SAndroid Build Coastguard Worker } else if (t->hsize_mm < base.max_display_width_mm - 9 &&
628*193032a3SAndroid Build Coastguard Worker t->vsize_mm < base.max_display_height_mm - 9) {
629*193032a3SAndroid Build Coastguard Worker fail("Mismatch of image size %ux%u mm vs display size %ux%u mm.\n",
630*193032a3SAndroid Build Coastguard Worker t->hsize_mm, t->vsize_mm, base.max_display_width_mm, base.max_display_height_mm);
631*193032a3SAndroid Build Coastguard Worker }
632*193032a3SAndroid Build Coastguard Worker return ok;
633*193032a3SAndroid Build Coastguard Worker }
634*193032a3SAndroid Build Coastguard Worker
containerid2s(const unsigned char * x)635*193032a3SAndroid Build Coastguard Worker std::string containerid2s(const unsigned char *x)
636*193032a3SAndroid Build Coastguard Worker {
637*193032a3SAndroid Build Coastguard Worker char buf[40];
638*193032a3SAndroid Build Coastguard Worker
639*193032a3SAndroid Build Coastguard Worker sprintf(buf, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
640*193032a3SAndroid Build Coastguard Worker x[0], x[1], x[2], x[3],
641*193032a3SAndroid Build Coastguard Worker x[4], x[5],
642*193032a3SAndroid Build Coastguard Worker x[6], x[7],
643*193032a3SAndroid Build Coastguard Worker x[8], x[9],
644*193032a3SAndroid Build Coastguard Worker x[10], x[11], x[12], x[13], x[14], x[15]);
645*193032a3SAndroid Build Coastguard Worker return buf;
646*193032a3SAndroid Build Coastguard Worker }
647*193032a3SAndroid Build Coastguard Worker
utohex(unsigned char x)648*193032a3SAndroid Build Coastguard Worker std::string utohex(unsigned char x)
649*193032a3SAndroid Build Coastguard Worker {
650*193032a3SAndroid Build Coastguard Worker char buf[10];
651*193032a3SAndroid Build Coastguard Worker
652*193032a3SAndroid Build Coastguard Worker sprintf(buf, "0x%02hhx", x);
653*193032a3SAndroid Build Coastguard Worker return buf;
654*193032a3SAndroid Build Coastguard Worker }
655*193032a3SAndroid Build Coastguard Worker
oui_name(unsigned oui,bool reverse)656*193032a3SAndroid Build Coastguard Worker const char *oui_name(unsigned oui, bool reverse)
657*193032a3SAndroid Build Coastguard Worker {
658*193032a3SAndroid Build Coastguard Worker if (reverse)
659*193032a3SAndroid Build Coastguard Worker oui = (oui >> 16) | (oui & 0xff00) | ((oui & 0xff) << 16);
660*193032a3SAndroid Build Coastguard Worker
661*193032a3SAndroid Build Coastguard Worker switch (oui) {
662*193032a3SAndroid Build Coastguard Worker case 0x00001a: return "AMD";
663*193032a3SAndroid Build Coastguard Worker case 0x000c03: return "HDMI";
664*193032a3SAndroid Build Coastguard Worker case 0x00044b: return "NVIDIA";
665*193032a3SAndroid Build Coastguard Worker case 0x000c6e: return "ASUS";
666*193032a3SAndroid Build Coastguard Worker case 0x0010fa: return "Apple";
667*193032a3SAndroid Build Coastguard Worker case 0x0014b9: return "MSTAR";
668*193032a3SAndroid Build Coastguard Worker case 0x00d046: return "Dolby";
669*193032a3SAndroid Build Coastguard Worker case 0x00e047: return "InFocus";
670*193032a3SAndroid Build Coastguard Worker case 0x3a0292: return "VESA";
671*193032a3SAndroid Build Coastguard Worker case 0x90848b: return "HDR10+";
672*193032a3SAndroid Build Coastguard Worker case 0xc45dd8: return "HDMI Forum";
673*193032a3SAndroid Build Coastguard Worker case 0xca125c: return "Microsoft";
674*193032a3SAndroid Build Coastguard Worker default: return NULL;
675*193032a3SAndroid Build Coastguard Worker }
676*193032a3SAndroid Build Coastguard Worker }
677*193032a3SAndroid Build Coastguard Worker
ouitohex(unsigned oui)678*193032a3SAndroid Build Coastguard Worker std::string ouitohex(unsigned oui)
679*193032a3SAndroid Build Coastguard Worker {
680*193032a3SAndroid Build Coastguard Worker char buf[32];
681*193032a3SAndroid Build Coastguard Worker
682*193032a3SAndroid Build Coastguard Worker sprintf(buf, "%02X-%02X-%02X", (oui >> 16) & 0xff, (oui >> 8) & 0xff, oui & 0xff);
683*193032a3SAndroid Build Coastguard Worker return buf;
684*193032a3SAndroid Build Coastguard Worker }
685*193032a3SAndroid Build Coastguard Worker
memchk(const unsigned char * x,unsigned len,unsigned char v)686*193032a3SAndroid Build Coastguard Worker bool memchk(const unsigned char *x, unsigned len, unsigned char v)
687*193032a3SAndroid Build Coastguard Worker {
688*193032a3SAndroid Build Coastguard Worker for (unsigned i = 0; i < len; i++)
689*193032a3SAndroid Build Coastguard Worker if (x[i] != v)
690*193032a3SAndroid Build Coastguard Worker return false;
691*193032a3SAndroid Build Coastguard Worker return true;
692*193032a3SAndroid Build Coastguard Worker }
693*193032a3SAndroid Build Coastguard Worker
hex_block(const char * prefix,const unsigned char * x,unsigned length,bool show_ascii,unsigned step)694*193032a3SAndroid Build Coastguard Worker void hex_block(const char *prefix, const unsigned char *x,
695*193032a3SAndroid Build Coastguard Worker unsigned length, bool show_ascii, unsigned step)
696*193032a3SAndroid Build Coastguard Worker {
697*193032a3SAndroid Build Coastguard Worker unsigned i, j;
698*193032a3SAndroid Build Coastguard Worker
699*193032a3SAndroid Build Coastguard Worker if (!length)
700*193032a3SAndroid Build Coastguard Worker return;
701*193032a3SAndroid Build Coastguard Worker
702*193032a3SAndroid Build Coastguard Worker for (i = 0; i < length; i += step) {
703*193032a3SAndroid Build Coastguard Worker unsigned len = min(step, length - i);
704*193032a3SAndroid Build Coastguard Worker
705*193032a3SAndroid Build Coastguard Worker printf("%s", prefix);
706*193032a3SAndroid Build Coastguard Worker for (j = 0; j < len; j++)
707*193032a3SAndroid Build Coastguard Worker printf("%s%02x", j ? " " : "", x[i + j]);
708*193032a3SAndroid Build Coastguard Worker
709*193032a3SAndroid Build Coastguard Worker if (show_ascii) {
710*193032a3SAndroid Build Coastguard Worker for (j = len; j < step; j++)
711*193032a3SAndroid Build Coastguard Worker printf(" ");
712*193032a3SAndroid Build Coastguard Worker printf(" '");
713*193032a3SAndroid Build Coastguard Worker for (j = 0; j < len; j++)
714*193032a3SAndroid Build Coastguard Worker printf("%c", x[i + j] >= ' ' && x[i + j] <= '~' ? x[i + j] : '.');
715*193032a3SAndroid Build Coastguard Worker printf("'");
716*193032a3SAndroid Build Coastguard Worker }
717*193032a3SAndroid Build Coastguard Worker printf("\n");
718*193032a3SAndroid Build Coastguard Worker }
719*193032a3SAndroid Build Coastguard Worker }
720*193032a3SAndroid Build Coastguard Worker
edid_add_byte(const char * s,bool two_digits=true)721*193032a3SAndroid Build Coastguard Worker static bool edid_add_byte(const char *s, bool two_digits = true)
722*193032a3SAndroid Build Coastguard Worker {
723*193032a3SAndroid Build Coastguard Worker char buf[3];
724*193032a3SAndroid Build Coastguard Worker
725*193032a3SAndroid Build Coastguard Worker if (state.edid_size == sizeof(edid))
726*193032a3SAndroid Build Coastguard Worker return false;
727*193032a3SAndroid Build Coastguard Worker buf[0] = s[0];
728*193032a3SAndroid Build Coastguard Worker buf[1] = two_digits ? s[1] : 0;
729*193032a3SAndroid Build Coastguard Worker buf[2] = 0;
730*193032a3SAndroid Build Coastguard Worker edid[state.edid_size++] = strtoul(buf, NULL, 16);
731*193032a3SAndroid Build Coastguard Worker return true;
732*193032a3SAndroid Build Coastguard Worker }
733*193032a3SAndroid Build Coastguard Worker
extract_edid_quantumdata(const char * start)734*193032a3SAndroid Build Coastguard Worker static bool extract_edid_quantumdata(const char *start)
735*193032a3SAndroid Build Coastguard Worker {
736*193032a3SAndroid Build Coastguard Worker /* Parse QuantumData 980 EDID files */
737*193032a3SAndroid Build Coastguard Worker do {
738*193032a3SAndroid Build Coastguard Worker start = strstr(start, ">");
739*193032a3SAndroid Build Coastguard Worker if (!start)
740*193032a3SAndroid Build Coastguard Worker return false;
741*193032a3SAndroid Build Coastguard Worker start++;
742*193032a3SAndroid Build Coastguard Worker for (unsigned i = 0; start[i] && start[i + 1] && i < 256; i += 2)
743*193032a3SAndroid Build Coastguard Worker if (!edid_add_byte(start + i))
744*193032a3SAndroid Build Coastguard Worker return false;
745*193032a3SAndroid Build Coastguard Worker start = strstr(start, "<BLOCK");
746*193032a3SAndroid Build Coastguard Worker } while (start);
747*193032a3SAndroid Build Coastguard Worker return state.edid_size;
748*193032a3SAndroid Build Coastguard Worker }
749*193032a3SAndroid Build Coastguard Worker
750*193032a3SAndroid Build Coastguard Worker static const char *ignore_chars = ",:;";
751*193032a3SAndroid Build Coastguard Worker
extract_edid_hex(const char * s,bool require_two_digits=true)752*193032a3SAndroid Build Coastguard Worker static bool extract_edid_hex(const char *s, bool require_two_digits = true)
753*193032a3SAndroid Build Coastguard Worker {
754*193032a3SAndroid Build Coastguard Worker for (; *s; s++) {
755*193032a3SAndroid Build Coastguard Worker if (isspace(*s) || strchr(ignore_chars, *s))
756*193032a3SAndroid Build Coastguard Worker continue;
757*193032a3SAndroid Build Coastguard Worker
758*193032a3SAndroid Build Coastguard Worker if (*s == '0' && tolower(s[1]) == 'x') {
759*193032a3SAndroid Build Coastguard Worker s++;
760*193032a3SAndroid Build Coastguard Worker continue;
761*193032a3SAndroid Build Coastguard Worker }
762*193032a3SAndroid Build Coastguard Worker
763*193032a3SAndroid Build Coastguard Worker /* Read one or two hex digits from the log */
764*193032a3SAndroid Build Coastguard Worker if (!isxdigit(s[0])) {
765*193032a3SAndroid Build Coastguard Worker if (state.edid_size && state.edid_size % 128 == 0)
766*193032a3SAndroid Build Coastguard Worker break;
767*193032a3SAndroid Build Coastguard Worker return false;
768*193032a3SAndroid Build Coastguard Worker }
769*193032a3SAndroid Build Coastguard Worker if (require_two_digits && !isxdigit(s[1])) {
770*193032a3SAndroid Build Coastguard Worker odd_hex_digits = true;
771*193032a3SAndroid Build Coastguard Worker return false;
772*193032a3SAndroid Build Coastguard Worker }
773*193032a3SAndroid Build Coastguard Worker if (!edid_add_byte(s, isxdigit(s[1])))
774*193032a3SAndroid Build Coastguard Worker return false;
775*193032a3SAndroid Build Coastguard Worker if (isxdigit(s[1]))
776*193032a3SAndroid Build Coastguard Worker s++;
777*193032a3SAndroid Build Coastguard Worker }
778*193032a3SAndroid Build Coastguard Worker return state.edid_size;
779*193032a3SAndroid Build Coastguard Worker }
780*193032a3SAndroid Build Coastguard Worker
extract_edid_xrandr(const char * start)781*193032a3SAndroid Build Coastguard Worker static bool extract_edid_xrandr(const char *start)
782*193032a3SAndroid Build Coastguard Worker {
783*193032a3SAndroid Build Coastguard Worker static const char indentation1[] = " ";
784*193032a3SAndroid Build Coastguard Worker static const char indentation2[] = "\t\t";
785*193032a3SAndroid Build Coastguard Worker /* Used to detect that we've gone past the EDID property */
786*193032a3SAndroid Build Coastguard Worker static const char half_indentation1[] = " ";
787*193032a3SAndroid Build Coastguard Worker static const char half_indentation2[] = "\t";
788*193032a3SAndroid Build Coastguard Worker const char *indentation;
789*193032a3SAndroid Build Coastguard Worker const char *s;
790*193032a3SAndroid Build Coastguard Worker
791*193032a3SAndroid Build Coastguard Worker for (;;) {
792*193032a3SAndroid Build Coastguard Worker unsigned j;
793*193032a3SAndroid Build Coastguard Worker
794*193032a3SAndroid Build Coastguard Worker /* Get the next start of the line of EDID hex, assuming spaces for indentation */
795*193032a3SAndroid Build Coastguard Worker s = strstr(start, indentation = indentation1);
796*193032a3SAndroid Build Coastguard Worker /* Did we skip the start of another property? */
797*193032a3SAndroid Build Coastguard Worker if (s && s > strstr(start, half_indentation1))
798*193032a3SAndroid Build Coastguard Worker break;
799*193032a3SAndroid Build Coastguard Worker
800*193032a3SAndroid Build Coastguard Worker /* If we failed, retry assuming tabs for indentation */
801*193032a3SAndroid Build Coastguard Worker if (!s) {
802*193032a3SAndroid Build Coastguard Worker s = strstr(start, indentation = indentation2);
803*193032a3SAndroid Build Coastguard Worker /* Did we skip the start of another property? */
804*193032a3SAndroid Build Coastguard Worker if (s && s > strstr(start, half_indentation2))
805*193032a3SAndroid Build Coastguard Worker break;
806*193032a3SAndroid Build Coastguard Worker }
807*193032a3SAndroid Build Coastguard Worker
808*193032a3SAndroid Build Coastguard Worker if (!s)
809*193032a3SAndroid Build Coastguard Worker break;
810*193032a3SAndroid Build Coastguard Worker
811*193032a3SAndroid Build Coastguard Worker start = s + strlen(indentation);
812*193032a3SAndroid Build Coastguard Worker
813*193032a3SAndroid Build Coastguard Worker for (j = 0; j < 16; j++, start += 2) {
814*193032a3SAndroid Build Coastguard Worker /* Read a %02x from the log */
815*193032a3SAndroid Build Coastguard Worker if (!isxdigit(start[0]) || !isxdigit(start[1])) {
816*193032a3SAndroid Build Coastguard Worker if (j)
817*193032a3SAndroid Build Coastguard Worker break;
818*193032a3SAndroid Build Coastguard Worker return false;
819*193032a3SAndroid Build Coastguard Worker }
820*193032a3SAndroid Build Coastguard Worker if (!edid_add_byte(start))
821*193032a3SAndroid Build Coastguard Worker return false;
822*193032a3SAndroid Build Coastguard Worker }
823*193032a3SAndroid Build Coastguard Worker }
824*193032a3SAndroid Build Coastguard Worker return state.edid_size;
825*193032a3SAndroid Build Coastguard Worker }
826*193032a3SAndroid Build Coastguard Worker
extract_edid_xorg(const char * start)827*193032a3SAndroid Build Coastguard Worker static bool extract_edid_xorg(const char *start)
828*193032a3SAndroid Build Coastguard Worker {
829*193032a3SAndroid Build Coastguard Worker bool find_first_num = true;
830*193032a3SAndroid Build Coastguard Worker
831*193032a3SAndroid Build Coastguard Worker for (; *start; start++) {
832*193032a3SAndroid Build Coastguard Worker if (find_first_num) {
833*193032a3SAndroid Build Coastguard Worker const char *s;
834*193032a3SAndroid Build Coastguard Worker
835*193032a3SAndroid Build Coastguard Worker /* skip ahead to the : */
836*193032a3SAndroid Build Coastguard Worker s = strstr(start, ": \t");
837*193032a3SAndroid Build Coastguard Worker if (!s)
838*193032a3SAndroid Build Coastguard Worker s = strstr(start, ": ");
839*193032a3SAndroid Build Coastguard Worker if (!s)
840*193032a3SAndroid Build Coastguard Worker break;
841*193032a3SAndroid Build Coastguard Worker start = s;
842*193032a3SAndroid Build Coastguard Worker /* and find the first number */
843*193032a3SAndroid Build Coastguard Worker while (!isxdigit(start[1]))
844*193032a3SAndroid Build Coastguard Worker start++;
845*193032a3SAndroid Build Coastguard Worker find_first_num = false;
846*193032a3SAndroid Build Coastguard Worker continue;
847*193032a3SAndroid Build Coastguard Worker } else {
848*193032a3SAndroid Build Coastguard Worker /* Read a %02x from the log */
849*193032a3SAndroid Build Coastguard Worker if (!isxdigit(*start)) {
850*193032a3SAndroid Build Coastguard Worker find_first_num = true;
851*193032a3SAndroid Build Coastguard Worker continue;
852*193032a3SAndroid Build Coastguard Worker }
853*193032a3SAndroid Build Coastguard Worker if (!edid_add_byte(start))
854*193032a3SAndroid Build Coastguard Worker return false;
855*193032a3SAndroid Build Coastguard Worker start++;
856*193032a3SAndroid Build Coastguard Worker }
857*193032a3SAndroid Build Coastguard Worker }
858*193032a3SAndroid Build Coastguard Worker return state.edid_size;
859*193032a3SAndroid Build Coastguard Worker }
860*193032a3SAndroid Build Coastguard Worker
extract_edid(int fd,FILE * error)861*193032a3SAndroid Build Coastguard Worker static bool extract_edid(int fd, FILE *error)
862*193032a3SAndroid Build Coastguard Worker {
863*193032a3SAndroid Build Coastguard Worker std::vector<char> edid_data;
864*193032a3SAndroid Build Coastguard Worker char buf[EDID_PAGE_SIZE];
865*193032a3SAndroid Build Coastguard Worker
866*193032a3SAndroid Build Coastguard Worker for (;;) {
867*193032a3SAndroid Build Coastguard Worker ssize_t i = read(fd, buf, sizeof(buf));
868*193032a3SAndroid Build Coastguard Worker
869*193032a3SAndroid Build Coastguard Worker if (i < 0)
870*193032a3SAndroid Build Coastguard Worker return false;
871*193032a3SAndroid Build Coastguard Worker if (i == 0)
872*193032a3SAndroid Build Coastguard Worker break;
873*193032a3SAndroid Build Coastguard Worker edid_data.insert(edid_data.end(), buf, buf + i);
874*193032a3SAndroid Build Coastguard Worker }
875*193032a3SAndroid Build Coastguard Worker
876*193032a3SAndroid Build Coastguard Worker if (edid_data.empty()) {
877*193032a3SAndroid Build Coastguard Worker state.edid_size = 0;
878*193032a3SAndroid Build Coastguard Worker return false;
879*193032a3SAndroid Build Coastguard Worker }
880*193032a3SAndroid Build Coastguard Worker
881*193032a3SAndroid Build Coastguard Worker const char *data = &edid_data[0];
882*193032a3SAndroid Build Coastguard Worker const char *start;
883*193032a3SAndroid Build Coastguard Worker
884*193032a3SAndroid Build Coastguard Worker /* Look for edid-decode output */
885*193032a3SAndroid Build Coastguard Worker start = strstr(data, "EDID (hex):");
886*193032a3SAndroid Build Coastguard Worker if (!start)
887*193032a3SAndroid Build Coastguard Worker start = strstr(data, "edid-decode (hex):");
888*193032a3SAndroid Build Coastguard Worker if (start)
889*193032a3SAndroid Build Coastguard Worker return extract_edid_hex(strchr(start, ':'));
890*193032a3SAndroid Build Coastguard Worker
891*193032a3SAndroid Build Coastguard Worker /* Look for C-array */
892*193032a3SAndroid Build Coastguard Worker start = strstr(data, "unsigned char edid[] = {");
893*193032a3SAndroid Build Coastguard Worker if (start)
894*193032a3SAndroid Build Coastguard Worker return extract_edid_hex(strchr(start, '{') + 1, false);
895*193032a3SAndroid Build Coastguard Worker
896*193032a3SAndroid Build Coastguard Worker /* Look for QuantumData EDID output */
897*193032a3SAndroid Build Coastguard Worker start = strstr(data, "<BLOCK");
898*193032a3SAndroid Build Coastguard Worker if (start)
899*193032a3SAndroid Build Coastguard Worker return extract_edid_quantumdata(start);
900*193032a3SAndroid Build Coastguard Worker
901*193032a3SAndroid Build Coastguard Worker /* Look for xrandr --verbose output (lines of 16 hex bytes) */
902*193032a3SAndroid Build Coastguard Worker start = strstr(data, "EDID_DATA:");
903*193032a3SAndroid Build Coastguard Worker if (!start)
904*193032a3SAndroid Build Coastguard Worker start = strstr(data, "EDID:");
905*193032a3SAndroid Build Coastguard Worker if (start)
906*193032a3SAndroid Build Coastguard Worker return extract_edid_xrandr(start);
907*193032a3SAndroid Build Coastguard Worker
908*193032a3SAndroid Build Coastguard Worker /* Look for an EDID in an Xorg.0.log file */
909*193032a3SAndroid Build Coastguard Worker start = strstr(data, "EDID (in hex):");
910*193032a3SAndroid Build Coastguard Worker if (start)
911*193032a3SAndroid Build Coastguard Worker start = strstr(start, "(II)");
912*193032a3SAndroid Build Coastguard Worker if (start)
913*193032a3SAndroid Build Coastguard Worker return extract_edid_xorg(start);
914*193032a3SAndroid Build Coastguard Worker
915*193032a3SAndroid Build Coastguard Worker unsigned i;
916*193032a3SAndroid Build Coastguard Worker
917*193032a3SAndroid Build Coastguard Worker /* Is the EDID provided in hex? */
918*193032a3SAndroid Build Coastguard Worker for (i = 0; i < 32 && (isspace(data[i]) || strchr(ignore_chars, data[i]) ||
919*193032a3SAndroid Build Coastguard Worker tolower(data[i]) == 'x' || isxdigit(data[i])); i++);
920*193032a3SAndroid Build Coastguard Worker
921*193032a3SAndroid Build Coastguard Worker if (i == 32)
922*193032a3SAndroid Build Coastguard Worker return extract_edid_hex(data);
923*193032a3SAndroid Build Coastguard Worker
924*193032a3SAndroid Build Coastguard Worker /* Assume binary */
925*193032a3SAndroid Build Coastguard Worker if (edid_data.size() > sizeof(edid)) {
926*193032a3SAndroid Build Coastguard Worker fprintf(error, "Binary EDID length %zu is greater than %zu.\n",
927*193032a3SAndroid Build Coastguard Worker edid_data.size(), sizeof(edid));
928*193032a3SAndroid Build Coastguard Worker return false;
929*193032a3SAndroid Build Coastguard Worker }
930*193032a3SAndroid Build Coastguard Worker memcpy(edid, data, edid_data.size());
931*193032a3SAndroid Build Coastguard Worker state.edid_size = edid_data.size();
932*193032a3SAndroid Build Coastguard Worker return true;
933*193032a3SAndroid Build Coastguard Worker }
934*193032a3SAndroid Build Coastguard Worker
crc_calc(const unsigned char * b)935*193032a3SAndroid Build Coastguard Worker static unsigned char crc_calc(const unsigned char *b)
936*193032a3SAndroid Build Coastguard Worker {
937*193032a3SAndroid Build Coastguard Worker unsigned char sum = 0;
938*193032a3SAndroid Build Coastguard Worker unsigned i;
939*193032a3SAndroid Build Coastguard Worker
940*193032a3SAndroid Build Coastguard Worker for (i = 0; i < 127; i++)
941*193032a3SAndroid Build Coastguard Worker sum += b[i];
942*193032a3SAndroid Build Coastguard Worker return 256 - sum;
943*193032a3SAndroid Build Coastguard Worker }
944*193032a3SAndroid Build Coastguard Worker
crc_ok(const unsigned char * b)945*193032a3SAndroid Build Coastguard Worker static int crc_ok(const unsigned char *b)
946*193032a3SAndroid Build Coastguard Worker {
947*193032a3SAndroid Build Coastguard Worker return crc_calc(b) == b[127];
948*193032a3SAndroid Build Coastguard Worker }
949*193032a3SAndroid Build Coastguard Worker
hexdumpedid(FILE * f,const unsigned char * edid,unsigned size)950*193032a3SAndroid Build Coastguard Worker static void hexdumpedid(FILE *f, const unsigned char *edid, unsigned size)
951*193032a3SAndroid Build Coastguard Worker {
952*193032a3SAndroid Build Coastguard Worker unsigned b, i, j;
953*193032a3SAndroid Build Coastguard Worker
954*193032a3SAndroid Build Coastguard Worker for (b = 0; b < size / 128; b++) {
955*193032a3SAndroid Build Coastguard Worker const unsigned char *buf = edid + 128 * b;
956*193032a3SAndroid Build Coastguard Worker
957*193032a3SAndroid Build Coastguard Worker if (b)
958*193032a3SAndroid Build Coastguard Worker fprintf(f, "\n");
959*193032a3SAndroid Build Coastguard Worker for (i = 0; i < 128; i += 0x10) {
960*193032a3SAndroid Build Coastguard Worker fprintf(f, "%02x", buf[i]);
961*193032a3SAndroid Build Coastguard Worker for (j = 1; j < 0x10; j++) {
962*193032a3SAndroid Build Coastguard Worker fprintf(f, " %02x", buf[i + j]);
963*193032a3SAndroid Build Coastguard Worker }
964*193032a3SAndroid Build Coastguard Worker fprintf(f, "\n");
965*193032a3SAndroid Build Coastguard Worker }
966*193032a3SAndroid Build Coastguard Worker if (!crc_ok(buf))
967*193032a3SAndroid Build Coastguard Worker fprintf(f, "Block %u has a checksum error (should be 0x%02x).\n",
968*193032a3SAndroid Build Coastguard Worker b, crc_calc(buf));
969*193032a3SAndroid Build Coastguard Worker }
970*193032a3SAndroid Build Coastguard Worker }
971*193032a3SAndroid Build Coastguard Worker
carraydumpedid(FILE * f,const unsigned char * edid,unsigned size)972*193032a3SAndroid Build Coastguard Worker static void carraydumpedid(FILE *f, const unsigned char *edid, unsigned size)
973*193032a3SAndroid Build Coastguard Worker {
974*193032a3SAndroid Build Coastguard Worker unsigned b, i, j;
975*193032a3SAndroid Build Coastguard Worker
976*193032a3SAndroid Build Coastguard Worker fprintf(f, "const unsigned char edid[] = {\n");
977*193032a3SAndroid Build Coastguard Worker for (b = 0; b < size / 128; b++) {
978*193032a3SAndroid Build Coastguard Worker const unsigned char *buf = edid + 128 * b;
979*193032a3SAndroid Build Coastguard Worker
980*193032a3SAndroid Build Coastguard Worker if (b)
981*193032a3SAndroid Build Coastguard Worker fprintf(f, "\n");
982*193032a3SAndroid Build Coastguard Worker for (i = 0; i < 128; i += 8) {
983*193032a3SAndroid Build Coastguard Worker fprintf(f, "\t0x%02x,", buf[i]);
984*193032a3SAndroid Build Coastguard Worker for (j = 1; j < 8; j++) {
985*193032a3SAndroid Build Coastguard Worker fprintf(f, " 0x%02x,", buf[i + j]);
986*193032a3SAndroid Build Coastguard Worker }
987*193032a3SAndroid Build Coastguard Worker fprintf(f, "\n");
988*193032a3SAndroid Build Coastguard Worker }
989*193032a3SAndroid Build Coastguard Worker if (!crc_ok(buf))
990*193032a3SAndroid Build Coastguard Worker fprintf(f, "\t/* Block %u has a checksum error (should be 0x%02x). */\n",
991*193032a3SAndroid Build Coastguard Worker b, crc_calc(buf));
992*193032a3SAndroid Build Coastguard Worker }
993*193032a3SAndroid Build Coastguard Worker fprintf(f, "};\n");
994*193032a3SAndroid Build Coastguard Worker }
995*193032a3SAndroid Build Coastguard Worker
996*193032a3SAndroid Build Coastguard Worker // This format can be read by the QuantumData EDID editor
xmldumpedid(FILE * f,const unsigned char * edid,unsigned size)997*193032a3SAndroid Build Coastguard Worker static void xmldumpedid(FILE *f, const unsigned char *edid, unsigned size)
998*193032a3SAndroid Build Coastguard Worker {
999*193032a3SAndroid Build Coastguard Worker fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
1000*193032a3SAndroid Build Coastguard Worker fprintf(f, "<DATAOBJ>\n");
1001*193032a3SAndroid Build Coastguard Worker fprintf(f, " <HEADER TYPE=\"DID\" VERSION=\"1.0\"/>\n");
1002*193032a3SAndroid Build Coastguard Worker fprintf(f, " <DATA>\n");
1003*193032a3SAndroid Build Coastguard Worker for (unsigned b = 0; b < size / 128; b++) {
1004*193032a3SAndroid Build Coastguard Worker const unsigned char *buf = edid + 128 * b;
1005*193032a3SAndroid Build Coastguard Worker
1006*193032a3SAndroid Build Coastguard Worker fprintf(f, " <BLOCK%u>", b);
1007*193032a3SAndroid Build Coastguard Worker for (unsigned i = 0; i < 128; i++)
1008*193032a3SAndroid Build Coastguard Worker fprintf(f, "%02X", buf[i]);
1009*193032a3SAndroid Build Coastguard Worker fprintf(f, "</BLOCK%u>\n", b);
1010*193032a3SAndroid Build Coastguard Worker }
1011*193032a3SAndroid Build Coastguard Worker fprintf(f, " </DATA>\n");
1012*193032a3SAndroid Build Coastguard Worker fprintf(f, "</DATAOBJ>\n");
1013*193032a3SAndroid Build Coastguard Worker }
1014*193032a3SAndroid Build Coastguard Worker
1015*193032a3SAndroid Build Coastguard Worker
edid_to_file(const char * to_file,enum output_format out_fmt)1016*193032a3SAndroid Build Coastguard Worker static int edid_to_file(const char *to_file, enum output_format out_fmt)
1017*193032a3SAndroid Build Coastguard Worker {
1018*193032a3SAndroid Build Coastguard Worker FILE *out;
1019*193032a3SAndroid Build Coastguard Worker
1020*193032a3SAndroid Build Coastguard Worker if (!strcmp(to_file, "-")) {
1021*193032a3SAndroid Build Coastguard Worker to_file = "stdout";
1022*193032a3SAndroid Build Coastguard Worker out = stdout;
1023*193032a3SAndroid Build Coastguard Worker } else if ((out = fopen(to_file, "w")) == NULL) {
1024*193032a3SAndroid Build Coastguard Worker perror(to_file);
1025*193032a3SAndroid Build Coastguard Worker return -1;
1026*193032a3SAndroid Build Coastguard Worker }
1027*193032a3SAndroid Build Coastguard Worker if (out_fmt == OUT_FMT_DEFAULT)
1028*193032a3SAndroid Build Coastguard Worker out_fmt = out == stdout ? OUT_FMT_HEX : OUT_FMT_RAW;
1029*193032a3SAndroid Build Coastguard Worker
1030*193032a3SAndroid Build Coastguard Worker switch (out_fmt) {
1031*193032a3SAndroid Build Coastguard Worker default:
1032*193032a3SAndroid Build Coastguard Worker case OUT_FMT_HEX:
1033*193032a3SAndroid Build Coastguard Worker hexdumpedid(out, edid, state.edid_size);
1034*193032a3SAndroid Build Coastguard Worker break;
1035*193032a3SAndroid Build Coastguard Worker case OUT_FMT_RAW:
1036*193032a3SAndroid Build Coastguard Worker fwrite(edid, state.edid_size, 1, out);
1037*193032a3SAndroid Build Coastguard Worker break;
1038*193032a3SAndroid Build Coastguard Worker case OUT_FMT_CARRAY:
1039*193032a3SAndroid Build Coastguard Worker carraydumpedid(out, edid, state.edid_size);
1040*193032a3SAndroid Build Coastguard Worker break;
1041*193032a3SAndroid Build Coastguard Worker case OUT_FMT_XML:
1042*193032a3SAndroid Build Coastguard Worker xmldumpedid(out, edid, state.edid_size);
1043*193032a3SAndroid Build Coastguard Worker break;
1044*193032a3SAndroid Build Coastguard Worker }
1045*193032a3SAndroid Build Coastguard Worker
1046*193032a3SAndroid Build Coastguard Worker if (out != stdout)
1047*193032a3SAndroid Build Coastguard Worker fclose(out);
1048*193032a3SAndroid Build Coastguard Worker return 0;
1049*193032a3SAndroid Build Coastguard Worker }
1050*193032a3SAndroid Build Coastguard Worker
edid_from_file(const char * from_file,FILE * error)1051*193032a3SAndroid Build Coastguard Worker static int edid_from_file(const char *from_file, FILE *error)
1052*193032a3SAndroid Build Coastguard Worker {
1053*193032a3SAndroid Build Coastguard Worker #ifdef O_BINARY
1054*193032a3SAndroid Build Coastguard Worker // Windows compatibility
1055*193032a3SAndroid Build Coastguard Worker int flags = O_RDONLY | O_BINARY;
1056*193032a3SAndroid Build Coastguard Worker #else
1057*193032a3SAndroid Build Coastguard Worker int flags = O_RDONLY;
1058*193032a3SAndroid Build Coastguard Worker #endif
1059*193032a3SAndroid Build Coastguard Worker int fd;
1060*193032a3SAndroid Build Coastguard Worker
1061*193032a3SAndroid Build Coastguard Worker if (!strcmp(from_file, "-")) {
1062*193032a3SAndroid Build Coastguard Worker from_file = "stdin";
1063*193032a3SAndroid Build Coastguard Worker fd = 0;
1064*193032a3SAndroid Build Coastguard Worker } else if ((fd = open(from_file, flags)) == -1) {
1065*193032a3SAndroid Build Coastguard Worker perror(from_file);
1066*193032a3SAndroid Build Coastguard Worker return -1;
1067*193032a3SAndroid Build Coastguard Worker }
1068*193032a3SAndroid Build Coastguard Worker
1069*193032a3SAndroid Build Coastguard Worker odd_hex_digits = false;
1070*193032a3SAndroid Build Coastguard Worker if (!extract_edid(fd, error)) {
1071*193032a3SAndroid Build Coastguard Worker if (!state.edid_size) {
1072*193032a3SAndroid Build Coastguard Worker fprintf(error, "EDID of '%s' was empty.\n", from_file);
1073*193032a3SAndroid Build Coastguard Worker return -1;
1074*193032a3SAndroid Build Coastguard Worker }
1075*193032a3SAndroid Build Coastguard Worker fprintf(error, "EDID extract of '%s' failed: ", from_file);
1076*193032a3SAndroid Build Coastguard Worker if (odd_hex_digits)
1077*193032a3SAndroid Build Coastguard Worker fprintf(error, "odd number of hexadecimal digits.\n");
1078*193032a3SAndroid Build Coastguard Worker else
1079*193032a3SAndroid Build Coastguard Worker fprintf(error, "unknown format.\n");
1080*193032a3SAndroid Build Coastguard Worker return -1;
1081*193032a3SAndroid Build Coastguard Worker }
1082*193032a3SAndroid Build Coastguard Worker if (state.edid_size % EDID_PAGE_SIZE) {
1083*193032a3SAndroid Build Coastguard Worker fprintf(error, "EDID length %u is not a multiple of %u.\n",
1084*193032a3SAndroid Build Coastguard Worker state.edid_size, EDID_PAGE_SIZE);
1085*193032a3SAndroid Build Coastguard Worker return -1;
1086*193032a3SAndroid Build Coastguard Worker }
1087*193032a3SAndroid Build Coastguard Worker state.num_blocks = state.edid_size / EDID_PAGE_SIZE;
1088*193032a3SAndroid Build Coastguard Worker if (fd != 0)
1089*193032a3SAndroid Build Coastguard Worker close(fd);
1090*193032a3SAndroid Build Coastguard Worker
1091*193032a3SAndroid Build Coastguard Worker if (memcmp(edid, "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", 8)) {
1092*193032a3SAndroid Build Coastguard Worker fprintf(error, "No EDID header found in '%s'.\n", from_file);
1093*193032a3SAndroid Build Coastguard Worker return -1;
1094*193032a3SAndroid Build Coastguard Worker }
1095*193032a3SAndroid Build Coastguard Worker return 0;
1096*193032a3SAndroid Build Coastguard Worker }
1097*193032a3SAndroid Build Coastguard Worker
1098*193032a3SAndroid Build Coastguard Worker /* generic extension code */
1099*193032a3SAndroid Build Coastguard Worker
block_name(unsigned char block)1100*193032a3SAndroid Build Coastguard Worker std::string block_name(unsigned char block)
1101*193032a3SAndroid Build Coastguard Worker {
1102*193032a3SAndroid Build Coastguard Worker char buf[10];
1103*193032a3SAndroid Build Coastguard Worker
1104*193032a3SAndroid Build Coastguard Worker switch (block) {
1105*193032a3SAndroid Build Coastguard Worker case 0x00: return "Base EDID";
1106*193032a3SAndroid Build Coastguard Worker case 0x02: return "CTA-861 Extension Block";
1107*193032a3SAndroid Build Coastguard Worker case 0x10: return "Video Timing Extension Block";
1108*193032a3SAndroid Build Coastguard Worker case 0x20: return "EDID 2.0 Extension Block";
1109*193032a3SAndroid Build Coastguard Worker case 0x40: return "Display Information Extension Block";
1110*193032a3SAndroid Build Coastguard Worker case 0x50: return "Localized String Extension Block";
1111*193032a3SAndroid Build Coastguard Worker case 0x60: return "Microdisplay Interface Extension Block";
1112*193032a3SAndroid Build Coastguard Worker case 0x70: return "DisplayID Extension Block";
1113*193032a3SAndroid Build Coastguard Worker case 0xf0: return "Block Map Extension Block";
1114*193032a3SAndroid Build Coastguard Worker case 0xff: return "Manufacturer-Specific Extension Block";
1115*193032a3SAndroid Build Coastguard Worker default:
1116*193032a3SAndroid Build Coastguard Worker sprintf(buf, " 0x%02x", block);
1117*193032a3SAndroid Build Coastguard Worker return std::string("Unknown EDID Extension Block") + buf;
1118*193032a3SAndroid Build Coastguard Worker }
1119*193032a3SAndroid Build Coastguard Worker }
1120*193032a3SAndroid Build Coastguard Worker
parse_block_map(const unsigned char * x)1121*193032a3SAndroid Build Coastguard Worker void edid_state::parse_block_map(const unsigned char *x)
1122*193032a3SAndroid Build Coastguard Worker {
1123*193032a3SAndroid Build Coastguard Worker unsigned last_valid_block_tag = 0;
1124*193032a3SAndroid Build Coastguard Worker bool fail_once = false;
1125*193032a3SAndroid Build Coastguard Worker unsigned offset = 1;
1126*193032a3SAndroid Build Coastguard Worker unsigned i;
1127*193032a3SAndroid Build Coastguard Worker
1128*193032a3SAndroid Build Coastguard Worker if (block_nr == 1)
1129*193032a3SAndroid Build Coastguard Worker block_map.saw_block_1 = true;
1130*193032a3SAndroid Build Coastguard Worker else if (!block_map.saw_block_1)
1131*193032a3SAndroid Build Coastguard Worker fail("No EDID Block Map Extension found in block 1.\n");
1132*193032a3SAndroid Build Coastguard Worker else if (block_nr == 128)
1133*193032a3SAndroid Build Coastguard Worker block_map.saw_block_128 = true;
1134*193032a3SAndroid Build Coastguard Worker
1135*193032a3SAndroid Build Coastguard Worker if (block_nr > 1)
1136*193032a3SAndroid Build Coastguard Worker offset = 128;
1137*193032a3SAndroid Build Coastguard Worker
1138*193032a3SAndroid Build Coastguard Worker for (i = 1; i < 127; i++) {
1139*193032a3SAndroid Build Coastguard Worker unsigned block = offset + i;
1140*193032a3SAndroid Build Coastguard Worker
1141*193032a3SAndroid Build Coastguard Worker if (x[i]) {
1142*193032a3SAndroid Build Coastguard Worker last_valid_block_tag++;
1143*193032a3SAndroid Build Coastguard Worker if (i != last_valid_block_tag && !fail_once) {
1144*193032a3SAndroid Build Coastguard Worker fail("Valid block tags are not consecutive.\n");
1145*193032a3SAndroid Build Coastguard Worker fail_once = true;
1146*193032a3SAndroid Build Coastguard Worker }
1147*193032a3SAndroid Build Coastguard Worker printf(" Block %3u: %s\n", block, block_name(x[i]).c_str());
1148*193032a3SAndroid Build Coastguard Worker if (block >= num_blocks) {
1149*193032a3SAndroid Build Coastguard Worker if (!fail_once)
1150*193032a3SAndroid Build Coastguard Worker fail("Invalid block number %u.\n", block);
1151*193032a3SAndroid Build Coastguard Worker fail_once = true;
1152*193032a3SAndroid Build Coastguard Worker } else if (x[i] != edid[block * EDID_PAGE_SIZE]) {
1153*193032a3SAndroid Build Coastguard Worker fail("Block %u tag mismatch: expected 0x%02x, but got 0x%02x.\n",
1154*193032a3SAndroid Build Coastguard Worker block, edid[block * EDID_PAGE_SIZE], x[i]);
1155*193032a3SAndroid Build Coastguard Worker }
1156*193032a3SAndroid Build Coastguard Worker } else if (block < num_blocks) {
1157*193032a3SAndroid Build Coastguard Worker fail("Block %u tag mismatch: expected 0x%02x, but got 0x00.\n",
1158*193032a3SAndroid Build Coastguard Worker block, edid[block * EDID_PAGE_SIZE]);
1159*193032a3SAndroid Build Coastguard Worker }
1160*193032a3SAndroid Build Coastguard Worker }
1161*193032a3SAndroid Build Coastguard Worker }
1162*193032a3SAndroid Build Coastguard Worker
preparse_extension(const unsigned char * x)1163*193032a3SAndroid Build Coastguard Worker void edid_state::preparse_extension(const unsigned char *x)
1164*193032a3SAndroid Build Coastguard Worker {
1165*193032a3SAndroid Build Coastguard Worker switch (x[0]) {
1166*193032a3SAndroid Build Coastguard Worker case 0x02:
1167*193032a3SAndroid Build Coastguard Worker has_cta = true;
1168*193032a3SAndroid Build Coastguard Worker preparse_cta_block(x);
1169*193032a3SAndroid Build Coastguard Worker break;
1170*193032a3SAndroid Build Coastguard Worker case 0x70:
1171*193032a3SAndroid Build Coastguard Worker has_dispid = true;
1172*193032a3SAndroid Build Coastguard Worker preparse_displayid_block(x);
1173*193032a3SAndroid Build Coastguard Worker break;
1174*193032a3SAndroid Build Coastguard Worker }
1175*193032a3SAndroid Build Coastguard Worker }
1176*193032a3SAndroid Build Coastguard Worker
parse_extension(const unsigned char * x)1177*193032a3SAndroid Build Coastguard Worker void edid_state::parse_extension(const unsigned char *x)
1178*193032a3SAndroid Build Coastguard Worker {
1179*193032a3SAndroid Build Coastguard Worker block = block_name(x[0]);
1180*193032a3SAndroid Build Coastguard Worker data_block.clear();
1181*193032a3SAndroid Build Coastguard Worker
1182*193032a3SAndroid Build Coastguard Worker printf("\n");
1183*193032a3SAndroid Build Coastguard Worker if (block_nr && x[0] == 0)
1184*193032a3SAndroid Build Coastguard Worker block = "Unknown EDID Extension Block 0x00";
1185*193032a3SAndroid Build Coastguard Worker printf("Block %u, %s:\n", block_nr, block.c_str());
1186*193032a3SAndroid Build Coastguard Worker
1187*193032a3SAndroid Build Coastguard Worker switch (x[0]) {
1188*193032a3SAndroid Build Coastguard Worker case 0x02:
1189*193032a3SAndroid Build Coastguard Worker parse_cta_block(x);
1190*193032a3SAndroid Build Coastguard Worker break;
1191*193032a3SAndroid Build Coastguard Worker case 0x10:
1192*193032a3SAndroid Build Coastguard Worker parse_vtb_ext_block(x);
1193*193032a3SAndroid Build Coastguard Worker break;
1194*193032a3SAndroid Build Coastguard Worker case 0x20:
1195*193032a3SAndroid Build Coastguard Worker fail("Deprecated extension block for EDID 2.0, do not use.\n");
1196*193032a3SAndroid Build Coastguard Worker break;
1197*193032a3SAndroid Build Coastguard Worker case 0x40:
1198*193032a3SAndroid Build Coastguard Worker parse_di_ext_block(x);
1199*193032a3SAndroid Build Coastguard Worker break;
1200*193032a3SAndroid Build Coastguard Worker case 0x50:
1201*193032a3SAndroid Build Coastguard Worker parse_ls_ext_block(x);
1202*193032a3SAndroid Build Coastguard Worker break;
1203*193032a3SAndroid Build Coastguard Worker case 0x70:
1204*193032a3SAndroid Build Coastguard Worker parse_displayid_block(x);
1205*193032a3SAndroid Build Coastguard Worker break;
1206*193032a3SAndroid Build Coastguard Worker case 0xf0:
1207*193032a3SAndroid Build Coastguard Worker parse_block_map(x);
1208*193032a3SAndroid Build Coastguard Worker if (block_nr != 1 && block_nr != 128)
1209*193032a3SAndroid Build Coastguard Worker fail("Must be used in block 1 and 128.\n");
1210*193032a3SAndroid Build Coastguard Worker break;
1211*193032a3SAndroid Build Coastguard Worker default:
1212*193032a3SAndroid Build Coastguard Worker hex_block(" ", x, EDID_PAGE_SIZE);
1213*193032a3SAndroid Build Coastguard Worker fail("Unknown Extension Block.\n");
1214*193032a3SAndroid Build Coastguard Worker break;
1215*193032a3SAndroid Build Coastguard Worker }
1216*193032a3SAndroid Build Coastguard Worker
1217*193032a3SAndroid Build Coastguard Worker data_block.clear();
1218*193032a3SAndroid Build Coastguard Worker do_checksum("", x, EDID_PAGE_SIZE);
1219*193032a3SAndroid Build Coastguard Worker }
1220*193032a3SAndroid Build Coastguard Worker
parse_edid()1221*193032a3SAndroid Build Coastguard Worker int edid_state::parse_edid()
1222*193032a3SAndroid Build Coastguard Worker {
1223*193032a3SAndroid Build Coastguard Worker hide_serial_numbers = options[OptHideSerialNumbers];
1224*193032a3SAndroid Build Coastguard Worker
1225*193032a3SAndroid Build Coastguard Worker for (unsigned i = 1; i < num_blocks; i++)
1226*193032a3SAndroid Build Coastguard Worker preparse_extension(edid + i * EDID_PAGE_SIZE);
1227*193032a3SAndroid Build Coastguard Worker
1228*193032a3SAndroid Build Coastguard Worker if (options[OptPhysicalAddress]) {
1229*193032a3SAndroid Build Coastguard Worker printf("%x.%x.%x.%x\n",
1230*193032a3SAndroid Build Coastguard Worker (cta.preparsed_phys_addr >> 12) & 0xf,
1231*193032a3SAndroid Build Coastguard Worker (cta.preparsed_phys_addr >> 8) & 0xf,
1232*193032a3SAndroid Build Coastguard Worker (cta.preparsed_phys_addr >> 4) & 0xf,
1233*193032a3SAndroid Build Coastguard Worker cta.preparsed_phys_addr & 0xf);
1234*193032a3SAndroid Build Coastguard Worker return 0;
1235*193032a3SAndroid Build Coastguard Worker }
1236*193032a3SAndroid Build Coastguard Worker
1237*193032a3SAndroid Build Coastguard Worker if (!options[OptSkipHexDump]) {
1238*193032a3SAndroid Build Coastguard Worker printf("edid-decode (hex):\n\n");
1239*193032a3SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_blocks; i++) {
1240*193032a3SAndroid Build Coastguard Worker hex_block("", edid + i * EDID_PAGE_SIZE, EDID_PAGE_SIZE, false);
1241*193032a3SAndroid Build Coastguard Worker if (i == num_blocks - 1 && options[OptOnlyHexDump])
1242*193032a3SAndroid Build Coastguard Worker return 0;
1243*193032a3SAndroid Build Coastguard Worker printf("\n");
1244*193032a3SAndroid Build Coastguard Worker }
1245*193032a3SAndroid Build Coastguard Worker printf("----------------\n\n");
1246*193032a3SAndroid Build Coastguard Worker }
1247*193032a3SAndroid Build Coastguard Worker
1248*193032a3SAndroid Build Coastguard Worker block = block_name(0x00);
1249*193032a3SAndroid Build Coastguard Worker printf("Block %u, %s:\n", block_nr, block.c_str());
1250*193032a3SAndroid Build Coastguard Worker parse_base_block(edid);
1251*193032a3SAndroid Build Coastguard Worker
1252*193032a3SAndroid Build Coastguard Worker for (unsigned i = 1; i < num_blocks; i++) {
1253*193032a3SAndroid Build Coastguard Worker block_nr++;
1254*193032a3SAndroid Build Coastguard Worker printf("\n----------------\n");
1255*193032a3SAndroid Build Coastguard Worker parse_extension(edid + i * EDID_PAGE_SIZE);
1256*193032a3SAndroid Build Coastguard Worker }
1257*193032a3SAndroid Build Coastguard Worker
1258*193032a3SAndroid Build Coastguard Worker block = "";
1259*193032a3SAndroid Build Coastguard Worker block_nr = EDID_MAX_BLOCKS;
1260*193032a3SAndroid Build Coastguard Worker
1261*193032a3SAndroid Build Coastguard Worker if (has_cta)
1262*193032a3SAndroid Build Coastguard Worker cta_resolve_svrs();
1263*193032a3SAndroid Build Coastguard Worker
1264*193032a3SAndroid Build Coastguard Worker if (options[OptPreferredTimings] && base.preferred_timing.is_valid()) {
1265*193032a3SAndroid Build Coastguard Worker printf("\n----------------\n");
1266*193032a3SAndroid Build Coastguard Worker printf("\nPreferred Video Timing if only Block 0 is parsed:\n");
1267*193032a3SAndroid Build Coastguard Worker print_timings(" ", base.preferred_timing, true, false);
1268*193032a3SAndroid Build Coastguard Worker }
1269*193032a3SAndroid Build Coastguard Worker
1270*193032a3SAndroid Build Coastguard Worker if (options[OptNativeTimings] &&
1271*193032a3SAndroid Build Coastguard Worker base.preferred_timing.is_valid() && base.preferred_is_also_native) {
1272*193032a3SAndroid Build Coastguard Worker printf("\n----------------\n");
1273*193032a3SAndroid Build Coastguard Worker printf("\nNative Video Timing if only Block 0 is parsed:\n");
1274*193032a3SAndroid Build Coastguard Worker print_timings(" ", base.preferred_timing, true, false);
1275*193032a3SAndroid Build Coastguard Worker }
1276*193032a3SAndroid Build Coastguard Worker
1277*193032a3SAndroid Build Coastguard Worker if (options[OptPreferredTimings] && !cta.preferred_timings.empty()) {
1278*193032a3SAndroid Build Coastguard Worker printf("\n----------------\n");
1279*193032a3SAndroid Build Coastguard Worker printf("\nPreferred Video Timing%s if Block 0 and CTA-861 Blocks are parsed:\n",
1280*193032a3SAndroid Build Coastguard Worker cta.preferred_timings.size() > 1 ? "s" : "");
1281*193032a3SAndroid Build Coastguard Worker for (vec_timings_ext::iterator iter = cta.preferred_timings.begin();
1282*193032a3SAndroid Build Coastguard Worker iter != cta.preferred_timings.end(); ++iter)
1283*193032a3SAndroid Build Coastguard Worker print_timings(" ", *iter, true, false);
1284*193032a3SAndroid Build Coastguard Worker }
1285*193032a3SAndroid Build Coastguard Worker
1286*193032a3SAndroid Build Coastguard Worker if (options[OptNativeTimings] && !cta.native_timings.empty()) {
1287*193032a3SAndroid Build Coastguard Worker printf("\n----------------\n");
1288*193032a3SAndroid Build Coastguard Worker printf("\nNative Video Timing%s if Block 0 and CTA-861 Blocks are parsed:\n",
1289*193032a3SAndroid Build Coastguard Worker cta.native_timings.size() > 1 ? "s" : "");
1290*193032a3SAndroid Build Coastguard Worker for (vec_timings_ext::iterator iter = cta.native_timings.begin();
1291*193032a3SAndroid Build Coastguard Worker iter != cta.native_timings.end(); ++iter)
1292*193032a3SAndroid Build Coastguard Worker print_timings(" ", *iter, true, false);
1293*193032a3SAndroid Build Coastguard Worker }
1294*193032a3SAndroid Build Coastguard Worker
1295*193032a3SAndroid Build Coastguard Worker if (options[OptPreferredTimings] && !dispid.preferred_timings.empty()) {
1296*193032a3SAndroid Build Coastguard Worker printf("\n----------------\n");
1297*193032a3SAndroid Build Coastguard Worker printf("\nPreferred Video Timing%s if Block 0 and DisplayID Blocks are parsed:\n",
1298*193032a3SAndroid Build Coastguard Worker dispid.preferred_timings.size() > 1 ? "s" : "");
1299*193032a3SAndroid Build Coastguard Worker for (vec_timings_ext::iterator iter = dispid.preferred_timings.begin();
1300*193032a3SAndroid Build Coastguard Worker iter != dispid.preferred_timings.end(); ++iter)
1301*193032a3SAndroid Build Coastguard Worker print_timings(" ", *iter, true, false);
1302*193032a3SAndroid Build Coastguard Worker }
1303*193032a3SAndroid Build Coastguard Worker
1304*193032a3SAndroid Build Coastguard Worker if (!options[OptCheck] && !options[OptCheckInline])
1305*193032a3SAndroid Build Coastguard Worker return 0;
1306*193032a3SAndroid Build Coastguard Worker
1307*193032a3SAndroid Build Coastguard Worker check_base_block();
1308*193032a3SAndroid Build Coastguard Worker if (has_cta)
1309*193032a3SAndroid Build Coastguard Worker check_cta_blocks();
1310*193032a3SAndroid Build Coastguard Worker if (has_dispid)
1311*193032a3SAndroid Build Coastguard Worker check_displayid_blocks();
1312*193032a3SAndroid Build Coastguard Worker
1313*193032a3SAndroid Build Coastguard Worker printf("\n----------------\n");
1314*193032a3SAndroid Build Coastguard Worker
1315*193032a3SAndroid Build Coastguard Worker if (!options[OptSkipSHA] && strlen(STRING(SHA))) {
1316*193032a3SAndroid Build Coastguard Worker printf("\nedid-decode SHA: %s %s\n", STRING(SHA), STRING(DATE));
1317*193032a3SAndroid Build Coastguard Worker }
1318*193032a3SAndroid Build Coastguard Worker
1319*193032a3SAndroid Build Coastguard Worker if (options[OptCheck]) {
1320*193032a3SAndroid Build Coastguard Worker if (warnings)
1321*193032a3SAndroid Build Coastguard Worker show_msgs(true);
1322*193032a3SAndroid Build Coastguard Worker if (failures)
1323*193032a3SAndroid Build Coastguard Worker show_msgs(false);
1324*193032a3SAndroid Build Coastguard Worker }
1325*193032a3SAndroid Build Coastguard Worker printf("\nEDID conformity: %s\n", failures ? "FAIL" : "PASS");
1326*193032a3SAndroid Build Coastguard Worker return failures ? -2 : 0;
1327*193032a3SAndroid Build Coastguard Worker }
1328*193032a3SAndroid Build Coastguard Worker
1329*193032a3SAndroid Build Coastguard Worker enum cvt_opts {
1330*193032a3SAndroid Build Coastguard Worker CVT_WIDTH = 0,
1331*193032a3SAndroid Build Coastguard Worker CVT_HEIGHT,
1332*193032a3SAndroid Build Coastguard Worker CVT_FPS,
1333*193032a3SAndroid Build Coastguard Worker CVT_INTERLACED,
1334*193032a3SAndroid Build Coastguard Worker CVT_OVERSCAN,
1335*193032a3SAndroid Build Coastguard Worker CVT_RB,
1336*193032a3SAndroid Build Coastguard Worker CVT_ALT,
1337*193032a3SAndroid Build Coastguard Worker CVT_RB_H_BLANK,
1338*193032a3SAndroid Build Coastguard Worker };
1339*193032a3SAndroid Build Coastguard Worker
parse_cvt_subopt(char ** subopt_str,double * value)1340*193032a3SAndroid Build Coastguard Worker static int parse_cvt_subopt(char **subopt_str, double *value)
1341*193032a3SAndroid Build Coastguard Worker {
1342*193032a3SAndroid Build Coastguard Worker int opt;
1343*193032a3SAndroid Build Coastguard Worker char *opt_str;
1344*193032a3SAndroid Build Coastguard Worker
1345*193032a3SAndroid Build Coastguard Worker static const char * const subopt_list[] = {
1346*193032a3SAndroid Build Coastguard Worker "w",
1347*193032a3SAndroid Build Coastguard Worker "h",
1348*193032a3SAndroid Build Coastguard Worker "fps",
1349*193032a3SAndroid Build Coastguard Worker "interlaced",
1350*193032a3SAndroid Build Coastguard Worker "overscan",
1351*193032a3SAndroid Build Coastguard Worker "rb",
1352*193032a3SAndroid Build Coastguard Worker "alt",
1353*193032a3SAndroid Build Coastguard Worker "hblank",
1354*193032a3SAndroid Build Coastguard Worker nullptr
1355*193032a3SAndroid Build Coastguard Worker };
1356*193032a3SAndroid Build Coastguard Worker
1357*193032a3SAndroid Build Coastguard Worker opt = getsubopt(subopt_str, (char* const*) subopt_list, &opt_str);
1358*193032a3SAndroid Build Coastguard Worker
1359*193032a3SAndroid Build Coastguard Worker if (opt == -1) {
1360*193032a3SAndroid Build Coastguard Worker fprintf(stderr, "Invalid suboptions specified.\n");
1361*193032a3SAndroid Build Coastguard Worker usage();
1362*193032a3SAndroid Build Coastguard Worker std::exit(EXIT_FAILURE);
1363*193032a3SAndroid Build Coastguard Worker }
1364*193032a3SAndroid Build Coastguard Worker if (opt_str == nullptr && opt != CVT_INTERLACED && opt != CVT_ALT &&
1365*193032a3SAndroid Build Coastguard Worker opt != CVT_OVERSCAN) {
1366*193032a3SAndroid Build Coastguard Worker fprintf(stderr, "No value given to suboption <%s>.\n",
1367*193032a3SAndroid Build Coastguard Worker subopt_list[opt]);
1368*193032a3SAndroid Build Coastguard Worker usage();
1369*193032a3SAndroid Build Coastguard Worker std::exit(EXIT_FAILURE);
1370*193032a3SAndroid Build Coastguard Worker }
1371*193032a3SAndroid Build Coastguard Worker
1372*193032a3SAndroid Build Coastguard Worker if (opt_str)
1373*193032a3SAndroid Build Coastguard Worker *value = strtod(opt_str, nullptr);
1374*193032a3SAndroid Build Coastguard Worker return opt;
1375*193032a3SAndroid Build Coastguard Worker }
1376*193032a3SAndroid Build Coastguard Worker
parse_cvt(char * optarg)1377*193032a3SAndroid Build Coastguard Worker static void parse_cvt(char *optarg)
1378*193032a3SAndroid Build Coastguard Worker {
1379*193032a3SAndroid Build Coastguard Worker unsigned w = 0, h = 0;
1380*193032a3SAndroid Build Coastguard Worker double fps = 0;
1381*193032a3SAndroid Build Coastguard Worker unsigned rb = RB_NONE;
1382*193032a3SAndroid Build Coastguard Worker unsigned rb_h_blank = 0;
1383*193032a3SAndroid Build Coastguard Worker bool interlaced = false;
1384*193032a3SAndroid Build Coastguard Worker bool alt = false;
1385*193032a3SAndroid Build Coastguard Worker bool overscan = false;
1386*193032a3SAndroid Build Coastguard Worker
1387*193032a3SAndroid Build Coastguard Worker while (*optarg != '\0') {
1388*193032a3SAndroid Build Coastguard Worker int opt;
1389*193032a3SAndroid Build Coastguard Worker double opt_val;
1390*193032a3SAndroid Build Coastguard Worker
1391*193032a3SAndroid Build Coastguard Worker opt = parse_cvt_subopt(&optarg, &opt_val);
1392*193032a3SAndroid Build Coastguard Worker
1393*193032a3SAndroid Build Coastguard Worker switch (opt) {
1394*193032a3SAndroid Build Coastguard Worker case CVT_WIDTH:
1395*193032a3SAndroid Build Coastguard Worker w = round(opt_val);
1396*193032a3SAndroid Build Coastguard Worker break;
1397*193032a3SAndroid Build Coastguard Worker case CVT_HEIGHT:
1398*193032a3SAndroid Build Coastguard Worker h = round(opt_val);
1399*193032a3SAndroid Build Coastguard Worker break;
1400*193032a3SAndroid Build Coastguard Worker case CVT_FPS:
1401*193032a3SAndroid Build Coastguard Worker fps = opt_val;
1402*193032a3SAndroid Build Coastguard Worker break;
1403*193032a3SAndroid Build Coastguard Worker case CVT_RB:
1404*193032a3SAndroid Build Coastguard Worker rb = opt_val;
1405*193032a3SAndroid Build Coastguard Worker break;
1406*193032a3SAndroid Build Coastguard Worker case CVT_OVERSCAN:
1407*193032a3SAndroid Build Coastguard Worker overscan = true;
1408*193032a3SAndroid Build Coastguard Worker break;
1409*193032a3SAndroid Build Coastguard Worker case CVT_INTERLACED:
1410*193032a3SAndroid Build Coastguard Worker interlaced = opt_val;
1411*193032a3SAndroid Build Coastguard Worker break;
1412*193032a3SAndroid Build Coastguard Worker case CVT_ALT:
1413*193032a3SAndroid Build Coastguard Worker alt = opt_val;
1414*193032a3SAndroid Build Coastguard Worker break;
1415*193032a3SAndroid Build Coastguard Worker case CVT_RB_H_BLANK:
1416*193032a3SAndroid Build Coastguard Worker rb_h_blank = opt_val;
1417*193032a3SAndroid Build Coastguard Worker break;
1418*193032a3SAndroid Build Coastguard Worker default:
1419*193032a3SAndroid Build Coastguard Worker break;
1420*193032a3SAndroid Build Coastguard Worker }
1421*193032a3SAndroid Build Coastguard Worker }
1422*193032a3SAndroid Build Coastguard Worker
1423*193032a3SAndroid Build Coastguard Worker if (!w || !h || !fps) {
1424*193032a3SAndroid Build Coastguard Worker fprintf(stderr, "Missing width, height and/or fps.\n");
1425*193032a3SAndroid Build Coastguard Worker usage();
1426*193032a3SAndroid Build Coastguard Worker std::exit(EXIT_FAILURE);
1427*193032a3SAndroid Build Coastguard Worker }
1428*193032a3SAndroid Build Coastguard Worker if (interlaced)
1429*193032a3SAndroid Build Coastguard Worker fps /= 2;
1430*193032a3SAndroid Build Coastguard Worker timings t = state.calc_cvt_mode(w, h, fps, rb, interlaced, overscan, alt, rb_h_blank);
1431*193032a3SAndroid Build Coastguard Worker state.print_timings("", &t, "CVT", "", true, false);
1432*193032a3SAndroid Build Coastguard Worker }
1433*193032a3SAndroid Build Coastguard Worker
1434*193032a3SAndroid Build Coastguard Worker struct gtf_parsed_data {
1435*193032a3SAndroid Build Coastguard Worker unsigned w, h;
1436*193032a3SAndroid Build Coastguard Worker double freq;
1437*193032a3SAndroid Build Coastguard Worker double C, M, K, J;
1438*193032a3SAndroid Build Coastguard Worker bool overscan;
1439*193032a3SAndroid Build Coastguard Worker bool interlaced;
1440*193032a3SAndroid Build Coastguard Worker bool secondary;
1441*193032a3SAndroid Build Coastguard Worker bool params_from_edid;
1442*193032a3SAndroid Build Coastguard Worker enum gtf_ip_parm ip_parm;
1443*193032a3SAndroid Build Coastguard Worker };
1444*193032a3SAndroid Build Coastguard Worker
1445*193032a3SAndroid Build Coastguard Worker enum gtf_opts {
1446*193032a3SAndroid Build Coastguard Worker GTF_WIDTH = 0,
1447*193032a3SAndroid Build Coastguard Worker GTF_HEIGHT,
1448*193032a3SAndroid Build Coastguard Worker GTF_FPS,
1449*193032a3SAndroid Build Coastguard Worker GTF_HORFREQ,
1450*193032a3SAndroid Build Coastguard Worker GTF_PIXCLK,
1451*193032a3SAndroid Build Coastguard Worker GTF_INTERLACED,
1452*193032a3SAndroid Build Coastguard Worker GTF_OVERSCAN,
1453*193032a3SAndroid Build Coastguard Worker GTF_SECONDARY,
1454*193032a3SAndroid Build Coastguard Worker GTF_C2,
1455*193032a3SAndroid Build Coastguard Worker GTF_M,
1456*193032a3SAndroid Build Coastguard Worker GTF_K,
1457*193032a3SAndroid Build Coastguard Worker GTF_J2,
1458*193032a3SAndroid Build Coastguard Worker };
1459*193032a3SAndroid Build Coastguard Worker
parse_gtf_subopt(char ** subopt_str,double * value)1460*193032a3SAndroid Build Coastguard Worker static int parse_gtf_subopt(char **subopt_str, double *value)
1461*193032a3SAndroid Build Coastguard Worker {
1462*193032a3SAndroid Build Coastguard Worker int opt;
1463*193032a3SAndroid Build Coastguard Worker char *opt_str;
1464*193032a3SAndroid Build Coastguard Worker
1465*193032a3SAndroid Build Coastguard Worker static const char * const subopt_list[] = {
1466*193032a3SAndroid Build Coastguard Worker "w",
1467*193032a3SAndroid Build Coastguard Worker "h",
1468*193032a3SAndroid Build Coastguard Worker "fps",
1469*193032a3SAndroid Build Coastguard Worker "horfreq",
1470*193032a3SAndroid Build Coastguard Worker "pixclk",
1471*193032a3SAndroid Build Coastguard Worker "interlaced",
1472*193032a3SAndroid Build Coastguard Worker "overscan",
1473*193032a3SAndroid Build Coastguard Worker "secondary",
1474*193032a3SAndroid Build Coastguard Worker "C",
1475*193032a3SAndroid Build Coastguard Worker "M",
1476*193032a3SAndroid Build Coastguard Worker "K",
1477*193032a3SAndroid Build Coastguard Worker "J",
1478*193032a3SAndroid Build Coastguard Worker nullptr
1479*193032a3SAndroid Build Coastguard Worker };
1480*193032a3SAndroid Build Coastguard Worker
1481*193032a3SAndroid Build Coastguard Worker opt = getsubopt(subopt_str, (char * const *)subopt_list, &opt_str);
1482*193032a3SAndroid Build Coastguard Worker
1483*193032a3SAndroid Build Coastguard Worker if (opt == -1) {
1484*193032a3SAndroid Build Coastguard Worker fprintf(stderr, "Invalid suboptions specified.\n");
1485*193032a3SAndroid Build Coastguard Worker usage();
1486*193032a3SAndroid Build Coastguard Worker std::exit(EXIT_FAILURE);
1487*193032a3SAndroid Build Coastguard Worker }
1488*193032a3SAndroid Build Coastguard Worker if (opt_str == nullptr && opt != GTF_INTERLACED && opt != GTF_OVERSCAN &&
1489*193032a3SAndroid Build Coastguard Worker opt != GTF_SECONDARY) {
1490*193032a3SAndroid Build Coastguard Worker fprintf(stderr, "No value given to suboption <%s>.\n",
1491*193032a3SAndroid Build Coastguard Worker subopt_list[opt]);
1492*193032a3SAndroid Build Coastguard Worker usage();
1493*193032a3SAndroid Build Coastguard Worker std::exit(EXIT_FAILURE);
1494*193032a3SAndroid Build Coastguard Worker }
1495*193032a3SAndroid Build Coastguard Worker
1496*193032a3SAndroid Build Coastguard Worker if (opt == GTF_C2 || opt == GTF_J2)
1497*193032a3SAndroid Build Coastguard Worker *value = round(2.0 * strtod(opt_str, nullptr));
1498*193032a3SAndroid Build Coastguard Worker else if (opt_str)
1499*193032a3SAndroid Build Coastguard Worker *value = strtod(opt_str, nullptr);
1500*193032a3SAndroid Build Coastguard Worker return opt;
1501*193032a3SAndroid Build Coastguard Worker }
1502*193032a3SAndroid Build Coastguard Worker
parse_gtf(char * optarg,gtf_parsed_data & data)1503*193032a3SAndroid Build Coastguard Worker static void parse_gtf(char *optarg, gtf_parsed_data &data)
1504*193032a3SAndroid Build Coastguard Worker {
1505*193032a3SAndroid Build Coastguard Worker memset(&data, 0, sizeof(data));
1506*193032a3SAndroid Build Coastguard Worker data.params_from_edid = true;
1507*193032a3SAndroid Build Coastguard Worker data.C = 40;
1508*193032a3SAndroid Build Coastguard Worker data.M = 600;
1509*193032a3SAndroid Build Coastguard Worker data.K = 128;
1510*193032a3SAndroid Build Coastguard Worker data.J = 20;
1511*193032a3SAndroid Build Coastguard Worker
1512*193032a3SAndroid Build Coastguard Worker while (*optarg != '\0') {
1513*193032a3SAndroid Build Coastguard Worker int opt;
1514*193032a3SAndroid Build Coastguard Worker double opt_val;
1515*193032a3SAndroid Build Coastguard Worker
1516*193032a3SAndroid Build Coastguard Worker opt = parse_gtf_subopt(&optarg, &opt_val);
1517*193032a3SAndroid Build Coastguard Worker
1518*193032a3SAndroid Build Coastguard Worker switch (opt) {
1519*193032a3SAndroid Build Coastguard Worker case GTF_WIDTH:
1520*193032a3SAndroid Build Coastguard Worker data.w = round(opt_val);
1521*193032a3SAndroid Build Coastguard Worker break;
1522*193032a3SAndroid Build Coastguard Worker case GTF_HEIGHT:
1523*193032a3SAndroid Build Coastguard Worker data.h = round(opt_val);
1524*193032a3SAndroid Build Coastguard Worker break;
1525*193032a3SAndroid Build Coastguard Worker case GTF_FPS:
1526*193032a3SAndroid Build Coastguard Worker data.freq = opt_val;
1527*193032a3SAndroid Build Coastguard Worker data.ip_parm = gtf_ip_vert_freq;
1528*193032a3SAndroid Build Coastguard Worker break;
1529*193032a3SAndroid Build Coastguard Worker case GTF_HORFREQ:
1530*193032a3SAndroid Build Coastguard Worker data.freq = opt_val;
1531*193032a3SAndroid Build Coastguard Worker data.ip_parm = gtf_ip_hor_freq;
1532*193032a3SAndroid Build Coastguard Worker break;
1533*193032a3SAndroid Build Coastguard Worker case GTF_PIXCLK:
1534*193032a3SAndroid Build Coastguard Worker data.freq = opt_val;
1535*193032a3SAndroid Build Coastguard Worker data.ip_parm = gtf_ip_clk_freq;
1536*193032a3SAndroid Build Coastguard Worker break;
1537*193032a3SAndroid Build Coastguard Worker case GTF_INTERLACED:
1538*193032a3SAndroid Build Coastguard Worker data.interlaced = true;
1539*193032a3SAndroid Build Coastguard Worker break;
1540*193032a3SAndroid Build Coastguard Worker case GTF_OVERSCAN:
1541*193032a3SAndroid Build Coastguard Worker data.overscan = true;
1542*193032a3SAndroid Build Coastguard Worker break;
1543*193032a3SAndroid Build Coastguard Worker case GTF_SECONDARY:
1544*193032a3SAndroid Build Coastguard Worker data.secondary = true;
1545*193032a3SAndroid Build Coastguard Worker break;
1546*193032a3SAndroid Build Coastguard Worker case GTF_C2:
1547*193032a3SAndroid Build Coastguard Worker data.C = opt_val / 2.0;
1548*193032a3SAndroid Build Coastguard Worker data.params_from_edid = false;
1549*193032a3SAndroid Build Coastguard Worker break;
1550*193032a3SAndroid Build Coastguard Worker case GTF_M:
1551*193032a3SAndroid Build Coastguard Worker data.M = round(opt_val);
1552*193032a3SAndroid Build Coastguard Worker data.params_from_edid = false;
1553*193032a3SAndroid Build Coastguard Worker break;
1554*193032a3SAndroid Build Coastguard Worker case GTF_K:
1555*193032a3SAndroid Build Coastguard Worker data.K = round(opt_val);
1556*193032a3SAndroid Build Coastguard Worker data.params_from_edid = false;
1557*193032a3SAndroid Build Coastguard Worker break;
1558*193032a3SAndroid Build Coastguard Worker case GTF_J2:
1559*193032a3SAndroid Build Coastguard Worker data.J = opt_val / 2.0;
1560*193032a3SAndroid Build Coastguard Worker data.params_from_edid = false;
1561*193032a3SAndroid Build Coastguard Worker break;
1562*193032a3SAndroid Build Coastguard Worker default:
1563*193032a3SAndroid Build Coastguard Worker break;
1564*193032a3SAndroid Build Coastguard Worker }
1565*193032a3SAndroid Build Coastguard Worker }
1566*193032a3SAndroid Build Coastguard Worker
1567*193032a3SAndroid Build Coastguard Worker if (!data.w || !data.h) {
1568*193032a3SAndroid Build Coastguard Worker fprintf(stderr, "Missing width and/or height.\n");
1569*193032a3SAndroid Build Coastguard Worker usage();
1570*193032a3SAndroid Build Coastguard Worker std::exit(EXIT_FAILURE);
1571*193032a3SAndroid Build Coastguard Worker }
1572*193032a3SAndroid Build Coastguard Worker if (!data.freq) {
1573*193032a3SAndroid Build Coastguard Worker fprintf(stderr, "One of fps, horfreq or pixclk must be given.\n");
1574*193032a3SAndroid Build Coastguard Worker usage();
1575*193032a3SAndroid Build Coastguard Worker std::exit(EXIT_FAILURE);
1576*193032a3SAndroid Build Coastguard Worker }
1577*193032a3SAndroid Build Coastguard Worker if (!data.secondary)
1578*193032a3SAndroid Build Coastguard Worker data.params_from_edid = false;
1579*193032a3SAndroid Build Coastguard Worker if (data.interlaced && data.ip_parm == gtf_ip_vert_freq)
1580*193032a3SAndroid Build Coastguard Worker data.freq /= 2;
1581*193032a3SAndroid Build Coastguard Worker }
1582*193032a3SAndroid Build Coastguard Worker
show_gtf(gtf_parsed_data & data)1583*193032a3SAndroid Build Coastguard Worker static void show_gtf(gtf_parsed_data &data)
1584*193032a3SAndroid Build Coastguard Worker {
1585*193032a3SAndroid Build Coastguard Worker timings t;
1586*193032a3SAndroid Build Coastguard Worker
1587*193032a3SAndroid Build Coastguard Worker t = state.calc_gtf_mode(data.w, data.h, data.freq, data.interlaced,
1588*193032a3SAndroid Build Coastguard Worker data.ip_parm, data.overscan, data.secondary,
1589*193032a3SAndroid Build Coastguard Worker data.C, data.M, data.K, data.J);
1590*193032a3SAndroid Build Coastguard Worker calc_ratio(&t);
1591*193032a3SAndroid Build Coastguard Worker state.print_timings("", &t, "GTF", "", true, false);
1592*193032a3SAndroid Build Coastguard Worker }
1593*193032a3SAndroid Build Coastguard Worker
main(int argc,char ** argv)1594*193032a3SAndroid Build Coastguard Worker int main(int argc, char **argv)
1595*193032a3SAndroid Build Coastguard Worker {
1596*193032a3SAndroid Build Coastguard Worker char short_options[26 * 2 * 2 + 1];
1597*193032a3SAndroid Build Coastguard Worker enum output_format out_fmt = OUT_FMT_DEFAULT;
1598*193032a3SAndroid Build Coastguard Worker gtf_parsed_data gtf_data;
1599*193032a3SAndroid Build Coastguard Worker int ret;
1600*193032a3SAndroid Build Coastguard Worker
1601*193032a3SAndroid Build Coastguard Worker while (1) {
1602*193032a3SAndroid Build Coastguard Worker int option_index = 0;
1603*193032a3SAndroid Build Coastguard Worker unsigned idx = 0;
1604*193032a3SAndroid Build Coastguard Worker unsigned i, val;
1605*193032a3SAndroid Build Coastguard Worker const timings *t;
1606*193032a3SAndroid Build Coastguard Worker char buf[16];
1607*193032a3SAndroid Build Coastguard Worker
1608*193032a3SAndroid Build Coastguard Worker for (i = 0; long_options[i].name; i++) {
1609*193032a3SAndroid Build Coastguard Worker if (!isalpha(long_options[i].val))
1610*193032a3SAndroid Build Coastguard Worker continue;
1611*193032a3SAndroid Build Coastguard Worker short_options[idx++] = long_options[i].val;
1612*193032a3SAndroid Build Coastguard Worker if (long_options[i].has_arg == required_argument)
1613*193032a3SAndroid Build Coastguard Worker short_options[idx++] = ':';
1614*193032a3SAndroid Build Coastguard Worker }
1615*193032a3SAndroid Build Coastguard Worker short_options[idx] = 0;
1616*193032a3SAndroid Build Coastguard Worker int ch = getopt_long(argc, argv, short_options,
1617*193032a3SAndroid Build Coastguard Worker long_options, &option_index);
1618*193032a3SAndroid Build Coastguard Worker if (ch == -1)
1619*193032a3SAndroid Build Coastguard Worker break;
1620*193032a3SAndroid Build Coastguard Worker
1621*193032a3SAndroid Build Coastguard Worker options[ch] = 1;
1622*193032a3SAndroid Build Coastguard Worker switch (ch) {
1623*193032a3SAndroid Build Coastguard Worker case OptHelp:
1624*193032a3SAndroid Build Coastguard Worker usage();
1625*193032a3SAndroid Build Coastguard Worker return -1;
1626*193032a3SAndroid Build Coastguard Worker case OptOutputFormat:
1627*193032a3SAndroid Build Coastguard Worker if (!strcmp(optarg, "hex")) {
1628*193032a3SAndroid Build Coastguard Worker out_fmt = OUT_FMT_HEX;
1629*193032a3SAndroid Build Coastguard Worker } else if (!strcmp(optarg, "raw")) {
1630*193032a3SAndroid Build Coastguard Worker out_fmt = OUT_FMT_RAW;
1631*193032a3SAndroid Build Coastguard Worker } else if (!strcmp(optarg, "carray")) {
1632*193032a3SAndroid Build Coastguard Worker out_fmt = OUT_FMT_CARRAY;
1633*193032a3SAndroid Build Coastguard Worker } else if (!strcmp(optarg, "xml")) {
1634*193032a3SAndroid Build Coastguard Worker out_fmt = OUT_FMT_XML;
1635*193032a3SAndroid Build Coastguard Worker } else {
1636*193032a3SAndroid Build Coastguard Worker usage();
1637*193032a3SAndroid Build Coastguard Worker exit(1);
1638*193032a3SAndroid Build Coastguard Worker }
1639*193032a3SAndroid Build Coastguard Worker break;
1640*193032a3SAndroid Build Coastguard Worker case OptSTD: {
1641*193032a3SAndroid Build Coastguard Worker unsigned char byte1, byte2 = 0;
1642*193032a3SAndroid Build Coastguard Worker char *endptr;
1643*193032a3SAndroid Build Coastguard Worker
1644*193032a3SAndroid Build Coastguard Worker byte1 = strtoul(optarg, &endptr, 0);
1645*193032a3SAndroid Build Coastguard Worker if (*endptr == ',')
1646*193032a3SAndroid Build Coastguard Worker byte2 = strtoul(endptr + 1, NULL, 0);
1647*193032a3SAndroid Build Coastguard Worker state.print_standard_timing("", byte1, byte2, false, true);
1648*193032a3SAndroid Build Coastguard Worker break;
1649*193032a3SAndroid Build Coastguard Worker }
1650*193032a3SAndroid Build Coastguard Worker case OptDMT:
1651*193032a3SAndroid Build Coastguard Worker val = strtoul(optarg, NULL, 0);
1652*193032a3SAndroid Build Coastguard Worker t = find_dmt_id(val);
1653*193032a3SAndroid Build Coastguard Worker if (t) {
1654*193032a3SAndroid Build Coastguard Worker sprintf(buf, "DMT 0x%02x", val);
1655*193032a3SAndroid Build Coastguard Worker state.print_timings("", t, buf, "", true, false);
1656*193032a3SAndroid Build Coastguard Worker } else {
1657*193032a3SAndroid Build Coastguard Worker fprintf(stderr, "Unknown DMT code 0x%02x.\n", val);
1658*193032a3SAndroid Build Coastguard Worker }
1659*193032a3SAndroid Build Coastguard Worker break;
1660*193032a3SAndroid Build Coastguard Worker case OptVIC:
1661*193032a3SAndroid Build Coastguard Worker val = strtoul(optarg, NULL, 0);
1662*193032a3SAndroid Build Coastguard Worker t = find_vic_id(val);
1663*193032a3SAndroid Build Coastguard Worker if (t) {
1664*193032a3SAndroid Build Coastguard Worker sprintf(buf, "VIC %3u", val);
1665*193032a3SAndroid Build Coastguard Worker state.print_timings("", t, buf, "", true, false);
1666*193032a3SAndroid Build Coastguard Worker } else {
1667*193032a3SAndroid Build Coastguard Worker fprintf(stderr, "Unknown VIC code %u.\n", val);
1668*193032a3SAndroid Build Coastguard Worker }
1669*193032a3SAndroid Build Coastguard Worker break;
1670*193032a3SAndroid Build Coastguard Worker case OptHDMIVIC:
1671*193032a3SAndroid Build Coastguard Worker val = strtoul(optarg, NULL, 0);
1672*193032a3SAndroid Build Coastguard Worker t = find_hdmi_vic_id(val);
1673*193032a3SAndroid Build Coastguard Worker if (t) {
1674*193032a3SAndroid Build Coastguard Worker sprintf(buf, "HDMI VIC %u", val);
1675*193032a3SAndroid Build Coastguard Worker state.print_timings("", t, buf, "", true, false);
1676*193032a3SAndroid Build Coastguard Worker } else {
1677*193032a3SAndroid Build Coastguard Worker fprintf(stderr, "Unknown HDMI VIC code %u.\n", val);
1678*193032a3SAndroid Build Coastguard Worker }
1679*193032a3SAndroid Build Coastguard Worker break;
1680*193032a3SAndroid Build Coastguard Worker case OptCVT:
1681*193032a3SAndroid Build Coastguard Worker parse_cvt(optarg);
1682*193032a3SAndroid Build Coastguard Worker break;
1683*193032a3SAndroid Build Coastguard Worker case OptGTF:
1684*193032a3SAndroid Build Coastguard Worker parse_gtf(optarg, gtf_data);
1685*193032a3SAndroid Build Coastguard Worker break;
1686*193032a3SAndroid Build Coastguard Worker case ':':
1687*193032a3SAndroid Build Coastguard Worker fprintf(stderr, "Option '%s' requires a value.\n",
1688*193032a3SAndroid Build Coastguard Worker argv[optind]);
1689*193032a3SAndroid Build Coastguard Worker usage();
1690*193032a3SAndroid Build Coastguard Worker return -1;
1691*193032a3SAndroid Build Coastguard Worker case '?':
1692*193032a3SAndroid Build Coastguard Worker fprintf(stderr, "Unknown argument '%s'.\n",
1693*193032a3SAndroid Build Coastguard Worker argv[optind]);
1694*193032a3SAndroid Build Coastguard Worker usage();
1695*193032a3SAndroid Build Coastguard Worker return -1;
1696*193032a3SAndroid Build Coastguard Worker }
1697*193032a3SAndroid Build Coastguard Worker }
1698*193032a3SAndroid Build Coastguard Worker if (optind == argc && options[OptVersion]) {
1699*193032a3SAndroid Build Coastguard Worker if (strlen(STRING(SHA)))
1700*193032a3SAndroid Build Coastguard Worker printf("edid-decode SHA: %s %s\n", STRING(SHA), STRING(DATE));
1701*193032a3SAndroid Build Coastguard Worker else
1702*193032a3SAndroid Build Coastguard Worker printf("edid-decode SHA: not available\n");
1703*193032a3SAndroid Build Coastguard Worker return 0;
1704*193032a3SAndroid Build Coastguard Worker }
1705*193032a3SAndroid Build Coastguard Worker
1706*193032a3SAndroid Build Coastguard Worker if (options[OptListEstTimings])
1707*193032a3SAndroid Build Coastguard Worker state.list_established_timings();
1708*193032a3SAndroid Build Coastguard Worker if (options[OptListDMTs])
1709*193032a3SAndroid Build Coastguard Worker state.list_dmts();
1710*193032a3SAndroid Build Coastguard Worker if (options[OptListVICs])
1711*193032a3SAndroid Build Coastguard Worker state.cta_list_vics();
1712*193032a3SAndroid Build Coastguard Worker if (options[OptListHDMIVICs])
1713*193032a3SAndroid Build Coastguard Worker state.cta_list_hdmi_vics();
1714*193032a3SAndroid Build Coastguard Worker
1715*193032a3SAndroid Build Coastguard Worker if (options[OptListEstTimings] || options[OptListDMTs] ||
1716*193032a3SAndroid Build Coastguard Worker options[OptListVICs] || options[OptListHDMIVICs])
1717*193032a3SAndroid Build Coastguard Worker return 0;
1718*193032a3SAndroid Build Coastguard Worker
1719*193032a3SAndroid Build Coastguard Worker if (options[OptCVT] || options[OptDMT] || options[OptVIC] ||
1720*193032a3SAndroid Build Coastguard Worker options[OptHDMIVIC] || options[OptSTD])
1721*193032a3SAndroid Build Coastguard Worker return 0;
1722*193032a3SAndroid Build Coastguard Worker
1723*193032a3SAndroid Build Coastguard Worker if (options[OptGTF] && (!gtf_data.params_from_edid || optind == argc)) {
1724*193032a3SAndroid Build Coastguard Worker show_gtf(gtf_data);
1725*193032a3SAndroid Build Coastguard Worker return 0;
1726*193032a3SAndroid Build Coastguard Worker }
1727*193032a3SAndroid Build Coastguard Worker
1728*193032a3SAndroid Build Coastguard Worker if (optind == argc)
1729*193032a3SAndroid Build Coastguard Worker ret = edid_from_file("-", stdout);
1730*193032a3SAndroid Build Coastguard Worker else
1731*193032a3SAndroid Build Coastguard Worker ret = edid_from_file(argv[optind], argv[optind + 1] ? stderr : stdout);
1732*193032a3SAndroid Build Coastguard Worker
1733*193032a3SAndroid Build Coastguard Worker if (ret && options[OptPhysicalAddress]) {
1734*193032a3SAndroid Build Coastguard Worker printf("f.f.f.f\n");
1735*193032a3SAndroid Build Coastguard Worker return 0;
1736*193032a3SAndroid Build Coastguard Worker }
1737*193032a3SAndroid Build Coastguard Worker if (optind < argc - 1)
1738*193032a3SAndroid Build Coastguard Worker return ret ? ret : edid_to_file(argv[optind + 1], out_fmt);
1739*193032a3SAndroid Build Coastguard Worker
1740*193032a3SAndroid Build Coastguard Worker if (options[OptGTF]) {
1741*193032a3SAndroid Build Coastguard Worker timings t;
1742*193032a3SAndroid Build Coastguard Worker
1743*193032a3SAndroid Build Coastguard Worker // Find the Secondary Curve
1744*193032a3SAndroid Build Coastguard Worker state.preparse_detailed_block(edid + 0x36);
1745*193032a3SAndroid Build Coastguard Worker state.preparse_detailed_block(edid + 0x48);
1746*193032a3SAndroid Build Coastguard Worker state.preparse_detailed_block(edid + 0x5a);
1747*193032a3SAndroid Build Coastguard Worker state.preparse_detailed_block(edid + 0x6c);
1748*193032a3SAndroid Build Coastguard Worker
1749*193032a3SAndroid Build Coastguard Worker t = state.calc_gtf_mode(gtf_data.w, gtf_data.h, gtf_data.freq,
1750*193032a3SAndroid Build Coastguard Worker gtf_data.interlaced, gtf_data.ip_parm,
1751*193032a3SAndroid Build Coastguard Worker gtf_data.overscan);
1752*193032a3SAndroid Build Coastguard Worker unsigned hbl = t.hfp + t.hsync + t.hbp;
1753*193032a3SAndroid Build Coastguard Worker unsigned htotal = t.hact + hbl;
1754*193032a3SAndroid Build Coastguard Worker double hor_freq_khz = htotal ? (double)t.pixclk_khz / htotal : 0;
1755*193032a3SAndroid Build Coastguard Worker
1756*193032a3SAndroid Build Coastguard Worker if (state.base.supports_sec_gtf &&
1757*193032a3SAndroid Build Coastguard Worker hor_freq_khz >= state.base.sec_gtf_start_freq) {
1758*193032a3SAndroid Build Coastguard Worker t = state.calc_gtf_mode(gtf_data.w, gtf_data.h, gtf_data.freq,
1759*193032a3SAndroid Build Coastguard Worker gtf_data.interlaced, gtf_data.ip_parm,
1760*193032a3SAndroid Build Coastguard Worker gtf_data.overscan, true,
1761*193032a3SAndroid Build Coastguard Worker state.base.C, state.base.M,
1762*193032a3SAndroid Build Coastguard Worker state.base.K, state.base.J);
1763*193032a3SAndroid Build Coastguard Worker }
1764*193032a3SAndroid Build Coastguard Worker calc_ratio(&t);
1765*193032a3SAndroid Build Coastguard Worker if (t.hfp <= 0)
1766*193032a3SAndroid Build Coastguard Worker state.print_timings("", &t, "GTF", "INVALID: Hfront <= 0", true, false);
1767*193032a3SAndroid Build Coastguard Worker else
1768*193032a3SAndroid Build Coastguard Worker state.print_timings("", &t, "GTF", "", true, false);
1769*193032a3SAndroid Build Coastguard Worker return 0;
1770*193032a3SAndroid Build Coastguard Worker }
1771*193032a3SAndroid Build Coastguard Worker
1772*193032a3SAndroid Build Coastguard Worker return ret ? ret : state.parse_edid();
1773*193032a3SAndroid Build Coastguard Worker }
1774*193032a3SAndroid Build Coastguard Worker
1775*193032a3SAndroid Build Coastguard Worker #ifdef __EMSCRIPTEN__
1776*193032a3SAndroid Build Coastguard Worker /*
1777*193032a3SAndroid Build Coastguard Worker * The surrounding JavaScript implementation will call this function
1778*193032a3SAndroid Build Coastguard Worker * each time it wants to decode an EDID. So this should reset all the
1779*193032a3SAndroid Build Coastguard Worker * state and start over.
1780*193032a3SAndroid Build Coastguard Worker */
parse_edid(const char * input)1781*193032a3SAndroid Build Coastguard Worker extern "C" int parse_edid(const char *input)
1782*193032a3SAndroid Build Coastguard Worker {
1783*193032a3SAndroid Build Coastguard Worker for (unsigned i = 0; i < EDID_MAX_BLOCKS + 1; i++) {
1784*193032a3SAndroid Build Coastguard Worker s_msgs[i][0].clear();
1785*193032a3SAndroid Build Coastguard Worker s_msgs[i][1].clear();
1786*193032a3SAndroid Build Coastguard Worker }
1787*193032a3SAndroid Build Coastguard Worker options[OptCheck] = 1;
1788*193032a3SAndroid Build Coastguard Worker options[OptPreferredTimings] = 1;
1789*193032a3SAndroid Build Coastguard Worker options[OptNativeTimings] = 1;
1790*193032a3SAndroid Build Coastguard Worker state = edid_state();
1791*193032a3SAndroid Build Coastguard Worker int ret = edid_from_file(input, stderr);
1792*193032a3SAndroid Build Coastguard Worker return ret ? ret : state.parse_edid();
1793*193032a3SAndroid Build Coastguard Worker }
1794*193032a3SAndroid Build Coastguard Worker #endif
1795