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 <ctype.h>
22 #include <string.h>
23
24
25 //
26 // from hereon a bunch of decoders follow for each EDID section
27 //
28
29 static void
decode_vendor(edid1_vendor * vendor,const edid1_vendor_raw * raw)30 decode_vendor(edid1_vendor *vendor, const edid1_vendor_raw *raw)
31 {
32 vendor->manufacturer[0] = raw->c1 + '@';
33 vendor->manufacturer[1] = ((raw->c2_high << 3) | raw->c2_low) + '@';
34 vendor->manufacturer[2] = raw->c3 + '@';
35 vendor->manufacturer[3] = 0;
36 vendor->prod_id = B_LENDIAN_TO_HOST_INT16(raw->prod_id);
37 vendor->serial = B_LENDIAN_TO_HOST_INT32(raw->serial);
38 vendor->week = raw->week;
39 vendor->year = raw->year + 1990;
40 }
41
42
43 static void
decode_version(edid1_version * version,const edid1_version_raw * raw)44 decode_version(edid1_version *version, const edid1_version_raw *raw)
45 {
46 version->version = raw->version;
47 version->revision = raw->revision;
48 }
49
50
51 static void
decode_display(edid1_display * display,const edid1_display_raw * raw)52 decode_display(edid1_display *display, const edid1_display_raw *raw)
53 {
54 // We need to dig into one of the union to get the first
55 // bit which should always align. then we can pick the right
56 // data structure to parse.
57 display->input_type = raw->analog_params.input_type;
58
59 if (display->input_type != 0) {
60 // digital
61 display->digital_params.bit_depth = 0;
62 if (raw->digital_params.bit_depth > 0 && raw->digital_params.bit_depth < 7)
63 display->digital_params.bit_depth = raw->digital_params.bit_depth * 2 + 4;
64 display->digital_params.interface = raw->digital_params.interface;
65 } else {
66 // analog
67 display->analog_params.input_voltage = raw->analog_params.input_voltage;
68 display->analog_params.setup = raw->analog_params.setup;
69 display->analog_params.sep_sync = raw->analog_params.sep_sync;
70 display->analog_params.comp_sync = raw->analog_params.comp_sync;
71 display->analog_params.sync_on_green = raw->analog_params.sync_on_green;
72 display->analog_params.sync_serr = raw->analog_params.sync_serr;
73 }
74
75 display->h_size = raw->h_size;
76 display->v_size = raw->v_size;
77 display->gamma = raw->gamma;
78
79 display->dpms_standby = raw->dpms_standby;
80 display->dpms_suspend = raw->dpms_suspend;
81 display->dpms_off = raw->dpms_off;
82 display->display_type = raw->display_type;
83 display->std_colour_space = raw->std_colour_space;
84 display->preferred_timing_mode = raw->preferred_timing_mode;
85 display->gtf_supported = raw->gtf_supported;
86
87 display->red_x = ((uint16)raw->red_x << 2) | raw->red_x_low;
88 display->red_y = ((uint16)raw->red_y << 2) | raw->red_y_low;
89 display->green_x = ((uint16)raw->green_x << 2) | raw->green_x_low;
90 display->green_y = ((uint16)raw->green_y << 2) | raw->green_y_low;
91 display->blue_x = ((uint16)raw->blue_x << 2) | raw->blue_x_low;
92 display->blue_y = ((uint16)raw->blue_y << 2) | raw->blue_y_low;
93 display->white_x = ((uint16)raw->white_x << 2) | raw->white_x_low;
94 display->white_y = ((uint16)raw->white_y << 2) | raw->white_y_low;
95 }
96
97
98 static void
decode_std_timing(edid1_std_timing * timing,const edid1_std_timing_raw * raw)99 decode_std_timing(edid1_std_timing *timing, const edid1_std_timing_raw *raw)
100 {
101 timing->h_size = (raw->timing.h_size + 31) * 8;
102 timing->ratio = raw->timing.ratio;
103
104 switch (raw->timing.ratio) {
105 case 0:
106 timing->v_size = timing->h_size;
107 break;
108
109 case 1:
110 timing->v_size = timing->h_size * 3 / 4;
111 break;
112
113 case 2:
114 timing->v_size = timing->h_size * 4 / 5;
115 break;
116
117 case 3:
118 timing->v_size = timing->h_size * 9 / 16;
119 break;
120 }
121 timing->refresh = raw->timing.refresh + 60;
122 timing->id = raw->id;
123 }
124
125
126 static void
decode_whitepoint(edid1_whitepoint * whitepoint,const edid1_whitepoint_raw * raw)127 decode_whitepoint(edid1_whitepoint *whitepoint, const edid1_whitepoint_raw *raw)
128 {
129 whitepoint[0].index = raw->index1;
130 whitepoint[0].white_x = ((uint16)raw->white_x1 << 2) | raw->white_x1_low;
131 whitepoint[0].white_y = ((uint16)raw->white_y1 << 2) | raw->white_y1_low;
132 whitepoint[0].gamma = raw->gamma1;
133
134 whitepoint[1].index = raw->index2;
135 whitepoint[1].white_x = ((uint16)raw->white_x2 << 2) | raw->white_x2_low;
136 whitepoint[1].white_y = ((uint16)raw->white_y2 << 2) | raw->white_y2_low;
137 whitepoint[1].gamma = raw->gamma2;
138 }
139
140
141 static void
decode_detailed_timing(edid1_detailed_timing * timing,const edid1_detailed_timing_raw * raw)142 decode_detailed_timing(edid1_detailed_timing *timing,
143 const edid1_detailed_timing_raw *raw)
144 {
145 timing->pixel_clock = raw->pixel_clock;
146 timing->h_active = ((uint16)raw->h_active_high << 8) | raw->h_active;
147 timing->h_blank = ((uint16)raw->h_blank_high << 8) | raw->h_blank;
148 timing->v_active = ((uint16)raw->v_active_high << 8) | raw->v_active;
149 timing->v_blank = ((uint16)raw->v_blank_high << 8) | raw->v_blank;
150 timing->h_sync_off = ((uint16)raw->h_sync_off_high << 8) | raw->h_sync_off;
151 timing->h_sync_width = ((uint16)raw->h_sync_width_high << 8) | raw->h_sync_width;
152 timing->v_sync_off = ((uint16)raw->v_sync_off_high << 4) | raw->v_sync_off;
153 timing->v_sync_width = ((uint16)raw->v_sync_width_high << 4) | raw->v_sync_width;
154 timing->h_size = ((uint16)raw->h_size_high << 8) | raw->h_size;
155 timing->v_size = ((uint16)raw->v_size_high << 8) | raw->v_size;
156 timing->h_border = raw->h_border;
157 timing->v_border = raw->v_border;
158 timing->interlaced = raw->interlaced;
159 timing->stereo = raw->stereo;
160 timing->sync = raw->sync;
161 timing->misc = raw->misc;
162 }
163
164
165 //! copy string until 0xa, removing trailing spaces
166 static void
copy_str(char * dest,const uint8 * src,size_t len)167 copy_str(char *dest, const uint8 *src, size_t len)
168 {
169 uint32 i;
170
171 // copy until 0xa
172 for (i = 0; i < len; i++) {
173 if (*src == 0xa)
174 break;
175 if (!isgraph(*src) && *src != 0x20)
176 break;
177 *dest++ = *src++;
178 }
179
180 // remove trailing spaces
181 while (i-- > 0) {
182 if (*(dest - 1) != ' ')
183 break;
184
185 dest--;
186 }
187
188 *dest = '\0';
189 }
190
191
192 static void
decode_detailed_monitor(edid1_detailed_monitor * monitor,const edid1_detailed_monitor_raw * raw,bool enableExtra)193 decode_detailed_monitor(edid1_detailed_monitor *monitor,
194 const edid1_detailed_monitor_raw *raw, bool enableExtra)
195 {
196 int i, j;
197
198 for (i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i, ++monitor, ++raw) {
199
200 // workaround: normally, all four bytes must be zero for detailed
201 // description, but at least some Formac monitors violate that:
202 // they have some additional info that start at zero_4(!),
203 // so even if only the first two _or_ the other two bytes are
204 // zero, we accept it as a monitor description block
205 if (enableExtra
206 && ((raw->extra.zero_0[0] == 0 && raw->extra.zero_0[1] == 0)
207 || (raw->extra.zero_0[2] == 0 && raw->extra.zero_4 == 0))) {
208 monitor->monitor_desc_type = raw->extra.monitor_desc_type;
209
210 switch (raw->extra.monitor_desc_type) {
211 case EDID1_SERIAL_NUMBER:
212 copy_str(monitor->data.serial_number,
213 raw->extra.data.serial_number, EDID1_EXTRA_STRING_LEN);
214 break;
215
216 case EDID1_ASCII_DATA:
217 copy_str(monitor->data.ascii_data,
218 raw->extra.data.ascii_data, EDID1_EXTRA_STRING_LEN);
219 break;
220
221 case EDID1_MONITOR_RANGES:
222 monitor->data.monitor_range = raw->extra.data.monitor_range;
223 break;
224
225 case EDID1_MONITOR_NAME:
226 copy_str(monitor->data.monitor_name,
227 raw->extra.data.monitor_name, EDID1_EXTRA_STRING_LEN);
228 break;
229
230 case EDID1_ADD_COLOUR_POINTER:
231 decode_whitepoint(monitor->data.whitepoint,
232 &raw->extra.data.whitepoint);
233 break;
234
235 case EDID1_ADD_STD_TIMING:
236 for (j = 0; j < EDID1_NUM_EXTRA_STD_TIMING; ++j) {
237 decode_std_timing(&monitor->data.std_timing[j],
238 &raw->extra.data.std_timing[j]);
239 }
240 break;
241 }
242 } else if (raw->detailed_timing.pixel_clock > 0) {
243 monitor->monitor_desc_type = EDID1_IS_DETAILED_TIMING;
244 decode_detailed_timing(&monitor->data.detailed_timing,
245 &raw->detailed_timing);
246 }
247 }
248 }
249
250
251 static void
decode_cta_block(edid1_info * edid,const cta_raw * raw)252 decode_cta_block(edid1_info *edid, const cta_raw *raw)
253 {
254 unsigned int i, j;
255
256 edid->cta_block.tag = raw->tag;
257 edid->cta_block.revision = raw->revision;
258 edid->cta_block.num_native_detailed = raw->num_native_detailed;
259 edid->cta_block.ycbcr422_supported = raw->ycbcr422;
260 edid->cta_block.ycbcr444_supported = raw->ycbcr444;
261 edid->cta_block.audio_supported = raw->audio;
262 edid->cta_block.underscan = raw->underscan;
263 edid->cta_block.num_data_blocks = 0;
264
265 for (i = 4; i < raw->offset;) {
266 cta_data_block* block = (cta_data_block*)&((uint8*)raw)[i];
267 memcpy(&edid->cta_block.data_blocks[edid->cta_block.num_data_blocks++],
268 block, block->length + 1);
269 i += block->length + 1;
270 }
271
272 for (i = raw->offset, j = 0; i + sizeof(edid1_detailed_timing_raw) - 1 < 128;
273 i += sizeof(edid1_detailed_timing_raw), j++) {
274 const edid1_detailed_timing_raw* timing =
275 (const edid1_detailed_timing_raw*)&((uint8*)raw)[i];
276 decode_detailed_timing(&edid->cta_block.detailed_timing[j], timing);
277 }
278 }
279
280
281 static void
decode_displayid_block(edid1_info * edid,const displayid_raw * raw)282 decode_displayid_block(edid1_info *edid, const displayid_raw *raw)
283 {
284 edid->displayid_block.tag = raw->tag;
285 edid->displayid_block.version = raw->version;
286 edid->displayid_block.extension_count = raw->extension_count;
287 }
288
289
290 // #pragma mark -
291
292
293 //! Main function to decode edid data
294 void
edid_decode(edid1_info * edid,const edid1_raw * raw)295 edid_decode(edid1_info *edid, const edid1_raw *raw)
296 {
297 int i;
298 memset(edid, 0, sizeof(edid1_info));
299
300 decode_vendor(&edid->vendor, &raw->vendor);
301 decode_version(&edid->version, &raw->version);
302 decode_display(&edid->display, &raw->display);
303
304 edid->established_timing = raw->established_timing;
305
306 for (i = 0; i < EDID1_NUM_STD_TIMING; ++i) {
307 decode_std_timing(&edid->std_timing[i], &raw->std_timing[i]);
308 }
309
310 decode_detailed_monitor(edid->detailed_monitor, raw->detailed_monitor,
311 edid->version.version == 1 && edid->version.revision >= 1);
312
313 edid->num_sections = raw->num_sections;
314
315 for (i = 1; i < 1 + edid->num_sections; i++) {
316 cta_raw* cta = (cta_raw*)&raw[i];
317 switch (cta->tag) {
318 case 0x2:
319 decode_cta_block(edid, cta);
320 break;
321 case 0x70:
322 decode_displayid_block(edid, (displayid_raw*)&raw[i]);
323 break;
324 default:
325 //printf("edid_decode unknown tag 0x%x\n", cta->tag);
326 break;
327 }
328 }
329 }
330