• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <stdio.h>
6 #include <string.h>
7 #include <stdlib.h>
8 
9 #include "edid_utils.h"
10 
11 /* Dump out an EDID block in a simple format */
show_edid_data(FILE * outfile,unsigned char * edid_data,int items,int base)12 void show_edid_data(FILE *outfile, unsigned char *edid_data,
13 		    int items, int base)
14 {
15 	int item = 0;
16 
17 	while (item < items) {
18 		int i;
19 		fprintf(outfile, " 0x%04x:  ", item + base);
20 		for (i = 0; i < 16; i++) {
21 			fprintf(outfile, "%02x ", edid_data[item++]);
22 			if (item >= items)
23 				break;
24 		}
25 		fprintf(outfile, "\n");
26 	}
27 }
28 
29 
30 unsigned char test_edid1[256] = {
31 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
32 	0x06, 0xaf, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00,
33 	0x01, 0x12, 0x01, 0x03, 0x80, 0x1a, 0x0e, 0x78,
34 	0x0a, 0x99, 0x85, 0x95, 0x55, 0x56, 0x92, 0x28,
35 	0x22, 0x50, 0x54, 0x00, 0x00, 0x00, 0x01, 0x01,
36 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
37 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x96, 0x19,
38 	0x56, 0x28, 0x50, 0x00, 0x08, 0x30, 0x18, 0x10,
39 	0x24, 0x00, 0x00, 0x90, 0x10, 0x00, 0x00, 0x18,
40 	0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
41 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42 	0x00, 0x20, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x41,
43 	0x55, 0x4f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
44 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfe,
45 	0x00, 0x42, 0x31, 0x31, 0x36, 0x58, 0x57, 0x30,
46 	0x32, 0x20, 0x56, 0x30, 0x20, 0x0a, 0x00, 0xf8
47 };
48 
49 unsigned char test_edid2[256] = {
50 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
51 	0x30, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52 	0x00, 0x14, 0x01, 0x03, 0x80, 0x1a, 0x0e, 0x78,
53 	0x0a, 0xbf, 0x45, 0x95, 0x58, 0x52, 0x8a, 0x28,
54 	0x25, 0x50, 0x54, 0x00, 0x00, 0x00, 0x01, 0x01,
55 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
56 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x84, 0x1c,
57 	0x56, 0xa8, 0x50, 0x00, 0x19, 0x30, 0x30, 0x20,
58 	0x35, 0x00, 0x00, 0x90, 0x10, 0x00, 0x00, 0x1b,
59 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 	0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x4c,
62 	0x47, 0x20, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61,
63 	0x79, 0x0a, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
64 	0x00, 0x4c, 0x50, 0x31, 0x31, 0x36, 0x57, 0x48,
65 	0x31, 0x2d, 0x54, 0x4c, 0x4e, 0x31, 0x00, 0x4e
66 };
67 
68 unsigned char test_edid3[256] = {
69 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
70 	0x4d, 0xd9, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
71 	0x00, 0x11, 0x01, 0x03, 0x80, 0x00, 0x00, 0x78,
72 	0x0a, 0x0d, 0xc9, 0xa0, 0x57, 0x47, 0x98, 0x27,
73 	0x12, 0x48, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x01,
74 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
75 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1d,
76 	0x80, 0xd0, 0x72, 0x1c, 0x16, 0x20, 0x10, 0x2c,
77 	0x25, 0x80, 0xc4, 0x8e, 0x21, 0x00, 0x00, 0x9e,
78 	0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20,
79 	0x58, 0x2c, 0x25, 0x00, 0xc4, 0x8e, 0x21, 0x00,
80 	0x00, 0x9e, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x48,
81 	0x44, 0x4d, 0x49, 0x20, 0x4c, 0x4c, 0x43, 0x0a,
82 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd,
83 	0x00, 0x3b, 0x3d, 0x0f, 0x2d, 0x08, 0x00, 0x0a,
84 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xc0,
85 	0x02, 0x03, 0x1e, 0x47, 0x4f, 0x94, 0x13, 0x05,
86 	0x03, 0x04, 0x02, 0x01, 0x16, 0x15, 0x07, 0x06,
87 	0x11, 0x10, 0x12, 0x1f, 0x23, 0x09, 0x07, 0x01,
88 	0x65, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x8c, 0x0a,
89 	0xd0, 0x90, 0x20, 0x40, 0x31, 0x20, 0x0c, 0x40,
90 	0x55, 0x00, 0x13, 0x8e, 0x21, 0x00, 0x00, 0x18,
91 	0x01, 0x1d, 0x00, 0xbc, 0x52, 0xd0, 0x1e, 0x20,
92 	0xb8, 0x28, 0x55, 0x40, 0xc4, 0x8e, 0x21, 0x00,
93 	0x00, 0x1e, 0x8c, 0x0a, 0xd0, 0x8a, 0x20, 0xe0,
94 	0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xc4, 0x8e,
95 	0x21, 0x00, 0x00, 0x18, 0x01, 0x1d, 0x00, 0x72,
96 	0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
97 	0xc4, 0x8e, 0x21, 0x00, 0x00, 0x1e, 0x8c, 0x0a,
98 	0xd0, 0x8a, 0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e,
99 	0x96, 0x00, 0x13, 0x8e, 0x21, 0x00, 0x00, 0x18,
100 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb
101 };
102 
103 unsigned char test_edid4[256] = {
104 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
105 	0x4c, 0x2d, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00,
106 	0x31, 0x0f, 0x01, 0x03, 0x80, 0x10, 0x09, 0x8c,
107 	0x0a, 0xe2, 0xbd, 0xa1, 0x5b, 0x4a, 0x98, 0x24,
108 	0x15, 0x47, 0x4a, 0x20, 0x00, 0x00, 0x01, 0x01,
109 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
110 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1d,
111 	0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28,
112 	0x55, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e,
113 	0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20,
114 	0x58, 0x2c, 0x25, 0x00, 0xa0, 0x5a, 0x00, 0x00,
115 	0x00, 0x9e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
116 	0x3d, 0x1e, 0x2e, 0x08, 0x00, 0x0a, 0x20, 0x20,
117 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
118 	0x00, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47,
119 	0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x8d,
120 	0x02, 0x03, 0x16, 0x71, 0x43, 0x84, 0x05, 0x03,
121 	0x23, 0x09, 0x07, 0x07, 0x83, 0x01, 0x00, 0x00,
122 	0x65, 0x03, 0x0c, 0x00, 0x20, 0x00, 0x8c, 0x0a,
123 	0xd0, 0x8a, 0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e,
124 	0x96, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x18,
125 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
128 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30
136 };
137 
138 unsigned char test_edid5[256] = {
139 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
140 	0x3d, 0xcb, 0x61, 0x07, 0x00, 0x00, 0x00, 0x00,
141 	0x00, 0x11, 0x01, 0x03, 0x80, 0x00, 0x00, 0x78,
142 	0x0a, 0x0d, 0xc9, 0xa0, 0x57, 0x47, 0x98, 0x27,
143 	0x12, 0x48, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x01,
144 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
145 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1d,
146 	0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c,
147 	0x25, 0x00, 0xc4, 0x8e, 0x21, 0x00, 0x00, 0x9e,
148 	0x01, 0x1d, 0x80, 0xd0, 0x72, 0x1c, 0x16, 0x20,
149 	0x10, 0x2c, 0x25, 0x80, 0xc4, 0x8e, 0x21, 0x00,
150 	0x00, 0x9e, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x54,
151 	0x58, 0x2d, 0x53, 0x52, 0x36, 0x30, 0x35, 0x0a,
152 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd,
153 	0x00, 0x17, 0xf0, 0x0f, 0x7e, 0x11, 0x00, 0x0a,
154 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x93,
155 	0x02, 0x03, 0x3b, 0x72, 0x55, 0x85, 0x04, 0x03,
156 	0x02, 0x0e, 0x0f, 0x07, 0x23, 0x24, 0x10, 0x94,
157 	0x13, 0x12, 0x11, 0x1d, 0x1e, 0x16, 0x25, 0x26,
158 	0x01, 0x1f, 0x35, 0x09, 0x7f, 0x07, 0x0f, 0x7f,
159 	0x07, 0x17, 0x07, 0x50, 0x3f, 0x06, 0xc0, 0x57,
160 	0x06, 0x00, 0x5f, 0x7e, 0x01, 0x67, 0x5e, 0x00,
161 	0x83, 0x4f, 0x00, 0x00, 0x66, 0x03, 0x0c, 0x00,
162 	0x20, 0x00, 0x80, 0x8c, 0x0a, 0xd0, 0x8a, 0x20,
163 	0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xc4,
164 	0x8e, 0x21, 0x00, 0x00, 0x18, 0x8c, 0x0a, 0xd0,
165 	0x90, 0x20, 0x40, 0x31, 0x20, 0x0c, 0x40, 0x55,
166 	0x00, 0xc4, 0x8e, 0x21, 0x00, 0x00, 0x18, 0x01,
167 	0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e,
168 	0x28, 0x55, 0x00, 0xc4, 0x8e, 0x21, 0x00, 0x00,
169 	0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd
171 };
172 
173 /* Has DTD that is too wide */
174 unsigned char test_edid6[256] = {
175 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
176 	0x10, 0xac, 0x63, 0x40, 0x4c, 0x35, 0x31, 0x33,
177 	0x0c, 0x15, 0x01, 0x03, 0x80, 0x40, 0x28, 0x78,
178 	0xea, 0x8d, 0x85, 0xad, 0x4f, 0x35, 0xb1, 0x25,
179 	0x0e, 0x50, 0x54, 0xa5, 0x4b, 0x00, 0x71, 0x4f,
180 	0x81, 0x00, 0x81, 0x80, 0xa9, 0x40, 0xd1, 0x00,
181 	0xd1, 0x40, 0x01, 0x01, 0x01, 0x01, 0xe2, 0x68,
182 	0x00, 0xa0, 0xa0, 0x40, 0x2e, 0x60, 0x30, 0x20,
183 	0x36, 0x00, 0x81, 0x91, 0x21, 0x00, 0x00, 0x1a,
184 	0x00, 0x00, 0x00, 0xff, 0x00, 0x50, 0x48, 0x35,
185 	0x4e, 0x59, 0x31, 0x33, 0x4d, 0x33, 0x31, 0x35,
186 	0x4c, 0x0a, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x44,
187 	0x45, 0x4c, 0x4c, 0x20, 0x55, 0x33, 0x30, 0x31,
188 	0x31, 0x0a, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd,
189 	0x00, 0x31, 0x56, 0x1d, 0x71, 0x1c, 0x00, 0x0a,
190 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0xb0
191 };
192 
193 static unsigned char *test_edids[N_TEST_EDIDS] = {
194 	test_edid1, test_edid2, test_edid3, test_edid4, test_edid5,
195 	test_edid6
196 };
197 
get_test_edid(int n,unsigned char * dst)198 int get_test_edid(int n, unsigned char *dst)
199 {
200 	if ((n < 1) || (n > N_TEST_EDIDS))
201 		return -1;
202 	memcpy(dst, test_edids[n-1], 256);
203 	return 0;
204 }
205 
show_test_edid(FILE * outfile,int n)206 int show_test_edid(FILE *outfile, int n)
207 {
208 	if ((n < 1) || (n > N_TEST_EDIDS))
209 		return -1;
210 	fprintf(outfile, "Test EDID %d\n", n);
211 	show_edid(outfile, test_edids[n-1], 1);
212 	return 0;
213 }
214 
get_dtd_string(const char * str,char * buf,int buf_size)215 static void get_dtd_string(const char *str, char *buf, int buf_size)
216 {
217 	int stp;
218 	int len = buf_size < 14 ? buf_size : 14;
219 
220 	strncpy(buf, str, len - 1);
221 	for (stp = 0; stp < len - 1; stp++)
222 		if (buf[stp] == 0x0a)
223 			buf[stp] = 0;
224 	buf[stp] = 0;
225 }
226 
227 /* Print an edid descriptor block (standard case is at 54 + 18 * i) */
show_edid_dtd(FILE * outfile,unsigned char * base)228 void show_edid_dtd(FILE *outfile, unsigned char *base)
229 {
230 	int pelclk = base[DTD_PCLK_LO] + (base[DTD_PCLK_HI]<<8);
231 	char monstr[DTD_SIZE];
232 
233 	if (pelclk != 0) {
234 		int hres = base[DTD_HA_LO] + ((base[DTD_HABL_HI] & 0xf0)<<4);
235 		int hbl = base[DTD_HBL_LO] + ((base[DTD_HABL_HI] & 0x0f)<<8);
236 		int vres = base[DTD_VA_LO] + ((base[DTD_VABL_HI] & 0xf0)<<4);
237 		int vbl = base[DTD_VBL_LO] + ((base[DTD_VABL_HI] & 0x0f)<<8);
238 		int hso = base[DTD_HSO_LO] + ((base[DTD_HVSX_HI] & 0xc0)<<2);
239 		int hsw = base[DTD_HSW_LO] + ((base[DTD_HVSX_HI] & 0x30)<<4);
240 		int vso = (base[DTD_VSX_LO] >> 4) +
241 			   ((base[DTD_HVSX_HI] & 0x0c) << 2);
242 		int vsw = (base[DTD_VSX_LO] & 0xf) +
243 			   ((base[DTD_HVSX_HI] & 0x03) << 4);
244 		int hsiz = base[DTD_HSIZE_LO] +
245 			   ((base[DTD_HVSIZE_HI] & 0xf0) << 4);
246 		int vsiz = base[DTD_VSIZE_LO] +
247 			   ((base[DTD_HVSIZE_HI] & 0x0f) << 8);
248 		int hbdr = base[DTD_HBORDER];
249 		int vbdr = base[DTD_VBORDER];
250 		int mdflg = base[DTD_FLAGS];
251 
252 		int refr = (pelclk * 10000)/((hres+hbl)*(vres+vbl));
253 		int refm = (pelclk * 10000)%((hres+hbl)*(vres+vbl));
254 		int refd = (refm*100)/((hres+hbl)*(vres+vbl));
255 
256 		fprintf(outfile,
257 			"%dx%d%c@%d.%02d, dot clock %d  %cHsync %cVsync\n",
258 			hres, vres, (mdflg & 0x80) ? 'i' : 'p',
259 			refr, refd,
260 			pelclk * 10000,
261 			(mdflg & 0x2) ? '+' : '-',
262 			(mdflg & 0x4) ? '+' : '-');
263 		fprintf(outfile, "H: start %d, end %d, total %d\n",
264 			hres+hso, hres+hso+hsw, hres+hbl);
265 		fprintf(outfile, "V: start %d, end %d, total %d\n",
266 			vres+vso, vres+vso+vsw, vres+vbl);
267 		fprintf(outfile, "Size %dx%dmm, Border %dx%d pixels\n",
268 			hsiz, vsiz, hbdr, vbdr);
269 		return;
270 	}
271 
272 	switch (base[DTD_TYPETAG]) {
273 	case DTDTYPE_SERIAL:
274 	case DTDTYPE_STRING:
275 	case DTDTYPE_NAME:
276 		get_dtd_string((const char *)base + DTD_STRING,
277 			       monstr, DTD_SIZE);
278 
279 		if (base[3] != DTDTYPE_STRING)
280 			fprintf(outfile, "%s: %s\n",
281 				(base[3] == DTDTYPE_NAME) ?
282 				"Name" : "Serial",
283 				monstr);
284 		else
285 			fprintf(outfile, "%s\n", monstr);
286 		break;
287 
288 	case DTDTYPE_LIMITS:
289 		fprintf(outfile,
290 			"V %d - %d Hz, H %d - %d kHz, Pel <= %d MHz\n",
291 			base[DTD_MINV_HZ], base[DTD_MAXV_HZ],
292 			base[DTD_MINH_kHZ], base[DTD_MAXH_kHZ],
293 			base[DTD_MAXCLK_100kHZ]*10);
294 		break;
295 
296 	default:
297 		fprintf(outfile,
298 			"Undecoded descriptor block type 0x%x\n",
299 			base[DTD_TYPETAG]);
300 		break;
301 	}
302 }
303 
304 
305 char *sad_audio_type[16] = {
306 	"Reserved", "LPCM", "AC-3", "MPEG1 (Layer 1 and 2)",
307 	"MP3", "MPEG2", "AAC", "DTS",
308 	"ATRAC", "SACD", "DD+", "DTS-HD",
309 	"MLP/Dolby TrueHD", "DST Audio", "WMA Pro", "Reserved",
310 };
311 
312 char *uscanstr[4] = {
313 	"not supported",
314 	"always overscan",
315 	"always underscan",
316 	"supports both over- and underscan",
317 };
318 
show_audio_dbc(FILE * outfile,const unsigned char * edid_ext,int dbc)319 static inline void show_audio_dbc(FILE *outfile,
320 				  const unsigned char *edid_ext,
321 				  int dbc)
322 {
323 	int dbp = dbc + 1;
324 	int db_len = edid_ext[dbc+DBC_TAG_LENGTH] & DBC_LEN_MASK;
325 
326 	while (dbp < (dbc + db_len + 1)) {
327 		int atype =
328 			(edid_ext[dbp + DBCA_FORMAT]>>3) & 0xf;
329 		unsigned char dbca_rate = edid_ext[dbp + DBCA_RATE];
330 
331 		fprintf(outfile, "Audio: %d channels %s: ",
332 			(edid_ext[dbp + DBCA_FORMAT] & 0x7) + 1,
333 			sad_audio_type[atype]);
334 
335 		if (dbca_rate & 0x40)
336 			fprintf(outfile, "192k ");
337 		if (dbca_rate & 0x20)
338 			fprintf(outfile, "176k ");
339 		if (dbca_rate & 0x10)
340 			fprintf(outfile, "96k ");
341 		if (dbca_rate & 0x08)
342 			fprintf(outfile, "88k ");
343 		if (dbca_rate & 0x04)
344 			fprintf(outfile, "48k ");
345 		if (dbca_rate & 0x02)
346 			fprintf(outfile, "44k ");
347 		if (dbca_rate & 0x01)
348 			fprintf(outfile, "32k ");
349 
350 		if (atype == 1) {
351 			unsigned char dbca_info = edid_ext[dbp + DBCA_INFO];
352 			fprintf(outfile, "%s%s%s\n",
353 				(dbca_info & 0x4) ? "24-bit " : "",
354 				(dbca_info & 0x2) ? "20-bit " : "",
355 				(dbca_info & 0x1) ? "16-bit" : "");
356 		} else if ((atype >= 2) && (atype <= 8)) {
357 			fprintf(outfile, "Max %dkHz\n",
358 				edid_ext[dbp + DBCA_INFO] * 8);
359 		} else {
360 			fprintf(outfile, "Codec vendor flags 0x%02x\n",
361 				edid_ext[dbp + DBCA_INFO]);
362 		}
363 
364 		dbp += DBCA_SIZE;
365 	}
366 }
367 
show_vendor_dbc(FILE * outfile,const unsigned char * edid_ext,int dbp)368 static inline void show_vendor_dbc(FILE *outfile,
369 				   const unsigned char *edid_ext,
370 				   int dbp)
371 {
372 	if ((edid_ext[dbp + DBCVND_IEEE_LO] != 0x03) ||
373 	    (edid_ext[dbp + DBCVND_IEEE_MID] != 0x0C) ||
374 	    (edid_ext[dbp + DBCVND_IEEE_HI] != 0x00)) {
375 		fprintf(outfile, "Vendor block for %02x-%02x-%02x",
376 			edid_ext[dbp + DBCVND_IEEE_LO],
377 			edid_ext[dbp + DBCVND_IEEE_MID],
378 			edid_ext[dbp + DBCVND_IEEE_HI]);
379 		return;
380 	}
381 
382 	fprintf(outfile,
383 		"HDMI Vendor block (CEC @0x%04x):\n"
384 		"Support: %s%s%s%s%s%s\n",
385 		edid_ext[dbp + DBCVHDMI_CEC_LO] +
386 		(edid_ext[dbp + DBCVHDMI_CEC_HI] << 8),
387 		(edid_ext[dbp + DBCVHDMI_SUPPORT] & 0x80) ? "AI " : "",
388 		(edid_ext[dbp + DBCVHDMI_SUPPORT] & 0x40) ? "DC_48bit " : "",
389 		(edid_ext[dbp + DBCVHDMI_SUPPORT] & 0x20) ? "DC_36bit " : "",
390 		(edid_ext[dbp + DBCVHDMI_SUPPORT] & 0x10) ? "DC_30bit " : "",
391 		(edid_ext[dbp + DBCVHDMI_SUPPORT] & 0x08) ? "DC_Y444 " : "",
392 		(edid_ext[dbp + DBCVHDMI_SUPPORT] & 0x01) ? "DVI_Dual" : "");
393 
394 	if (edid_ext[dbp + DBCVHDMI_MAXTMDS_5MHz] > 0)
395 		fprintf(outfile, "Max TMDS Frequency %dMHz\n",
396 			edid_ext[dbp + DBCVHDMI_MAXTMDS_5MHz]*5);
397 
398 	if (edid_ext[dbp + DBCVHDMI_LATFLAGS] & 0x80)
399 		fprintf(outfile, "Video latency %dms, audio latency %dms\n",
400 			2 * (edid_ext[dbp + DBCVHDMI_VLAT] - 1),
401 			2 * (edid_ext[dbp + DBCVHDMI_ALAT] - 1));
402 
403 	if (edid_ext[dbp + 7] & 0x40)
404 		fprintf(outfile,
405 			"Interlaced Video latency %dms, audio latency %dms\n",
406 			2 * (edid_ext[dbp + DBCVHDMI_IVLAT] - 1),
407 			2 * (edid_ext[dbp + DBCVHDMI_IALAT] - 1));
408 }
409 
show_extended_dbc(FILE * outfile,const unsigned char * edid_ext,int dbc)410 static void show_extended_dbc(FILE *outfile,
411 			      const unsigned char *edid_ext,
412 			      int dbc)
413 {
414 	int dbp = dbc + 1;
415 	int db_len = edid_ext[dbc + DBC_TAG_LENGTH] & DBC_LEN_MASK;
416 
417 	switch (edid_ext[dbp + DBC_ETAG]) {
418 	case DBC_ETAG_VCDB:
419 	{
420 		unsigned char vcdb_flags;
421 
422 		fprintf(outfile, "Video Capabilities:\n");
423 		fprintf(outfile,
424 			"  Quantization range selectable: %s\n",
425 			(edid_ext[dbp + VCDB_FLAGS] & 0x40) ?
426 				"unknown" : "via AVI Q");
427 
428 		/* PT field zero implies no data, just use IT
429 		 * and CE fields
430 		 */
431 		vcdb_flags = edid_ext[dbp + VCDB_FLAGS];
432 		if (VCDB_S_PT(vcdb_flags))
433 			fprintf(outfile,
434 				"  Preferred mode %s\n",
435 				uscanstr[VCDB_S_PT(vcdb_flags)]);
436 		fprintf(outfile, "  IT modes %s\n",
437 			uscanstr[VCDB_S_IT(vcdb_flags)]);
438 		fprintf(outfile, "  CE modes %s\n",
439 			uscanstr[VCDB_S_CE(vcdb_flags)]);
440 		break;
441 	}
442 
443 	case DBC_ETAG_COL:
444 		fprintf(outfile,
445 			"Colorimetry supports %s%s metadata 0x%x\n",
446 			(edid_ext[dbp + COL_FLAGS] & 0x02) ? "HD(YCC709) " : "",
447 			(edid_ext[dbp + COL_FLAGS] & 0x01) ? "SD(YCC601) " : "",
448 			(edid_ext[dbp + COL_META] & 0x07));
449 		break;
450 
451 	default:
452 		fprintf(outfile,
453 			"Unknown extended tag data block 0x%x,  length 0x%x\n",
454 			edid_ext[dbc + DBC_ETAG], db_len);
455 	}
456 }
457 
show_cea_timing(FILE * outfile,unsigned char * edid_ext)458 void show_cea_timing(FILE *outfile, unsigned char *edid_ext)
459 {
460 	int i, dbc;
461 	int off_dtd = edid_ext[CEA_DTD_OFFSET];
462 	int n_dtd;
463 	fprintf(outfile, "Found CEA EDID Timing Extension rev 3\n");
464 
465 	if (off_dtd < CEA_DBC_START) {
466 		fprintf(outfile, "Block is empty (off_dtd = %d)\n", off_dtd);
467 		return;
468 	}
469 	/* Ends with 0 and a checksum, have at least one pad byte */
470 	n_dtd = (CEA_LAST_PAD - off_dtd)/DTD_SIZE;
471 	fprintf(outfile,
472 		"Block has DTDs starting at offset %d (%d bytes of DBCs)\n",
473 		off_dtd, off_dtd - CEA_DBC_START);
474 	fprintf(outfile, "There is space for %d DTDs in extension\n", n_dtd);
475 	fprintf(outfile,
476 		"There are %d native DTDs (between regular and extensions)\n",
477 		edid_ext[CEA_NATIVE_DTDS] & 0xf);
478 	fprintf(outfile, "IT formats %sdefault to underscan\n",
479 		(edid_ext[CEA_SUPPORT] & 0x80) ? "" : "do not ");
480 	fprintf(outfile,
481 		"Support: %sbasic audio, %sYCrCb 4:4:4, %sYCrCb 4:2:2\n",
482 		(edid_ext[CEA_SUPPORT] & 0x40) ? "" : "no ",
483 		(edid_ext[CEA_SUPPORT] & 0x20) ? "" : "no ",
484 		(edid_ext[CEA_SUPPORT] & 0x10) ? "" : "no ");
485 
486 	/* Between offset 4 and off_dtd is the Data Block Collection */
487 	/* There may be none, in which case off_dtd == 4             */
488 	dbc = CEA_DBC_START;
489 	while (dbc < off_dtd) {
490 		int db_len = edid_ext[dbc + DBC_TAG_LENGTH] & DBC_LEN_MASK;
491 		int dbp = dbc + 1;
492 
493 		switch (edid_ext[dbc+DBC_TAG_LENGTH] >> DBC_TAG_SHIFT) {
494 		case DBC_TAG_AUDIO:
495 			/* Audio Data Block */
496 			show_audio_dbc(outfile, edid_ext, dbc);
497 			break;
498 
499 		case DBC_TAG_VIDEO:
500 			/* Vidio Data Block */
501 			while (dbp < (dbc + db_len + 1)) {
502 				int vtype = edid_ext[dbp + DBCV_CODE] & 0x7f;
503 				fprintf(outfile, "Video: Code %d %s\n", vtype,
504 					(edid_ext[dbp + DBCV_CODE] & 0x80) ?
505 						"(native)" : "");
506 				dbp += DBCV_SIZE;
507 			}
508 			break;
509 
510 		case DBC_TAG_VENDOR:
511 			/* Vendor Data Block */
512 			show_vendor_dbc(outfile, edid_ext, dbc + 1);
513 			break;
514 
515 		case DBC_TAG_SPEAKER:
516 		{
517 			/* Speaker allocation Block */
518 			unsigned char dbcsp_alloc = edid_ext[dbp + DBCSP_ALLOC];
519 
520 			fprintf(outfile, "Speakers: %s%s%s%s%s%s%s\n",
521 				(dbcsp_alloc & 0x40) ? "RearCenter L/R " : "",
522 				(dbcsp_alloc & 0x20) ? "FrontCenter L/R " : "",
523 				(dbcsp_alloc & 0x10) ? "Rear Center" : "",
524 				(dbcsp_alloc & 0x08) ? "Rear L/R " : "",
525 				(dbcsp_alloc & 0x04) ? "Front Center " : "",
526 				(dbcsp_alloc & 0x02) ? "LFE " : "",
527 				(dbcsp_alloc & 0x01) ? "Front L/R " : "");
528 			break;
529 		}
530 
531 		case DBC_TAG_EXTENDED:
532 			show_extended_dbc(outfile, edid_ext, dbc);
533 			break;
534 
535 		default:
536 			fprintf(outfile,
537 				"Unknown Data Block type tag 0x%x, len 0x%x\n",
538 				edid_ext[dbc+DBC_TAG_LENGTH] >> DBC_TAG_SHIFT,
539 				db_len);
540 			break;
541 		}
542 
543 		dbc += db_len + 1;
544 	}
545 	for (i = 0; i < n_dtd; i++) {
546 		/* Find 0,0 when we hit padding */
547 		if ((edid_ext[off_dtd + DTD_SIZE * i + DTD_PCLK_LO] == 0) &&
548 		    (edid_ext[off_dtd + DTD_SIZE * i + DTD_PCLK_HI] == 0)) {
549 			fprintf(outfile,
550 				"End of DTD padding after %d DTDs\n", i);
551 			break;
552 		}
553 		show_edid_dtd(outfile, edid_ext + (off_dtd + DTD_SIZE * i));
554 	}
555 }
556 
557 
edid_valid(const unsigned char * edid_data)558 int edid_valid(const unsigned char *edid_data)
559 {
560 	return ((edid_data[EDID_HDR + 0] == 0x00) &&
561 		(edid_data[EDID_HDR + 1] == 0xff) &&
562 		(edid_data[EDID_HDR + 2] == 0xff) &&
563 		(edid_data[EDID_HDR + 3] == 0xff) &&
564 		(edid_data[EDID_HDR + 4] == 0xff) &&
565 		(edid_data[EDID_HDR + 5] == 0xff) &&
566 		(edid_data[EDID_HDR + 6] == 0xff) &&
567 		(edid_data[EDID_HDR + 7] == 0x00));
568 }
569 
edid_lpcm_support(const unsigned char * edid_data,int ext)570 int edid_lpcm_support(const unsigned char *edid_data, int ext)
571 {
572 	const unsigned char *edid_ext = edid_data + EDID_SIZE;
573 	int dbc;
574 	int off_dtd = edid_ext[CEA_DTD_OFFSET];
575 
576 	/* No if no extension, which can happen for two reasons */
577 	/* a) ext < 1 indicates no data was read into the extension area */
578 	/* b) edid_data[126] < 1 indicates EDID does not use extension area */
579 	if ((ext < 1) || (edid_data[EDID_EXT_FLAG] < 1))
580 		return 0;
581 
582 	/* No if extension is not CEA rev 3 */
583 	if (!((edid_ext[EEXT_TAG] == 0x02) && (edid_ext[EEXT_REV] == 0x03)))
584 		return 0;
585 
586 	/* If DBC block is not empty look for audio info */
587 	if (off_dtd <= CEA_DBC_START)
588 		goto done_dtd;
589 
590 	/* Between offset 4 and off_dtd is the Data Block Collection */
591 	/* There may be none, in which case off_dtd == 4             */
592 	dbc = CEA_DBC_START;
593 	while (dbc < off_dtd) {
594 		int db_len = edid_ext[dbc + DBC_TAG_LENGTH] & DBC_LEN_MASK;
595 		int dbp = dbc + 1;
596 		unsigned char dbc_type;
597 
598 		/* Audio Data Block, type LPCM, return bitmap of frequencies */
599 		dbc_type = edid_ext[dbc + DBC_TAG_LENGTH] >> DBC_TAG_SHIFT;
600 		if ((dbc_type == DBC_TAG_AUDIO) &&
601 		    (((edid_ext[dbp + DBCA_FORMAT]>>3) & 0xF) == DBCA_FMT_LPCM))
602 			return edid_ext[dbp + DBCA_RATE];
603 
604 		dbc += db_len + 1;
605 	}
606 	/* Get here if failed to find LPCM info in DBC block */
607 
608 done_dtd:
609 	/* Last chance is to look for Basic Audio support. Return bitmap for 32,
610 	 * 44.1, 48 */
611 	if (edid_ext[CEA_SUPPORT] & 0x40)
612 		return 0x7;
613 
614 	return 0;
615 }
616 
617 
edid_has_hdmi_info(const unsigned char * edid_data,int ext)618 int edid_has_hdmi_info(const unsigned char *edid_data, int ext)
619 {
620 	const unsigned char *edid_ext = edid_data + EDID_SIZE;
621 	int dbc;
622 	int off_dtd = edid_ext[CEA_DTD_OFFSET];
623 
624 	/* No if no extension, which can happen for two reasons */
625 	/* a) ext < 1 indicates no data was read into the extension area */
626 	/* b) edid_data[126] < 1 indicates EDID does not use extension area */
627 	if ((ext < 1) || (edid_data[EDID_EXT_FLAG] < 1))
628 		return 0;
629 
630 	/* No if extension is not CEA rev 3 */
631 	if (!((edid_ext[EEXT_TAG] == 0x02) && (edid_ext[EEXT_REV] == 0x03)))
632 		return 0;
633 
634 	/* No if block is empty */
635 	if (off_dtd < CEA_DBC_START)
636 		return 0;
637 
638 	/* Between offset 4 and off_dtd is the Data Block Collection */
639 	/* There may be none, in which case off_dtd == 4             */
640 	dbc = CEA_DBC_START;
641 	while (dbc < off_dtd) {
642 		int db_len = edid_ext[dbc + DBC_TAG_LENGTH] & DBC_LEN_MASK;
643 		int dbp = dbc + 1;
644 		unsigned char dbc_type;
645 
646 		dbc_type = edid_ext[dbc + DBC_TAG_LENGTH] >> DBC_TAG_SHIFT;
647 		if (dbc_type == DBC_TAG_VENDOR) {
648 			/* Vendor Data Block */
649 			if ((edid_ext[dbp + DBCVND_IEEE_LO] == 0x03) &&
650 			    (edid_ext[dbp + DBCVND_IEEE_MID] == 0x0C) &&
651 			    (edid_ext[dbp + DBCVND_IEEE_HI] == 0x00))
652 				return 1;
653 		}
654 		dbc += db_len + 1;
655 	}
656 	return 0;
657 }
658 
659 /* Print out an EDID */
show_edid(FILE * outfile,unsigned char * edid_data,int ext)660 void show_edid(FILE *outfile, unsigned char *edid_data, int ext)
661 {
662 	int i;
663 	int edidver = edid_data[EDID_VERSION];
664 	int edidrev = edid_data[EDID_REVISION];
665 	unsigned char *edid_ext;
666 	unsigned char edid_features;
667 
668 	if (!edid_valid(edid_data)) {
669 		fprintf(outfile, "Block does not contain EDID header\n");
670 		return;
671 	}
672 	/* unsigned edid_data so the right shifts pull in zeros */
673 	fprintf(outfile, "Manufacturer ID %c%c%c, product ID 0x%x\n",
674 		'@' + (edid_data[EDID_MFG_EID]>>2),
675 		'@' + (((edid_data[EDID_MFG_EID] & 3)<<3) +
676 			(edid_data[EDID_MFG_EID+1]>>5)),
677 		'@' + (edid_data[EDID_MFG_EID+1] & 0x1f),
678 		edid_data[EDID_MFG_PROD_LO] + (edid_data[EDID_MFG_PROD_HI]<<8));
679 	fprintf(outfile,
680 		"Manufactured wk %d of %d. Edid version %d.%d\n",
681 		edid_data[EDID_MFG_WEEK], 1990+edid_data[EDID_MFG_YEAR],
682 		edidver, edidrev);
683 	fprintf(outfile,
684 		"Input: %s, vid level %d, %s, %s %s %s %s sync, %dx%dcm, Gamma %f\n",
685 		(edid_data[EDID_VIDEO_IN] & 0x80) ? "digital" : "analog",
686 		(edid_data[EDID_VIDEO_IN]>>5) & 3,
687 		(edid_data[EDID_VIDEO_IN] & 0x10) ? "Blank to black" : "",
688 		(edid_data[EDID_VIDEO_IN] & 0x08) ? "Separate" : "",
689 		(edid_data[EDID_VIDEO_IN] & 0x04) ? "Composite" : "",
690 		(edid_data[EDID_VIDEO_IN] & 0x02) ? "On-green" : "",
691 		(edid_data[EDID_VIDEO_IN] & 0x01) ? "Serration V" : "",
692 		edid_data[EDID_MAX_HSIZE], edid_data[EDID_MAX_VSIZE],
693 		1.0+((float)edid_data[EDID_GAMMA]/100.0));
694 
695 	edid_features = edid_data[EDID_FEATURES];
696 	fprintf(outfile, "Features: %s %s %s %s %s %s %s\n",
697 		(edid_features & 0x80) ? "standby" : "",
698 		(edid_features & 0x40) ? "suspend" : "",
699 		(edid_features & 0x20) ? "active-off" : "",
700 		(edid_features & 0x18) ? "colour" : "monochrome",
701 		(edid_features & 0x04) ? "std-cspace" : "non-std-cspace",
702 		(edid_features & 0x02) ? "preferred-timing" : "",
703 		(edid_features & 0x01) ? "default-GTF" : "");
704 
705 	fprintf(outfile, "Established Timing:\n");
706 	if (edid_data[EDID_ESTTIME1] & 0x80)
707 		fprintf(outfile, "720x400@70\n");
708 	if (edid_data[EDID_ESTTIME1] & 0x40)
709 		fprintf(outfile, "720x400@88\n");
710 	if (edid_data[EDID_ESTTIME1] & 0x20)
711 		fprintf(outfile, "640x480@60\n");
712 	if (edid_data[EDID_ESTTIME1] & 0x10)
713 		fprintf(outfile, "640x480@67\n");
714 	if (edid_data[EDID_ESTTIME1] & 0x08)
715 		fprintf(outfile, "640x480@72\n");
716 	if (edid_data[EDID_ESTTIME1] & 0x04)
717 		fprintf(outfile, "640x480@75\n");
718 	if (edid_data[EDID_ESTTIME1] & 0x02)
719 		fprintf(outfile, "800x600@56\n");
720 	if (edid_data[EDID_ESTTIME1] & 0x01)
721 		fprintf(outfile, "800x600@60\n");
722 	if (edid_data[EDID_ESTTIME2] & 0x80)
723 		fprintf(outfile, "800x600@72\n");
724 	if (edid_data[EDID_ESTTIME2] & 0x40)
725 		fprintf(outfile, "800x600@75\n");
726 	if (edid_data[EDID_ESTTIME2] & 0x20)
727 		fprintf(outfile, "832x624@75\n");
728 	if (edid_data[EDID_ESTTIME2] & 0x10)
729 		fprintf(outfile, "1024x768i@87\n");
730 	if (edid_data[EDID_ESTTIME2] & 0x08)
731 		fprintf(outfile, "1024x768@60\n");
732 	if (edid_data[EDID_ESTTIME2] & 0x04)
733 		fprintf(outfile, "1024x768@70\n");
734 	if (edid_data[EDID_ESTTIME2] & 0x02)
735 		fprintf(outfile, "1024x768@75\n");
736 	if (edid_data[EDID_ESTTIME2] & 0x01)
737 		fprintf(outfile, "1280x1024@75\n");
738 	if (edid_data[EDID_MFGTIME]  & 0x80)
739 		fprintf(outfile, "1152x870@75\n");
740 
741 	fprintf(outfile, "Standard timing:\n");
742 	for (i = 0; i < EDID_N_STDTIME; i++) {
743 		int hinfo = edid_data[EDID_STDTIMEH + 2 * i];
744 		int vinfo = edid_data[EDID_STDTIMEV + 2 * i];
745 		int hres, vres;
746 
747 		/* 01 01 is pad by spec, but 00 00 and 20 20 are see in wild */
748 		if (((hinfo == 0x01) && (vinfo == 0x01)) ||
749 		    ((hinfo == 0x00) && (vinfo == 0x00)) ||
750 		    ((hinfo == 0x20) && (vinfo == 0x20)))
751 			continue;
752 		hres = (hinfo * 8) + 248;
753 		switch (vinfo >> 6) {
754 		case ASPECT_16_10:
755 			vres = (hres * 10)/16;
756 			break;
757 		case ASPECT_4_3:
758 			vres = (hres * 3)/4;
759 			break;
760 		case ASPECT_5_4:
761 			vres = (hres * 4)/5;
762 			break;
763 		case ASPECT_16_9:
764 			vres = (hres * 9)/16;
765 			break;
766 			/* Default only hit if compiler broken */
767 		default:
768 			vres = 0;
769 		}
770 		fprintf(outfile, "%d: %dx%d@%d\n",
771 			i, hres, vres, 60 + (vinfo & 0x3f));
772 	}
773 
774 	fprintf(outfile, "Descriptor blocks:\n");
775 	for (i = 0; i < EDID_N_DTDS; i++)
776 		show_edid_dtd(outfile,
777 			      edid_data + (EDID_DTD_BASE + i * DTD_SIZE));
778 	fprintf(outfile,
779 		"EDID contains %d extensions\n",
780 		edid_data[EDID_EXT_FLAG]);
781 
782 	edid_ext = edid_data + EDID_SIZE;
783 
784 	if ((ext >= 1) && (edid_data[EDID_EXT_FLAG] >= 1)) {
785 		unsigned char eext_tag = edid_ext[EEXT_TAG];
786 		if ((eext_tag == 0x02) && (edid_ext[EEXT_REV] == 0x03)) {
787 			show_cea_timing(outfile, edid_ext);
788 		} else {
789 			char *tagtype;
790 			switch (eext_tag) {
791 			case 0x01:
792 				tagtype = "LCD Timings";
793 				break;
794 			case 0x02:
795 				tagtype = "CEA";
796 				break;
797 			case 0x20:
798 				tagtype = "EDID 2.0";
799 				break;
800 			case 0x30:
801 				tagtype = "Color Information";
802 				break;
803 			case 0x40:
804 				tagtype = "DVI Feature";
805 				break;
806 			case 0x50:
807 				tagtype = "Touch Screen Map";
808 				break;
809 			case 0xF0:
810 				tagtype = "Block Map";
811 				break;
812 			case 0xFF:
813 				tagtype = "Manufacturer";
814 				break;
815 			default:
816 				tagtype = "Unknown";
817 			}
818 			fprintf(outfile,
819 				"EDID %s ext tag 0x%02x rev 0x%02x skipped\n",
820 				tagtype,
821 				edid_ext[EEXT_TAG],
822 				edid_ext[EEXT_REV]);
823 		}
824 	}
825 }
826 
827 
828 /* Pixel counts normally round to 8 */
829 #define CLOSE_ENOUGH(a, b) (abs((a)-(b)) < 16)
830 
831 /* These match order of defines ASPECT_x_y in edid_utils.h */
832 char *aspect_to_str[]={"16:10","4:3","5:4","16:9"};
833 
find_aspect(int h,int v)834 int find_aspect(int h, int v)
835 {
836 	if (CLOSE_ENOUGH((h * 3), (v * 4)))
837 		return ASPECT_4_3;
838 	if (CLOSE_ENOUGH((h * 4), (v * 5)))
839 		return ASPECT_5_4;
840 	if (CLOSE_ENOUGH((h * 9), (v * 16)))
841 		return ASPECT_16_9;
842 	if (CLOSE_ENOUGH((h * 10), (v * 16)))
843 		return ASPECT_16_10;
844 
845 	return -1;
846 }
847 
find_aspect_fromisize(unsigned char * edid_data)848 int find_aspect_fromisize(unsigned char *edid_data)
849 {
850 	int hsiz = edid_data[EDID_MAX_HSIZE];
851 	int vsiz = edid_data[EDID_MAX_VSIZE];
852 	int res;
853 
854 	/* Zero size for projector */
855 	/* Only use this code if there was no preferred resolution */
856 	/* So assume it is an older 4:3 projector not a video one  */
857 	if ((hsiz == 0) && (vsiz == 0))
858 		return ASPECT_4_3;
859 
860 	res = find_aspect(hsiz, vsiz);
861 
862 	/* If things didn't work out, assume the old 4:3 case */
863 	if (res < 0)
864 		return ASPECT_4_3;
865 	else
866 		return res;
867 }
868 
edid_get_monitor_name(const unsigned char * edid_data,char * buf,unsigned int buf_size)869 int edid_get_monitor_name(const unsigned char *edid_data,
870 			  char *buf,
871 			  unsigned int buf_size)
872 {
873 	int i;
874 	const unsigned char *dtd;
875 
876 	for (i = 0; i < EDID_N_DTDS; i++) {
877 		dtd = edid_data + (EDID_DTD_BASE + i * DTD_SIZE);
878 		if (dtd[DTD_PCLK_LO] == 0x00 && dtd[DTD_PCLK_HI] == 0x00 &&
879 		    dtd[DTD_TYPETAG] == DTDTYPE_NAME) {
880 			get_dtd_string((const char *)dtd + DTD_STRING,
881 				       buf, buf_size);
882 			return 0;
883 		}
884 	}
885 
886 	return -1;
887 }
888