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