2 * Copyright 2003, Thomas Kurschel. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
12 The EDID information is tightly packed; this file takes care of
13 converting it to a usable structure.
19 #include <KernelExport.h>
25 // from hereon a bunch of decoders follow for each EDID section
29 decode_vendor(edid1_vendor
*vendor
, const edid1_vendor_raw
*raw
)
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;
43 decode_version(edid1_version
*version
, const edid1_version_raw
*raw
)
45 version
->version
= raw
->version
;
46 version
->revision
= raw
->revision
;
51 decode_display(edid1_display
*display
, const edid1_display_raw
*raw
)
53 display
->input_type
= raw
->input_type
;
54 display
->input_voltage
= raw
->input_voltage
;
55 display
->setup
= raw
->setup
;
56 display
->sep_sync
= raw
->sep_sync
;
57 display
->comp_sync
= raw
->comp_sync
;
58 display
->sync_on_green
= raw
->sync_on_green
;
59 display
->sync_serr
= raw
->sync_serr
;
61 display
->h_size
= raw
->h_size
;
62 display
->v_size
= raw
->v_size
;
63 display
->gamma
= raw
->gamma
;
65 display
->dpms_standby
= raw
->dpms_standby
;
66 display
->dpms_suspend
= raw
->dpms_suspend
;
67 display
->dpms_off
= raw
->dpms_off
;
68 display
->display_type
= raw
->display_type
;
69 display
->std_colour_space
= raw
->std_colour_space
;
70 display
->preferred_timing_mode
= raw
->preferred_timing_mode
;
71 display
->gtf_supported
= raw
->gtf_supported
;
73 display
->red_x
= ((uint16
)raw
->red_x
<< 2) | raw
->red_x_low
;
74 display
->red_y
= ((uint16
)raw
->red_y
<< 2) | raw
->red_y_low
;
75 display
->green_x
= ((uint16
)raw
->green_x
<< 2) | raw
->green_x_low
;
76 display
->green_y
= ((uint16
)raw
->green_y
<< 2) | raw
->green_y_low
;
77 display
->blue_x
= ((uint16
)raw
->blue_x
<< 2) | raw
->blue_x_low
;
78 display
->blue_y
= ((uint16
)raw
->blue_y
<< 2) | raw
->blue_y_low
;
79 display
->white_x
= ((uint16
)raw
->white_x
<< 2) | raw
->white_x_low
;
80 display
->white_y
= ((uint16
)raw
->white_y
<< 2) | raw
->white_y_low
;
85 decode_std_timing(edid1_std_timing
*timing
, const edid1_std_timing_raw
*raw
)
87 timing
->h_size
= (raw
->timing
.h_size
+ 31) * 8;
88 timing
->ratio
= raw
->timing
.ratio
;
90 switch (raw
->timing
.ratio
) {
92 timing
->v_size
= timing
->h_size
;
96 timing
->v_size
= timing
->h_size
* 3 / 4;
100 timing
->v_size
= timing
->h_size
* 4 / 5;
104 timing
->v_size
= timing
->h_size
* 9 / 16;
107 timing
->refresh
= raw
->timing
.refresh
+ 60;
108 timing
->id
= raw
->id
;
113 decode_whitepoint(edid1_whitepoint
*whitepoint
, const edid1_whitepoint_raw
*raw
)
115 whitepoint
[0].index
= raw
->index1
;
116 whitepoint
[0].white_x
= ((uint16
)raw
->white_x1
<< 2) | raw
->white_x1_low
;
117 whitepoint
[0].white_y
= ((uint16
)raw
->white_y1
<< 2) | raw
->white_y1_low
;
118 whitepoint
[0].gamma
= raw
->gamma1
;
120 whitepoint
[1].index
= raw
->index2
;
121 whitepoint
[1].white_x
= ((uint16
)raw
->white_x2
<< 2) | raw
->white_x2_low
;
122 whitepoint
[1].white_y
= ((uint16
)raw
->white_y2
<< 2) | raw
->white_y2_low
;
123 whitepoint
[1].gamma
= raw
->gamma2
;
128 decode_detailed_timing(edid1_detailed_timing
*timing
,
129 const edid1_detailed_timing_raw
*raw
)
131 timing
->pixel_clock
= raw
->pixel_clock
;
132 timing
->h_active
= ((uint16
)raw
->h_active_high
<< 8) | raw
->h_active
;
133 timing
->h_blank
= ((uint16
)raw
->h_blank_high
<< 8) | raw
->h_blank
;
134 timing
->v_active
= ((uint16
)raw
->v_active_high
<< 8) | raw
->v_active
;
135 timing
->v_blank
= ((uint16
)raw
->v_blank_high
<< 8) | raw
->v_blank
;
136 timing
->h_sync_off
= ((uint16
)raw
->h_sync_off_high
<< 8) | raw
->h_sync_off
;
137 timing
->h_sync_width
= ((uint16
)raw
->h_sync_width_high
<< 8) | raw
->h_sync_width
;
138 timing
->v_sync_off
= ((uint16
)raw
->v_sync_off_high
<< 4) | raw
->v_sync_off
;
139 timing
->v_sync_width
= ((uint16
)raw
->v_sync_width_high
<< 4) | raw
->v_sync_width
;
140 timing
->h_size
= ((uint16
)raw
->h_size_high
<< 8) | raw
->h_size
;
141 timing
->v_size
= ((uint16
)raw
->v_size_high
<< 8) | raw
->v_size
;
142 timing
->h_border
= raw
->h_border
;
143 timing
->v_border
= raw
->v_border
;
144 timing
->interlaced
= raw
->interlaced
;
145 timing
->stereo
= raw
->stereo
;
146 timing
->sync
= raw
->sync
;
147 timing
->misc
= raw
->misc
;
151 //! copy string until 0xa, removing trailing spaces
153 copy_str(char *dest
, const uint8
*src
, size_t len
)
158 for (i
= 0; i
< len
; i
++) {
165 // remove trailing spaces
167 if (*(dest
- 1) != ' ')
178 decode_detailed_monitor(edid1_detailed_monitor
*monitor
,
179 const edid1_detailed_monitor_raw
*raw
, bool enableExtra
)
183 for (i
= 0; i
< EDID1_NUM_DETAILED_MONITOR_DESC
; ++i
, ++monitor
, ++raw
) {
185 // workaround: normally, all four bytes must be zero for detailed
186 // description, but at least some Formac monitors violate that:
187 // they have some additional info that start at zero_4(!),
188 // so even if only the first two _or_ the other two bytes are
189 // zero, we accept it as a monitor description block
191 && ((raw
->extra
.zero_0
[0] == 0 && raw
->extra
.zero_0
[1] == 0)
192 || (raw
->extra
.zero_0
[2] == 0 && raw
->extra
.zero_4
== 0))) {
193 monitor
->monitor_desc_type
= raw
->extra
.monitor_desc_type
;
195 switch (raw
->extra
.monitor_desc_type
) {
196 case EDID1_SERIAL_NUMBER
:
197 copy_str(monitor
->data
.serial_number
,
198 raw
->extra
.data
.serial_number
, EDID1_EXTRA_STRING_LEN
);
201 case EDID1_ASCII_DATA
:
202 copy_str(monitor
->data
.ascii_data
,
203 raw
->extra
.data
.ascii_data
, EDID1_EXTRA_STRING_LEN
);
206 case EDID1_MONITOR_RANGES
:
207 monitor
->data
.monitor_range
= raw
->extra
.data
.monitor_range
;
210 case EDID1_MONITOR_NAME
:
211 copy_str(monitor
->data
.monitor_name
,
212 raw
->extra
.data
.monitor_name
, EDID1_EXTRA_STRING_LEN
);
215 case EDID1_ADD_COLOUR_POINTER
:
216 decode_whitepoint(monitor
->data
.whitepoint
,
217 &raw
->extra
.data
.whitepoint
);
220 case EDID1_ADD_STD_TIMING
:
221 for (j
= 0; j
< EDID1_NUM_EXTRA_STD_TIMING
; ++j
) {
222 decode_std_timing(&monitor
->data
.std_timing
[j
],
223 &raw
->extra
.data
.std_timing
[j
]);
227 } else if (raw
->detailed_timing
.pixel_clock
> 0) {
228 monitor
->monitor_desc_type
= EDID1_IS_DETAILED_TIMING
;
229 decode_detailed_timing(&monitor
->data
.detailed_timing
,
230 &raw
->detailed_timing
);
239 //! Main function to decode edid data
241 edid_decode(edid1_info
*edid
, const edid1_raw
*raw
)
244 memset(edid
, 0, sizeof(edid1_info
));
246 decode_vendor(&edid
->vendor
, &raw
->vendor
);
247 decode_version(&edid
->version
, &raw
->version
);
248 decode_display(&edid
->display
, &raw
->display
);
250 edid
->established_timing
= raw
->established_timing
;
252 for (i
= 0; i
< EDID1_NUM_STD_TIMING
; ++i
) {
253 decode_std_timing(&edid
->std_timing
[i
], &raw
->std_timing
[i
]);
256 decode_detailed_monitor(edid
->detailed_monitor
, raw
->detailed_monitor
,
257 edid
->version
.version
== 1 && edid
->version
.revision
>= 1);