xref: /haiku/src/add-ons/accelerants/common/decode_edid.c (revision 9e25244c5e9051f6cd333820d6332397361abd6c)
1 /*
2  * Copyright 2003, Thomas Kurschel. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 /*!
8 	Part of DDC driver
9 
10 	EDID decoder.
11 
12 	The EDID information is tightly packed; this file takes care of
13 	converting it to a usable structure.
14 */
15 
16 
17 #include "edid.h"
18 
19 #include <KernelExport.h>
20 
21 #include <string.h>
22 
23 
24 //
25 // from hereon a bunch of decoders follow for each EDID section
26 //
27 
28 static void
29 decode_vendor(edid1_vendor *vendor, const edid1_vendor_raw *raw)
30 {
31 	vendor->manufacturer[0] = raw->c1 + '@';
32 	vendor->manufacturer[1] = ((raw->c2_high << 3) | raw->c2_low) + '@';
33 	vendor->manufacturer[2] = raw->c3 + '@';
34 	vendor->manufacturer[3] = 0;
35 	vendor->prod_id = B_LENDIAN_TO_HOST_INT16(raw->prod_id);
36 	vendor->serial = B_LENDIAN_TO_HOST_INT32(raw->serial);
37 	vendor->week = raw->week;
38 	vendor->year = raw->year + 1990;
39 }
40 
41 
42 static void
43 decode_version(edid1_version *version, const edid1_version_raw *raw)
44 {
45 	version->version = raw->version;
46 	version->revision = raw->revision;
47 }
48 
49 
50 static void
51 decode_display(edid1_display *display, const edid1_display_raw *raw)
52 {
53 	// We need to dig into one of the union to get the first
54 	// bit which should always align. then we can pick the right
55 	// data structure to parse.
56 	display->input_type = raw->analog_params.input_type;
57 
58 	if (display->input_type != 0) {
59 		// digital
60 		display->digital_params.bit_depth = 0;
61 		if (raw->digital_params.bit_depth > 0 && raw->digital_params.bit_depth < 7)
62 			display->digital_params.bit_depth = raw->digital_params.bit_depth * 2 + 4;
63 		display->digital_params.interface = raw->digital_params.interface;
64 	} else {
65 		// analog
66 		display->analog_params.input_voltage = raw->analog_params.input_voltage;
67 		display->analog_params.setup = raw->analog_params.setup;
68 		display->analog_params.sep_sync = raw->analog_params.sep_sync;
69 		display->analog_params.comp_sync = raw->analog_params.comp_sync;
70 		display->analog_params.sync_on_green = raw->analog_params.sync_on_green;
71 		display->analog_params.sync_serr = raw->analog_params.sync_serr;
72 	}
73 
74 	display->h_size = raw->h_size;
75 	display->v_size = raw->v_size;
76 	display->gamma = raw->gamma;
77 
78 	display->dpms_standby = raw->dpms_standby;
79 	display->dpms_suspend = raw->dpms_suspend;
80 	display->dpms_off = raw->dpms_off;
81 	display->display_type = raw->display_type;
82 	display->std_colour_space = raw->std_colour_space;
83 	display->preferred_timing_mode = raw->preferred_timing_mode;
84 	display->gtf_supported = raw->gtf_supported;
85 
86 	display->red_x = ((uint16)raw->red_x << 2) | raw->red_x_low;
87 	display->red_y = ((uint16)raw->red_y << 2) | raw->red_y_low;
88 	display->green_x = ((uint16)raw->green_x << 2) | raw->green_x_low;
89 	display->green_y = ((uint16)raw->green_y << 2) | raw->green_y_low;
90 	display->blue_x = ((uint16)raw->blue_x << 2) | raw->blue_x_low;
91 	display->blue_y = ((uint16)raw->blue_y << 2) | raw->blue_y_low;
92 	display->white_x = ((uint16)raw->white_x << 2) | raw->white_x_low;
93 	display->white_y = ((uint16)raw->white_y << 2) | raw->white_y_low;
94 }
95 
96 
97 static void
98 decode_std_timing(edid1_std_timing *timing, const edid1_std_timing_raw *raw)
99 {
100 	timing->h_size = (raw->timing.h_size + 31) * 8;
101 	timing->ratio = raw->timing.ratio;
102 
103 	switch (raw->timing.ratio) {
104 		case 0:
105 			timing->v_size = timing->h_size;
106 			break;
107 
108 		case 1:
109 			timing->v_size = timing->h_size * 3 / 4;
110 			break;
111 
112 		case 2:
113 			timing->v_size = timing->h_size * 4 / 5;
114 			break;
115 
116 		case 3:
117 			timing->v_size = timing->h_size * 9 / 16;
118 			break;
119 	}
120 	timing->refresh = raw->timing.refresh + 60;
121 	timing->id = raw->id;
122 }
123 
124 
125 static void
126 decode_whitepoint(edid1_whitepoint *whitepoint, const edid1_whitepoint_raw *raw)
127 {
128 	whitepoint[0].index = raw->index1;
129 	whitepoint[0].white_x = ((uint16)raw->white_x1 << 2) | raw->white_x1_low;
130 	whitepoint[0].white_y = ((uint16)raw->white_y1 << 2) | raw->white_y1_low;
131 	whitepoint[0].gamma = raw->gamma1;
132 
133 	whitepoint[1].index = raw->index2;
134 	whitepoint[1].white_x = ((uint16)raw->white_x2 << 2) | raw->white_x2_low;
135 	whitepoint[1].white_y = ((uint16)raw->white_y2 << 2) | raw->white_y2_low;
136 	whitepoint[1].gamma = raw->gamma2;
137 }
138 
139 
140 static void
141 decode_detailed_timing(edid1_detailed_timing *timing,
142 	const edid1_detailed_timing_raw *raw)
143 {
144 	timing->pixel_clock = raw->pixel_clock;
145 	timing->h_active = ((uint16)raw->h_active_high << 8) | raw->h_active;
146 	timing->h_blank = ((uint16)raw->h_blank_high << 8) | raw->h_blank;
147 	timing->v_active = ((uint16)raw->v_active_high << 8) | raw->v_active;
148 	timing->v_blank = ((uint16)raw->v_blank_high << 8) | raw->v_blank;
149 	timing->h_sync_off = ((uint16)raw->h_sync_off_high << 8) | raw->h_sync_off;
150 	timing->h_sync_width = ((uint16)raw->h_sync_width_high << 8) | raw->h_sync_width;
151 	timing->v_sync_off = ((uint16)raw->v_sync_off_high << 4) | raw->v_sync_off;
152 	timing->v_sync_width = ((uint16)raw->v_sync_width_high << 4) | raw->v_sync_width;
153 	timing->h_size = ((uint16)raw->h_size_high << 8) | raw->h_size;
154 	timing->v_size = ((uint16)raw->v_size_high << 8) | raw->v_size;
155 	timing->h_border = raw->h_border;
156 	timing->v_border = raw->v_border;
157 	timing->interlaced = raw->interlaced;
158 	timing->stereo = raw->stereo;
159 	timing->sync = raw->sync;
160 	timing->misc = raw->misc;
161 }
162 
163 
164 //! copy string until 0xa, removing trailing spaces
165 static void
166 copy_str(char *dest, const uint8 *src, size_t len)
167 {
168 	uint32 i;
169 
170 	// copy until 0xa
171 	for (i = 0; i < len; i++) {
172 		if (*src == 0xa)
173 			break;
174 
175 		*dest++ = *src++;
176 	}
177 
178 	// remove trailing spaces
179 	while (i-- > 0) {
180 		if (*(dest - 1) != ' ')
181 			break;
182 
183 		dest--;
184 	}
185 
186 	*dest = '\0';
187 }
188 
189 
190 static void
191 decode_detailed_monitor(edid1_detailed_monitor *monitor,
192 	const edid1_detailed_monitor_raw *raw, bool enableExtra)
193 {
194 	int i, j;
195 
196 	for (i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i, ++monitor, ++raw) {
197 
198 		// workaround: normally, all four bytes must be zero for detailed
199 		// description, but at least some Formac monitors violate that:
200 		// they have some additional info that start at zero_4(!),
201 		// so even if only the first two _or_ the other two bytes are
202 		// zero, we accept it as a monitor description block
203 		if (enableExtra
204 			&& ((raw->extra.zero_0[0] == 0 && raw->extra.zero_0[1] == 0)
205 				|| (raw->extra.zero_0[2] == 0 && raw->extra.zero_4 == 0))) {
206 			monitor->monitor_desc_type = raw->extra.monitor_desc_type;
207 
208 			switch (raw->extra.monitor_desc_type) {
209 				case EDID1_SERIAL_NUMBER:
210 					copy_str(monitor->data.serial_number,
211 						raw->extra.data.serial_number, EDID1_EXTRA_STRING_LEN);
212 					break;
213 
214 				case EDID1_ASCII_DATA:
215 					copy_str(monitor->data.ascii_data,
216 						raw->extra.data.ascii_data, EDID1_EXTRA_STRING_LEN);
217 					break;
218 
219 				case EDID1_MONITOR_RANGES:
220 					monitor->data.monitor_range = raw->extra.data.monitor_range;
221 					break;
222 
223 				case EDID1_MONITOR_NAME:
224 					copy_str(monitor->data.monitor_name,
225 						raw->extra.data.monitor_name, EDID1_EXTRA_STRING_LEN);
226 					break;
227 
228 				case EDID1_ADD_COLOUR_POINTER:
229 					decode_whitepoint(monitor->data.whitepoint,
230 						&raw->extra.data.whitepoint);
231 					break;
232 
233 				case EDID1_ADD_STD_TIMING:
234 					for (j = 0; j < EDID1_NUM_EXTRA_STD_TIMING; ++j) {
235 						decode_std_timing(&monitor->data.std_timing[j],
236 							&raw->extra.data.std_timing[j]);
237 					}
238 					break;
239 			}
240 		} else if (raw->detailed_timing.pixel_clock > 0) {
241 			monitor->monitor_desc_type = EDID1_IS_DETAILED_TIMING;
242 			decode_detailed_timing(&monitor->data.detailed_timing,
243 				&raw->detailed_timing);
244 		}
245 	}
246 }
247 
248 
249 //	#pragma mark -
250 
251 
252 //!	Main function to decode edid data
253 void
254 edid_decode(edid1_info *edid, const edid1_raw *raw)
255 {
256 	int i;
257 	memset(edid, 0, sizeof(edid1_info));
258 
259 	decode_vendor(&edid->vendor, &raw->vendor);
260 	decode_version(&edid->version, &raw->version);
261 	decode_display(&edid->display, &raw->display);
262 
263 	edid->established_timing = raw->established_timing;
264 
265 	for (i = 0; i < EDID1_NUM_STD_TIMING; ++i) {
266 		decode_std_timing(&edid->std_timing[i], &raw->std_timing[i]);
267 	}
268 
269 	decode_detailed_monitor(edid->detailed_monitor, raw->detailed_monitor,
270 		edid->version.version == 1 && edid->version.revision >= 1);
271 }
272