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